Skip to content

Commit

Permalink
Added net471 build in attempt to fix #75
Browse files Browse the repository at this point in the history
  • Loading branch information
madelson committed Nov 9, 2020
1 parent 801101c commit d0a3cd5
Show file tree
Hide file tree
Showing 6 changed files with 85 additions and 121 deletions.
81 changes: 36 additions & 45 deletions MedallionShell.Tests/GeneralTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
namespace Medallion.Shell.Tests
{
using System.Collections;
using System.Text.RegularExpressions;
using static UnitTestHelpers;

public class GeneralTest
Expand Down Expand Up @@ -145,45 +146,39 @@ public void TestZeroTimeout()
[Test]
public void TestCancellationAlreadyCanceled()
{
using (var alreadyCanceled = new CancellationTokenSource(millisecondsDelay: 0))
{
var command = TestShell.Run(SampleCommand, new object[] { "sleep", 1000000 }, o => o.CancellationToken(alreadyCanceled.Token));
Assert.Throws<TaskCanceledException>(() => command.Wait());
Assert.Throws<TaskCanceledException>(() => command.Result.ToString());
command.Task.Status.ShouldEqual(TaskStatus.Canceled);
Assert.DoesNotThrow(() => command.ProcessId.ToString(), "still executes a command and gets a process ID");
}
using var alreadyCanceled = new CancellationTokenSource(millisecondsDelay: 0);
var command = TestShell.Run(SampleCommand, new object[] { "sleep", 1000000 }, o => o.CancellationToken(alreadyCanceled.Token));
Assert.Throws<TaskCanceledException>(() => command.Wait());
Assert.Throws<TaskCanceledException>(() => command.Result.ToString());
command.Task.Status.ShouldEqual(TaskStatus.Canceled);
Assert.DoesNotThrow(() => command.ProcessId.ToString(), "still executes a command and gets a process ID");
}

[Test]
public void TestCancellationNotCanceled()
{
using (var notCanceled = new CancellationTokenSource())
{
var command = TestShell.Run(SampleCommand, new object[] { "sleep", 1000000 }, o => o.CancellationToken(notCanceled.Token));
command.Task.Wait(50).ShouldEqual(false);
command.Kill();
command.Task.Wait(1000).ShouldEqual(true);
command.Result.Success.ShouldEqual(false);
}
using var notCanceled = new CancellationTokenSource();
var command = TestShell.Run(SampleCommand, new object[] { "sleep", 1000000 }, o => o.CancellationToken(notCanceled.Token));
command.Task.Wait(50).ShouldEqual(false);
command.Kill();
command.Task.Wait(1000).ShouldEqual(true);
command.Result.Success.ShouldEqual(false);
}

[Test]
public void TestCancellationCanceledPartway()
{
using (var cancellationTokenSource = new CancellationTokenSource())
{
var results = new SyncCollection();
var command = TestShell.Run(SampleCommand, new object[] { "echo", "--per-char" }, o => o.CancellationToken(cancellationTokenSource.Token)) > results;
command.StandardInput.WriteLine("hello");
var timeout = Task.Delay(TimeSpan.FromSeconds(10));
while (results.Count == 0 && !timeout.IsCompleted) { }
results.Count.ShouldEqual(1);
cancellationTokenSource.Cancel();
var aggregateException = Assert.Throws<AggregateException>(() => command.Task.Wait(1000));
Assert.IsInstanceOf<TaskCanceledException>(aggregateException.GetBaseException());
CollectionAssert.AreEqual(results, new[] { "hello" });
}
using var cancellationTokenSource = new CancellationTokenSource();
var results = new SyncCollection();
var command = TestShell.Run(SampleCommand, new object[] { "echo", "--per-char" }, o => o.CancellationToken(cancellationTokenSource.Token)) > results;
command.StandardInput.WriteLine("hello");
var timeout = Task.Delay(TimeSpan.FromSeconds(10));
while (results.Count == 0 && !timeout.IsCompleted) { }
results.Count.ShouldEqual(1);
cancellationTokenSource.Cancel();
var aggregateException = Assert.Throws<AggregateException>(() => command.Task.Wait(1000));
Assert.IsInstanceOf<TaskCanceledException>(aggregateException.GetBaseException());
CollectionAssert.AreEqual(results, new[] { "hello" });
}

private class SyncCollection : ICollection<string>
Expand All @@ -207,16 +202,14 @@ private class SyncCollection : ICollection<string>
[Test]
public void TestCancellationCanceledAfterCompletion()
{
using (var cancellationTokenSource = new CancellationTokenSource())
{
var results = new List<string>();
var command = TestShell.Run(SampleCommand, new object[] { "echo" }, o => o.CancellationToken(cancellationTokenSource.Token)) > results;
command.StandardInput.WriteLine("hello");
command.StandardInput.Close();
command.Task.Wait(1000).ShouldEqual(true);
cancellationTokenSource.Cancel();
command.Result.Success.ShouldEqual(true);
}
using var cancellationTokenSource = new CancellationTokenSource();
var results = new List<string>();
var command = TestShell.Run(SampleCommand, new object[] { "echo" }, o => o.CancellationToken(cancellationTokenSource.Token)) > results;
command.StandardInput.WriteLine("hello");
command.StandardInput.Close();
command.Task.Wait(1000).ShouldEqual(true);
cancellationTokenSource.Cancel();
command.Result.Success.ShouldEqual(true);
}

[Test]
Expand Down Expand Up @@ -357,7 +350,7 @@ public void TestVersioning()
var version = typeof(Command).GetTypeInfo().Assembly.GetName().Version.ToString();
var informationalVersion = (AssemblyInformationalVersionAttribute)typeof(Command).GetTypeInfo().Assembly.GetCustomAttribute(typeof(AssemblyInformationalVersionAttribute));
Assert.IsNotNull(informationalVersion);
version.ShouldEqual(informationalVersion.InformationalVersion + ".0");
version.ShouldEqual(Regex.Replace(informationalVersion.InformationalVersion, "-.*$", string.Empty) + ".0");
}

[Test]
Expand Down Expand Up @@ -495,12 +488,10 @@ void TestHelper(bool disposeOnExit)

#if !NETCOREAPP2_2
// https://stackoverflow.com/questions/2633628/can-i-get-command-line-arguments-of-other-processes-from-net-c
string GetCommandLine(int processId)
static string GetCommandLine(int processId)
{
using (var searcher = new System.Management.ManagementObjectSearcher("SELECT CommandLine FROM Win32_Process WHERE ProcessId = " + processId))
{
return searcher.Get().Cast<System.Management.ManagementBaseObject>().Single()["CommandLine"].ToString();
}
using var searcher = new System.Management.ManagementObjectSearcher("SELECT CommandLine FROM Win32_Process WHERE ProcessId = " + processId);
return searcher.Get().Cast<System.Management.ManagementBaseObject>().Single()["CommandLine"].ToString();
}
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
Expand Down
2 changes: 1 addition & 1 deletion MedallionShell.Tests/Streams/PipeTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -364,7 +364,7 @@ public static Task WriteTextAsync(this Pipe @this, string text)
return new StreamWriter(@this.InputStream) { AutoFlush = true }.WriteAsync(text);
}

public static async Task<string?> ReadTextAsync(this Pipe @this, int count, CancellationToken token = default(CancellationToken))
public static async Task<string?> ReadTextAsync(this Pipe @this, int count, CancellationToken token = default)
{
var bytes = new byte[count];
var bytesRead = 0;
Expand Down
10 changes: 5 additions & 5 deletions MedallionShell/MedallionShell.csproj
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFrameworks>netstandard1.3;netstandard2.0;net45;net46</TargetFrameworks>
<TargetFrameworks>netstandard1.3;netstandard2.0;net45;net46;net471</TargetFrameworks>
</PropertyGroup>

<PropertyGroup>
<RootNamespace>Medallion.Shell</RootNamespace>
<Version>1.6.1</Version>
<AssemblyVersion>1.6.1.0</AssemblyVersion>
<FileVersion>1.6.1.0</FileVersion>
<Version>1.6.2-rc01</Version>
<AssemblyVersion>1.6.2.0</AssemblyVersion>
<FileVersion>1.6.2.0</FileVersion>
<Authors>Michael Adelson</Authors>
<Description>A lightweight, cross-platform library that simplifies working with processes in .NET</Description>
<Copyright>Copyright © 2017 Michael Adelson</Copyright>
Expand Down Expand Up @@ -42,7 +42,7 @@
<ItemGroup Condition="'$(TargetFramework)' == 'netstandard1.3'">
<PackageReference Include="System.Diagnostics.Process" version="4.3.0" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'net46'">
<ItemGroup Condition="'$(TargetFramework)' == 'net46' or '$(TargetFramework)' == 'net45'">
<PackageReference Include="System.Runtime.InteropServices.RuntimeInformation" Version="4.3.0" />
</ItemGroup>

Expand Down
25 changes: 1 addition & 24 deletions MedallionShell/PlatformCompatibilityHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,30 +13,7 @@ internal static class PlatformCompatibilityHelper
// see http://www.mono-project.com/docs/faq/technical/
public static readonly bool IsMono = Type.GetType("Mono.Runtime") != null;

public static bool IsWindows
{
get
{
#if !NET45
return RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
#else
if (!IsMono) { return true; }
#pragma warning disable DE0007, DE0009
switch (Environment.OSVersion.Platform)
{
case PlatformID.Win32S:
case PlatformID.Win32Windows:
case PlatformID.Win32NT:
case PlatformID.WinCE:
case PlatformID.Xbox:
return true;
default:
return false;
}
#pragma warning restore DE0007, DE0009
#endif
}
}
public static bool IsWindows => RuntimeInformation.IsOSPlatform(OSPlatform.Windows);

public static CommandLineSyntax GetDefaultCommandLineSyntax()
{
Expand Down
60 changes: 29 additions & 31 deletions MedallionShell/Signals/WindowsProcessSignaler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -69,43 +69,41 @@ private static async Task<bool> SendSignalFromCurrentProcess(int processId, Nati
await SignalFromCurrentProcessLock.WaitAsync().ConfigureAwait(false);
try
{
using (var waitForSignalSemaphore = new SemaphoreSlim(initialCount: 0, maxCount: 1))
using var waitForSignalSemaphore = new SemaphoreSlim(initialCount: 0, maxCount: 1);
NativeMethods.ConsoleCtrlDelegate handler = receivedSignal =>
{
NativeMethods.ConsoleCtrlDelegate handler = receivedSignal =>
if (receivedSignal == signal)
{
if (receivedSignal == signal)
{
waitForSignalSemaphore.Release();
// if we're signaling another process on the same console, we return true
// to prevent the signal from bubbling. If we're signaling ourselves, we
// allow it to bubble since presumably that's what the caller wanted
return processId != ProcessHelper.CurrentProcessId;
}
return false;
};
if (!NativeMethods.SetConsoleCtrlHandler(handler, add: true))
{
Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());
waitForSignalSemaphore.Release();
// if we're signaling another process on the same console, we return true
// to prevent the signal from bubbling. If we're signaling ourselves, we
// allow it to bubble since presumably that's what the caller wanted
return processId != ProcessHelper.CurrentProcessId;
}
try
return false;
};
if (!NativeMethods.SetConsoleCtrlHandler(handler, add: true))
{
Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());
}
try
{
if (!NativeMethods.GenerateConsoleCtrlEvent(signal, NativeMethods.AllProcessesWithCurrentConsoleGroup))
{
if (!NativeMethods.GenerateConsoleCtrlEvent(signal, NativeMethods.AllProcessesWithCurrentConsoleGroup))
{
return false;
}

// Wait until the signal has reached our handler and been handled to know that it is safe to
// remove the handler.
// Timeout here just to ensure we don't hang forever if something weird happens (e. g. someone
// else registers a handler concurrently with us).
return await waitForSignalSemaphore.WaitAsync(TimeSpan.FromSeconds(30)).ConfigureAwait(false);
return false;
}
finally

// Wait until the signal has reached our handler and been handled to know that it is safe to
// remove the handler.
// Timeout here just to ensure we don't hang forever if something weird happens (e. g. someone
// else registers a handler concurrently with us).
return await waitForSignalSemaphore.WaitAsync(TimeSpan.FromSeconds(30)).ConfigureAwait(false);
}
finally
{
if (!NativeMethods.SetConsoleCtrlHandler(handler, add: false))
{
if (!NativeMethods.SetConsoleCtrlHandler(handler, add: false))
{
Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());
}
Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());
}
}
}
Expand Down
28 changes: 13 additions & 15 deletions MedallionShell/Streams/ProcessStreamWriter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -124,23 +124,21 @@ public Task PipeFromAsync(IEnumerable<char> chars, bool leaveWriterOpen = false)
: () => Task.Run(async () =>
{
var buffer = new char[Constants.CharBufferSize];
using (var enumerator = chars.GetEnumerator())
using var enumerator = chars.GetEnumerator();
while (true)
{
while (true)
var i = 0;
while (i < buffer.Length && enumerator.MoveNext())
{
var i = 0;
while (i < buffer.Length && enumerator.MoveNext())
{
buffer[i++] = enumerator.Current;
}
if (i > 0)
{
await this.WriteAsync(buffer, 0, count: i).ConfigureAwait(false);
}
else
{
break;
}
buffer[i++] = enumerator.Current;
}
if (i > 0)
{
await this.WriteAsync(buffer, 0, count: i).ConfigureAwait(false);
}
else
{
break;
}
}
}),
Expand Down

0 comments on commit d0a3cd5

Please sign in to comment.