diff --git a/PowerShellGitHubDev.psm1 b/PowerShellGitHubDev.psm1 new file mode 100644 index 0000000000..0a694e96d6 --- /dev/null +++ b/PowerShellGitHubDev.psm1 @@ -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 " ` + --vendor "Microsoft " ` + --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 = @" + + + + + + +"@ + $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 + } + } +} diff --git a/PowerShellGithubDev.psm1 b/PowerShellGithubDev.psm1 deleted file mode 100644 index 3091b2edfe..0000000000 --- a/PowerShellGithubDev.psm1 +++ /dev/null @@ -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 = @" - - - - - - -"@ - $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 - } - } -} \ No newline at end of file diff --git a/appveyor.yml b/appveyor.yml index 9a53bddff3..143f6e2bc5 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -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) diff --git a/build.sh b/build.sh index 5ff4d8e2be..a94094d8e3 100755 --- a/build.sh +++ b/build.sh @@ -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" diff --git a/package/powershell b/package/powershell new file mode 120000 index 0000000000..61bd3470b7 --- /dev/null +++ b/package/powershell @@ -0,0 +1 @@ +../share/powershell/powershell \ No newline at end of file diff --git a/src/Microsoft.PowerShell.Linux.Host/PSL_profile.ps1 b/src/Microsoft.PowerShell.Linux.Host/PSL_profile.ps1 index 7276644e18..de4c4f2da7 100644 --- a/src/Microsoft.PowerShell.Linux.Host/PSL_profile.ps1 +++ b/src/Microsoft.PowerShell.Linux.Host/PSL_profile.ps1 @@ -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 - -"@ diff --git a/src/Microsoft.PowerShell.Linux.Host/main.cs b/src/Microsoft.PowerShell.Linux.Host/main.cs index aec3e215c6..e8605c79f5 100644 --- a/src/Microsoft.PowerShell.Linux.Host/main.cs +++ b/src/Microsoft.PowerShell.Linux.Host/main.cs @@ -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); } diff --git a/src/Microsoft.PowerShell.Linux.Host/readline.cs b/src/Microsoft.PowerShell.Linux.Host/readline.cs index d3ca82870e..da98f6bc6d 100644 --- a/src/Microsoft.PowerShell.Linux.Host/readline.cs +++ b/src/Microsoft.PowerShell.Linux.Host/readline.cs @@ -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. 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. 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) diff --git a/src/Microsoft.PowerShell.Linux.Host/ui.cs b/src/Microsoft.PowerShell.Linux.Host/ui.cs index c1c6626eaf..4d105d6556 100644 --- a/src/Microsoft.PowerShell.Linux.Host/ui.cs +++ b/src/Microsoft.PowerShell.Linux.Host/ui.cs @@ -54,7 +54,7 @@ namespace Microsoft.PowerShell.Linux.Host { this.Write( ConsoleColor.White, - ConsoleColor.Black, + Console.BackgroundColor, caption + System.Environment.NewLine + message + " "); Dictionary results = new Dictionary(); @@ -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). /// - /// The forground color of the display. + /// The foreground color of the display. /// The background color of the display. /// The line to be written. 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)); }