Merge pull request #572 from PowerShell/self-host

Enable self-hosting
This commit is contained in:
Andy Schwartzmeyer
2016-02-22 15:12:04 -08:00
9 changed files with 297 additions and 137 deletions
+160
View File
@@ -0,0 +1,160 @@
# TODO: use PowerShell to check OS when available
try {
$Runtime = [System.Runtime.InteropServices.RuntimeInformation]
$OSPlatform = [System.Runtime.InteropServices.OSPlatform]
$Linux = $Runtime::IsOSPlatform($OSPlatform::Linux)
$OSX = $Runtime::IsOSPlatform($OSPlatform::OSX)
$Windows = $Runtime::IsOSPlatform($OSPlatform::Windows)
} catch [System.Management.Automation.RuntimeException] {
$Linux = $false
$OSX = $false
$Windows = $true
}
function Start-PSBuild
{
param(
[switch]$Restore,
[string]$Output = "$PSScriptRoot/bin"
)
if (-Not (Get-Command "dotnet" -ErrorAction SilentlyContinue)) {
throw "Build dependency 'dotnet' not found in PATH! See: https://dotnet.github.io/getting-started/"
}
New-Item -Force -Type Directory $Output | Out-Null
$Top = "$PSScriptRoot/src/Microsoft.PowerShell.Linux.Host"
if ($Restore -Or -Not (Test-Path "$Top/project.lock.json")) {
dotnet restore
}
if ($Linux -Or $OSX) {
$InstallCommand = if ($Linux) { "apt-get" } elseif ($OSX) { "brew" }
foreach ($Dependency in "cmake", "g++") {
if (-Not (Get-Command $Dependency -ErrorAction SilentlyContinue)) {
throw "Build dependency '$Dependency' not found in PATH! Run '$InstallCommand install $Dependency'"
}
}
$Ext = if ($Linux) { "so" } elseif ($OSX) { "dylib" }
$Lib = "src/libpsl-native.$Ext"
Write-Host "Building $Lib"
pushd "src/libpsl-native"
cmake -DCMAKE_BUILD_TYPE=Debug .
make -j
ctest -V
if (-Not (Test-Path $Lib)) { throw "Compilation of $Lib failed" }
cp $Lib $Output
popd
}
Write-Host "Building PowerShell"
$Configuration =
if ($Linux -Or $OSX) { "Linux" }
elseif ($Windows) { "Debug" }
dotnet publish -o $Output -c $Configuration -f "netstandardapp1.5" $Top
}
function Start-PSPackage
{
param(
[version]$Version = "0.1.0",
[int]$Iteration = 1
)
if ($Windows) { throw "Building Windows packages is not yet supported!" }
if (-Not (Get-Command "fpm" -ErrorAction SilentlyContinue)) {
throw "Build dependency 'fpm' not found in PATH! See: https://github.com/jordansissel/fpm"
}
Start-PSBuild
Write-Host "Change permissions for packaging"
chmod -R go=u bin
$Output = if ($Linux) { "deb" } elseif ($OSX) { "osxpkg" }
fpm --force --verbose `
--name "powershell" `
--version $Version `
--iteration $Iteration `
--maintainer "Andrew Schwartzmeyer <andschwa@microsoft.com>" `
--vendor "Microsoft <mageng@microsoft.com>" `
--url "https://github.com/PowerShell/PowerShell" `
--license "Unlicensed" `
--description "Open PowerShell on .NET Core\nPowerShell is an open-source, cross-platform, scripting language and rich object shell. Built upon .NET Core, it is also a C# REPL.\n" `
--category "shells" `
--depends "libunwind8" `
--depends "libicu52" `
--deb-build-depends "dotnet" `
--deb-build-depends "cmake" `
--deb-build-depends "g++" `
-t $Output `
-s dir `
-- "bin/=/usr/local/share/powershell/" "package/powershell=/usr/local/bin"
}
function Start-DevPSGitHub
{
param(
[switch]$ZapDisable,
[string[]]$ArgumentList = '',
[switch]$LoadProfile,
[string]$binDir = "$PSScriptRoot\binFull",
[switch]$NoNewWindow
)
try
{
if ($LoadProfile -eq $false)
{
$ArgumentList = @('-noprofile') + $ArgumentList
}
$env:DEVPATH = $binDir
if ($ZapDisable)
{
$env:COMPLUS_ZapDisable = 1
}
if (-Not (Test-Path $binDir\powershell.exe.config))
{
$configContents = @"
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<runtime>
<developmentMode developerInstallation="true"/>
</runtime>
</configuration>
"@
$configContents | Out-File -Encoding Ascii $binDir\powershell.exe.config
}
# splatting for the win
$startProcessArgs = @{
FilePath = "$binDir\powershell.exe"
ArgumentList = "$ArgumentList"
}
if ($NoNewWindow) {
$startProcessArgs.NoNewWindow = $true
$startProcessArgs.Wait = $true
}
Start-Process @startProcessArgs
}
finally
{
ri env:DEVPATH
if ($ZapDisable)
{
ri env:COMPLUS_ZapDisable
}
}
}
-58
View File
@@ -1,58 +0,0 @@
function Start-DevPSGithub
{
param(
[switch]$ZapDisable,
[string[]]$ArgumentList = '',
[switch]$LoadProfile,
[string]$binDir = "$PSScriptRoot\binFull",
[switch]$NoNewWindow
)
try
{
if ($LoadProfile -eq $false)
{
$ArgumentList = @('-noprofile') + $ArgumentList
}
$env:DEVPATH = $binDir
if ($ZapDisable)
{
$env:COMPLUS_ZapDisable = 1
}
if (!(Test-Path $binDir\powershell.exe.config))
{
$configContents = @"
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<runtime>
<developmentMode developerInstallation="true"/>
</runtime>
</configuration>
"@
$configContents | Out-File -Encoding Ascii $binDir\powershell.exe.config
}
# splatting for the win
$startProcessArgs = @{
FilePath = "$binDir\powershell.exe"
ArgumentList = "$ArgumentList"
}
if ($NoNewWindow) {
$startProcessArgs.NoNewWindow = $true
$startProcessArgs.Wait = $true
}
Start-Process @startProcessArgs
}
finally
{
ri env:DEVPATH
if ($ZapDisable)
{
ri env:COMPLUS_ZapDisable
}
}
}
+6 -5
View File
@@ -18,9 +18,10 @@ install:
- ps: ./install.ps1 -version 1.0.0.001425 -channel beta
build_script:
- ps: $env:Path += ";$env:LocalAppData\Microsoft\dotnet\cli\bin"
- ps: dotnet restore
- ps: .\build.ps1
- ps: |
$env:Path += ";$env:LocalAppData\Microsoft\dotnet\cli\bin"
Import-Module .\PowerShellGitHubDev.psm1
Start-PSBuild
- ps: .\build.fullCLR.ps1
test_script:
@@ -34,9 +35,9 @@ test_script:
# For now we don't fail the build if these tests failed
#
# FullCLR
Import-Module .\PowerShellGithubDev.psm1
Import-Module .\PowerShellGitHubDev.psm1
$testResultsFile = ".\TestsResults.FullCLR.xml"
Start-DevPSGithub -binDir $pwd\binFull -NoNewWindow -ArgumentList '-command', "Import-Module .\src\Microsoft.PowerShell.Linux.Host\Modules\Pester; Invoke-Pester test/fullCLR -OutputFormat NUnitXml -OutputFile $testResultsFile"
Start-DevPSGitHub -binDir $pwd\binFull -NoNewWindow -ArgumentList '-command', "Import-Module .\bin\Modules\Pester; Invoke-Pester test/fullCLR -OutputFormat NUnitXml -OutputFile $testResultsFile"
(New-Object 'System.Net.WebClient').UploadFile("https://ci.appveyor.com/api/testresults/nunit/$($env:APPVEYOR_JOB_ID)", (Resolve-Path $testResultsFile))
# we want to fail the build, if these tests failed
$x = [xml](cat -raw .\TestsResults.FullCLR.xml)
+3
View File
@@ -23,3 +23,6 @@ popd
# Publish PowerShell to bin, with LINUX defined through a configuration
dotnet publish --output "$BIN" --configuration Linux src/Microsoft.PowerShell.Linux.Host
# Fix permissions for packaging
chmod -R go=u "$BIN"
+1
View File
@@ -0,0 +1 @@
../share/powershell/powershell
@@ -1,15 +1,3 @@
function prompt {
"PSL " + $(get-location) + "> "
"PS " + $(get-location) + "> "
}
@"
Welcome to Project Magrathea!
This is the Core PowerShell On Linux / OS X / Windows console
=============================================================
- Type 'Get-Help' for help
- Type 'Exit' to exit
- Type 'Invoke-Pester test/powershell' to run the tests
"@
+1 -1
View File
@@ -518,7 +518,7 @@ OPTIONS
prompt = "PS> ";
}
this.myHost.UI.Write(ConsoleColor.White, ConsoleColor.Black, prompt);
this.myHost.UI.Write(ConsoleColor.White, Console.BackgroundColor, prompt);
string cmd = consoleReadLine.Read(this.myHost.Runspace);
this.Execute(cmd);
}
+114 -48
View File
@@ -133,61 +133,127 @@ namespace Microsoft.PowerShell.Linux.Host
{
ConsoleKeyInfo key = Console.ReadKey(true);
switch (key.Key)
// Basic Emacs-style readline implementation
if (key.Modifiers.HasFlag(ConsoleModifiers.Control))
{
case ConsoleKey.Backspace:
this.OnBackspace();
break;
case ConsoleKey.Delete:
this.OnDelete();
break;
case ConsoleKey.Enter:
previousKeyPress = key;
return this.OnEnter();
case ConsoleKey.RightArrow:
this.OnRight(key.Modifiers);
break;
case ConsoleKey.LeftArrow:
this.OnLeft(key.Modifiers);
break;
case ConsoleKey.Escape:
this.OnEscape();
break;
case ConsoleKey.Home:
this.OnHome();
break;
case ConsoleKey.End:
this.OnEnd();
break;
case ConsoleKey.Tab:
this.OnTab();
break;
case ConsoleKey.UpArrow:
this.OnUpArrow();
break;
case ConsoleKey.DownArrow:
this.OnDownArrow();
break;
switch (key.Key)
{
case ConsoleKey.A:
this.OnHome();
break;
case ConsoleKey.E:
this.OnEnd();
break;
// TODO: save buffer, yank with Ctrl-Y
/*
case ConsoleKey.K:
this.OnEscape();
break;
*/
case ConsoleKey.D:
this.OnDelete();
break;
case ConsoleKey.B:
this.OnLeft(key.Modifiers);
break;
case ConsoleKey.F:
this.OnRight(key.Modifiers);
break;
case ConsoleKey.P:
// TODO: incremental search
case ConsoleKey.R:
this.OnUpArrow();
break;
case ConsoleKey.N:
// TODO: incremental search
case ConsoleKey.S:
this.OnDownArrow();
break;
case ConsoleKey.J:
this.OnEnter();
break;
// TODO: save and restore buffer
/*
case ConsoleKey.L:
this.BufferFromString("clear");
previousKeyPress = key;
return this.OnEnter();
*/
}
}
else if (key.Modifiers.HasFlag(ConsoleModifiers.Alt))
{
switch (key.Key)
{
// TODO: OnDelete(key)
// TODO: OnBackspace(key)
case ConsoleKey.B:
this.OnLeft(key.Modifiers);
break;
case ConsoleKey.F:
this.OnRight(key.Modifiers);
break;
}
}
// Unmodified keys
else
{
switch (key.Key)
{
case ConsoleKey.Backspace:
this.OnBackspace();
break;
case ConsoleKey.Delete:
this.OnDelete();
break;
case ConsoleKey.Enter:
previousKeyPress = key;
return this.OnEnter();
case ConsoleKey.RightArrow:
this.OnRight(key.Modifiers);
break;
case ConsoleKey.LeftArrow:
this.OnLeft(key.Modifiers);
break;
case ConsoleKey.Escape:
this.OnEscape();
break;
case ConsoleKey.Home:
this.OnHome();
break;
case ConsoleKey.End:
this.OnEnd();
break;
case ConsoleKey.Tab:
this.OnTab();
break;
case ConsoleKey.UpArrow:
this.OnUpArrow();
break;
case ConsoleKey.DownArrow:
this.OnDownArrow();
break;
// TODO: case ConsoleKey.LeftWindows: not available in linux
// TODO: case ConsoleKey.RightWindows: not available in linux
default:
default:
if (key.KeyChar == '\x0D')
{
goto case ConsoleKey.Enter; // Ctrl-M
}
if (key.KeyChar == '\x0D')
{
goto case ConsoleKey.Enter; // Ctrl-M
}
if (key.KeyChar == '\x08')
{
goto case ConsoleKey.Backspace; // Ctrl-H
}
if (key.KeyChar == '\x08')
{
goto case ConsoleKey.Backspace; // Ctrl-H
}
this.Insert(key.KeyChar);
this.Insert(key.KeyChar);
this.Render();
break;
this.Render();
break;
}
}
previousKeyPress = key;
}
@@ -446,7 +512,7 @@ namespace Microsoft.PowerShell.Linux.Host
/// and Shift keys.</param>
private void OnLeft(ConsoleModifiers consoleModifiers)
{
if ((consoleModifiers & ConsoleModifiers.Control) != 0)
if (consoleModifiers.HasFlag(ConsoleModifiers.Alt))
{
// Move back to the start of the previous word.
if (this.buffer.Length > 0 && this.current != 0)
@@ -493,7 +559,7 @@ namespace Microsoft.PowerShell.Linux.Host
/// and Shift keys.</param>
private void OnRight(ConsoleModifiers consoleModifiers)
{
if ((consoleModifiers & ConsoleModifiers.Control) != 0)
if (consoleModifiers.HasFlag(ConsoleModifiers.Alt))
{
// Move to the next word.
if (this.buffer.Length != 0 && this.current < this.buffer.Length)
+11 -12
View File
@@ -54,7 +54,7 @@ namespace Microsoft.PowerShell.Linux.Host
{
this.Write(
ConsoleColor.White,
ConsoleColor.Black,
Console.BackgroundColor,
caption + System.Environment.NewLine + message + " ");
Dictionary<string, PSObject> results =
new Dictionary<string, PSObject>();
@@ -96,7 +96,7 @@ namespace Microsoft.PowerShell.Linux.Host
// Write the caption and message strings in Blue.
this.WriteLine(
ConsoleColor.Blue,
ConsoleColor.Black,
Console.BackgroundColor,
caption + System.Environment.NewLine + message + System.Environment.NewLine);
// Convert the choice collection into something that is
@@ -124,7 +124,7 @@ namespace Microsoft.PowerShell.Linux.Host
// chosen, or the loop is interrupted with ctrl-C.
while (true)
{
this.WriteLine(ConsoleColor.Cyan, ConsoleColor.Black, sb.ToString());
this.WriteLine(ConsoleColor.Cyan, Console.BackgroundColor, sb.ToString());
string data = Console.ReadLine().Trim().ToUpper();
// If the choice string was empty, use the default selection.
@@ -170,7 +170,7 @@ namespace Microsoft.PowerShell.Linux.Host
// Write the caption and message strings in Blue.
this.WriteLine(
ConsoleColor.Blue,
ConsoleColor.Black,
Console.BackgroundColor,
caption + System.Environment.NewLine + message + System.Environment.NewLine);
// Convert the choice collection into something that is
@@ -217,7 +217,7 @@ namespace Microsoft.PowerShell.Linux.Host
this.WriteLine(
ConsoleColor.Cyan,
ConsoleColor.Black,
Console.BackgroundColor,
sb.ToString());
// Read prompts until a match is made, the default is
// chosen, or the loop is interrupted with ctrl-C.
@@ -226,7 +226,7 @@ namespace Microsoft.PowerShell.Linux.Host
{
ReadNext:
string prompt = string.Format(CultureInfo.CurrentCulture, "Choice[{0}]:", results.Count);
this.Write(ConsoleColor.Cyan, ConsoleColor.Black, prompt);
this.Write(ConsoleColor.Cyan, Console.BackgroundColor, prompt);
string data = Console.ReadLine().Trim().ToUpper();
// If the choice string was empty, no more choices have been made.
@@ -352,7 +352,6 @@ ReadNext:
Console.ForegroundColor = foregroundColor;
Console.BackgroundColor = backgroundColor;
Console.Write(value);
//Console.Write(value);
Console.ResetColor();
}
@@ -361,7 +360,7 @@ ReadNext:
/// Writes a line of characters to the output display of the host
/// with foreground and background colors and appends a newline (carriage return).
/// </summary>
/// <param name="foregroundColor">The forground color of the display. </param>
/// <param name="foregroundColor">The foreground color of the display. </param>
/// <param name="backgroundColor">The background color of the display. </param>
/// <param name="value">The line to be written.</param>
public override void WriteLine(
@@ -383,7 +382,7 @@ ReadNext:
{
this.WriteLine(
ConsoleColor.Yellow,
ConsoleColor.Black,
Console.BackgroundColor,
String.Format(CultureInfo.CurrentCulture, "DEBUG: {0}", message));
}
@@ -396,7 +395,7 @@ ReadNext:
{
this.WriteLine(
ConsoleColor.Red,
ConsoleColor.Black,
Console.BackgroundColor,
value);
}
@@ -454,7 +453,7 @@ ReadNext:
{
this.WriteLine(
ConsoleColor.Green,
ConsoleColor.Black,
Console.BackgroundColor,
String.Format(CultureInfo.CurrentCulture, "VERBOSE: {0}", message));
}
@@ -466,7 +465,7 @@ ReadNext:
{
this.WriteLine(
ConsoleColor.Yellow,
ConsoleColor.Black,
Console.BackgroundColor,
String.Format(CultureInfo.CurrentCulture, "WARNING: {0}", message));
}