diff --git a/src/Shared/CommandLineUtils/Utilities/ArgumentEscaper.cs b/src/Shared/CommandLineUtils/Utilities/ArgumentEscaper.cs deleted file mode 100644 index 92543e7f237e5af2beb400a3f8edfade5a054739..0000000000000000000000000000000000000000 --- a/src/Shared/CommandLineUtils/Utilities/ArgumentEscaper.cs +++ /dev/null @@ -1,109 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System.Collections.Generic; -using System.Linq; -using System.Text; - -namespace Microsoft.Extensions.CommandLineUtils -{ - /// <summary> - /// A utility for escaping arguments for new processes. - /// </summary> - internal static class ArgumentEscaper - { - /// <summary> - /// Undo the processing which took place to create string[] args in Main, so that the next process will - /// receive the same string[] args. - /// </summary> - /// <remarks> - /// See https://blogs.msdn.microsoft.com/twistylittlepassagesallalike/2011/04/23/everyone-quotes-command-line-arguments-the-wrong-way/ - /// </remarks> - /// <param name="args">The arguments to concatenate.</param> - /// <returns>The escaped arguments, concatenated.</returns> - public static string EscapeAndConcatenate(IEnumerable<string> args) - => string.Join(" ", args.Select(EscapeSingleArg)); - - private static string EscapeSingleArg(string arg) - { - var sb = new StringBuilder(); - - var needsQuotes = ShouldSurroundWithQuotes(arg); - var isQuoted = needsQuotes || IsSurroundedWithQuotes(arg); - - if (needsQuotes) - { - sb.Append('"'); - } - - for (int i = 0; i < arg.Length; ++i) - { - var backslashes = 0; - - // Consume all backslashes - while (i < arg.Length && arg[i] == '\\') - { - backslashes++; - i++; - } - - if (i == arg.Length && isQuoted) - { - // Escape any backslashes at the end of the arg when the argument is also quoted. - // This ensures the outside quote is interpreted as an argument delimiter - sb.Append('\\', 2 * backslashes); - } - else if (i == arg.Length) - { - // At then end of the arg, which isn't quoted, - // just add the backslashes, no need to escape - sb.Append('\\', backslashes); - } - else if (arg[i] == '"') - { - // Escape any preceding backslashes and the quote - sb.Append('\\', (2 * backslashes) + 1); - sb.Append('"'); - } - else - { - // Output any consumed backslashes and the character - sb.Append('\\', backslashes); - sb.Append(arg[i]); - } - } - - if (needsQuotes) - { - sb.Append('"'); - } - - return sb.ToString(); - } - - private static bool ShouldSurroundWithQuotes(string argument) - { - // Don't quote already quoted strings - if (IsSurroundedWithQuotes(argument)) - { - return false; - } - - // Only quote if whitespace exists in the string - return ContainsWhitespace(argument); - } - - private static bool IsSurroundedWithQuotes(string argument) - { - if (argument.Length <= 1) - { - return false; - } - - return argument[0] == '"' && argument[argument.Length - 1] == '"'; - } - - private static bool ContainsWhitespace(string argument) - => argument.IndexOfAny(new[] { ' ', '\t', '\n' }) >= 0; - } -} diff --git a/src/Shared/test/Shared.Tests/ArgumentEscaperTests.cs b/src/Shared/test/Shared.Tests/ArgumentEscaperTests.cs deleted file mode 100644 index a706b05bfcb98bd928df252f2490be2342319d6d..0000000000000000000000000000000000000000 --- a/src/Shared/test/Shared.Tests/ArgumentEscaperTests.cs +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using Xunit; - -namespace Microsoft.Extensions.CommandLineUtils -{ - public class ArgumentEscaperTests - { - [Theory] - [InlineData(new[] { "one", "two", "three" }, "one two three")] - [InlineData(new[] { "line1\nline2", "word1\tword2" }, "\"line1\nline2\" \"word1\tword2\"")] - [InlineData(new[] { "with spaces" }, "\"with spaces\"")] - [InlineData(new[] { @"with\backslash" }, @"with\backslash")] - [InlineData(new[] { @"""quotedwith\backslash""" }, @"\""quotedwith\backslash\""")] - [InlineData(new[] { @"C:\Users\" }, @"C:\Users\")] - [InlineData(new[] { @"C:\Program Files\dotnet\" }, @"""C:\Program Files\dotnet\\""")] - [InlineData(new[] { @"backslash\""preceedingquote" }, @"backslash\\\""preceedingquote")] - public void EscapesArguments(string[] args, string expected) - { - Assert.Equal(expected, ArgumentEscaper.EscapeAndConcatenate(args)); - } - } -} diff --git a/src/Tools/dotnet-getdocument/src/Exe.cs b/src/Tools/dotnet-getdocument/src/Exe.cs index bfdf3caf6f4ffcb43f26c6938dbe2920b83a585a..978082e681008421a624b070d31e1af8e777708d 100644 --- a/src/Tools/dotnet-getdocument/src/Exe.cs +++ b/src/Tools/dotnet-getdocument/src/Exe.cs @@ -18,17 +18,19 @@ namespace Microsoft.Extensions.ApiDescription.Tool string workingDirectory = null, bool interceptOutput = false) { - var arguments = ArgumentEscaper.EscapeAndConcatenate(args); - - reporter.WriteVerbose(executable + " " + arguments); + reporter.WriteVerbose(executable + " " + string.Join(" " , args)); var startInfo = new ProcessStartInfo { FileName = executable, - Arguments = arguments, UseShellExecute = false, RedirectStandardOutput = interceptOutput }; + foreach (var argument in args) + { + startInfo.ArgumentList.Add(argument); + } + if (workingDirectory != null) { startInfo.WorkingDirectory = workingDirectory; diff --git a/src/Tools/dotnet-user-secrets/src/Internal/ProjectIdResolver.cs b/src/Tools/dotnet-user-secrets/src/Internal/ProjectIdResolver.cs index bc473fd7fa9d6397ea0ea2b5f3248eaadec5fccb..ca24296dc92a56e7d4d78ac89a511114b4367b06 100644 --- a/src/Tools/dotnet-user-secrets/src/Internal/ProjectIdResolver.cs +++ b/src/Tools/dotnet-user-secrets/src/Internal/ProjectIdResolver.cs @@ -43,25 +43,24 @@ namespace Microsoft.Extensions.SecretManager.Tools.Internal var outputFile = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName()); try { - var args = new[] - { - "msbuild", - projectFile, - "/nologo", - "/t:_ExtractUserSecretsMetadata", // defined in SecretManager.targets - "/p:_UserSecretsMetadataFile=" + outputFile, - "/p:Configuration=" + configuration, - "/p:CustomAfterMicrosoftCommonTargets=" + _targetsFile, - "/p:CustomAfterMicrosoftCommonCrossTargetingTargets=" + _targetsFile, - "-verbosity:detailed", - }; var psi = new ProcessStartInfo { FileName = DotNetMuxer.MuxerPathOrDefault(), - Arguments = ArgumentEscaper.EscapeAndConcatenate(args), RedirectStandardOutput = true, RedirectStandardError = true, UseShellExecute = false, + ArgumentList = + { + "msbuild", + projectFile, + "/nologo", + "/t:_ExtractUserSecretsMetadata", // defined in SecretManager.targets + "/p:_UserSecretsMetadataFile=" + outputFile, + "/p:Configuration=" + configuration, + "/p:CustomAfterMicrosoftCommonTargets=" + _targetsFile, + "/p:CustomAfterMicrosoftCommonCrossTargetingTargets=" + _targetsFile, + "-verbosity:detailed", + } }; #if DEBUG