From ee9ac5316e9e2d0a07588cc48f0d90f5e180ecf9 Mon Sep 17 00:00:00 2001 From: Jihoon Park Date: Mon, 27 May 2024 11:17:13 -0400 Subject: [PATCH] Close #119: Clean up Mono support and replace it with robust .NET 8 support --- MedallionShell.Tests/CommandLineSyntaxTest.cs | 113 +------------ MedallionShell.Tests/GeneralTest.cs | 8 +- .../MedallionShell.Tests.csproj | 25 +-- .../PlatformCompatibilityTest.cs | 38 +---- ...x.cs => CrossPlatformCommandLineSyntax.cs} | 15 +- MedallionShell/ErrorExitCodeException.cs | 4 +- MedallionShell/MedallionShell.csproj | 2 +- MedallionShell/MonoUnixCommandLineSyntax.cs | 68 -------- MedallionShell/PlatformCompatibilityHelper.cs | 44 +---- MedallionShell/ProcessCommand.cs | 3 +- MedallionShell/ProcessHelper.cs | 2 +- .../PublicAPI/net45/PublicAPI.Shipped.txt | 6 +- .../PublicAPI/net46/PublicAPI.Shipped.txt | 6 +- .../PublicAPI/net471/PublicAPI.Shipped.txt | 6 +- .../PublicAPI/net6.0/PublicAPI.Shipped.txt | 6 +- .../PublicAPI/net8.0/PublicAPI.Shipped.txt | 153 ++++++++++++++++++ .../PublicAPI/net8.0/PublicAPI.Unshipped.txt | 1 + .../netstandard1.3/PublicAPI.Shipped.txt | 6 +- .../netstandard2.0/PublicAPI.Shipped.txt | 6 +- .../Streams/ProcessStreamWrapper.cs | 8 +- NugetDocumentation.md | 2 +- README.md | 4 +- SampleCommand/PlatformCompatibilityTests.cs | 7 +- SampleCommand/SampleCommand.csproj | 4 +- appveyor.yml | 11 +- 25 files changed, 222 insertions(+), 326 deletions(-) rename MedallionShell/{WindowsCommandLineSyntax.cs => CrossPlatformCommandLineSyntax.cs} (83%) delete mode 100644 MedallionShell/MonoUnixCommandLineSyntax.cs create mode 100644 MedallionShell/PublicAPI/net8.0/PublicAPI.Shipped.txt create mode 100644 MedallionShell/PublicAPI/net8.0/PublicAPI.Unshipped.txt diff --git a/MedallionShell.Tests/CommandLineSyntaxTest.cs b/MedallionShell.Tests/CommandLineSyntaxTest.cs index 7f7c87e..22115f0 100644 --- a/MedallionShell.Tests/CommandLineSyntaxTest.cs +++ b/MedallionShell.Tests/CommandLineSyntaxTest.cs @@ -14,7 +14,7 @@ public class CommandLineSyntaxTest [Test] public void TestArgumentValidation([Values] bool isWindowsSyntax) { - var syntax = isWindowsSyntax ? new WindowsCommandLineSyntax() : new MonoUnixCommandLineSyntax().As(); + var syntax = new CrossPlatformCommandLineSyntax().As(); Assert.Throws(() => syntax.CreateArgumentString(null!)); Assert.Throws(() => syntax.CreateArgumentString(["a", null!, "b"])); } @@ -29,7 +29,7 @@ public void TestArgumentValidation([Values] bool isWindowsSyntax) [TestCase("\r", "\n", "\r\n")] [TestCase("", "\"", "\\", "")] [TestCase("abc", "a\\b", "a\\ b\"")] - // these chars are treated specially on mono unix + // these chars are treated specially on mono unix, so keeping. [TestCase("`,\\`", "`", "$ $", "$", "\\", "\\$\r\n")] // cases from https://docs.microsoft.com/en-us/cpp/cpp/parsing-cpp-command-line-arguments?view=vs-2019 [TestCase("abc", "d", "e")] @@ -49,7 +49,6 @@ private void TestArgumentsRoundTripHelper(string[] arguments) { this.TestRealRoundTrip(arguments); this.TestAgainstNetCoreArgumentParser(arguments); - this.TestAgainstMonoUnixArgumentParser(arguments); } private void TestRealRoundTrip(string[] arguments) @@ -61,19 +60,12 @@ private void TestRealRoundTrip(string[] arguments) private void TestAgainstNetCoreArgumentParser(string[] arguments) { - var argumentString = new WindowsCommandLineSyntax().CreateArgumentString(arguments); + var argumentString = new CrossPlatformCommandLineSyntax().CreateArgumentString(arguments); var result = new List(); ParseArgumentsIntoList(argumentString, result); CollectionAssert.AreEqual(actual: result, expected: arguments); } - private void TestAgainstMonoUnixArgumentParser(string[] arguments) - { - var argumentString = new MonoUnixCommandLineSyntax().CreateArgumentString(arguments); - var result = SplitCommandLine(argumentString); - CollectionAssert.AreEqual(actual: result, expected: arguments); - } - #region ---- .NET Core Arguments Parser ---- // copied from https://github.com/dotnet/corefx/blob/ccb68c0602656cea9a2a33f35f54dccba9eef784/src/System.Diagnostics.Process/src/System/Diagnostics/Process.Unix.cs#L785 @@ -182,104 +174,5 @@ private static string GetNextArgument(string arguments, ref int i) return currentArgument.ToString(); } #endregion - - #region ---- Mono Unix Arguments Parser ---- - // based on https://github.com/mono/mono/blob/c114ff59d96baba4479361b2679b7de602517877/mono/eglib/gshell.c - - public static List SplitCommandLine(string commandLine) - { - var escaped = false; - var fresh = true; - var quoteChar = '\0'; - var str = new StringBuilder(); - var result = new List(); - - for (var i = 0; i < commandLine.Length; ++i) - { - var c = commandLine[i]; - if (escaped) - { - /* - * \CHAR is only special inside a double quote if CHAR is - * one of: $`"\ and newline - */ - if (quoteChar == '"') - { - if (!(c == '$' || c == '`' || c == '"' || c == '\\')) - { - str.Append('\\'); - } - str.Append(c); - } - else - { - if (!char.IsWhiteSpace(c)) - { - str.Append(c); - } - } - escaped = false; - } - else if (quoteChar != '\0') - { - if (c == quoteChar) - { - quoteChar = '\0'; - if (fresh && (i + 1 == commandLine.Length || char.IsWhiteSpace(commandLine[i + 1]))) - { - result.Add(str.ToString()); - str.Clear(); - } - } - else if (c == '\\') - { - escaped = true; - } - else - { - str.Append(c); - } - } - else if (char.IsWhiteSpace(c)) - { - if (str.Length > 0) - { - result.Add(str.ToString()); - str.Clear(); - } - } - else if (c == '\\') - { - escaped = true; - } - else if (c == '\'' || c == '"') - { - fresh = str.Length == 0; - quoteChar = c; - } - else - { - str.Append(c); - } - } - - if (escaped) - { - throw new FormatException($"Unfinished escape: '{commandLine}'"); - } - - if (quoteChar != '\0') - { - throw new FormatException($"Unfinished quote: '{commandLine}'"); - } - - if (str.Length > 0) - { - result.Add(str.ToString()); - } - - return result; - } - #endregion } } diff --git a/MedallionShell.Tests/GeneralTest.cs b/MedallionShell.Tests/GeneralTest.cs index c1a7f42..83accd0 100644 --- a/MedallionShell.Tests/GeneralTest.cs +++ b/MedallionShell.Tests/GeneralTest.cs @@ -400,7 +400,7 @@ public void TestEncoding() var bytes = new byte[] { 255 }; var inputEncoded = Console.InputEncoding.GetString(bytes); inputEncoded.ShouldEqual(Console.OutputEncoding.GetString(bytes)); // sanity check - // mono and .NET Core will default to UTF8 + // .NET Core will default to UTF8 var defaultsToUtf8 = Console.InputEncoding.WebName == Encoding.UTF8.WebName; if (!defaultsToUtf8) { @@ -582,10 +582,8 @@ public void TestProcessKeepsWritingAfterOutputIsClosed() command.StandardInput.WriteLine(new string('a', i)); } - // workaround for https://github.com/mono/mono/issues/18279; so far - // I've encountered this only on Mono Linux - if (PlatformCompatibilityHelper.IsMono - && !RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + // TODO: This used to be a workaround for https://github.com/mono/mono/issues/18279 + if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { command.StandardInput.Dispose(); command.Task.Wait(TimeSpan.FromSeconds(1000)).ShouldEqual(true); diff --git a/MedallionShell.Tests/MedallionShell.Tests.csproj b/MedallionShell.Tests/MedallionShell.Tests.csproj index e449524..fbad9df 100644 --- a/MedallionShell.Tests/MedallionShell.Tests.csproj +++ b/MedallionShell.Tests/MedallionShell.Tests.csproj @@ -1,34 +1,37 @@  - - net6.0;net462 + + + + net8.0;net6.0;net462 false Latest enable - True - ..\stylecop.analyzers.ruleset - true + True + ..\stylecop.analyzers.ruleset + true 1591 Medallion.Shell.Tests - - - - + + + + All - + - + + diff --git a/MedallionShell.Tests/PlatformCompatibilityTest.cs b/MedallionShell.Tests/PlatformCompatibilityTest.cs index 6460034..6f759f0 100644 --- a/MedallionShell.Tests/PlatformCompatibilityTest.cs +++ b/MedallionShell.Tests/PlatformCompatibilityTest.cs @@ -1,25 +1,19 @@ using System; -using System.Collections.Generic; -using System.Linq; using System.Linq.Expressions; -using System.Runtime.InteropServices; -using System.Text; using System.Threading.Tasks; using NUnit.Framework; using SampleCommand; namespace Medallion.Shell.Tests { - using System.IO; - using static UnitTestHelpers; - public class PlatformCompatibilityTest { [Test] public Task TestReadAfterExit() => RunTestAsync(() => PlatformCompatibilityTests.TestReadAfterExit()); - [Test] - public Task TestWriteAfterExit() => RunTestAsync(() => PlatformCompatibilityTests.TestWriteAfterExit()); + // TODO: fix in https://github.com/madelson/MedallionShell/issues/117 + //[Test] + //public Task TestWriteAfterExit() => RunTestAsync(() => PlatformCompatibilityTests.TestWriteAfterExit()); [Test] public Task TestFlushAfterExit() => RunTestAsync(() => PlatformCompatibilityTests.TestFlushAfterExit()); @@ -50,33 +44,7 @@ private static async Task RunTestAsync(Expression testMethod) var compiled = testMethod.Compile(); Assert.DoesNotThrow(() => compiled(), "should run on current platform"); - // don't bother testing running Mono from .NET Core or Mono itself -#if NETFRAMEWORK - if (!PlatformCompatibilityHelper.IsMono) - { - var methodName = ((MethodCallExpression)testMethod.Body).Method.Name; - - var monoPath = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? @"C:\Program Files\Mono\bin\mono.exe" : "/usr/bin/mono"; - if (!File.Exists(monoPath)) - { - // https://www.appveyor.com/docs/environment-variables/ - if (Environment.GetEnvironmentVariable("APPVEYOR")?.ToLowerInvariant() == "true") - { - // not on VS2017 VM yet: https://www.appveyor.com/docs/windows-images-software/ - Console.WriteLine("On APPVEYOR with no Mono installed; skipping mono test"); - return; - } - - Assert.Fail($"Could not find mono install at {monoPath}"); - } - - var command = Command.Run(monoPath, SampleCommand, nameof(PlatformCompatibilityTests), methodName); - await command.Task; - command.Result.Success.ShouldEqual(true, "should run on Mono. Got: " + command.Result.StandardError); - } -#else await Task.CompletedTask; // make the compiler happy -#endif } } } diff --git a/MedallionShell/WindowsCommandLineSyntax.cs b/MedallionShell/CrossPlatformCommandLineSyntax.cs similarity index 83% rename from MedallionShell/WindowsCommandLineSyntax.cs rename to MedallionShell/CrossPlatformCommandLineSyntax.cs index e5b99fd..817876f 100644 --- a/MedallionShell/WindowsCommandLineSyntax.cs +++ b/MedallionShell/CrossPlatformCommandLineSyntax.cs @@ -1,24 +1,21 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Text; -using System.Text.RegularExpressions; -using System.Threading.Tasks; namespace Medallion.Shell { /// - /// Provides functionality for windows. + /// Provides cross-platform functionality. /// /// Note that while this class uses windows parsing rules, .NET Core actually follows the same rules when parsing - /// into argv for unix-like systems. Therefore, this class is actually - /// cross-platform compatible. The one exception is Mono running on Unix, which uses a different escaping scheme. + /// into argv for unix-like systems. + /// This does not work for Mono running on Unix, which uses a different escaping scheme. /// - public sealed class WindowsCommandLineSyntax : CommandLineSyntax + public sealed class CrossPlatformCommandLineSyntax : CommandLineSyntax { /// - /// Provides functionality for windows + /// Provides cross-platform functionality /// public override string CreateArgumentString(IEnumerable arguments) => CreateArgumentString(arguments, AppendArgument); diff --git a/MedallionShell/ErrorExitCodeException.cs b/MedallionShell/ErrorExitCodeException.cs index 19038f6..7f88e94 100644 --- a/MedallionShell/ErrorExitCodeException.cs +++ b/MedallionShell/ErrorExitCodeException.cs @@ -14,9 +14,9 @@ namespace Medallion.Shell public sealed class ErrorExitCodeException : Exception { internal ErrorExitCodeException(Process process) - : base(string.Format("Process {0} ({1} {2}) exited with non-zero value {3}", process.Id, process.StartInfo.FileName, process.StartInfo.Arguments, process.SafeGetExitCode())) + : base(string.Format("Process {0} ({1} {2}) exited with non-zero value {3}", process.Id, process.StartInfo.FileName, process.StartInfo.Arguments, process.ExitCode)) { - this.ExitCode = process.SafeGetExitCode(); + this.ExitCode = process.ExitCode; } /// diff --git a/MedallionShell/MedallionShell.csproj b/MedallionShell/MedallionShell.csproj index 3efaeac..12be097 100644 --- a/MedallionShell/MedallionShell.csproj +++ b/MedallionShell/MedallionShell.csproj @@ -1,7 +1,7 @@  - net6.0;netstandard1.3;netstandard2.0;net45;net46;net471 + net8.0;net6.0;netstandard1.3;netstandard2.0;net45;net46;net471 diff --git a/MedallionShell/MonoUnixCommandLineSyntax.cs b/MedallionShell/MonoUnixCommandLineSyntax.cs deleted file mode 100644 index 99466f4..0000000 --- a/MedallionShell/MonoUnixCommandLineSyntax.cs +++ /dev/null @@ -1,68 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -namespace Medallion.Shell -{ - /// - /// Mono on unix uses a different, incompatible method of splitting the command line into arguments - /// than is the default on Windows. This is referenced here: https://bugzilla.xamarin.com/show_bug.cgi?id=19296, - /// although the "quick fix" it mentions does not fully account for the differences. - /// - internal sealed class MonoUnixCommandLineSyntax : CommandLineSyntax - { - // On unix, it seems that Mono calls g_shell_parse_argv: - // https://github.com/mono/mono/blob/e8c660ce90efc7966ffc6fa9753ac237b2afadf2/mono/metadata/w32process-unix.c#L2174 - // follow that to here: - // https://github.com/mono/mono/blob/e8c660ce90efc7966ffc6fa9753ac237b2afadf2/mono/metadata/w32process-unix.c#L1638 - // calls g_shell_parse_argv here: - // https://github.com/mono/mono/blob/e8c660ce90efc7966ffc6fa9753ac237b2afadf2/mono/metadata/w32process-unix.c#L1786 - // defined here: https://github.com/mono/mono/blob/c114ff59d96baba4479361b2679b7de602517877/mono/eglib/gshell.c - - public override string CreateArgumentString(IEnumerable arguments) => CreateArgumentString(arguments, AppendArgument); - - private static void AppendArgument(string argument, StringBuilder builder) - { - // this method reverse-engineers the code Mono uses to split the command line. - // A C# port of Mono's split method can be seen in the tests - - if (argument.Length > 0 - && !argument.Any(IsSpecialCharacter)) - { - builder.Append(argument); - return; - } - - builder.Append('"'); - for (var i = 0; i < argument.Length; ++i) - { - var @char = argument[i]; - switch (@char) - { - case '$': - case '`': - case '"': - case '\\': - builder.Append('\\'); - break; - } - builder.Append(@char); - } - builder.Append('"'); - } - - private static bool IsSpecialCharacter(char @char) - { - switch (@char) - { - case '\\': - case '\'': - case '"': - return true; - default: - return char.IsWhiteSpace(@char); - } - } - } -} diff --git a/MedallionShell/PlatformCompatibilityHelper.cs b/MedallionShell/PlatformCompatibilityHelper.cs index a827a2d..9708126 100644 --- a/MedallionShell/PlatformCompatibilityHelper.cs +++ b/MedallionShell/PlatformCompatibilityHelper.cs @@ -1,18 +1,12 @@ using System; -using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Runtime.InteropServices; -using System.Text; -using Medallion.Shell.Streams; namespace Medallion.Shell { 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 readonly bool IsWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows); /// @@ -21,38 +15,12 @@ internal static class PlatformCompatibilityHelper /// public static bool ProcessStreamsUseSyncIO => IsWindows; - public static bool ProcessStreamWriteThrowsOnProcessEnd => !IsWindows || IsMono; - - public static readonly CommandLineSyntax DefaultCommandLineSyntax = - IsMono && !IsWindows - ? new MonoUnixCommandLineSyntax() - : new WindowsCommandLineSyntax(); + public static bool ProcessStreamWriteThrowsOnProcessEnd => !IsWindows; - public static int SafeGetExitCode(this Process process) - { - if (IsMono) - { - // an oddity of Mono is that it cannot return an exit code of -1; interpreting this as something - // else. Unfortunately, this is what we get when calling Kill() on a .NET process on Windows. This - // hack works around the issue. See https://github.com/mono/mono/blob/master/mcs/class/referencesource/System/services/monitoring/system/diagnosticts/Process.cs - // for where this happens in the Mono source - try { return process.ExitCode; } - catch (InvalidOperationException ex) - when (ex.Message == "Cannot get the exit code from a non-child process on Unix") - { - return -1; - } - } - - return process.ExitCode; - } + public static readonly CommandLineSyntax DefaultCommandLineSyntax = new CrossPlatformCommandLineSyntax(); /// - /// Starts the given and captures the standard IO streams. This method works around Mono.Android-specific - /// issue https://github.com/madelson/MedallionShell/issues/22, where a process that exits quickly causes the initialization of - /// the standard input writer to fail (since setting AutoFlush = true triggers a write which on Mono crashes for a closed process). - /// - /// If https://github.com/mono/mono/issues/8478 is ever addressed, we wouldn't need this any more. + /// Starts the given and captures the standard IO streams. /// public static bool SafeStart(this Process process, out StreamWriter? standardInput, out StreamReader? standardOutput, out StreamReader? standardError) { @@ -69,11 +37,7 @@ public static bool SafeStart(this Process process, out StreamWriter? standardInp // process.StandardInput.BaseStream.Write(new byte[1000], 0, 1000); // process.StandardInput.BaseStream.Flush(); } - catch (IOException ex) - // note that AFAIK the exact type check here isn't necessary, but it seems more robust against - // other types of IOExceptions (e. g. FileNotFoundException, PathTooLongException) that could in - // theory be thrown here and trigger this - when (IsMono && ex.GetType() == typeof(IOException)) + catch { standardInput = redirectStandardInput ? new StreamWriter(Stream.Null, Console.InputEncoding) { AutoFlush = true } : null; standardOutput = redirectStandardOutput ? new StreamReader(Stream.Null, Console.OutputEncoding) : null; diff --git a/MedallionShell/ProcessCommand.cs b/MedallionShell/ProcessCommand.cs index c038175..176a064 100644 --- a/MedallionShell/ProcessCommand.cs +++ b/MedallionShell/ProcessCommand.cs @@ -170,8 +170,7 @@ private static Task CreateProcessMonitoringTask(Process process) { var taskBuilder = new TaskCompletionSource(); // note: calling TrySetResult here on the off chance that a bug causes this event to fire twice. - // Apparently old versions of mono had such a bug. The issue is that any exception in this event - // can down the process since it fires on an unprotected threadpool thread + // The issue is that any exception in this event can down the process since it fires on an unprotected threadpool thread process.Exited += (o, e) => taskBuilder.TrySetResult(false); return taskBuilder.Task; diff --git a/MedallionShell/ProcessHelper.cs b/MedallionShell/ProcessHelper.cs index bcef9e6..b13d273 100644 --- a/MedallionShell/ProcessHelper.cs +++ b/MedallionShell/ProcessHelper.cs @@ -91,7 +91,7 @@ public static Task CreateProcessTask( // disposes out from under us try { - var exitCode = process.SafeGetExitCode(); + var exitCode = process.ExitCode; if (throwOnError && exitCode != 0) { taskBuilder.SetException(new ErrorExitCodeException(process)); diff --git a/MedallionShell/PublicAPI/net45/PublicAPI.Shipped.txt b/MedallionShell/PublicAPI/net45/PublicAPI.Shipped.txt index 48d22c1..77d318e 100644 --- a/MedallionShell/PublicAPI/net45/PublicAPI.Shipped.txt +++ b/MedallionShell/PublicAPI/net45/PublicAPI.Shipped.txt @@ -80,8 +80,8 @@ Medallion.Shell.Streams.ProcessStreamWriter.PipeFromAsync(System.Collections.Gen Medallion.Shell.Streams.ProcessStreamWriter.PipeFromAsync(System.IO.FileInfo! file, bool leaveWriterOpen = false) -> System.Threading.Tasks.Task! Medallion.Shell.Streams.ProcessStreamWriter.PipeFromAsync(System.IO.Stream! stream, bool leaveWriterOpen = false, bool leaveStreamOpen = false) -> System.Threading.Tasks.Task! Medallion.Shell.Streams.ProcessStreamWriter.PipeFromAsync(System.IO.TextReader! reader, bool leaveWriterOpen = false, bool leaveReaderOpen = false) -> System.Threading.Tasks.Task! -Medallion.Shell.WindowsCommandLineSyntax -Medallion.Shell.WindowsCommandLineSyntax.WindowsCommandLineSyntax() -> void +Medallion.Shell.CrossPlatformCommandLineSyntax +Medallion.Shell.CrossPlatformCommandLineSyntax.CrossPlatformCommandLineSyntax() -> void override Medallion.Shell.Streams.ProcessStreamWriter.Encoding.get -> System.Text.Encoding! override Medallion.Shell.Streams.ProcessStreamWriter.Flush() -> void override Medallion.Shell.Streams.ProcessStreamWriter.FlushAsync() -> System.Threading.Tasks.Task! @@ -130,7 +130,7 @@ override Medallion.Shell.Streams.ProcessStreamWriter.WriteLineAsync() -> System. override Medallion.Shell.Streams.ProcessStreamWriter.WriteLineAsync(char value) -> System.Threading.Tasks.Task! override Medallion.Shell.Streams.ProcessStreamWriter.WriteLineAsync(char[]! buffer, int index, int count) -> System.Threading.Tasks.Task! override Medallion.Shell.Streams.ProcessStreamWriter.WriteLineAsync(string? value) -> System.Threading.Tasks.Task! -override Medallion.Shell.WindowsCommandLineSyntax.CreateArgumentString(System.Collections.Generic.IEnumerable! arguments) -> string! +override Medallion.Shell.CrossPlatformCommandLineSyntax.CreateArgumentString(System.Collections.Generic.IEnumerable! arguments) -> string! static Medallion.Shell.Command.operator <(Medallion.Shell.Command! command, System.Collections.Generic.IEnumerable! chars) -> Medallion.Shell.Command! static Medallion.Shell.Command.operator <(Medallion.Shell.Command! command, System.Collections.Generic.IEnumerable! lines) -> Medallion.Shell.Command! static Medallion.Shell.Command.operator <(Medallion.Shell.Command! command, System.IO.FileInfo! file) -> Medallion.Shell.Command! diff --git a/MedallionShell/PublicAPI/net46/PublicAPI.Shipped.txt b/MedallionShell/PublicAPI/net46/PublicAPI.Shipped.txt index 48d22c1..77d318e 100644 --- a/MedallionShell/PublicAPI/net46/PublicAPI.Shipped.txt +++ b/MedallionShell/PublicAPI/net46/PublicAPI.Shipped.txt @@ -80,8 +80,8 @@ Medallion.Shell.Streams.ProcessStreamWriter.PipeFromAsync(System.Collections.Gen Medallion.Shell.Streams.ProcessStreamWriter.PipeFromAsync(System.IO.FileInfo! file, bool leaveWriterOpen = false) -> System.Threading.Tasks.Task! Medallion.Shell.Streams.ProcessStreamWriter.PipeFromAsync(System.IO.Stream! stream, bool leaveWriterOpen = false, bool leaveStreamOpen = false) -> System.Threading.Tasks.Task! Medallion.Shell.Streams.ProcessStreamWriter.PipeFromAsync(System.IO.TextReader! reader, bool leaveWriterOpen = false, bool leaveReaderOpen = false) -> System.Threading.Tasks.Task! -Medallion.Shell.WindowsCommandLineSyntax -Medallion.Shell.WindowsCommandLineSyntax.WindowsCommandLineSyntax() -> void +Medallion.Shell.CrossPlatformCommandLineSyntax +Medallion.Shell.CrossPlatformCommandLineSyntax.CrossPlatformCommandLineSyntax() -> void override Medallion.Shell.Streams.ProcessStreamWriter.Encoding.get -> System.Text.Encoding! override Medallion.Shell.Streams.ProcessStreamWriter.Flush() -> void override Medallion.Shell.Streams.ProcessStreamWriter.FlushAsync() -> System.Threading.Tasks.Task! @@ -130,7 +130,7 @@ override Medallion.Shell.Streams.ProcessStreamWriter.WriteLineAsync() -> System. override Medallion.Shell.Streams.ProcessStreamWriter.WriteLineAsync(char value) -> System.Threading.Tasks.Task! override Medallion.Shell.Streams.ProcessStreamWriter.WriteLineAsync(char[]! buffer, int index, int count) -> System.Threading.Tasks.Task! override Medallion.Shell.Streams.ProcessStreamWriter.WriteLineAsync(string? value) -> System.Threading.Tasks.Task! -override Medallion.Shell.WindowsCommandLineSyntax.CreateArgumentString(System.Collections.Generic.IEnumerable! arguments) -> string! +override Medallion.Shell.CrossPlatformCommandLineSyntax.CreateArgumentString(System.Collections.Generic.IEnumerable! arguments) -> string! static Medallion.Shell.Command.operator <(Medallion.Shell.Command! command, System.Collections.Generic.IEnumerable! chars) -> Medallion.Shell.Command! static Medallion.Shell.Command.operator <(Medallion.Shell.Command! command, System.Collections.Generic.IEnumerable! lines) -> Medallion.Shell.Command! static Medallion.Shell.Command.operator <(Medallion.Shell.Command! command, System.IO.FileInfo! file) -> Medallion.Shell.Command! diff --git a/MedallionShell/PublicAPI/net471/PublicAPI.Shipped.txt b/MedallionShell/PublicAPI/net471/PublicAPI.Shipped.txt index 48d22c1..77d318e 100644 --- a/MedallionShell/PublicAPI/net471/PublicAPI.Shipped.txt +++ b/MedallionShell/PublicAPI/net471/PublicAPI.Shipped.txt @@ -80,8 +80,8 @@ Medallion.Shell.Streams.ProcessStreamWriter.PipeFromAsync(System.Collections.Gen Medallion.Shell.Streams.ProcessStreamWriter.PipeFromAsync(System.IO.FileInfo! file, bool leaveWriterOpen = false) -> System.Threading.Tasks.Task! Medallion.Shell.Streams.ProcessStreamWriter.PipeFromAsync(System.IO.Stream! stream, bool leaveWriterOpen = false, bool leaveStreamOpen = false) -> System.Threading.Tasks.Task! Medallion.Shell.Streams.ProcessStreamWriter.PipeFromAsync(System.IO.TextReader! reader, bool leaveWriterOpen = false, bool leaveReaderOpen = false) -> System.Threading.Tasks.Task! -Medallion.Shell.WindowsCommandLineSyntax -Medallion.Shell.WindowsCommandLineSyntax.WindowsCommandLineSyntax() -> void +Medallion.Shell.CrossPlatformCommandLineSyntax +Medallion.Shell.CrossPlatformCommandLineSyntax.CrossPlatformCommandLineSyntax() -> void override Medallion.Shell.Streams.ProcessStreamWriter.Encoding.get -> System.Text.Encoding! override Medallion.Shell.Streams.ProcessStreamWriter.Flush() -> void override Medallion.Shell.Streams.ProcessStreamWriter.FlushAsync() -> System.Threading.Tasks.Task! @@ -130,7 +130,7 @@ override Medallion.Shell.Streams.ProcessStreamWriter.WriteLineAsync() -> System. override Medallion.Shell.Streams.ProcessStreamWriter.WriteLineAsync(char value) -> System.Threading.Tasks.Task! override Medallion.Shell.Streams.ProcessStreamWriter.WriteLineAsync(char[]! buffer, int index, int count) -> System.Threading.Tasks.Task! override Medallion.Shell.Streams.ProcessStreamWriter.WriteLineAsync(string? value) -> System.Threading.Tasks.Task! -override Medallion.Shell.WindowsCommandLineSyntax.CreateArgumentString(System.Collections.Generic.IEnumerable! arguments) -> string! +override Medallion.Shell.CrossPlatformCommandLineSyntax.CreateArgumentString(System.Collections.Generic.IEnumerable! arguments) -> string! static Medallion.Shell.Command.operator <(Medallion.Shell.Command! command, System.Collections.Generic.IEnumerable! chars) -> Medallion.Shell.Command! static Medallion.Shell.Command.operator <(Medallion.Shell.Command! command, System.Collections.Generic.IEnumerable! lines) -> Medallion.Shell.Command! static Medallion.Shell.Command.operator <(Medallion.Shell.Command! command, System.IO.FileInfo! file) -> Medallion.Shell.Command! diff --git a/MedallionShell/PublicAPI/net6.0/PublicAPI.Shipped.txt b/MedallionShell/PublicAPI/net6.0/PublicAPI.Shipped.txt index 90efd96..3aab347 100644 --- a/MedallionShell/PublicAPI/net6.0/PublicAPI.Shipped.txt +++ b/MedallionShell/PublicAPI/net6.0/PublicAPI.Shipped.txt @@ -80,8 +80,8 @@ Medallion.Shell.Streams.ProcessStreamWriter.PipeFromAsync(System.Collections.Gen Medallion.Shell.Streams.ProcessStreamWriter.PipeFromAsync(System.IO.FileInfo! file, bool leaveWriterOpen = false) -> System.Threading.Tasks.Task! Medallion.Shell.Streams.ProcessStreamWriter.PipeFromAsync(System.IO.Stream! stream, bool leaveWriterOpen = false, bool leaveStreamOpen = false) -> System.Threading.Tasks.Task! Medallion.Shell.Streams.ProcessStreamWriter.PipeFromAsync(System.IO.TextReader! reader, bool leaveWriterOpen = false, bool leaveReaderOpen = false) -> System.Threading.Tasks.Task! -Medallion.Shell.WindowsCommandLineSyntax -Medallion.Shell.WindowsCommandLineSyntax.WindowsCommandLineSyntax() -> void +Medallion.Shell.CrossPlatformCommandLineSyntax +Medallion.Shell.CrossPlatformCommandLineSyntax.CrossPlatformCommandLineSyntax() -> void override Medallion.Shell.Streams.ProcessStreamWriter.Encoding.get -> System.Text.Encoding! override Medallion.Shell.Streams.ProcessStreamWriter.Flush() -> void override Medallion.Shell.Streams.ProcessStreamWriter.FlushAsync() -> System.Threading.Tasks.Task! @@ -134,7 +134,7 @@ override Medallion.Shell.Streams.ProcessStreamWriter.WriteLineAsync(char value) override Medallion.Shell.Streams.ProcessStreamWriter.WriteLineAsync(char[]! buffer, int index, int count) -> System.Threading.Tasks.Task! override Medallion.Shell.Streams.ProcessStreamWriter.WriteLineAsync(string? value) -> System.Threading.Tasks.Task! override Medallion.Shell.Streams.ProcessStreamWriter.WriteLineAsync(System.ReadOnlyMemory buffer, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.Task! -override Medallion.Shell.WindowsCommandLineSyntax.CreateArgumentString(System.Collections.Generic.IEnumerable! arguments) -> string! +override Medallion.Shell.CrossPlatformCommandLineSyntax.CreateArgumentString(System.Collections.Generic.IEnumerable! arguments) -> string! static Medallion.Shell.Command.operator <(Medallion.Shell.Command! command, System.Collections.Generic.IEnumerable! chars) -> Medallion.Shell.Command! static Medallion.Shell.Command.operator <(Medallion.Shell.Command! command, System.Collections.Generic.IEnumerable! lines) -> Medallion.Shell.Command! static Medallion.Shell.Command.operator <(Medallion.Shell.Command! command, System.IO.FileInfo! file) -> Medallion.Shell.Command! diff --git a/MedallionShell/PublicAPI/net8.0/PublicAPI.Shipped.txt b/MedallionShell/PublicAPI/net8.0/PublicAPI.Shipped.txt new file mode 100644 index 0000000..3aab347 --- /dev/null +++ b/MedallionShell/PublicAPI/net8.0/PublicAPI.Shipped.txt @@ -0,0 +1,153 @@ +#nullable enable +abstract Medallion.Shell.Command.Kill() -> void +abstract Medallion.Shell.Command.Process.get -> System.Diagnostics.Process! +abstract Medallion.Shell.Command.Processes.get -> System.Collections.Generic.IReadOnlyList! +abstract Medallion.Shell.Command.ProcessId.get -> int +abstract Medallion.Shell.Command.ProcessIds.get -> System.Collections.Generic.IReadOnlyList! +abstract Medallion.Shell.Command.StandardError.get -> Medallion.Shell.Streams.ProcessStreamReader! +abstract Medallion.Shell.Command.StandardInput.get -> Medallion.Shell.Streams.ProcessStreamWriter! +abstract Medallion.Shell.Command.StandardOutput.get -> Medallion.Shell.Streams.ProcessStreamReader! +abstract Medallion.Shell.Command.Task.get -> System.Threading.Tasks.Task! +abstract Medallion.Shell.CommandLineSyntax.CreateArgumentString(System.Collections.Generic.IEnumerable! arguments) -> string! +abstract Medallion.Shell.Streams.ProcessStreamReader.BaseStream.get -> System.IO.Stream! +abstract Medallion.Shell.Streams.ProcessStreamReader.Discard() -> void +abstract Medallion.Shell.Streams.ProcessStreamReader.Encoding.get -> System.Text.Encoding! +abstract Medallion.Shell.Streams.ProcessStreamReader.StopBuffering() -> void +Medallion.Shell.Command +Medallion.Shell.Command.GetOutputAndErrorLines() -> System.Collections.Generic.IEnumerable! +Medallion.Shell.Command.PipeTo(Medallion.Shell.Command! second) -> Medallion.Shell.Command! +Medallion.Shell.Command.RedirectFrom(System.Collections.Generic.IEnumerable! chars) -> Medallion.Shell.Command! +Medallion.Shell.Command.RedirectFrom(System.Collections.Generic.IEnumerable! lines) -> Medallion.Shell.Command! +Medallion.Shell.Command.RedirectFrom(System.IO.FileInfo! file) -> Medallion.Shell.Command! +Medallion.Shell.Command.RedirectFrom(System.IO.Stream! stream) -> Medallion.Shell.Command! +Medallion.Shell.Command.RedirectFrom(System.IO.TextReader! reader) -> Medallion.Shell.Command! +Medallion.Shell.Command.RedirectStandardErrorTo(System.Collections.Generic.ICollection! chars) -> Medallion.Shell.Command! +Medallion.Shell.Command.RedirectStandardErrorTo(System.Collections.Generic.ICollection! lines) -> Medallion.Shell.Command! +Medallion.Shell.Command.RedirectStandardErrorTo(System.IO.FileInfo! file) -> Medallion.Shell.Command! +Medallion.Shell.Command.RedirectStandardErrorTo(System.IO.Stream! stream) -> Medallion.Shell.Command! +Medallion.Shell.Command.RedirectStandardErrorTo(System.IO.TextWriter! writer) -> Medallion.Shell.Command! +Medallion.Shell.Command.RedirectTo(System.Collections.Generic.ICollection! chars) -> Medallion.Shell.Command! +Medallion.Shell.Command.RedirectTo(System.Collections.Generic.ICollection! lines) -> Medallion.Shell.Command! +Medallion.Shell.Command.RedirectTo(System.IO.FileInfo! file) -> Medallion.Shell.Command! +Medallion.Shell.Command.RedirectTo(System.IO.Stream! stream) -> Medallion.Shell.Command! +Medallion.Shell.Command.RedirectTo(System.IO.TextWriter! writer) -> Medallion.Shell.Command! +Medallion.Shell.Command.Result.get -> Medallion.Shell.CommandResult! +Medallion.Shell.Command.TrySignalAsync(Medallion.Shell.CommandSignal! signal) -> System.Threading.Tasks.Task! +Medallion.Shell.Command.Wait() -> void +Medallion.Shell.CommandLineSyntax +Medallion.Shell.CommandLineSyntax.CommandLineSyntax() -> void +Medallion.Shell.CommandResult +Medallion.Shell.CommandResult.ExitCode.get -> int +Medallion.Shell.CommandResult.StandardError.get -> string! +Medallion.Shell.CommandResult.StandardOutput.get -> string! +Medallion.Shell.CommandResult.Success.get -> bool +Medallion.Shell.CommandSignal +Medallion.Shell.ErrorExitCodeException +Medallion.Shell.ErrorExitCodeException.ExitCode.get -> int +Medallion.Shell.Shell +Medallion.Shell.Shell.Options +Medallion.Shell.Shell.Options.CancellationToken(System.Threading.CancellationToken cancellationToken) -> Medallion.Shell.Shell.Options! +Medallion.Shell.Shell.Options.Command(System.Action! initializer) -> Medallion.Shell.Shell.Options! +Medallion.Shell.Shell.Options.Command(System.Func! initializer) -> Medallion.Shell.Shell.Options! +Medallion.Shell.Shell.Options.DisposeOnExit(bool value = true) -> Medallion.Shell.Shell.Options! +Medallion.Shell.Shell.Options.Encoding(System.Text.Encoding! encoding) -> Medallion.Shell.Shell.Options! +Medallion.Shell.Shell.Options.EnvironmentVariable(string! name, string! value) -> Medallion.Shell.Shell.Options! +Medallion.Shell.Shell.Options.EnvironmentVariables(System.Collections.Generic.IEnumerable>! environmentVariables) -> Medallion.Shell.Shell.Options! +Medallion.Shell.Shell.Options.RestoreDefaults() -> Medallion.Shell.Shell.Options! +Medallion.Shell.Shell.Options.StartInfo(System.Action! initializer) -> Medallion.Shell.Shell.Options! +Medallion.Shell.Shell.Options.Syntax(Medallion.Shell.CommandLineSyntax! syntax) -> Medallion.Shell.Shell.Options! +Medallion.Shell.Shell.Options.ThrowOnError(bool value = true) -> Medallion.Shell.Shell.Options! +Medallion.Shell.Shell.Options.Timeout(System.TimeSpan timeout) -> Medallion.Shell.Shell.Options! +Medallion.Shell.Shell.Options.WorkingDirectory(string! path) -> Medallion.Shell.Shell.Options! +Medallion.Shell.Shell.Run(string! executable, params object![]! arguments) -> Medallion.Shell.Command! +Medallion.Shell.Shell.Run(string! executable, System.Collections.Generic.IEnumerable? arguments = null, System.Action? options = null) -> Medallion.Shell.Command! +Medallion.Shell.Shell.Shell(System.Action! options) -> void +Medallion.Shell.Shell.TryAttachToProcess(int processId, out Medallion.Shell.Command? attachedCommand) -> bool +Medallion.Shell.Shell.TryAttachToProcess(int processId, System.Action? options, out Medallion.Shell.Command? attachedCommand) -> bool +Medallion.Shell.Streams.ProcessStreamReader +Medallion.Shell.Streams.ProcessStreamReader.GetLines() -> System.Collections.Generic.IEnumerable! +Medallion.Shell.Streams.ProcessStreamReader.PipeToAsync(System.Collections.Generic.ICollection! chars, bool leaveReaderOpen = false) -> System.Threading.Tasks.Task! +Medallion.Shell.Streams.ProcessStreamReader.PipeToAsync(System.Collections.Generic.ICollection! lines, bool leaveReaderOpen = false) -> System.Threading.Tasks.Task! +Medallion.Shell.Streams.ProcessStreamReader.PipeToAsync(System.IO.FileInfo! file, bool leaveReaderOpen = false) -> System.Threading.Tasks.Task! +Medallion.Shell.Streams.ProcessStreamReader.PipeToAsync(System.IO.Stream! stream, bool leaveReaderOpen = false, bool leaveStreamOpen = false) -> System.Threading.Tasks.Task! +Medallion.Shell.Streams.ProcessStreamReader.PipeToAsync(System.IO.TextWriter! writer, bool leaveReaderOpen = false, bool leaveWriterOpen = false) -> System.Threading.Tasks.Task! +Medallion.Shell.Streams.ProcessStreamWriter +Medallion.Shell.Streams.ProcessStreamWriter.AutoFlush.get -> bool +Medallion.Shell.Streams.ProcessStreamWriter.AutoFlush.set -> void +Medallion.Shell.Streams.ProcessStreamWriter.BaseStream.get -> System.IO.Stream! +Medallion.Shell.Streams.ProcessStreamWriter.PipeFromAsync(System.Collections.Generic.IEnumerable! chars, bool leaveWriterOpen = false) -> System.Threading.Tasks.Task! +Medallion.Shell.Streams.ProcessStreamWriter.PipeFromAsync(System.Collections.Generic.IEnumerable! lines, bool leaveWriterOpen = false) -> System.Threading.Tasks.Task! +Medallion.Shell.Streams.ProcessStreamWriter.PipeFromAsync(System.IO.FileInfo! file, bool leaveWriterOpen = false) -> System.Threading.Tasks.Task! +Medallion.Shell.Streams.ProcessStreamWriter.PipeFromAsync(System.IO.Stream! stream, bool leaveWriterOpen = false, bool leaveStreamOpen = false) -> System.Threading.Tasks.Task! +Medallion.Shell.Streams.ProcessStreamWriter.PipeFromAsync(System.IO.TextReader! reader, bool leaveWriterOpen = false, bool leaveReaderOpen = false) -> System.Threading.Tasks.Task! +Medallion.Shell.CrossPlatformCommandLineSyntax +Medallion.Shell.CrossPlatformCommandLineSyntax.CrossPlatformCommandLineSyntax() -> void +override Medallion.Shell.Streams.ProcessStreamWriter.Encoding.get -> System.Text.Encoding! +override Medallion.Shell.Streams.ProcessStreamWriter.Flush() -> void +override Medallion.Shell.Streams.ProcessStreamWriter.FlushAsync() -> System.Threading.Tasks.Task! +override Medallion.Shell.Streams.ProcessStreamWriter.FormatProvider.get -> System.IFormatProvider! +override Medallion.Shell.Streams.ProcessStreamWriter.NewLine.get -> string! +override Medallion.Shell.Streams.ProcessStreamWriter.NewLine.set -> void +override Medallion.Shell.Streams.ProcessStreamWriter.Write(bool value) -> void +override Medallion.Shell.Streams.ProcessStreamWriter.Write(char value) -> void +override Medallion.Shell.Streams.ProcessStreamWriter.Write(char[]? buffer) -> void +override Medallion.Shell.Streams.ProcessStreamWriter.Write(char[]! buffer, int index, int count) -> void +override Medallion.Shell.Streams.ProcessStreamWriter.Write(decimal value) -> void +override Medallion.Shell.Streams.ProcessStreamWriter.Write(double value) -> void +override Medallion.Shell.Streams.ProcessStreamWriter.Write(float value) -> void +override Medallion.Shell.Streams.ProcessStreamWriter.Write(int value) -> void +override Medallion.Shell.Streams.ProcessStreamWriter.Write(long value) -> void +override Medallion.Shell.Streams.ProcessStreamWriter.Write(object? value) -> void +override Medallion.Shell.Streams.ProcessStreamWriter.Write(string! format, object? arg0) -> void +override Medallion.Shell.Streams.ProcessStreamWriter.Write(string! format, object? arg0, object? arg1) -> void +override Medallion.Shell.Streams.ProcessStreamWriter.Write(string! format, object? arg0, object? arg1, object? arg2) -> void +override Medallion.Shell.Streams.ProcessStreamWriter.Write(string! format, params object?[]! arg) -> void +override Medallion.Shell.Streams.ProcessStreamWriter.Write(string? value) -> void +override Medallion.Shell.Streams.ProcessStreamWriter.Write(System.ReadOnlySpan buffer) -> void +override Medallion.Shell.Streams.ProcessStreamWriter.Write(uint value) -> void +override Medallion.Shell.Streams.ProcessStreamWriter.Write(ulong value) -> void +override Medallion.Shell.Streams.ProcessStreamWriter.WriteAsync(char value) -> System.Threading.Tasks.Task! +override Medallion.Shell.Streams.ProcessStreamWriter.WriteAsync(char[]! buffer, int index, int count) -> System.Threading.Tasks.Task! +override Medallion.Shell.Streams.ProcessStreamWriter.WriteAsync(string? value) -> System.Threading.Tasks.Task! +override Medallion.Shell.Streams.ProcessStreamWriter.WriteAsync(System.ReadOnlyMemory buffer, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.Task! +override Medallion.Shell.Streams.ProcessStreamWriter.WriteLine() -> void +override Medallion.Shell.Streams.ProcessStreamWriter.WriteLine(bool value) -> void +override Medallion.Shell.Streams.ProcessStreamWriter.WriteLine(char value) -> void +override Medallion.Shell.Streams.ProcessStreamWriter.WriteLine(char[]? buffer) -> void +override Medallion.Shell.Streams.ProcessStreamWriter.WriteLine(char[]! buffer, int index, int count) -> void +override Medallion.Shell.Streams.ProcessStreamWriter.WriteLine(decimal value) -> void +override Medallion.Shell.Streams.ProcessStreamWriter.WriteLine(double value) -> void +override Medallion.Shell.Streams.ProcessStreamWriter.WriteLine(float value) -> void +override Medallion.Shell.Streams.ProcessStreamWriter.WriteLine(int value) -> void +override Medallion.Shell.Streams.ProcessStreamWriter.WriteLine(long value) -> void +override Medallion.Shell.Streams.ProcessStreamWriter.WriteLine(object? value) -> void +override Medallion.Shell.Streams.ProcessStreamWriter.WriteLine(string! format, object? arg0) -> void +override Medallion.Shell.Streams.ProcessStreamWriter.WriteLine(string! format, object? arg0, object? arg1) -> void +override Medallion.Shell.Streams.ProcessStreamWriter.WriteLine(string! format, object? arg0, object? arg1, object? arg2) -> void +override Medallion.Shell.Streams.ProcessStreamWriter.WriteLine(string! format, params object?[]! arg) -> void +override Medallion.Shell.Streams.ProcessStreamWriter.WriteLine(string? value) -> void +override Medallion.Shell.Streams.ProcessStreamWriter.WriteLine(System.ReadOnlySpan buffer) -> void +override Medallion.Shell.Streams.ProcessStreamWriter.WriteLine(uint value) -> void +override Medallion.Shell.Streams.ProcessStreamWriter.WriteLine(ulong value) -> void +override Medallion.Shell.Streams.ProcessStreamWriter.WriteLineAsync() -> System.Threading.Tasks.Task! +override Medallion.Shell.Streams.ProcessStreamWriter.WriteLineAsync(char value) -> System.Threading.Tasks.Task! +override Medallion.Shell.Streams.ProcessStreamWriter.WriteLineAsync(char[]! buffer, int index, int count) -> System.Threading.Tasks.Task! +override Medallion.Shell.Streams.ProcessStreamWriter.WriteLineAsync(string? value) -> System.Threading.Tasks.Task! +override Medallion.Shell.Streams.ProcessStreamWriter.WriteLineAsync(System.ReadOnlyMemory buffer, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.Task! +override Medallion.Shell.CrossPlatformCommandLineSyntax.CreateArgumentString(System.Collections.Generic.IEnumerable! arguments) -> string! +static Medallion.Shell.Command.operator <(Medallion.Shell.Command! command, System.Collections.Generic.IEnumerable! chars) -> Medallion.Shell.Command! +static Medallion.Shell.Command.operator <(Medallion.Shell.Command! command, System.Collections.Generic.IEnumerable! lines) -> Medallion.Shell.Command! +static Medallion.Shell.Command.operator <(Medallion.Shell.Command! command, System.IO.FileInfo! file) -> Medallion.Shell.Command! +static Medallion.Shell.Command.operator <(Medallion.Shell.Command! command, System.IO.Stream! stream) -> Medallion.Shell.Command! +static Medallion.Shell.Command.operator >(Medallion.Shell.Command! command, System.Collections.Generic.IEnumerable! chars) -> Medallion.Shell.Command! +static Medallion.Shell.Command.operator >(Medallion.Shell.Command! command, System.Collections.Generic.IEnumerable! lines) -> Medallion.Shell.Command! +static Medallion.Shell.Command.operator >(Medallion.Shell.Command! command, System.IO.FileInfo! file) -> Medallion.Shell.Command! +static Medallion.Shell.Command.operator >(Medallion.Shell.Command! command, System.IO.Stream! stream) -> Medallion.Shell.Command! +static Medallion.Shell.Command.operator |(Medallion.Shell.Command! first, Medallion.Shell.Command! second) -> Medallion.Shell.Command! +static Medallion.Shell.Command.Run(string! executable, params object![]! arguments) -> Medallion.Shell.Command! +static Medallion.Shell.Command.Run(string! executable, System.Collections.Generic.IEnumerable? arguments = null, System.Action? options = null) -> Medallion.Shell.Command! +static Medallion.Shell.Command.TryAttachToProcess(int processId, out Medallion.Shell.Command? attachedCommand) -> bool +static Medallion.Shell.Command.TryAttachToProcess(int processId, System.Action! options, out Medallion.Shell.Command? attachedCommand) -> bool +static Medallion.Shell.CommandSignal.ControlC.get -> Medallion.Shell.CommandSignal! +static Medallion.Shell.CommandSignal.FromSystemValue(int signal) -> Medallion.Shell.CommandSignal! +static Medallion.Shell.Shell.Default.get -> Medallion.Shell.Shell! \ No newline at end of file diff --git a/MedallionShell/PublicAPI/net8.0/PublicAPI.Unshipped.txt b/MedallionShell/PublicAPI/net8.0/PublicAPI.Unshipped.txt new file mode 100644 index 0000000..5f28270 --- /dev/null +++ b/MedallionShell/PublicAPI/net8.0/PublicAPI.Unshipped.txt @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/MedallionShell/PublicAPI/netstandard1.3/PublicAPI.Shipped.txt b/MedallionShell/PublicAPI/netstandard1.3/PublicAPI.Shipped.txt index 2a1e21c..53988e8 100644 --- a/MedallionShell/PublicAPI/netstandard1.3/PublicAPI.Shipped.txt +++ b/MedallionShell/PublicAPI/netstandard1.3/PublicAPI.Shipped.txt @@ -78,8 +78,8 @@ Medallion.Shell.Streams.ProcessStreamWriter.PipeFromAsync(System.Collections.Gen Medallion.Shell.Streams.ProcessStreamWriter.PipeFromAsync(System.IO.FileInfo! file, bool leaveWriterOpen = false) -> System.Threading.Tasks.Task! Medallion.Shell.Streams.ProcessStreamWriter.PipeFromAsync(System.IO.Stream! stream, bool leaveWriterOpen = false, bool leaveStreamOpen = false) -> System.Threading.Tasks.Task! Medallion.Shell.Streams.ProcessStreamWriter.PipeFromAsync(System.IO.TextReader! reader, bool leaveWriterOpen = false, bool leaveReaderOpen = false) -> System.Threading.Tasks.Task! -Medallion.Shell.WindowsCommandLineSyntax -Medallion.Shell.WindowsCommandLineSyntax.WindowsCommandLineSyntax() -> void +Medallion.Shell.CrossPlatformCommandLineSyntax +Medallion.Shell.CrossPlatformCommandLineSyntax.CrossPlatformCommandLineSyntax() -> void override Medallion.Shell.Streams.ProcessStreamWriter.Encoding.get -> System.Text.Encoding! override Medallion.Shell.Streams.ProcessStreamWriter.Flush() -> void override Medallion.Shell.Streams.ProcessStreamWriter.FlushAsync() -> System.Threading.Tasks.Task! @@ -128,7 +128,7 @@ override Medallion.Shell.Streams.ProcessStreamWriter.WriteLineAsync() -> System. override Medallion.Shell.Streams.ProcessStreamWriter.WriteLineAsync(char value) -> System.Threading.Tasks.Task! override Medallion.Shell.Streams.ProcessStreamWriter.WriteLineAsync(char[]! buffer, int index, int count) -> System.Threading.Tasks.Task! override Medallion.Shell.Streams.ProcessStreamWriter.WriteLineAsync(string? value) -> System.Threading.Tasks.Task! -override Medallion.Shell.WindowsCommandLineSyntax.CreateArgumentString(System.Collections.Generic.IEnumerable! arguments) -> string! +override Medallion.Shell.CrossPlatformCommandLineSyntax.CreateArgumentString(System.Collections.Generic.IEnumerable! arguments) -> string! static Medallion.Shell.Command.operator <(Medallion.Shell.Command! command, System.Collections.Generic.IEnumerable! chars) -> Medallion.Shell.Command! static Medallion.Shell.Command.operator <(Medallion.Shell.Command! command, System.Collections.Generic.IEnumerable! lines) -> Medallion.Shell.Command! static Medallion.Shell.Command.operator <(Medallion.Shell.Command! command, System.IO.FileInfo! file) -> Medallion.Shell.Command! diff --git a/MedallionShell/PublicAPI/netstandard2.0/PublicAPI.Shipped.txt b/MedallionShell/PublicAPI/netstandard2.0/PublicAPI.Shipped.txt index 48d22c1..77d318e 100644 --- a/MedallionShell/PublicAPI/netstandard2.0/PublicAPI.Shipped.txt +++ b/MedallionShell/PublicAPI/netstandard2.0/PublicAPI.Shipped.txt @@ -80,8 +80,8 @@ Medallion.Shell.Streams.ProcessStreamWriter.PipeFromAsync(System.Collections.Gen Medallion.Shell.Streams.ProcessStreamWriter.PipeFromAsync(System.IO.FileInfo! file, bool leaveWriterOpen = false) -> System.Threading.Tasks.Task! Medallion.Shell.Streams.ProcessStreamWriter.PipeFromAsync(System.IO.Stream! stream, bool leaveWriterOpen = false, bool leaveStreamOpen = false) -> System.Threading.Tasks.Task! Medallion.Shell.Streams.ProcessStreamWriter.PipeFromAsync(System.IO.TextReader! reader, bool leaveWriterOpen = false, bool leaveReaderOpen = false) -> System.Threading.Tasks.Task! -Medallion.Shell.WindowsCommandLineSyntax -Medallion.Shell.WindowsCommandLineSyntax.WindowsCommandLineSyntax() -> void +Medallion.Shell.CrossPlatformCommandLineSyntax +Medallion.Shell.CrossPlatformCommandLineSyntax.CrossPlatformCommandLineSyntax() -> void override Medallion.Shell.Streams.ProcessStreamWriter.Encoding.get -> System.Text.Encoding! override Medallion.Shell.Streams.ProcessStreamWriter.Flush() -> void override Medallion.Shell.Streams.ProcessStreamWriter.FlushAsync() -> System.Threading.Tasks.Task! @@ -130,7 +130,7 @@ override Medallion.Shell.Streams.ProcessStreamWriter.WriteLineAsync() -> System. override Medallion.Shell.Streams.ProcessStreamWriter.WriteLineAsync(char value) -> System.Threading.Tasks.Task! override Medallion.Shell.Streams.ProcessStreamWriter.WriteLineAsync(char[]! buffer, int index, int count) -> System.Threading.Tasks.Task! override Medallion.Shell.Streams.ProcessStreamWriter.WriteLineAsync(string? value) -> System.Threading.Tasks.Task! -override Medallion.Shell.WindowsCommandLineSyntax.CreateArgumentString(System.Collections.Generic.IEnumerable! arguments) -> string! +override Medallion.Shell.CrossPlatformCommandLineSyntax.CreateArgumentString(System.Collections.Generic.IEnumerable! arguments) -> string! static Medallion.Shell.Command.operator <(Medallion.Shell.Command! command, System.Collections.Generic.IEnumerable! chars) -> Medallion.Shell.Command! static Medallion.Shell.Command.operator <(Medallion.Shell.Command! command, System.Collections.Generic.IEnumerable! lines) -> Medallion.Shell.Command! static Medallion.Shell.Command.operator <(Medallion.Shell.Command! command, System.IO.FileInfo! file) -> Medallion.Shell.Command! diff --git a/MedallionShell/Streams/ProcessStreamWrapper.cs b/MedallionShell/Streams/ProcessStreamWrapper.cs index d32daf6..9f2c592 100644 --- a/MedallionShell/Streams/ProcessStreamWrapper.cs +++ b/MedallionShell/Streams/ProcessStreamWrapper.cs @@ -1,9 +1,6 @@ using System; -using System.Collections.Generic; using System.Diagnostics; using System.IO; -using System.Security.Cryptography.X509Certificates; -using System.Text; using System.Threading; using System.Threading.Tasks; using static Medallion.Shell.PlatformCompatibilityHelper; @@ -13,8 +10,7 @@ namespace Medallion.Shell.Streams /// /// On .NET Core and .NET Framework on Windows, writing to the standard input after the process exits is a noop. /// - /// However, on Mono this will throw a "Write Fault" exception (https://github.com/madelson/MedallionShell/issues/6) - /// while .NET Core on Linux throws a "Broken Pipe" exception (https://github.com/madelson/MedallionShell/issues/46). + /// However, .NET Core on Linux throws a "Broken Pipe" exception (https://github.com/madelson/MedallionShell/issues/46). /// /// This class wraps the underlying to provide consistent behavior across platforms. /// @@ -44,7 +40,7 @@ public static Stream WrapIfNeeded(Stream stream, bool isReadStream) => public override int ReadTimeout { get => this.stream.ReadTimeout; set => this.stream.ReadTimeout = value; } public override int WriteTimeout { get => this.stream.WriteTimeout; set => this.stream.WriteTimeout = value; } - // Note: from my testing, try-catching on Flush() appears necessary with .NET core on Linux, but not on Mono + // Note: from my testing, try-catching on Flush() appears necessary with .NET core on Linux public override void Flush() => this.DoWriteOperation(default(bool), static (s, _) => s.Flush()); public override Task FlushAsync(CancellationToken cancellationToken) => diff --git a/NugetDocumentation.md b/NugetDocumentation.md index 94e4dae..00c7e4c 100644 --- a/NugetDocumentation.md +++ b/NugetDocumentation.md @@ -12,6 +12,6 @@ Here are some of the things the library takes care of for you: * Piping standard IO streams to and from various sources without creating deadlocks or race conditions * Properly escaping process arguments (a common source of security vulnerabilities) * Being able to recover from hangs through timeout, `CancellationToken`, and safe kill, and signal support -* Cross-platform support (e. g. signals and workarounds for Mono oddities) +* Cross-platform support **To learn more**, check out the [full documentation](https://github.com/madelson/MedallionShell/blob/master/README.md). \ No newline at end of file diff --git a/README.md b/README.md index 15bfb20..0b39cfa 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ Here are some of the things the library takes care of for you: * Piping standard IO streams to and from various sources without creating deadlocks or race conditions * Properly escaping process arguments (a common source of security vulnerabilities) * Being able to recover from hangs through timeout, `CancellationToken`, and safe kill, and signal support -* Cross-platform support (e. g. signals and workarounds for Mono oddities [#6](https://github.com/madelson/MedallionShell/issues/6), [#22](https://github.com/madelson/MedallionShell/issues/22), [#43](https://github.com/madelson/MedallionShell/issues/43), and [#44](https://github.com/madelson/MedallionShell/issues/44)) +* Cross-platform support ## API Overview @@ -113,7 +113,7 @@ This package is published from the [strong-name](https://github.com/madelson/Med ## Contributing Contributions are welcome! Please report any issues you encounter or ideas for enhancements. If you would like to contribute code, I ask that you file an issue first so that we can work out the details before you start coding and avoid wasted effort on your part. -**To build the code**, you will need VisualStudio 2019 or higher (community edition is fine) [download](https://www.visualstudio.com/vs/community/). Running all tests will require that you have installed Mono (for the Mono compat tests only). +**To build the code**, you will need VisualStudio 2019 or higher (community edition is fine) [download](https://www.visualstudio.com/vs/community/). Windows: [![Build status](https://ci.appveyor.com/api/projects/status/9idbmymiatbd8ncx/branch/master?svg=true)](https://ci.appveyor.com/project/madelson/medallionshell/branch/master) Linux: [![Build Status](https://travis-ci.com/madelson/MedallionShell.svg?branch=master)](https://travis-ci.com/madelson/MedallionShell) diff --git a/SampleCommand/PlatformCompatibilityTests.cs b/SampleCommand/PlatformCompatibilityTests.cs index 0c43ada..596f6bc 100644 --- a/SampleCommand/PlatformCompatibilityTests.cs +++ b/SampleCommand/PlatformCompatibilityTests.cs @@ -83,9 +83,6 @@ public static void TestReadAfterExit() } } - /// - /// See SafeGetExitCode comment - /// public static void TestExitWithMinusOne() { var command = TestShell.Run(SampleCommandPath, "exit", -1); @@ -114,8 +111,8 @@ public static void TestBadProcessFile() { var baseDirectory = Path.GetDirectoryName(SampleCommandPath)!; - AssertThrows(() => Command.Run(baseDirectory)); - AssertThrows(() => Command.Run(Path.Combine(baseDirectory, "DOES_NOT_EXIST.exe"))); + AssertThrows(() => Command.Run(baseDirectory)); + AssertThrows(() => Command.Run(Path.Combine(baseDirectory, "DOES_NOT_EXIST.exe"))); } public static void TestAttaching() diff --git a/SampleCommand/SampleCommand.csproj b/SampleCommand/SampleCommand.csproj index 0bebdfe..8feefec 100644 --- a/SampleCommand/SampleCommand.csproj +++ b/SampleCommand/SampleCommand.csproj @@ -1,8 +1,8 @@  - - net6.0;net46 + + net8.0;net6.0;net462 Exe false Latest diff --git a/appveyor.yml b/appveyor.yml index 5d6e14e..9b2eebd 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -22,13 +22,8 @@ for: matrix: only: - - image: "Ubuntu" + image: "Ubuntu2204" test_script: - - echo DOTNET TEST + # Do not test against .NET Framework on Ubuntu - dotnet test MedallionShell.sln -c Release -f net6.0 --no-build - # test mono via the NUnit console runner - - nuget install NUnit.Console -Version 3.16.3 -OutputDirectory testrunner -Source https://api.nuget.org/v3/index.json - - echo MONO NETCORE - - mono ./testrunner/NUnit.ConsoleRunner.3.16.3/tools/nunit3-console.exe ./MedallionShell.Tests/bin/Release/net6.0/MedallionShell.Tests.dll - - echo MONO NETFRAMEWORK - - mono ./testrunner/NUnit.ConsoleRunner.3.16.3/tools/nunit3-console.exe ./MedallionShell.Tests/bin/Release/net462/MedallionShell.Tests.dll \ No newline at end of file + - dotnet test MedallionShell.sln -c Release -f net8.0 --no-build