Adding Linux PowerShell support

This change introduces netstandard1.6 along with support for open PowerShell, included new functionality for Linux.  This includes:
- Changing cancellation pattern for stdin to explicitly close instead of relying on cancellation token handling.
- Adding basic input/output parsing for Linux.
- Adding support for unix sockets by default when on Linux.
This commit is contained in:
Justin Terry 2016-08-05 08:18:37 -07:00 коммит произвёл Stefan J. Wernli
Родитель 23a55896e2
Коммит 8dc8819e6d
24 изменённых файлов: 393 добавлений и 208 удалений

1
.gitignore поставляемый
Просмотреть файл

@ -1,4 +1,3 @@
pingme.txt
## Ignore Visual Studio temporary files, build results, and

79
.vscode/tasks.json поставляемый
Просмотреть файл

@ -5,7 +5,6 @@
// ${fileDirname}: the current opened file's dirname
// ${fileExtname}: the current opened file's extension
// ${cwd}: the current working directory of the spawned process
{
"version": "0.1.0",
"command": "cmd",
@ -13,22 +12,41 @@
"showOutput": "silent",
"args": [
"/c"
],
],
"tasks": [
{
"taskName": "restore",
"suppressTaskName": true,
"args" : ["dotnet", "restore"],
"args": [
"dotnet",
"restore"
],
"showOutput": "always",
"problemMatcher": "$msCompile"
},
{
"taskName": "build",
"suppressTaskName": true,
"args" : [
"dotnet", "publish", "${cwd}\\src\\Docker.PowerShell", "-o", "${cwd}\\src\\Docker.PowerShell\\bin\\Module\\Docker", "-r", "win",
"&&", "powershell", "-executionpolicy", "bypass", "-c", "New-ExternalHelp", "-Path", "${cwd}\\src\\Docker.PowerShell\\Help", "-OutputPath", "${cwd}\\src\\Docker.PowerShell\\bin\\Module\\Docker", "-Force"
],
"args": [
"dotnet",
"publish",
"${cwd}\\src\\Docker.PowerShell",
"-f",
"net46",
"-o",
"${cwd}\\src\\Docker.PowerShell\\bin\\Module\\Docker",
"&&",
"powershell",
"-executionpolicy",
"bypass",
"-c",
"New-ExternalHelp",
"-Path",
"${cwd}\\src\\Docker.PowerShell\\Help",
"-OutputPath",
"${cwd}\\src\\Docker.PowerShell\\bin\\Module\\Docker",
"-Force"
],
"showOutput": "always",
"isBuildCommand": true,
"problemMatcher": "$msCompile"
@ -36,26 +54,59 @@
{
"taskName": "test",
"suppressTaskName": true,
"args": ["start", "powershell", "-executionpolicy", "bypass", "-noexit", "-c", "ipmo", ".\\src\\Docker.PowerShell\\bin\\Module\\Docker"],
"args": [
"start",
"powershell",
"-executionpolicy",
"bypass",
"-noexit",
"-c",
"ipmo",
".\\src\\Docker.PowerShell\\bin\\Module\\Docker"
],
"showOutput": "never",
"isTestCommand": true
},
{
"taskName": "clean",
"suppressTaskName": true,
"args": ["del", "/Q", "/S", ".\\src\\*project.lock.json", "&&", "rmdir", "/Q", "/S", ".\\src\\Docker.PowerShell\\bin"],
"args": [
"del",
"/Q",
"/S",
".\\src\\*project.lock.json",
"&&",
"rmdir",
"/Q",
"/S",
".\\src\\Docker.PowerShell\\bin"
],
"showOutput": "always"
},
{
"taskName": "update-help",
"suppressTaskName": true,
"args": [
"powershell", "-executionpolicy", "bypass", "-c", "ipmo", ".\\src\\Docker.PowerShell\\bin\\Module\\Docker", ";",
"New-MarkdownHelp", "-Module", "Docker", "-OutputFolder", ".\\src\\Docker.PowerShell\\Help", "-ErrorAction", "SilentlyContinue", ";",
"Update-MarkdownHelp", "-Path", ".\\src\\Docker.PowerShell\\Help"
"powershell",
"-executionpolicy",
"bypass",
"-c",
"ipmo",
".\\src\\Docker.PowerShell\\bin\\Module\\Docker",
";",
"New-MarkdownHelp",
"-Module",
"Docker",
"-OutputFolder",
".\\src\\Docker.PowerShell\\Help",
"-ErrorAction",
"SilentlyContinue",
";",
"Update-MarkdownHelp",
"-Path",
".\\src\\Docker.PowerShell\\Help"
],
"showOutput": "always"
}
]
}
}

6
Nuget.config Normal file
Просмотреть файл

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<packageSources>
<add key="ps-feed" value="https://powershell.myget.org/F/powershell-core/api/v3/index.json" />
</packageSources>
</configuration>

Просмотреть файл

@ -35,7 +35,7 @@ feedback).
The dev builds are updated for every commit to master and are released to
https://ci.appveyor.com/nuget/docker-powershell-dev. To install the latest
build, in PowerShell run:
build, in PowerShell 5.0 run:
> Register-PSRepository -Name DockerPS-Dev -SourceLocation https://ci.appveyor.com/nuget/docker-powershell-dev
@ -46,11 +46,31 @@ After this, you can update to new development builds with just:
> Update-Module Docker
#### Linux and Mac OS X
If you are using cross-platform [PowerShell 6.0](https://github.com/PowerShell/PowerShell), you will need to use a different
feed and manually unpack the module to the correct location:
> Register-PSRepository -Name DockerPS-Dev -SourceLocation https://ci.appveyor.com/nuget/docker-powershell-dev
> Save-Module Docker-Core -Path $env:PSModulePath.split(";")[-1]
> Rename-Item "$($env:PSModulePath.split(";")[-1])/Docker-Core" "$($env:PSModulePath.split(";")[-1])/Docker"
After this, updating to a new development build will require closing any PowerShell windows that have
loaded the module and deleting the folder:
> Remove-Item -force -recur "$($env:PSModulePath.split(";")[-1])/Docker"
Then you can re-run the steps to find, download, and rename the module from the section above.
(NOTE: As the PowerShellGet support story improves for PowerShell 6.0 we will update these instructions.)
#### Need an offline workflow?
From an internet connected machine:
> Save-Package Docker -Source DockerPS-Dev -Path .
> Save-Module Docker -Path .
Copy the entire folder `.\Docker` to the destination at: `%ProgramFiles%\WindowsPowerShell\Modules`
@ -93,7 +113,13 @@ Once these are installed, you can run:
> dotnet restore
> dotnet publish .\src\Docker.PowerShell -o .\src\Docker.PowerShell\bin\Module\Docker -r win
> dotnet publish .\src\Docker.PowerShell -o .\src\Docker.PowerShell\bin\Module\Docker -f net46
or for a module targetted at cross-platform PowerShell:
> dotnet restore
> dotnet publish .\src\Docker.PowerShell -o .\src\Docker.PowerShell\bin\Module\Docker -f netstandard1.6
This will produce the PowerShell module at
`.\src\Docker.PowerShell\bin\Module\Docker` in the project folder.

Просмотреть файл

@ -1,13 +1,12 @@
version: '0.0.0.{build}'
pull_requests:
do_not_increment_build_number: true
image: WMF 5
init:
- ps: (new-object net.webclient).DownloadFile('https://dotnetcli.blob.core.windows.net/dotnet/beta/Installers/Latest/dotnet-dev-win-x64.latest.exe', "c:/dotnet-install.exe")
- ps: Start-Process c:\dotnet-install.exe -ArgumentList "/install","/quiet" -Wait
- ps: Install-PackageProvider NuGet -Force
- ps: Install-Module platyPS -Force
- ps: (new-object net.webclient).DownloadFile('https://dotnetcli.blob.core.windows.net/dotnet/Sdk/rel-1.0.0/dotnet-dev-win-x64.latest.exe', "c:/dotnet-install.exe")
- ps: Start-Process c:\dotnet-install.exe -ArgumentList "/install","/quiet" -Wait
install:
- ps: Install-Module platyPS -Force
- cmd: git submodule update --init --recursive
nuget:
disable_publish_on_pr: true
@ -31,14 +30,18 @@ build_script:
$projectFile = "src\Docker.PowerShell\project.json"
$project = Get-Content $projectFile -Raw | ConvertFrom-Json
$project.version = $version
ConvertTo-Json $project | Out-File -Encoding UTF8 $projectFile
ConvertTo-Json $project -Depth 100 | Out-File -Encoding UTF8 $projectFile
$manifest = "src\Docker.PowerShell\Docker.psd1"
(Get-Content $manifest -Raw) -replace "ModuleVersion.+","ModuleVersion = '$psversion'" | Out-File $manifest
- ps: dotnet restore
- ps: dotnet publish -r win -o $pwd\bin -c Release $pwd\src\Docker.PowerShell
- ps: New-ExternalHelp -Path src\Docker.PowerShell\Help -OutputPath bin
- ps: nuget pack src/Docker.PowerShell/Docker.nuspec -BasePath bin -OutputDirectory bin -Symbols -Version $psversion
- ps: dotnet build **/project.json
- ps: dotnet publish -f net46 -o $pwd\bin\net46 -c Release $pwd\src\Docker.PowerShell
- ps: New-ExternalHelp -Path src\Docker.PowerShell\Help -OutputPath bin\net46
- ps: nuget pack src/Docker.PowerShell/Docker.nuspec -BasePath bin\net46 -OutputDirectory bin -Symbols -Version $psversion
- ps: dotnet publish -f netstandard1.6 -o $pwd\bin\netstandard1.6 -c Release $pwd\src\Docker.PowerShell
- ps: New-ExternalHelp -Path src\Docker.PowerShell\Help -OutputPath bin\netstandard1.6
- ps: nuget pack src/Docker.PowerShell/Docker-Core.nuspec -BasePath bin\netstandard1.6 -OutputDirectory bin -Symbols -Version $psversion
test_script:
- ps: Register-PSRepository -Name test -SourceLocation $pwd\bin
- ps: Install-Module -Name Docker -Repository test -Force

@ -1 +1 @@
Subproject commit 4260a2f45148623c92dd7bbc1d9370af392ccfd1
Subproject commit 6a3fa67ec576c6d64c5a78ab3a7b78aeb9e0e908

Просмотреть файл

@ -4,15 +4,29 @@ using System.Security.Cryptography.X509Certificates;
using Docker.DotNet;
using Docker.DotNet.X509;
#if !NET46
using System.Runtime.InteropServices;
#endif
public class DockerFactory
{
private const string ApiVersion = "1.24";
private const string KeyFileName = "key.pfx";
private const string certPass = "p@ssw0rd";
private static readonly bool IsWindows =
#if NET46
true;
#else
RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
#endif
private static readonly string DefaultHost = IsWindows ? "npipe://./pipe/docker_engine" : "unix://var/run/docker.sock";
public static DockerClient CreateClient(string HostAddress, string CertificateLocation)
{
HostAddress = HostAddress ?? Environment.GetEnvironmentVariable("DOCKER_HOST") ?? "npipe://./pipe/docker_engine";
HostAddress = HostAddress ?? Environment.GetEnvironmentVariable("DOCKER_HOST") ?? DefaultHost;
CertificateLocation = CertificateLocation ?? Environment.GetEnvironmentVariable("DOCKER_CERT_PATH");
CertificateCredentials cred = null;

Просмотреть файл

@ -28,7 +28,7 @@ namespace Docker.PowerShell.Cmdlets
using (var fs = File.Create(filePath))
using (var stream = await DkrClient.Miscellaneous.GetImagesAsTarballAsync(names.ToArray(), CmdletCancellationToken))
using (CmdletCancellationToken.Register(() => stream.Close()))
using (CmdletCancellationToken.Register(() => stream.Dispose()))
{
await stream.CopyToAsync(fs);
}

Просмотреть файл

@ -47,7 +47,7 @@ namespace Docker.PowerShell.Cmdlets
using (var pushStream = await loadTask)
{
// ReadLineAsync is not cancellable without closing the whole stream, so register a callback to do just that.
using (CmdletCancellationToken.Register(() => pushStream.Close()))
using (CmdletCancellationToken.Register(() => pushStream.Dispose()))
using (var pullReader = new StreamReader(pushStream, new UTF8Encoding(false)))
{
string line;

Просмотреть файл

@ -118,7 +118,7 @@ namespace Docker.PowerShell.Cmdlets
WriteProgress(progressRecord);
// ReadLineAsync is not cancellable without closing the whole stream, so register a callback to do just that.
using (CmdletCancellationToken.Register(() => buildStream.Close()))
using (CmdletCancellationToken.Register(() => buildStream.Dispose()))
using (var buildReader = new StreamReader(buildStream, new UTF8Encoding(false)))
{
string line;

Просмотреть файл

@ -48,7 +48,7 @@ namespace Docker.PowerShell.Cmdlets
using (var pullStream = await pullTask)
{
// ReadLineAsync is not cancellable without closing the whole stream, so register a callback to do just that.
using (CmdletCancellationToken.Register(() => pullStream.Close()))
using (CmdletCancellationToken.Register(() => pullStream.Dispose()))
using (var pullReader = new StreamReader(pullStream, new UTF8Encoding(false)))
{
string line;

Просмотреть файл

@ -62,7 +62,7 @@ namespace Docker.PowerShell.Cmdlets
using (var pushStream = await pushTask)
{
// ReadLineAsync is not cancellable without closing the whole stream, so register a callback to do just that.
using (CmdletCancellationToken.Register(() => pushStream.Close()))
using (CmdletCancellationToken.Register(() => pushStream.Dispose()))
using (var pullReader = new StreamReader(pushStream, new UTF8Encoding(false)))
{
string line;

Просмотреть файл

@ -0,0 +1,14 @@
<?xml version="1.0"?>
<package >
<metadata>
<id>Docker-Core</id>
<version>0.0.0.0</version>
<authors>Microsoft</authors>
<owners>microsoft</owners>
<licenseUrl>https://raw.githubusercontent.com/Microsoft/Docker-PowerShell/master/LICENSE</licenseUrl>
<projectUrl>https://github.com/Microsoft/Docker-PowerShell</projectUrl>
<requireLicenseAcceptance>true</requireLicenseAcceptance>
<copyright>Copyright (c) Microsoft</copyright>
<description>This package contains cross-platform Docker PowerShell cmdlets that can be used to on any host running open-source PowerShell 6.0.</description>
</metadata>
</package>

Просмотреть файл

@ -14,7 +14,7 @@ ModuleVersion = '0.0.0.0'
# Minimum PowerShell version. This should match the reference assembly version
# in project.json (we require 5.0 due to dependencies on parameter completion).
PowerShellVersion = '5.0'
PowerShellVersion = '5.0.0'
# ID used to uniquely identify this module
GUID = '7cc6f829-b4b5-493d-9a99-f92dc54d7e10'

Просмотреть файл

@ -46,8 +46,6 @@ namespace Docker.PowerShell.Support
writer.Close(e);
throw;
}
writer.Close();
}
}, cancellationToken);
}

Просмотреть файл

@ -1,6 +1,5 @@
using System;
using System.IO;
using System.Runtime.InteropServices;
namespace Docker.PowerShell.Support
{
@ -10,96 +9,30 @@ namespace Docker.PowerShell.Support
Out,
}
internal class ConsoleStream : IDisposable
internal abstract class ConsoleStream : IDisposable
{
private IntPtr _handle;
private int _oldMode;
private int _currentMode;
public Stream Stream { get; private set; }
public ConsoleDirection Direction { get; private set; }
protected IntPtr _handle;
protected int _oldMode;
protected int _currentMode;
public Stream Stream { get; internal set; }
public ConsoleDirection Direction { get; internal set; }
public ConsoleStream(ConsoleDirection dir)
{
Direction = dir;
_handle = Win32ConsoleInterop.GetStdHandle(dir == ConsoleDirection.In ? Win32ConsoleInterop.STD_INPUT_HANDLE : Win32ConsoleInterop.STD_OUTPUT_HANDLE);
if (!Win32ConsoleInterop.GetConsoleMode(_handle, out _oldMode))
{
Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());
}
_currentMode = _oldMode;
// Now that it is known that this is a console, reopen the console handle for
// asynchronous access so that IO to it can be canceled.
var newHandle = Win32ConsoleInterop.CreateFile(
dir == ConsoleDirection.In ? "CONIN$" : "CONOUT$",
dir == ConsoleDirection.In ? Win32ConsoleInterop.GENERIC_READ : Win32ConsoleInterop.GENERIC_WRITE,
FileShare.ReadWrite,
new IntPtr(),
FileMode.Open,
Win32ConsoleInterop.FILE_FLAG_OVERLAPPED,
new IntPtr());
if (newHandle.IsInvalid)
{
Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());
}
Stream = new FileStream(newHandle, dir == ConsoleDirection.In ? FileAccess.Read : FileAccess.Write, 1, true);
}
public void EnableRawInputMode()
public virtual void EnableRawInputMode()
{
if (Direction != ConsoleDirection.In)
{
throw new InvalidOperationException("cannot set raw mode on output handle");
}
// Put the console in character mode with no input processing.
var newMode = _currentMode & ~(Win32ConsoleInterop.ENABLE_PROCESSED_INPUT |
Win32ConsoleInterop.ENABLE_LINE_INPUT |
Win32ConsoleInterop.ENABLE_ECHO_INPUT |
Win32ConsoleInterop.ENABLE_MOUSE_INPUT);
if (!Win32ConsoleInterop.SetConsoleMode(_handle, newMode))
{
Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());
}
_currentMode = newMode;
}
public void EnableVTMode()
public virtual void EnableVTMode()
{
int newMode;
if (Direction == ConsoleDirection.Out)
{
// Put the console in character mode with no input processing.
newMode = _currentMode | Win32ConsoleInterop.ENABLE_PROCESSED_OUTPUT | Win32ConsoleInterop.ENABLE_VIRTUAL_TERMINAL_PROCESSING | Win32ConsoleInterop.DISABLE_NEWLINE_AUTO_RETURN;
}
else
{
newMode = _currentMode | Win32ConsoleInterop.ENABLE_VIRTUAL_TERMINAL_INPUT;
}
if (!Win32ConsoleInterop.SetConsoleMode(_handle, newMode))
{
Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());
}
_currentMode = newMode;
}
public void Dispose()
public virtual void Dispose()
{
Stream.Dispose();
if (_currentMode != _oldMode)
{
if (Win32ConsoleInterop.SetConsoleMode(_handle, _oldMode))
{
_currentMode = _oldMode;
}
}
}
}
}

Просмотреть файл

@ -0,0 +1,12 @@
using System;
namespace Docker.PowerShell.Support
{
internal sealed class LinuxConsoleStream : ConsoleStream
{
public LinuxConsoleStream(ConsoleDirection dir) : base(dir)
{
Stream = dir == ConsoleDirection.In ? Console.OpenStandardInput() : Console.OpenStandardOutput();
}
}
}

Просмотреть файл

@ -4,18 +4,38 @@ using System.Threading;
using System.Threading.Tasks;
using Docker.DotNet;
#if !NET46
using System.Runtime.InteropServices;
#endif
namespace Docker.PowerShell.Support
{
internal static class MultiplexedStreamExtensions
{
private static readonly bool IsWindows =
#if NET46
true;
#else
RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
#endif
public static async Task CopyToConsoleAsync(this MultiplexedStream stream, bool tty, bool openStdin, CancellationToken cancellationToken)
{
Stream stdin = Stream.Null, stdout = Stream.Null, stderr = Stream.Null;
ConsoleStream conin = null, conout = null;
Task stdinReadTask = null;
try
{
// TODO: What if we are not attached to a console? If config.Tty is false, this should not be an error.
conout = new ConsoleStream(ConsoleDirection.Out);
if (IsWindows)
{
conout = new Win32ConsoleStream(ConsoleDirection.Out);
}
else
{
conout = new LinuxConsoleStream(ConsoleDirection.Out);
}
stdout = Console.OpenStandardOutput(); // Don't use conout's Stream because FileStream always buffers on net46.
if (tty)
{
@ -26,11 +46,17 @@ namespace Docker.PowerShell.Support
stderr = Console.OpenStandardError();
}
Task stdinRead = null;
CancellationTokenSource inputCancelToken = null;
if (openStdin)
{
conin = new ConsoleStream(ConsoleDirection.In);
if (IsWindows)
{
conin = new Win32ConsoleStream(ConsoleDirection.In);
}
else
{
conin = new LinuxConsoleStream(ConsoleDirection.In);
}
stdin = conin.Stream;
conin.EnableRawInputMode();
if (tty)
@ -38,33 +64,31 @@ namespace Docker.PowerShell.Support
conin.EnableVTMode();
}
inputCancelToken = new CancellationTokenSource();
stdinRead = stream.CopyFromAsync(stdin, inputCancelToken.Token).ContinueWith(x => stream.CloseWrite());
stdinReadTask = stream.CopyFromAsync(stdin, CancellationToken.None).ContinueWith(x => stream.CloseWrite());
}
await stream.CopyOutputToAsync(stdout, stdout, stderr, cancellationToken).ConfigureAwait(false);
if (stdinRead != null)
}
finally
{
conout?.Dispose();
conin?.Dispose();
stdout.Dispose();
stderr.Dispose();
stdin.Dispose();
if (stdinReadTask != null)
{
inputCancelToken.Cancel();
try
{
await stdinRead.ConfigureAwait(false);
// Make sure the read from stdin has finished before returning.
await stdinReadTask.ConfigureAwait(false);
}
catch (TaskCanceledException)
catch (ObjectDisposedException)
{
// Ignore.
}
}
}
finally
{
conin?.Dispose();
conout?.Dispose();
stdin.Dispose();
stdout.Dispose();
stderr.Dispose();
}
}
}
}

Просмотреть файл

@ -60,14 +60,17 @@ namespace Docker.PowerShell.Support
return _pipe.ReadAsync(buffer, offset, count, cancellationToken);
}
public override void Close()
{
_pipe.CloseReader();
}
public void Close(Exception e)
{
_pipe.CloseReader(e);
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
_pipe.CloseReader();
}
}
}
}

Просмотреть файл

@ -57,15 +57,18 @@ namespace Docker.PowerShell.Support
{
return _pipe.WriteAsync(buffer, offset, count, cancellationToken);
}
public override void Close()
{
_pipe.CloseWriter();
}
public void Close(Exception e)
{
_pipe.CloseWriter(e);
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
_pipe.CloseWriter();
}
base.Dispose(disposing);
}
}
}

Просмотреть файл

@ -1,49 +0,0 @@
using System;
using System.Runtime.InteropServices;
using Microsoft.Win32.SafeHandles;
namespace Docker.PowerShell.Support
{
internal static class Win32ConsoleInterop
{
[DllImport("api-ms-win-core-file-l1-1-0.dll", EntryPoint = "CreateFileW", SetLastError = true, CharSet = CharSet.Unicode, BestFitMapping = false)]
public static extern SafeFileHandle CreateFile(
string lpFileName,
int dwDesiredAccess,
System.IO.FileShare dwShareMode,
IntPtr securityAttrs,
System.IO.FileMode dwCreationDisposition,
int dwFlagsAndAttributes,
IntPtr hTemplateFile);
[DllImport("api-ms-win-core-console-l1-1-0.dll", SetLastError = true)]
public extern static bool GetConsoleMode(IntPtr handle, out int mode);
[DllImport("api-ms-win-core-console-l1-1-0.dll", SetLastError = true)]
public static extern bool SetConsoleMode(IntPtr handle, int mode);
[DllImport("api-ms-win-core-processenvironment-l1-1-0.dll", SetLastError = true)]
public static extern IntPtr GetStdHandle(int nStdHandle);
public const int STD_INPUT_HANDLE = -10;
public const int STD_OUTPUT_HANDLE = -11;
public const int STD_ERROR_HANDLE = -12;
public const int GENERIC_READ = unchecked((int)0x80000000);
public const int GENERIC_WRITE = 0x40000000;
public const int FILE_FLAG_OVERLAPPED = 0x40000000;
// Input flags.
public const int ENABLE_PROCESSED_INPUT = 0x1;
public const int ENABLE_LINE_INPUT = 0x2;
public const int ENABLE_ECHO_INPUT = 0x4;
public const int ENABLE_MOUSE_INPUT = 0x10;
public const int ENABLE_VIRTUAL_TERMINAL_INPUT = 0x200;
// Output flags.
public const int ENABLE_PROCESSED_OUTPUT = 0x1;
public const int ENABLE_VIRTUAL_TERMINAL_PROCESSING = 0x4;
public const int DISABLE_NEWLINE_AUTO_RETURN = 0x8;
}
}

Просмотреть файл

@ -0,0 +1,133 @@
using System;
using System.IO;
using System.Runtime.InteropServices;
using Microsoft.Win32.SafeHandles;
namespace Docker.PowerShell.Support
{
internal sealed class Win32ConsoleStream : ConsoleStream
{
public Win32ConsoleStream(ConsoleDirection dir) : base(dir)
{
_handle = GetStdHandle(dir == ConsoleDirection.In ? STD_INPUT_HANDLE : STD_OUTPUT_HANDLE);
if (!GetConsoleMode(_handle, out _oldMode))
{
Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());
}
_currentMode = _oldMode;
// Now that it is known that this is a console, reopen the console handle for
// asynchronous access so that IO to it can be canceled.
var newHandle = CreateFile(
dir == ConsoleDirection.In ? "CONIN$" : "CONOUT$",
dir == ConsoleDirection.In ? GENERIC_READ : GENERIC_WRITE,
FileShare.ReadWrite,
new IntPtr(),
FileMode.Open,
FILE_FLAG_OVERLAPPED,
new IntPtr());
if (newHandle.IsInvalid)
{
Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());
}
Stream = new FileStream(newHandle, dir == ConsoleDirection.In ? FileAccess.Read : FileAccess.Write, 1, true);
}
override public void EnableRawInputMode()
{
if (Direction != ConsoleDirection.In)
{
throw new InvalidOperationException("cannot set raw mode on output handle");
}
// Put the console in character mode with no input processing.
var newMode = _currentMode & ~(ENABLE_PROCESSED_INPUT |
ENABLE_LINE_INPUT |
ENABLE_ECHO_INPUT |
ENABLE_MOUSE_INPUT);
if (!SetConsoleMode(_handle, newMode))
{
Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());
}
_currentMode = newMode;
}
override public void EnableVTMode()
{
int newMode;
if (Direction == ConsoleDirection.Out)
{
// Put the console in character mode with no input processing.
newMode = _currentMode | ENABLE_PROCESSED_OUTPUT | ENABLE_VIRTUAL_TERMINAL_PROCESSING | DISABLE_NEWLINE_AUTO_RETURN;
}
else
{
newMode = _currentMode | ENABLE_VIRTUAL_TERMINAL_INPUT;
}
if (!SetConsoleMode(_handle, newMode))
{
Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());
}
_currentMode = newMode;
}
override public void Dispose()
{
if (_currentMode != _oldMode)
{
if (SetConsoleMode(_handle, _oldMode))
{
_currentMode = _oldMode;
}
}
base.Dispose();
}
[DllImport("api-ms-win-core-file-l1-1-0.dll", EntryPoint = "CreateFileW", SetLastError = true, CharSet = CharSet.Unicode, BestFitMapping = false)]
private static extern SafeFileHandle CreateFile(
string lpFileName,
int dwDesiredAccess,
System.IO.FileShare dwShareMode,
IntPtr securityAttrs,
System.IO.FileMode dwCreationDisposition,
int dwFlagsAndAttributes,
IntPtr hTemplateFile);
[DllImport("api-ms-win-core-console-l1-1-0.dll", SetLastError = true)]
private static extern bool GetConsoleMode(IntPtr handle, out int mode);
[DllImport("api-ms-win-core-console-l1-1-0.dll", SetLastError = true)]
private static extern bool SetConsoleMode(IntPtr handle, int mode);
[DllImport("api-ms-win-core-processenvironment-l1-1-0.dll", SetLastError = true)]
private static extern IntPtr GetStdHandle(int nStdHandle);
private const int STD_INPUT_HANDLE = -10;
private const int STD_OUTPUT_HANDLE = -11;
private const int STD_ERROR_HANDLE = -12;
private const int GENERIC_READ = unchecked((int)0x80000000);
private const int GENERIC_WRITE = 0x40000000;
private const int FILE_FLAG_OVERLAPPED = 0x40000000;
// Input flags.
private const int ENABLE_PROCESSED_INPUT = 0x1;
private const int ENABLE_LINE_INPUT = 0x2;
private const int ENABLE_ECHO_INPUT = 0x4;
private const int ENABLE_MOUSE_INPUT = 0x10;
private const int ENABLE_VIRTUAL_TERMINAL_INPUT = 0x200;
// Output flags.
private const int ENABLE_PROCESSED_OUTPUT = 0x1;
private const int ENABLE_VIRTUAL_TERMINAL_PROCESSING = 0x4;
private const int DISABLE_NEWLINE_AUTO_RETURN = 0x8;
}
}

Просмотреть файл

@ -1,19 +1,36 @@
{
"version": "0.0.0-alpha",
"description": "Docker.PowerShell Cmdlet Library",
"runtimes": {
"win": {}
},
"dependencies": {
"Docker.DotNet.X509": "2.124.2",
"Docker.DotNet": "2.124.2",
"Tar": "0.1.0-*",
"Microsoft.PowerShell.5.ReferenceAssemblies": "1.0.0"
"Tar": "0.1.0-*"
},
"frameworks": {
"net46": {}
"netstandard1.6": {
"imports": [
"portable-net45+win8"
],
"dependencies": {
"Microsoft.PowerShell.SDK": {
"version": "1.0.0-alpha9",
"type": "platform"
}
}
},
"net46": {
"dependencies": {
"Microsoft.PowerShell.5.ReferenceAssemblies": {
"version": "1.0.0",
"type": "build"
}
}
}
},
"publishOptions": {
"include": ["Docker.psd1", "Docker.Format.ps1xml"]
"include": [
"Docker.psd1",
"Docker.Format.ps1xml"
]
}
}
}

Просмотреть файл

@ -1,16 +1,14 @@
{
"version": "0.1.0",
"frameworks": {
"netstandard1.3": {
"imports": [ "dotnet", "netcore50" ],
"netstandard1.6": {
"dependencies": {
"System.IO": "4.0.10",
"System.IO.FileSystem": "4.0.0",
"System.Linq": "4.0.0",
"System.Runtime": "4.0.20",
"System.Text.Encoding": "4.0.10",
"System.Text.Encoding.Extensions": "4.0.10",
"System.Threading.Tasks": "4.0.10"
"NETStandard.Library": "1.6.0"
}
},
"netstandard1.3": {
"dependencies": {
"NETStandard.Library": "1.6.0"
}
}
}