xamarin-macios/tools/common/StringUtils.cs

277 строки
6.3 KiB
C#
Исходник Обычный вид История

using System;
Implement a different escaping/quoting algorithm for arguments to System.Diagnostics.Process. (#7177) * Implement a different escaping/quoting algorithm for arguments to System.Diagnostics.Process. mono changed how quotes should be escaped when passed to System.Diagnostic.Process, so we need to change accordingly. The main difference is that single quotes don't have to be escaped anymore. This solves problems like this: System.ComponentModel.Win32Exception : ApplicationName='nuget', CommandLine='restore '/Users/vsts/agent/2.158.0/work/1/s/tests/sampletester/bin/Debug/repositories/ios-samples/WorkingWithTables/Part 3 - Customizing a Table\'s appearance/3 - CellCustomTable/CellCustomTable.sln' -Verbosity detailed -SolutionDir '/Users/vsts/agent/2.158.0/work/1/s/tests/sampletester/bin/Debug/repositories/ios-samples/WorkingWithTables/Part 3 - Customizing a Table\'s appearance/3 - CellCustomTable'', CurrentDirectory='/Users/vsts/agent/2.158.0/work/1/s/tests/sampletester/bin/Debug/repositories', Native error= Cannot find the specified file at System.Diagnostics.Process.StartWithCreateProcess (System.Diagnostics.ProcessStartInfo startInfo) [0x0029f] in /Users/builder/jenkins/workspace/build-package-osx-mono/2019-08/external/bockbuild/builds/mono-x64/mcs/class/System/System.Diagnostics/Process.cs:778 ref: https://github.com/mono/mono/pull/15047 * Rework process arguments to pass arrays/lists around instead of quoted strings. And then only convert to a string at the very end when we create the Process instance. In the future there will be a ProcessStartInfo.ArgumentList property we can use to give the original array/list of arguments directly to the BCL so that we can avoid quoting at all. These changes gets us almost all the way there already (except that the ArgumentList property isn't available quite yet). We also have to bump to target framework version v4.7.2 from v4.5 in several places because of 'Array.Empty<T> ()' which is now used in more places. * Parse linker flags from LinkWith attributes. * [sampletester] Bump to v4.7.2 for Array.Empty<T> (). * Fix typo. * Rename GetVerbosity -> AddVerbosity. * Remove unnecessary string interpolation. * Remove unused variable. * [mtouch] Simplify code a bit. * Use implicitly typed arrays.
2019-10-14 17:18:46 +03:00
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Xamarin.Utils {
[generator] Register models with unique names to not match platform types. Fixes #3875. (#3879) * Move Registrar.SanitizeName to StringUtils.SanitizeObjectiveCName. * [generator] Register models with unique names to not match platform types. Fixes #3875. * [NSObject] Don't compare against a non-existent protocol. * [generator] Make it possible to register models like before if the binding developer wishes it. * [src] Make sure to not declare ObjC classes Apple already defines. Fixes these warnings at startup: Class DOMNodeFilter is implemented in both /System/Library/Frameworks/WebKit.framework/Versions/A/Frameworks/WebKitLegacy.framework/Versions/A/WebKitLegacy (0x7fffa944a788) and /Users/builder/data/lanes/6035/0ca02336/source/xamarin-macios/tests/xharness/tmp-test-dir/dont link-mac-unified/bin/x86/Debug-unified/dont link.app/Contents/MacOS/dont link (0x10d8a9958). One of the two will be used. Which one is undefined. Class WebOpenPanelResultListener is implemented in both /System/Library/Frameworks/WebKit.framework/Versions/A/Frameworks/WebKitLegacy.framework/Versions/A/WebKitLegacy (0x7fffa944e4c8) and /Users/builder/data/lanes/6035/0ca02336/source/xamarin-macios/tests/xharness/tmp-test-dir/dont link-mac-unified/bin/x86/Debug-unified/dont link.app/Contents/MacOS/dont link (0x10d8a9a98). One of the two will be used. Which one is undefined. Class WebPolicyDecisionListener is implemented in both /System/Library/Frameworks/WebKit.framework/Versions/A/Frameworks/WebKitLegacy.framework/Versions/A/WebKitLegacy (0x7fffa944e838) and /Users/builder/data/lanes/6035/0ca02336/source/xamarin-macios/tests/xharness/tmp-test-dir/dont link-mac-unified/bin/x86/Debug-unified/dont link.app/Contents/MacOS/dont link (0x10d8a9ae8). One of the two will be used. Which one is undefined. Class MTLCaptureScope is implemented in both /System/Library/Frameworks/Metal.framework/Versions/A/Metal (0x7fffa806f1d0) and /Users/builder/data/lanes/6035/0ca02336/source/xamarin-macios/tests/xharness/tmp-test-dir/dont link-mac-unified/bin/x86/Debug-unified/dont link.app/Contents/MacOS/dont link (0x10d8aa858). One of the two will be used. Which one is undefined. Class JSExport is implemented in both /System/Library/Frameworks/JavaScriptCore.framework/Versions/A/JavaScriptCore (0x7fffa7eb4f60) and /Users/builder/data/lanes/6035/0ca02336/source/xamarin-macios/tests/xharness/tmp-test-dir/dont link-mac-unified/bin/x86/Debug-unified/dont link.app/Contents/MacOS/dont link (0x10d8aaa38). One of the two will be used. Which one is undefined.
2018-04-06 18:24:07 +03:00
internal class StringUtils {
static StringUtils ()
{
PlatformID pid = Environment.OSVersion.Platform;
if (((int)pid != 128 && pid != PlatformID.Unix && pid != PlatformID.MacOSX))
shellQuoteChar = '"'; // Windows
else
shellQuoteChar = '\''; // !Windows
}
static char shellQuoteChar;
static char[] mustQuoteCharacters = new char [] { ' ', '\'', ',', '$', '\\' };
Implement a different escaping/quoting algorithm for arguments to System.Diagnostics.Process. (#7177) * Implement a different escaping/quoting algorithm for arguments to System.Diagnostics.Process. mono changed how quotes should be escaped when passed to System.Diagnostic.Process, so we need to change accordingly. The main difference is that single quotes don't have to be escaped anymore. This solves problems like this: System.ComponentModel.Win32Exception : ApplicationName='nuget', CommandLine='restore '/Users/vsts/agent/2.158.0/work/1/s/tests/sampletester/bin/Debug/repositories/ios-samples/WorkingWithTables/Part 3 - Customizing a Table\'s appearance/3 - CellCustomTable/CellCustomTable.sln' -Verbosity detailed -SolutionDir '/Users/vsts/agent/2.158.0/work/1/s/tests/sampletester/bin/Debug/repositories/ios-samples/WorkingWithTables/Part 3 - Customizing a Table\'s appearance/3 - CellCustomTable'', CurrentDirectory='/Users/vsts/agent/2.158.0/work/1/s/tests/sampletester/bin/Debug/repositories', Native error= Cannot find the specified file at System.Diagnostics.Process.StartWithCreateProcess (System.Diagnostics.ProcessStartInfo startInfo) [0x0029f] in /Users/builder/jenkins/workspace/build-package-osx-mono/2019-08/external/bockbuild/builds/mono-x64/mcs/class/System/System.Diagnostics/Process.cs:778 ref: https://github.com/mono/mono/pull/15047 * Rework process arguments to pass arrays/lists around instead of quoted strings. And then only convert to a string at the very end when we create the Process instance. In the future there will be a ProcessStartInfo.ArgumentList property we can use to give the original array/list of arguments directly to the BCL so that we can avoid quoting at all. These changes gets us almost all the way there already (except that the ArgumentList property isn't available quite yet). We also have to bump to target framework version v4.7.2 from v4.5 in several places because of 'Array.Empty<T> ()' which is now used in more places. * Parse linker flags from LinkWith attributes. * [sampletester] Bump to v4.7.2 for Array.Empty<T> (). * Fix typo. * Rename GetVerbosity -> AddVerbosity. * Remove unnecessary string interpolation. * Remove unused variable. * [mtouch] Simplify code a bit. * Use implicitly typed arrays.
2019-10-14 17:18:46 +03:00
static char [] mustQuoteCharactersProcess = { ' ', '\\', '"', '\'' };
public static string[] Quote (params string[] array)
{
if (array == null || array.Length == 0)
return array;
var rv = new string [array.Length];
for (var i = 0; i < array.Length; i++)
rv [i] = Quote (array [i]);
return rv;
}
public static string Quote (string f)
{
if (String.IsNullOrEmpty (f))
return f ?? String.Empty;
if (f.IndexOfAny (mustQuoteCharacters) == -1)
return f;
var s = new StringBuilder ();
s.Append (shellQuoteChar);
foreach (var c in f) {
if (c == '\'' || c == '"' || c == '\\')
s.Append ('\\');
s.Append (c);
}
s.Append (shellQuoteChar);
return s.ToString ();
}
Implement a different escaping/quoting algorithm for arguments to System.Diagnostics.Process. (#7177) * Implement a different escaping/quoting algorithm for arguments to System.Diagnostics.Process. mono changed how quotes should be escaped when passed to System.Diagnostic.Process, so we need to change accordingly. The main difference is that single quotes don't have to be escaped anymore. This solves problems like this: System.ComponentModel.Win32Exception : ApplicationName='nuget', CommandLine='restore '/Users/vsts/agent/2.158.0/work/1/s/tests/sampletester/bin/Debug/repositories/ios-samples/WorkingWithTables/Part 3 - Customizing a Table\'s appearance/3 - CellCustomTable/CellCustomTable.sln' -Verbosity detailed -SolutionDir '/Users/vsts/agent/2.158.0/work/1/s/tests/sampletester/bin/Debug/repositories/ios-samples/WorkingWithTables/Part 3 - Customizing a Table\'s appearance/3 - CellCustomTable'', CurrentDirectory='/Users/vsts/agent/2.158.0/work/1/s/tests/sampletester/bin/Debug/repositories', Native error= Cannot find the specified file at System.Diagnostics.Process.StartWithCreateProcess (System.Diagnostics.ProcessStartInfo startInfo) [0x0029f] in /Users/builder/jenkins/workspace/build-package-osx-mono/2019-08/external/bockbuild/builds/mono-x64/mcs/class/System/System.Diagnostics/Process.cs:778 ref: https://github.com/mono/mono/pull/15047 * Rework process arguments to pass arrays/lists around instead of quoted strings. And then only convert to a string at the very end when we create the Process instance. In the future there will be a ProcessStartInfo.ArgumentList property we can use to give the original array/list of arguments directly to the BCL so that we can avoid quoting at all. These changes gets us almost all the way there already (except that the ArgumentList property isn't available quite yet). We also have to bump to target framework version v4.7.2 from v4.5 in several places because of 'Array.Empty<T> ()' which is now used in more places. * Parse linker flags from LinkWith attributes. * [sampletester] Bump to v4.7.2 for Array.Empty<T> (). * Fix typo. * Rename GetVerbosity -> AddVerbosity. * Remove unnecessary string interpolation. * Remove unused variable. * [mtouch] Simplify code a bit. * Use implicitly typed arrays.
2019-10-14 17:18:46 +03:00
public static string [] QuoteForProcess (IList<string> arguments)
{
if (arguments == null)
return Array.Empty<string> ();
return QuoteForProcess (arguments.ToArray ());
}
public static string [] QuoteForProcess (params string [] array)
{
if (array == null || array.Length == 0)
return array;
var rv = new string [array.Length];
for (var i = 0; i < array.Length; i++)
rv [i] = QuoteForProcess (array [i]);
return rv;
}
// Quote input according to how System.Diagnostics.Process needs it quoted.
public static string QuoteForProcess (string f)
{
if (String.IsNullOrEmpty (f))
return f ?? String.Empty;
if (f.IndexOfAny (mustQuoteCharactersProcess) == -1)
return f;
var s = new StringBuilder ();
s.Append ('"');
foreach (var c in f) {
if (c == '"') {
s.Append ('\\');
s.Append (c).Append (c);
} else if (c == '\\') {
s.Append (c);
}
s.Append (c);
}
s.Append ('"');
return s.ToString ();
}
public static string FormatArguments (params string [] arguments)
{
return FormatArguments ((IList<string>) arguments);
}
public static string FormatArguments (IList<string> arguments)
{
return string.Join (" ", QuoteForProcess (arguments));
}
public static string Unquote (string input)
{
if (input == null || input.Length == 0 || input [0] != shellQuoteChar)
return input;
var builder = new StringBuilder ();
for (int i = 1; i < input.Length - 1; i++) {
char c = input [i];
if (c == '\\') {
builder.Append (input [i + 1]);
i++;
continue;
}
builder.Append (input [i]);
}
return builder.ToString ();
}
Implement a different escaping/quoting algorithm for arguments to System.Diagnostics.Process. (#7177) * Implement a different escaping/quoting algorithm for arguments to System.Diagnostics.Process. mono changed how quotes should be escaped when passed to System.Diagnostic.Process, so we need to change accordingly. The main difference is that single quotes don't have to be escaped anymore. This solves problems like this: System.ComponentModel.Win32Exception : ApplicationName='nuget', CommandLine='restore '/Users/vsts/agent/2.158.0/work/1/s/tests/sampletester/bin/Debug/repositories/ios-samples/WorkingWithTables/Part 3 - Customizing a Table\'s appearance/3 - CellCustomTable/CellCustomTable.sln' -Verbosity detailed -SolutionDir '/Users/vsts/agent/2.158.0/work/1/s/tests/sampletester/bin/Debug/repositories/ios-samples/WorkingWithTables/Part 3 - Customizing a Table\'s appearance/3 - CellCustomTable'', CurrentDirectory='/Users/vsts/agent/2.158.0/work/1/s/tests/sampletester/bin/Debug/repositories', Native error= Cannot find the specified file at System.Diagnostics.Process.StartWithCreateProcess (System.Diagnostics.ProcessStartInfo startInfo) [0x0029f] in /Users/builder/jenkins/workspace/build-package-osx-mono/2019-08/external/bockbuild/builds/mono-x64/mcs/class/System/System.Diagnostics/Process.cs:778 ref: https://github.com/mono/mono/pull/15047 * Rework process arguments to pass arrays/lists around instead of quoted strings. And then only convert to a string at the very end when we create the Process instance. In the future there will be a ProcessStartInfo.ArgumentList property we can use to give the original array/list of arguments directly to the BCL so that we can avoid quoting at all. These changes gets us almost all the way there already (except that the ArgumentList property isn't available quite yet). We also have to bump to target framework version v4.7.2 from v4.5 in several places because of 'Array.Empty<T> ()' which is now used in more places. * Parse linker flags from LinkWith attributes. * [sampletester] Bump to v4.7.2 for Array.Empty<T> (). * Fix typo. * Rename GetVerbosity -> AddVerbosity. * Remove unnecessary string interpolation. * Remove unused variable. * [mtouch] Simplify code a bit. * Use implicitly typed arrays.
2019-10-14 17:18:46 +03:00
public static bool TryParseArguments (string quotedArguments, out string [] argv, out Exception ex)
{
var builder = new StringBuilder ();
var args = new List<string> ();
string argument;
int i = 0, j;
char c;
while (i < quotedArguments.Length) {
c = quotedArguments [i];
if (c != ' ' && c != '\t') {
if ((argument = GetArgument (builder, quotedArguments, i, out j, out ex)) == null) {
argv = null;
return false;
}
args.Add (argument);
i = j;
}
i++;
}
argv = args.ToArray ();
ex = null;
return true;
}
static string GetArgument (StringBuilder builder, string buf, int startIndex, out int endIndex, out Exception ex)
{
bool escaped = false;
char qchar, c = '\0';
int i = startIndex;
builder.Clear ();
switch (buf [startIndex]) {
case '\'': qchar = '\''; i++; break;
case '"': qchar = '"'; i++; break;
default: qchar = '\0'; break;
}
while (i < buf.Length) {
c = buf [i];
if (c == qchar && !escaped) {
// unescaped qchar means we've reached the end of the argument
i++;
break;
}
if (c == '\\') {
escaped = true;
} else if (escaped) {
builder.Append (c);
escaped = false;
} else if (qchar == '\0' && (c == ' ' || c == '\t')) {
break;
} else if (qchar == '\0' && (c == '\'' || c == '"')) {
string sofar = builder.ToString ();
string embedded;
if ((embedded = GetArgument (builder, buf, i, out endIndex, out ex)) == null)
return null;
i = endIndex;
builder.Clear ();
builder.Append (sofar);
builder.Append (embedded);
continue;
} else {
builder.Append (c);
}
i++;
}
if (escaped || (qchar != '\0' && c != qchar)) {
ex = new FormatException (escaped ? "Incomplete escape sequence." : "No matching quote found.");
endIndex = -1;
return null;
}
endIndex = i;
ex = null;
return builder.ToString ();
}
// Version.Parse requires, minimally, both major and minor parts.
// However we want to accept `11` as `11.0`
public static Version ParseVersion (string v)
{
int major;
if (int.TryParse (v, out major))
return new Version (major, 0);
return Version.Parse (v);
}
[generator] Register models with unique names to not match platform types. Fixes #3875. (#3879) * Move Registrar.SanitizeName to StringUtils.SanitizeObjectiveCName. * [generator] Register models with unique names to not match platform types. Fixes #3875. * [NSObject] Don't compare against a non-existent protocol. * [generator] Make it possible to register models like before if the binding developer wishes it. * [src] Make sure to not declare ObjC classes Apple already defines. Fixes these warnings at startup: Class DOMNodeFilter is implemented in both /System/Library/Frameworks/WebKit.framework/Versions/A/Frameworks/WebKitLegacy.framework/Versions/A/WebKitLegacy (0x7fffa944a788) and /Users/builder/data/lanes/6035/0ca02336/source/xamarin-macios/tests/xharness/tmp-test-dir/dont link-mac-unified/bin/x86/Debug-unified/dont link.app/Contents/MacOS/dont link (0x10d8a9958). One of the two will be used. Which one is undefined. Class WebOpenPanelResultListener is implemented in both /System/Library/Frameworks/WebKit.framework/Versions/A/Frameworks/WebKitLegacy.framework/Versions/A/WebKitLegacy (0x7fffa944e4c8) and /Users/builder/data/lanes/6035/0ca02336/source/xamarin-macios/tests/xharness/tmp-test-dir/dont link-mac-unified/bin/x86/Debug-unified/dont link.app/Contents/MacOS/dont link (0x10d8a9a98). One of the two will be used. Which one is undefined. Class WebPolicyDecisionListener is implemented in both /System/Library/Frameworks/WebKit.framework/Versions/A/Frameworks/WebKitLegacy.framework/Versions/A/WebKitLegacy (0x7fffa944e838) and /Users/builder/data/lanes/6035/0ca02336/source/xamarin-macios/tests/xharness/tmp-test-dir/dont link-mac-unified/bin/x86/Debug-unified/dont link.app/Contents/MacOS/dont link (0x10d8a9ae8). One of the two will be used. Which one is undefined. Class MTLCaptureScope is implemented in both /System/Library/Frameworks/Metal.framework/Versions/A/Metal (0x7fffa806f1d0) and /Users/builder/data/lanes/6035/0ca02336/source/xamarin-macios/tests/xharness/tmp-test-dir/dont link-mac-unified/bin/x86/Debug-unified/dont link.app/Contents/MacOS/dont link (0x10d8aa858). One of the two will be used. Which one is undefined. Class JSExport is implemented in both /System/Library/Frameworks/JavaScriptCore.framework/Versions/A/JavaScriptCore (0x7fffa7eb4f60) and /Users/builder/data/lanes/6035/0ca02336/source/xamarin-macios/tests/xharness/tmp-test-dir/dont link-mac-unified/bin/x86/Debug-unified/dont link.app/Contents/MacOS/dont link (0x10d8aaa38). One of the two will be used. Which one is undefined.
2018-04-06 18:24:07 +03:00
public static string SanitizeObjectiveCName (string name)
{
StringBuilder sb = null;
for (int i = 0; i < name.Length; i++) {
var ch = name [i];
switch (ch) {
case '.':
case '+':
case '/':
case '`':
case '@':
case '<':
case '>':
case '$':
case '-':
if (sb == null)
sb = new StringBuilder (name, 0, i, name.Length);
sb.Append ('_');
break;
default:
if (sb != null)
sb.Append (ch);
break;
}
}
if (sb != null)
return sb.ToString ();
return name;
}
}
static class StringExtensions
{
[generator] Register models with unique names to not match platform types. Fixes #3875. (#3879) * Move Registrar.SanitizeName to StringUtils.SanitizeObjectiveCName. * [generator] Register models with unique names to not match platform types. Fixes #3875. * [NSObject] Don't compare against a non-existent protocol. * [generator] Make it possible to register models like before if the binding developer wishes it. * [src] Make sure to not declare ObjC classes Apple already defines. Fixes these warnings at startup: Class DOMNodeFilter is implemented in both /System/Library/Frameworks/WebKit.framework/Versions/A/Frameworks/WebKitLegacy.framework/Versions/A/WebKitLegacy (0x7fffa944a788) and /Users/builder/data/lanes/6035/0ca02336/source/xamarin-macios/tests/xharness/tmp-test-dir/dont link-mac-unified/bin/x86/Debug-unified/dont link.app/Contents/MacOS/dont link (0x10d8a9958). One of the two will be used. Which one is undefined. Class WebOpenPanelResultListener is implemented in both /System/Library/Frameworks/WebKit.framework/Versions/A/Frameworks/WebKitLegacy.framework/Versions/A/WebKitLegacy (0x7fffa944e4c8) and /Users/builder/data/lanes/6035/0ca02336/source/xamarin-macios/tests/xharness/tmp-test-dir/dont link-mac-unified/bin/x86/Debug-unified/dont link.app/Contents/MacOS/dont link (0x10d8a9a98). One of the two will be used. Which one is undefined. Class WebPolicyDecisionListener is implemented in both /System/Library/Frameworks/WebKit.framework/Versions/A/Frameworks/WebKitLegacy.framework/Versions/A/WebKitLegacy (0x7fffa944e838) and /Users/builder/data/lanes/6035/0ca02336/source/xamarin-macios/tests/xharness/tmp-test-dir/dont link-mac-unified/bin/x86/Debug-unified/dont link.app/Contents/MacOS/dont link (0x10d8a9ae8). One of the two will be used. Which one is undefined. Class MTLCaptureScope is implemented in both /System/Library/Frameworks/Metal.framework/Versions/A/Metal (0x7fffa806f1d0) and /Users/builder/data/lanes/6035/0ca02336/source/xamarin-macios/tests/xharness/tmp-test-dir/dont link-mac-unified/bin/x86/Debug-unified/dont link.app/Contents/MacOS/dont link (0x10d8aa858). One of the two will be used. Which one is undefined. Class JSExport is implemented in both /System/Library/Frameworks/JavaScriptCore.framework/Versions/A/JavaScriptCore (0x7fffa7eb4f60) and /Users/builder/data/lanes/6035/0ca02336/source/xamarin-macios/tests/xharness/tmp-test-dir/dont link-mac-unified/bin/x86/Debug-unified/dont link.app/Contents/MacOS/dont link (0x10d8aaa38). One of the two will be used. Which one is undefined.
2018-04-06 18:24:07 +03:00
internal static string [] SplitLines (this string s) => s.Split (new [] { Environment.NewLine }, StringSplitOptions.None);
// Adds an element to an array and returns a new array with the added element.
// The original array is not modified.
// If the original array is null, a new array is also created, with just the new value.
internal static T [] CopyAndAdd<T>(this T[] array, T value)
{
if (array == null || array.Length == 0)
return new T [] { value };
var tmpArray = array;
Array.Resize (ref array, array.Length + 1);
tmpArray[tmpArray.Length - 1] = value;
return tmpArray;
}
}
}