diff --git a/examples/ScratchPad.Fs.ArgumentPrinter/Program.fs b/examples/ScratchPad.Fs.ArgumentPrinter/Program.fs new file mode 100644 index 0000000..d0b6b98 --- /dev/null +++ b/examples/ScratchPad.Fs.ArgumentPrinter/Program.fs @@ -0,0 +1,8 @@ +// For more information see https://aka.ms/fsharp-console-apps + +open System + +let args = Environment.GetCommandLineArgs() +printfn "%i" args.Length +for a in args do + printfn "%s" a diff --git a/examples/ScratchPad.Fs.ArgumentPrinter/ScratchPad.Fs.ArgumentPrinter.fsproj b/examples/ScratchPad.Fs.ArgumentPrinter/ScratchPad.Fs.ArgumentPrinter.fsproj new file mode 100644 index 0000000..5a150c1 --- /dev/null +++ b/examples/ScratchPad.Fs.ArgumentPrinter/ScratchPad.Fs.ArgumentPrinter.fsproj @@ -0,0 +1,13 @@ + + + + Exe + net8.0 + false + + + + + + + diff --git a/examples/ScratchPad.Fs/Program.fs b/examples/ScratchPad.Fs/Program.fs index aba6e22..f1556cf 100644 --- a/examples/ScratchPad.Fs/Program.fs +++ b/examples/ScratchPad.Fs/Program.fs @@ -54,5 +54,6 @@ exec { run "dotnet" args } let _ = shell { exec "dotnet" args } let statusCode = exec { exit_code_of "dotnet" "--help"} +exec { run "dotnet" "run" "--project" "examples/ScratchPad.Fs.ArgumentPrinter" "--" "With Space" } printfn "That's all folks!" diff --git a/proc.sln b/proc.sln index e34d5ec..6cfbde5 100644 --- a/proc.sln +++ b/proc.sln @@ -41,6 +41,8 @@ Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "Proc.Fs", "src\Proc.Fs\Proc EndProject Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "ScratchPad.Fs", "examples\ScratchPad.Fs\ScratchPad.Fs.fsproj", "{C33E3F7C-0C2A-4DD2-91E4-328866195997}" EndProject +Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "ScratchPad.Fs.ArgumentPrinter", "examples\ScratchPad.Fs.ArgumentPrinter\ScratchPad.Fs.ArgumentPrinter.fsproj", "{50A40BEB-1C22-41CF-908F-F24FB34B1699}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -79,6 +81,10 @@ Global {C33E3F7C-0C2A-4DD2-91E4-328866195997}.Debug|Any CPU.Build.0 = Debug|Any CPU {C33E3F7C-0C2A-4DD2-91E4-328866195997}.Release|Any CPU.ActiveCfg = Release|Any CPU {C33E3F7C-0C2A-4DD2-91E4-328866195997}.Release|Any CPU.Build.0 = Release|Any CPU + {50A40BEB-1C22-41CF-908F-F24FB34B1699}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {50A40BEB-1C22-41CF-908F-F24FB34B1699}.Debug|Any CPU.Build.0 = Debug|Any CPU + {50A40BEB-1C22-41CF-908F-F24FB34B1699}.Release|Any CPU.ActiveCfg = Release|Any CPU + {50A40BEB-1C22-41CF-908F-F24FB34B1699}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -92,5 +98,6 @@ Global {D6997ADC-E933-418E-831C-DE1A78897493} = {E89606EC-111B-4151-997C-8006627F1926} {5EA4E26F-F623-473D-9CD7-E590A3E54239} = {9C336E9A-3FC8-4F77-A5B4-1D07E4E54924} {C33E3F7C-0C2A-4DD2-91E4-328866195997} = {E4B3DD3A-E36C-46D6-B35E-D824EB9B3C06} + {50A40BEB-1C22-41CF-908F-F24FB34B1699} = {E4B3DD3A-E36C-46D6-B35E-D824EB9B3C06} EndGlobalSection EndGlobal diff --git a/src/Proc/Extensions/ArgumentExtensions.cs b/src/Proc/Extensions/ArgumentExtensions.cs new file mode 100644 index 0000000..4a875e9 --- /dev/null +++ b/src/Proc/Extensions/ArgumentExtensions.cs @@ -0,0 +1,25 @@ +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace ProcNet.Extensions; + +internal static class ArgumentExtensions +{ + public static string NaivelyQuoteArguments(this IEnumerable arguments) + { + if (arguments == null) return string.Empty; + var args = arguments.ToList(); + if (args.Count == 0) return string.Empty; + var quotedArgs = args + .Select(a => + { + if (!a.Contains(" ")) return a; + return $"\"{a}\""; + }) + .ToList(); + return string.Join(" ", quotedArgs); + } + +} diff --git a/src/Proc/ObservableProcessBase.cs b/src/Proc/ObservableProcessBase.cs index 27b64b7..1fea092 100644 --- a/src/Proc/ObservableProcessBase.cs +++ b/src/Proc/ObservableProcessBase.cs @@ -7,6 +7,7 @@ using System.Reflection; using System.Threading; using System.Threading.Tasks; +using ProcNet.Extensions; using ProcNet.Std; namespace ProcNet @@ -140,13 +141,19 @@ private Process CreateProcess() var processStartInfo = new ProcessStartInfo { FileName = s.Binary, - Arguments = args != null ? string.Join(" ", args) : string.Empty, + #if !NETSTANDARD2_1 + Arguments = args.NaivelyQuoteArguments(), + #endif CreateNoWindow = true, UseShellExecute = false, RedirectStandardOutput = true, RedirectStandardError = true, RedirectStandardInput = true }; + #if NETSTANDARD2_1 + foreach (var arg in s.Args) + processStartInfo.ArgumentList.Add(arg); + #endif if (s.Environment != null) { foreach (var kv in s.Environment) diff --git a/src/Proc/Proc.Exec.cs b/src/Proc/Proc.Exec.cs index b0e5057..3bef3ef 100644 --- a/src/Proc/Proc.Exec.cs +++ b/src/Proc/Proc.Exec.cs @@ -1,6 +1,7 @@ using System; using System.Diagnostics; using System.Threading.Tasks; +using ProcNet.Extensions; namespace ProcNet { @@ -46,11 +47,18 @@ public static partial class Proc /// The exit code of the binary being run public static int? Exec(ExecArguments arguments, TimeSpan timeout) { - var args = string.Join(" ", arguments.Args ?? new string[]{}); - var info = new ProcessStartInfo(arguments.Binary, args) + var args = arguments.Args.NaivelyQuoteArguments(); + var info = new ProcessStartInfo(arguments.Binary) { UseShellExecute = false + #if !NETSTANDARD2_1 + , Arguments = args + #endif }; + #if NETSTANDARD2_1 + foreach (var arg in arguments.Args) + info.ArgumentList.Add(arg); + #endif var pwd = arguments.WorkingDirectory; if (!string.IsNullOrWhiteSpace(pwd)) info.WorkingDirectory = pwd; diff --git a/src/Proc/Proc.csproj b/src/Proc/Proc.csproj index 5d4a66a..a3cc545 100644 --- a/src/Proc/Proc.csproj +++ b/src/Proc/Proc.csproj @@ -2,7 +2,7 @@ proc - netstandard2.0;net461 + netstandard2.0;netstandard2.1;net461 ProcNet