diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/WixToolset.BuildTasks/Properties/AssemblyInfo.cs (renamed from src/WixToolset.BuildTasks/AssemblyInfo.cs) | 0 | ||||
| -rw-r--r-- | src/WixToolset.Core/CommandLine/CommandLineHelper.cs | 255 | ||||
| -rw-r--r-- | src/WixToolset.Core/CommandLine/CommandLineResponseFile.cs | 5 | ||||
| -rw-r--r-- | src/WixToolset.Core/Properties/AssemblyInfo.cs (renamed from src/WixToolset.Core/AssemblyInfo.cs) | 0 | ||||
| -rw-r--r-- | src/wix/Program.cs | 482 | ||||
| -rw-r--r-- | src/wix/X_CommandLine.cs | 394 |
6 files changed, 10 insertions, 1126 deletions
diff --git a/src/WixToolset.BuildTasks/AssemblyInfo.cs b/src/WixToolset.BuildTasks/Properties/AssemblyInfo.cs index ae52fce8..ae52fce8 100644 --- a/src/WixToolset.BuildTasks/AssemblyInfo.cs +++ b/src/WixToolset.BuildTasks/Properties/AssemblyInfo.cs | |||
diff --git a/src/WixToolset.Core/CommandLine/CommandLineHelper.cs b/src/WixToolset.Core/CommandLine/CommandLineHelper.cs deleted file mode 100644 index 86724603..00000000 --- a/src/WixToolset.Core/CommandLine/CommandLineHelper.cs +++ /dev/null | |||
| @@ -1,255 +0,0 @@ | |||
| 1 | // Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. | ||
| 2 | |||
| 3 | namespace WixToolset | ||
| 4 | { | ||
| 5 | using System; | ||
| 6 | using System.Collections.Generic; | ||
| 7 | using System.IO; | ||
| 8 | using System.Text; | ||
| 9 | using WixToolset.Data; | ||
| 10 | using WixToolset.Extensibility; | ||
| 11 | |||
| 12 | /// <summary> | ||
| 13 | /// Common utilities for Wix command-line processing. | ||
| 14 | /// </summary> | ||
| 15 | public static class CommandLineHelper | ||
| 16 | { | ||
| 17 | /// <summary> | ||
| 18 | /// Get a set of files that possibly have a search pattern in the path (such as '*'). | ||
| 19 | /// </summary> | ||
| 20 | /// <param name="searchPath">Search path to find files in.</param> | ||
| 21 | /// <param name="fileType">Type of file; typically "Source".</param> | ||
| 22 | /// <returns>An array of files matching the search path.</returns> | ||
| 23 | /// <remarks> | ||
| 24 | /// This method is written in this verbose way because it needs to support ".." in the path. | ||
| 25 | /// It needs the directory path isolated from the file name in order to use Directory.GetFiles | ||
| 26 | /// or DirectoryInfo.GetFiles. The only way to get this directory path is manually since | ||
| 27 | /// Path.GetDirectoryName does not support ".." in the path. | ||
| 28 | /// </remarks> | ||
| 29 | /// <exception cref="WixFileNotFoundException">Throws WixFileNotFoundException if no file matching the pattern can be found.</exception> | ||
| 30 | public static string[] GetFiles(string searchPath, string fileType) | ||
| 31 | { | ||
| 32 | if (null == searchPath) | ||
| 33 | { | ||
| 34 | throw new ArgumentNullException("searchPath"); | ||
| 35 | } | ||
| 36 | |||
| 37 | // convert alternate directory separators to the standard one | ||
| 38 | string filePath = searchPath.Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar); | ||
| 39 | int lastSeparator = filePath.LastIndexOf(Path.DirectorySeparatorChar); | ||
| 40 | string[] files = null; | ||
| 41 | |||
| 42 | try | ||
| 43 | { | ||
| 44 | if (0 > lastSeparator) | ||
| 45 | { | ||
| 46 | files = Directory.GetFiles(".", filePath); | ||
| 47 | } | ||
| 48 | else // found directory separator | ||
| 49 | { | ||
| 50 | files = Directory.GetFiles(filePath.Substring(0, lastSeparator + 1), filePath.Substring(lastSeparator + 1)); | ||
| 51 | } | ||
| 52 | } | ||
| 53 | catch (DirectoryNotFoundException) | ||
| 54 | { | ||
| 55 | // don't let this function throw the DirectoryNotFoundException. (this exception | ||
| 56 | // occurs for non-existant directories and invalid characters in the searchPattern) | ||
| 57 | } | ||
| 58 | catch (ArgumentException) | ||
| 59 | { | ||
| 60 | // don't let this function throw the ArgumentException. (this exception | ||
| 61 | // occurs in certain situations such as when passing a malformed UNC path) | ||
| 62 | } | ||
| 63 | catch (IOException) | ||
| 64 | { | ||
| 65 | throw new WixFileNotFoundException(searchPath, fileType); | ||
| 66 | } | ||
| 67 | |||
| 68 | // file could not be found or path is invalid in some way | ||
| 69 | if (null == files || 0 == files.Length) | ||
| 70 | { | ||
| 71 | throw new WixFileNotFoundException(searchPath, fileType); | ||
| 72 | } | ||
| 73 | |||
| 74 | return files; | ||
| 75 | } | ||
| 76 | |||
| 77 | /// <summary> | ||
| 78 | /// Validates that a valid string parameter (without "/" or "-"), and returns a bool indicating its validity | ||
| 79 | /// </summary> | ||
| 80 | /// <param name="args">The list of strings to check.</param> | ||
| 81 | /// <param name="index">The index (in args) of the commandline parameter to be validated.</param> | ||
| 82 | /// <returns>True if a valid string parameter exists there, false if not.</returns> | ||
| 83 | public static bool IsValidArg(string[] args, int index) | ||
| 84 | { | ||
| 85 | if (args.Length <= index || String.IsNullOrEmpty(args[index]) || '/' == args[index][0] || '-' == args[index][0]) | ||
| 86 | { | ||
| 87 | return false; | ||
| 88 | } | ||
| 89 | else | ||
| 90 | { | ||
| 91 | return true; | ||
| 92 | } | ||
| 93 | } | ||
| 94 | |||
| 95 | /// <summary> | ||
| 96 | /// Validates that a commandline parameter is a valid file or directory name, and throws appropriate warnings/errors if not | ||
| 97 | /// </summary> | ||
| 98 | /// <param name="path">The path to test.</param> | ||
| 99 | /// <returns>The string if it is valid, null if it is invalid.</returns> | ||
| 100 | public static string VerifyPath(string path) | ||
| 101 | { | ||
| 102 | return VerifyPath(path, false); | ||
| 103 | } | ||
| 104 | |||
| 105 | /// <summary> | ||
| 106 | /// Validates that a commandline parameter is a valid file or directory name, and throws appropriate warnings/errors if not | ||
| 107 | /// </summary> | ||
| 108 | /// <param name="path">The path to test.</param> | ||
| 109 | /// <param name="allowPrefix">Indicates if a colon-delimited prefix is allowed.</param> | ||
| 110 | /// <returns>The full path if it is valid, null if it is invalid.</returns> | ||
| 111 | public static string VerifyPath(string path, bool allowPrefix) | ||
| 112 | { | ||
| 113 | string fullPath; | ||
| 114 | |||
| 115 | if (0 <= path.IndexOf('\"')) | ||
| 116 | { | ||
| 117 | Messaging.Instance.OnMessage(WixErrors.PathCannotContainQuote(path)); | ||
| 118 | return null; | ||
| 119 | } | ||
| 120 | |||
| 121 | try | ||
| 122 | { | ||
| 123 | string prefix = null; | ||
| 124 | if (allowPrefix) | ||
| 125 | { | ||
| 126 | int prefixLength = path.IndexOf('=') + 1; | ||
| 127 | if (0 != prefixLength) | ||
| 128 | { | ||
| 129 | prefix = path.Substring(0, prefixLength); | ||
| 130 | path = path.Substring(prefixLength); | ||
| 131 | } | ||
| 132 | } | ||
| 133 | |||
| 134 | if (String.IsNullOrEmpty(prefix)) | ||
| 135 | { | ||
| 136 | fullPath = Path.GetFullPath(path); | ||
| 137 | } | ||
| 138 | else | ||
| 139 | { | ||
| 140 | fullPath = String.Concat(prefix, Path.GetFullPath(path)); | ||
| 141 | } | ||
| 142 | } | ||
| 143 | catch (Exception e) | ||
| 144 | { | ||
| 145 | Messaging.Instance.OnMessage(WixErrors.InvalidCommandLineFileName(path, e.Message)); | ||
| 146 | return null; | ||
| 147 | } | ||
| 148 | |||
| 149 | return fullPath; | ||
| 150 | } | ||
| 151 | |||
| 152 | /// <summary> | ||
| 153 | /// Validates that a string is a valid bind path, and throws appropriate warnings/errors if not | ||
| 154 | /// </summary> | ||
| 155 | /// <param name="commandlineSwitch">The commandline switch we're parsing (for error display purposes).</param> | ||
| 156 | /// <param name="args">The list of strings to check.</param> | ||
| 157 | /// <param name="index">The index (in args) of the commandline parameter to be parsed.</param> | ||
| 158 | /// <returns>The bind path if it is valid, null if it is invalid.</returns> | ||
| 159 | public static BindPath GetBindPath(string commandlineSwitch, string[] args, int index) | ||
| 160 | { | ||
| 161 | commandlineSwitch = String.Concat("-", commandlineSwitch); | ||
| 162 | |||
| 163 | if (!IsValidArg(args, index)) | ||
| 164 | { | ||
| 165 | Messaging.Instance.OnMessage(WixErrors.DirectoryPathRequired(commandlineSwitch)); | ||
| 166 | return null; | ||
| 167 | } | ||
| 168 | |||
| 169 | BindPath bindPath = BindPath.Parse(args[index]); | ||
| 170 | |||
| 171 | if (File.Exists(bindPath.Path)) | ||
| 172 | { | ||
| 173 | Messaging.Instance.OnMessage(WixErrors.ExpectedDirectoryGotFile(commandlineSwitch, bindPath.Path)); | ||
| 174 | return null; | ||
| 175 | } | ||
| 176 | |||
| 177 | bindPath.Path = VerifyPath(bindPath.Path, true); | ||
| 178 | return String.IsNullOrEmpty(bindPath.Path) ? null : bindPath; | ||
| 179 | } | ||
| 180 | |||
| 181 | /// <summary> | ||
| 182 | /// Validates that a commandline parameter is a valid file or directory name, and throws appropriate warnings/errors if not | ||
| 183 | /// </summary> | ||
| 184 | /// <param name="commandlineSwitch">The commandline switch we're parsing (for error display purposes).</param> | ||
| 185 | /// <param name="messageHandler">The messagehandler to report warnings/errors to.</param> | ||
| 186 | /// <param name="args">The list of strings to check.</param> | ||
| 187 | /// <param name="index">The index (in args) of the commandline parameter to be parsed.</param> | ||
| 188 | /// <returns>The string if it is valid, null if it is invalid.</returns> | ||
| 189 | public static string GetFileOrDirectory(string commandlineSwitch, string[] args, int index) | ||
| 190 | { | ||
| 191 | commandlineSwitch = String.Concat("-", commandlineSwitch); | ||
| 192 | |||
| 193 | if (!IsValidArg(args, index)) | ||
| 194 | { | ||
| 195 | Messaging.Instance.OnMessage(WixErrors.FileOrDirectoryPathRequired(commandlineSwitch)); | ||
| 196 | return null; | ||
| 197 | } | ||
| 198 | |||
| 199 | return VerifyPath(args[index]); | ||
| 200 | } | ||
| 201 | |||
| 202 | /// <summary> | ||
| 203 | /// Validates that a string is a valid directory name, and throws appropriate warnings/errors if not | ||
| 204 | /// </summary> | ||
| 205 | /// <param name="commandlineSwitch">The commandline switch we're parsing (for error display purposes).</param> | ||
| 206 | /// <param name="args">The list of strings to check.</param> | ||
| 207 | /// <param name="index">The index (in args) of the commandline parameter to be parsed.</param> | ||
| 208 | /// <param name="allowPrefix">Indicates if a colon-delimited prefix is allowed.</param> | ||
| 209 | /// <returns>The string if it is valid, null if it is invalid.</returns> | ||
| 210 | public static string GetDirectory(string commandlineSwitch, string[] args, int index, bool allowPrefix = false) | ||
| 211 | { | ||
| 212 | commandlineSwitch = String.Concat("-", commandlineSwitch); | ||
| 213 | |||
| 214 | if (!IsValidArg(args, index)) | ||
| 215 | { | ||
| 216 | Messaging.Instance.OnMessage(WixErrors.DirectoryPathRequired(commandlineSwitch)); | ||
| 217 | return null; | ||
| 218 | } | ||
| 219 | |||
| 220 | if (File.Exists(args[index])) | ||
| 221 | { | ||
| 222 | Messaging.Instance.OnMessage(WixErrors.ExpectedDirectoryGotFile(commandlineSwitch, args[index])); | ||
| 223 | return null; | ||
| 224 | } | ||
| 225 | |||
| 226 | return VerifyPath(args[index], allowPrefix); | ||
| 227 | } | ||
| 228 | |||
| 229 | /// <summary> | ||
| 230 | /// Validates that a string is a valid filename, and throws appropriate warnings/errors if not | ||
| 231 | /// </summary> | ||
| 232 | /// <param name="commandlineSwitch">The commandline switch we're parsing (for error display purposes).</param> | ||
| 233 | /// <param name="args">The list of strings to check.</param> | ||
| 234 | /// <param name="index">The index (in args) of the commandline parameter to be parsed.</param> | ||
| 235 | /// <returns>The string if it is valid, null if it is invalid.</returns> | ||
| 236 | public static string GetFile(string commandlineSwitch, string[] args, int index) | ||
| 237 | { | ||
| 238 | commandlineSwitch = String.Concat("-", commandlineSwitch); | ||
| 239 | |||
| 240 | if (!IsValidArg(args, index)) | ||
| 241 | { | ||
| 242 | Messaging.Instance.OnMessage(WixErrors.FilePathRequired(commandlineSwitch)); | ||
| 243 | return null; | ||
| 244 | } | ||
| 245 | |||
| 246 | if (Directory.Exists(args[index])) | ||
| 247 | { | ||
| 248 | Messaging.Instance.OnMessage(WixErrors.ExpectedFileGotDirectory(commandlineSwitch, args[index])); | ||
| 249 | return null; | ||
| 250 | } | ||
| 251 | |||
| 252 | return VerifyPath(args[index]); | ||
| 253 | } | ||
| 254 | } | ||
| 255 | } | ||
diff --git a/src/WixToolset.Core/CommandLine/CommandLineResponseFile.cs b/src/WixToolset.Core/CommandLine/CommandLineResponseFile.cs index f27296b7..578c3b22 100644 --- a/src/WixToolset.Core/CommandLine/CommandLineResponseFile.cs +++ b/src/WixToolset.Core/CommandLine/CommandLineResponseFile.cs | |||
| @@ -102,11 +102,6 @@ namespace WixToolset | |||
| 102 | return argsList.ToArray(); | 102 | return argsList.ToArray(); |
| 103 | } | 103 | } |
| 104 | 104 | ||
| 105 | /// <summary> | ||
| 106 | /// Expand enxironment variables contained in the passed string | ||
| 107 | /// </summary> | ||
| 108 | /// <param name="arguments"></param> | ||
| 109 | /// <returns></returns> | ||
| 110 | static private string ExpandEnvVars(string arguments) | 105 | static private string ExpandEnvVars(string arguments) |
| 111 | { | 106 | { |
| 112 | IDictionary id = Environment.GetEnvironmentVariables(); | 107 | IDictionary id = Environment.GetEnvironmentVariables(); |
diff --git a/src/WixToolset.Core/AssemblyInfo.cs b/src/WixToolset.Core/Properties/AssemblyInfo.cs index b3740b2a..b3740b2a 100644 --- a/src/WixToolset.Core/AssemblyInfo.cs +++ b/src/WixToolset.Core/Properties/AssemblyInfo.cs | |||
diff --git a/src/wix/Program.cs b/src/wix/Program.cs index 277f99fe..c60831d0 100644 --- a/src/wix/Program.cs +++ b/src/wix/Program.cs | |||
| @@ -6,16 +6,12 @@ namespace WixToolset.Core | |||
| 6 | using WixToolset.Data; | 6 | using WixToolset.Data; |
| 7 | 7 | ||
| 8 | /// <summary> | 8 | /// <summary> |
| 9 | /// The main entry point for candle. | 9 | /// Wix Toolset Command-Line Interface. |
| 10 | /// </summary> | 10 | /// </summary> |
| 11 | public sealed class Program | 11 | public sealed class Program |
| 12 | { | 12 | { |
| 13 | //private IEnumerable<IPreprocessorExtension> preprocessorExtensions; | ||
| 14 | //private IEnumerable<ICompilerExtension> compilerExtensions; | ||
| 15 | //private IEnumerable<IExtensionData> extensionData; | ||
| 16 | |||
| 17 | /// <summary> | 13 | /// <summary> |
| 18 | /// The main entry point for candle. | 14 | /// The main entry point for wix command-line interface. |
| 19 | /// </summary> | 15 | /// </summary> |
| 20 | /// <param name="args">Commandline arguments for the application.</param> | 16 | /// <param name="args">Commandline arguments for the application.</param> |
| 21 | /// <returns>Returns the application error code.</returns> | 17 | /// <returns>Returns the application error code.</returns> |
| @@ -33,474 +29,16 @@ namespace WixToolset.Core | |||
| 33 | 29 | ||
| 34 | private static void DisplayMessage(object sender, DisplayEventArgs e) | 30 | private static void DisplayMessage(object sender, DisplayEventArgs e) |
| 35 | { | 31 | { |
| 36 | Console.WriteLine(e.Message); | 32 | switch (e.Level) |
| 37 | } | ||
| 38 | |||
| 39 | #if false | ||
| 40 | private static ICommand ParseCommandLine(string[] args) | ||
| 41 | { | ||
| 42 | var next = String.Empty; | ||
| 43 | |||
| 44 | var command = Commands.Unknown; | ||
| 45 | var showLogo = true; | ||
| 46 | var showVersion = false; | ||
| 47 | var outputFolder = String.Empty; | ||
| 48 | var outputFile = String.Empty; | ||
| 49 | var sourceFile = String.Empty; | ||
| 50 | var verbose = false; | ||
| 51 | var files = new List<string>(); | ||
| 52 | var defines = new List<string>(); | ||
| 53 | var includePaths = new List<string>(); | ||
| 54 | var locFiles = new List<string>(); | ||
| 55 | var suppressedWarnings = new List<int>(); | ||
| 56 | |||
| 57 | var cli = CommandLine.Parse(args, (cmdline, arg) => Enum.TryParse(arg, true, out command), (cmdline, arg) => | ||
| 58 | { | ||
| 59 | if (cmdline.IsSwitch(arg)) | ||
| 60 | { | ||
| 61 | var parameter = arg.TrimStart(new[] { '-', '/' }); | ||
| 62 | switch (parameter.ToLowerInvariant()) | ||
| 63 | { | ||
| 64 | case "?": | ||
| 65 | case "h": | ||
| 66 | case "help": | ||
| 67 | cmdline.ShowHelp = true; | ||
| 68 | return true; | ||
| 69 | |||
| 70 | case "d": | ||
| 71 | case "define": | ||
| 72 | cmdline.GetNextArgumentOrError(defines); | ||
| 73 | return true; | ||
| 74 | |||
| 75 | case "i": | ||
| 76 | case "includepath": | ||
| 77 | cmdline.GetNextArgumentOrError(includePaths); | ||
| 78 | return true; | ||
| 79 | |||
| 80 | case "loc": | ||
| 81 | cmdline.GetNextArgumentAsFilePathOrError(locFiles, "localization files"); | ||
| 82 | return true; | ||
| 83 | |||
| 84 | case "o": | ||
| 85 | case "out": | ||
| 86 | cmdline.GetNextArgumentOrError(ref outputFile); | ||
| 87 | return true; | ||
| 88 | |||
| 89 | case "nologo": | ||
| 90 | showLogo = false; | ||
| 91 | return true; | ||
| 92 | |||
| 93 | case "v": | ||
| 94 | case "verbose": | ||
| 95 | verbose = true; | ||
| 96 | return true; | ||
| 97 | |||
| 98 | case "version": | ||
| 99 | case "-version": | ||
| 100 | showVersion = true; | ||
| 101 | return true; | ||
| 102 | } | ||
| 103 | |||
| 104 | return false; | ||
| 105 | } | ||
| 106 | else | ||
| 107 | { | ||
| 108 | files.AddRange(cmdline.GetFiles(arg, "source code")); | ||
| 109 | return true; | ||
| 110 | } | ||
| 111 | }); | ||
| 112 | |||
| 113 | if (showVersion) | ||
| 114 | { | ||
| 115 | return new VersionCommand(); | ||
| 116 | } | ||
| 117 | |||
| 118 | if (showLogo) | ||
| 119 | { | ||
| 120 | AppCommon.DisplayToolHeader(); | ||
| 121 | } | ||
| 122 | |||
| 123 | if (cli.ShowHelp) | ||
| 124 | { | ||
| 125 | return new HelpCommand(command); | ||
| 126 | } | ||
| 127 | |||
| 128 | switch (command) | ||
| 129 | { | ||
| 130 | case Commands.Build: | ||
| 131 | { | ||
| 132 | var sourceFiles = GatherSourceFiles(files, outputFolder); | ||
| 133 | var variables = GatherPreprocessorVariables(defines); | ||
| 134 | var extensions = cli.ExtensionManager; | ||
| 135 | return new BuildCommand(sourceFiles, variables, locFiles, outputFile); | ||
| 136 | } | ||
| 137 | |||
| 138 | case Commands.Compile: | ||
| 139 | { | ||
| 140 | var sourceFiles = GatherSourceFiles(files, outputFolder); | ||
| 141 | var variables = GatherPreprocessorVariables(defines); | ||
| 142 | return new CompileCommand(sourceFiles, variables); | ||
| 143 | } | ||
| 144 | } | ||
| 145 | |||
| 146 | return null; | ||
| 147 | } | ||
| 148 | |||
| 149 | private static IEnumerable<SourceFile> GatherSourceFiles(IEnumerable<string> sourceFiles, string intermediateDirectory) | ||
| 150 | { | ||
| 151 | var files = new List<SourceFile>(); | ||
| 152 | |||
| 153 | foreach (var item in sourceFiles) | ||
| 154 | { | ||
| 155 | var sourcePath = item; | ||
| 156 | var outputPath = Path.Combine(intermediateDirectory, Path.GetFileNameWithoutExtension(sourcePath) + ".wir"); | ||
| 157 | |||
| 158 | files.Add(new SourceFile(sourcePath, outputPath)); | ||
| 159 | } | ||
| 160 | |||
| 161 | return files; | ||
| 162 | } | ||
| 163 | |||
| 164 | private static IDictionary<string, string> GatherPreprocessorVariables(IEnumerable<string> defineConstants) | ||
| 165 | { | ||
| 166 | var variables = new Dictionary<string, string>(); | ||
| 167 | |||
| 168 | foreach (var pair in defineConstants) | ||
| 169 | { | ||
| 170 | string[] value = pair.Split(new[] { '=' }, 2); | ||
| 171 | |||
| 172 | if (variables.ContainsKey(value[0])) | ||
| 173 | { | ||
| 174 | Messaging.Instance.OnMessage(WixErrors.DuplicateVariableDefinition(value[0], (1 == value.Length) ? String.Empty : value[1], variables[value[0]])); | ||
| 175 | continue; | ||
| 176 | } | ||
| 177 | |||
| 178 | variables.Add(value[0], (1 == value.Length) ? String.Empty : value[1]); | ||
| 179 | } | ||
| 180 | |||
| 181 | return variables; | ||
| 182 | } | ||
| 183 | #endif | ||
| 184 | |||
| 185 | #if false | ||
| 186 | private static ICommand ParseCommandLine2(string[] args) | ||
| 187 | { | ||
| 188 | var command = Commands.Unknown; | ||
| 189 | |||
| 190 | var nologo = false; | ||
| 191 | var outputFolder = String.Empty; | ||
| 192 | var outputFile = String.Empty; | ||
| 193 | var sourceFile = String.Empty; | ||
| 194 | var verbose = false; | ||
| 195 | IReadOnlyList<string> files = Array.Empty<string>(); | ||
| 196 | IReadOnlyList<string> defines = Array.Empty<string>(); | ||
| 197 | IReadOnlyList<string> includePaths = Array.Empty<string>(); | ||
| 198 | IReadOnlyList<int> suppressedWarnings = Array.Empty<int>(); | ||
| 199 | IReadOnlyList<string> locFiles = Array.Empty<string>(); | ||
| 200 | |||
| 201 | ArgumentSyntax parsed = null; | ||
| 202 | try | ||
| 203 | { | ||
| 204 | parsed = ArgumentSyntax.Parse(args, syntax => | ||
| 205 | { | ||
| 206 | syntax.HandleErrors = false; | ||
| 207 | //syntax.HandleHelp = false; | ||
| 208 | syntax.ErrorOnUnexpectedArguments = false; | ||
| 209 | |||
| 210 | syntax.DefineCommand("build", ref command, Commands.Build, "Build to final output"); | ||
| 211 | syntax.DefineOptionList("d|D|define", ref defines, "Preprocessor name value pairs"); | ||
| 212 | syntax.DefineOptionList("I|includePath", ref includePaths, "Include search paths"); | ||
| 213 | syntax.DefineOption("nologo", ref nologo, false, "Do not display logo"); | ||
| 214 | syntax.DefineOption("o|out", ref outputFile, "Output file"); | ||
| 215 | syntax.DefineOptionList("sw", ref suppressedWarnings, false, "Do not display logo"); | ||
| 216 | syntax.DefineOption("v|verbose", ref verbose, false, "Display verbose messages"); | ||
| 217 | syntax.DefineOptionList("l|loc", ref locFiles, "Localization files to load (.wxl)"); | ||
| 218 | syntax.DefineParameterList("files", ref files, "Source files to compile (.wxs)"); | ||
| 219 | |||
| 220 | syntax.DefineCommand("preprocess", ref command, Commands.Preprocess, "Preprocess a source files"); | ||
| 221 | syntax.DefineOptionList("d|D|define", ref defines, "Preprocessor name value pairs"); | ||
| 222 | syntax.DefineOptionList("I|includePath", ref includePaths, "Include search paths"); | ||
| 223 | syntax.DefineOption("nologo", ref nologo, false, "Do not display logo"); | ||
| 224 | syntax.DefineOption("o|out", ref outputFile, "Output file"); | ||
| 225 | syntax.DefineParameter("file", ref sourceFile, "File to process"); | ||
| 226 | |||
| 227 | syntax.DefineCommand("compile", ref command, Commands.Compile, "Compile source files"); | ||
| 228 | syntax.DefineOptionList("I|includePath", ref includePaths, "Include search paths"); | ||
| 229 | syntax.DefineOption("nologo", ref nologo, false, "Do not display logo"); | ||
| 230 | syntax.DefineOption("o|out", ref outputFolder, "Output folder"); | ||
| 231 | syntax.DefineOptionList("sw", ref suppressedWarnings, false, "Do not display logo"); | ||
| 232 | syntax.DefineOption("v|verbose", ref verbose, false, "Display verbose messages"); | ||
| 233 | syntax.DefineParameterList("files", ref files, "Source files to compile (.wxs)"); | ||
| 234 | |||
| 235 | syntax.DefineCommand("link", ref command, Commands.Link, "Link intermediate files"); | ||
| 236 | syntax.DefineOption("nologo", ref nologo, "Do not display logo"); | ||
| 237 | syntax.DefineOption("o|out", ref outputFile, "Output intermediate file (.wir)"); | ||
| 238 | syntax.DefineParameterList("files", ref files, "Intermediate files to link (.wir)"); | ||
| 239 | |||
| 240 | syntax.DefineCommand("bind", ref command, Commands.Bind, "Bind to final output"); | ||
| 241 | syntax.DefineOption("nologo", ref nologo, false, "Do not display logo"); | ||
| 242 | syntax.DefineOption("o|out", ref outputFile, "Output file"); | ||
| 243 | syntax.DefineParameterList("files", ref files, "Intermediate files to bind (.wir)"); | ||
| 244 | |||
| 245 | syntax.DefineCommand("version", ref command, Commands.Version, "Display version information"); | ||
| 246 | }); | ||
| 247 | |||
| 248 | if (IsHelpRequested(parsed)) | ||
| 249 | { | ||
| 250 | var width = Console.WindowWidth - 2; | ||
| 251 | var text = parsed.GetHelpText(width < 20 ? 72 : width); | ||
| 252 | Console.Error.WriteLine(text); | ||
| 253 | |||
| 254 | return null; | ||
| 255 | } | ||
| 256 | |||
| 257 | //var u = result.GetArguments(); | ||
| 258 | |||
| 259 | //var p = result.GetActiveParameters(); | ||
| 260 | |||
| 261 | //var o = result.GetActiveOptions(); | ||
| 262 | |||
| 263 | //var a = result.GetActiveArguments(); | ||
| 264 | |||
| 265 | //var h = result.GetHelpText(); | ||
| 266 | |||
| 267 | //foreach (var x in p) | ||
| 268 | //{ | ||
| 269 | // Console.WriteLine("{0}", x.Name); | ||
| 270 | //} | ||
| 271 | |||
| 272 | switch (command) | ||
| 273 | { | ||
| 274 | case Commands.Build: | ||
| 275 | { | ||
| 276 | var sourceFiles = GatherSourceFiles(files, outputFolder); | ||
| 277 | var variables = GatherPreprocessorVariables(defines); | ||
| 278 | return new BuildCommand(sourceFiles, variables, locFiles, outputFile); | ||
| 279 | } | ||
| 280 | |||
| 281 | case Commands.Compile: | ||
| 282 | { | ||
| 283 | var sourceFiles = GatherSourceFiles(files, outputFolder); | ||
| 284 | var variables = GatherPreprocessorVariables(defines); | ||
| 285 | return new CompileCommand(sourceFiles, variables); | ||
| 286 | } | ||
| 287 | |||
| 288 | case Commands.Version: | ||
| 289 | return new VersionCommand(); | ||
| 290 | } | ||
| 291 | |||
| 292 | //var preprocessorVariables = this.GatherPreprocessorVariables(); | ||
| 293 | |||
| 294 | //foreach (var sourceFile in sourceFiles) | ||
| 295 | //{ | ||
| 296 | // var document = preprocessor.Process(sourceFile.SourcePath, preprocessorVariables); | ||
| 297 | |||
| 298 | // var intermediate = compiler.Compile(document); | ||
| 299 | |||
| 300 | // intermediate.Save(sourceFile.OutputPath); | ||
| 301 | //} | ||
| 302 | } | ||
| 303 | //catch (ArgumentSyntaxException e) | ||
| 304 | //{ | ||
| 305 | // if (IsHelpRequested(parsed)) | ||
| 306 | // { | ||
| 307 | // var width = Console.WindowWidth - 2; | ||
| 308 | // var text = parsed.GetHelpText(width < 20 ? 72 : width); | ||
| 309 | // Console.Error.WriteLine(text); | ||
| 310 | // } | ||
| 311 | // else | ||
| 312 | // { | ||
| 313 | // Console.Error.WriteLine(e.Message); | ||
| 314 | // } | ||
| 315 | //} | ||
| 316 | |||
| 317 | return null; | ||
| 318 | } | ||
| 319 | |||
| 320 | //private static bool IsHelpRequested(ArgumentSyntax syntax) | ||
| 321 | //{ | ||
| 322 | // return syntax?.RemainingArguments | ||
| 323 | // .Any(a => String.Equals(a, @"-?", StringComparison.Ordinal) || | ||
| 324 | // String.Equals(a, @"-h", StringComparison.Ordinal) || | ||
| 325 | // String.Equals(a, @"--help", StringComparison.Ordinal)) ?? false; | ||
| 326 | //} | ||
| 327 | #endif | ||
| 328 | |||
| 329 | #if false | ||
| 330 | private int Execute(string[] args) | ||
| 331 | { | ||
| 332 | try | ||
| 333 | { | ||
| 334 | string[] unparsed = this.ParseCommandLineAndLoadExtensions(args); | ||
| 335 | |||
| 336 | if (!Messaging.Instance.EncounteredError) | ||
| 337 | { | ||
| 338 | if (this.commandLine.ShowLogo) | ||
| 339 | { | ||
| 340 | AppCommon.DisplayToolHeader(); | ||
| 341 | } | ||
| 342 | |||
| 343 | if (this.commandLine.ShowHelp) | ||
| 344 | { | ||
| 345 | Console.WriteLine(CandleStrings.HelpMessage); | ||
| 346 | AppCommon.DisplayToolFooter(); | ||
| 347 | } | ||
| 348 | else | ||
| 349 | { | ||
| 350 | foreach (string arg in unparsed) | ||
| 351 | { | ||
| 352 | Messaging.Instance.OnMessage(WixWarnings.UnsupportedCommandLineArgument(arg)); | ||
| 353 | } | ||
| 354 | |||
| 355 | this.Run(); | ||
| 356 | } | ||
| 357 | } | ||
| 358 | } | ||
| 359 | catch (WixException we) | ||
| 360 | { | ||
| 361 | Messaging.Instance.OnMessage(we.Error); | ||
| 362 | } | ||
| 363 | catch (Exception e) | ||
| 364 | { | ||
| 365 | Messaging.Instance.OnMessage(WixErrors.UnexpectedException(e.Message, e.GetType().ToString(), e.StackTrace)); | ||
| 366 | if (e is NullReferenceException || e is SEHException) | ||
| 367 | { | ||
| 368 | throw; | ||
| 369 | } | ||
| 370 | } | ||
| 371 | |||
| 372 | return Messaging.Instance.LastErrorNumber; | ||
| 373 | } | ||
| 374 | |||
| 375 | private string[] ParseCommandLineAndLoadExtensions(string[] args) | ||
| 376 | { | ||
| 377 | this.commandLine = new CandleCommandLine(); | ||
| 378 | string[] unprocessed = commandLine.Parse(args); | ||
| 379 | if (Messaging.Instance.EncounteredError) | ||
| 380 | { | ||
| 381 | return unprocessed; | ||
| 382 | } | ||
| 383 | |||
| 384 | // Load extensions. | ||
| 385 | ExtensionManager extensionManager = new ExtensionManager(); | ||
| 386 | foreach (string extension in this.commandLine.Extensions) | ||
| 387 | { | ||
| 388 | extensionManager.Load(extension); | ||
| 389 | } | ||
| 390 | |||
| 391 | // Preprocessor extension command line processing. | ||
| 392 | this.preprocessorExtensions = extensionManager.Create<IPreprocessorExtension>(); | ||
| 393 | foreach (IExtensionCommandLine pce in this.preprocessorExtensions.Where(e => e is IExtensionCommandLine).Cast<IExtensionCommandLine>()) | ||
| 394 | { | ||
| 395 | pce.MessageHandler = Messaging.Instance; | ||
| 396 | unprocessed = pce.ParseCommandLine(unprocessed); | ||
| 397 | } | ||
| 398 | |||
| 399 | // Compiler extension command line processing. | ||
| 400 | this.compilerExtensions = extensionManager.Create<ICompilerExtension>(); | ||
| 401 | foreach (IExtensionCommandLine cce in this.compilerExtensions.Where(e => e is IExtensionCommandLine).Cast<IExtensionCommandLine>()) | ||
| 402 | { | ||
| 403 | cce.MessageHandler = Messaging.Instance; | ||
| 404 | unprocessed = cce.ParseCommandLine(unprocessed); | ||
| 405 | } | ||
| 406 | |||
| 407 | // Extension data command line processing. | ||
| 408 | this.extensionData = extensionManager.Create<IExtensionData>(); | ||
| 409 | foreach (IExtensionCommandLine dce in this.extensionData.Where(e => e is IExtensionCommandLine).Cast<IExtensionCommandLine>()) | ||
| 410 | { | 33 | { |
| 411 | dce.MessageHandler = Messaging.Instance; | 34 | case MessageLevel.Warning: |
| 412 | unprocessed = dce.ParseCommandLine(unprocessed); | 35 | case MessageLevel.Error: |
| 36 | Console.Error.WriteLine(e.Message); | ||
| 37 | break; | ||
| 38 | default: | ||
| 39 | Console.WriteLine(e.Message); | ||
| 40 | break; | ||
| 413 | } | 41 | } |
| 414 | |||
| 415 | return commandLine.ParsePostExtensions(unprocessed); | ||
| 416 | } | ||
| 417 | |||
| 418 | private void Run() | ||
| 419 | { | ||
| 420 | // Create the preprocessor and compiler | ||
| 421 | Preprocessor preprocessor = new Preprocessor(); | ||
| 422 | preprocessor.CurrentPlatform = this.commandLine.Platform; | ||
| 423 | |||
| 424 | foreach (string includePath in this.commandLine.IncludeSearchPaths) | ||
| 425 | { | ||
| 426 | preprocessor.IncludeSearchPaths.Add(includePath); | ||
| 427 | } | ||
| 428 | |||
| 429 | foreach (IPreprocessorExtension pe in this.preprocessorExtensions) | ||
| 430 | { | ||
| 431 | preprocessor.AddExtension(pe); | ||
| 432 | } | ||
| 433 | |||
| 434 | Compiler compiler = new Compiler(); | ||
| 435 | compiler.ShowPedanticMessages = this.commandLine.ShowPedanticMessages; | ||
| 436 | compiler.CurrentPlatform = this.commandLine.Platform; | ||
| 437 | |||
| 438 | foreach (IExtensionData ed in this.extensionData) | ||
| 439 | { | ||
| 440 | compiler.AddExtensionData(ed); | ||
| 441 | } | ||
| 442 | |||
| 443 | foreach (ICompilerExtension ce in this.compilerExtensions) | ||
| 444 | { | ||
| 445 | compiler.AddExtension(ce); | ||
| 446 | } | ||
| 447 | |||
| 448 | // Preprocess then compile each source file. | ||
| 449 | foreach (CompileFile file in this.commandLine.Files) | ||
| 450 | { | ||
| 451 | // print friendly message saying what file is being compiled | ||
| 452 | Console.WriteLine(file.SourcePath); | ||
| 453 | |||
| 454 | // preprocess the source | ||
| 455 | XDocument sourceDocument; | ||
| 456 | try | ||
| 457 | { | ||
| 458 | if (!String.IsNullOrEmpty(this.commandLine.PreprocessFile)) | ||
| 459 | { | ||
| 460 | preprocessor.PreprocessOut = this.commandLine.PreprocessFile.Equals("con:", StringComparison.OrdinalIgnoreCase) ? Console.Out : new StreamWriter(this.commandLine.PreprocessFile); | ||
| 461 | } | ||
| 462 | |||
| 463 | sourceDocument = preprocessor.Process(file.SourcePath, this.commandLine.PreprocessorVariables); | ||
| 464 | } | ||
| 465 | finally | ||
| 466 | { | ||
| 467 | if (null != preprocessor.PreprocessOut && Console.Out != preprocessor.PreprocessOut) | ||
| 468 | { | ||
| 469 | preprocessor.PreprocessOut.Close(); | ||
| 470 | } | ||
| 471 | } | ||
| 472 | |||
| 473 | // If we're not actually going to compile anything, move on to the next file. | ||
| 474 | if (null == sourceDocument || !String.IsNullOrEmpty(this.commandLine.PreprocessFile)) | ||
| 475 | { | ||
| 476 | continue; | ||
| 477 | } | ||
| 478 | |||
| 479 | // and now we do what we came here to do... | ||
| 480 | Intermediate intermediate = compiler.Compile(sourceDocument); | ||
| 481 | |||
| 482 | // save the intermediate to disk if no errors were found for this source file | ||
| 483 | if (null != intermediate) | ||
| 484 | { | ||
| 485 | intermediate.Save(file.OutputPath); | ||
| 486 | } | ||
| 487 | } | ||
| 488 | } | ||
| 489 | |||
| 490 | public interface IOptions | ||
| 491 | { | ||
| 492 | IEnumerable<SourceFile> SourceFiles { get; } | ||
| 493 | } | ||
| 494 | |||
| 495 | public class CompilerOptions : IOptions | ||
| 496 | { | ||
| 497 | public CompilerOptions(IEnumerable<SourceFile> sources) | ||
| 498 | { | ||
| 499 | this.SourceFiles = sources; | ||
| 500 | } | ||
| 501 | |||
| 502 | public IEnumerable<SourceFile> SourceFiles { get; private set; } | ||
| 503 | } | 42 | } |
| 504 | #endif | ||
| 505 | } | 43 | } |
| 506 | } | 44 | } |
diff --git a/src/wix/X_CommandLine.cs b/src/wix/X_CommandLine.cs deleted file mode 100644 index 2c7ceb83..00000000 --- a/src/wix/X_CommandLine.cs +++ /dev/null | |||
| @@ -1,394 +0,0 @@ | |||
| 1 | // Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. | ||
| 2 | |||
| 3 | namespace WixToolset.Core | ||
| 4 | { | ||
| 5 | using System; | ||
| 6 | using System.Collections.Generic; | ||
| 7 | using System.IO; | ||
| 8 | using System.Linq; | ||
| 9 | using System.Text; | ||
| 10 | using System.Text.RegularExpressions; | ||
| 11 | using WixToolset.Extensibility; | ||
| 12 | |||
| 13 | internal class X_CommandLine | ||
| 14 | { | ||
| 15 | private X_CommandLine() | ||
| 16 | { | ||
| 17 | } | ||
| 18 | |||
| 19 | public static string ExpectedArgument { get; } = "expected argument"; | ||
| 20 | |||
| 21 | public string ActiveCommand { get; private set; } | ||
| 22 | |||
| 23 | public string[] OriginalArguments { get; private set; } | ||
| 24 | |||
| 25 | public Queue<string> RemainingArguments { get; } = new Queue<string>(); | ||
| 26 | |||
| 27 | public ExtensionManager ExtensionManager { get; } = new ExtensionManager(); | ||
| 28 | |||
| 29 | public string ErrorArgument { get; set; } | ||
| 30 | |||
| 31 | public bool ShowHelp { get; set; } | ||
| 32 | |||
| 33 | public static X_CommandLine Parse(string commandLineString, Func<X_CommandLine, string, bool> parseArgument) | ||
| 34 | { | ||
| 35 | var arguments = X_CommandLine.ParseArgumentsToArray(commandLineString).ToArray(); | ||
| 36 | |||
| 37 | return X_CommandLine.Parse(arguments, null, parseArgument); | ||
| 38 | } | ||
| 39 | |||
| 40 | public static X_CommandLine Parse(string[] commandLineArguments, Func<X_CommandLine, string, bool> parseArgument) | ||
| 41 | { | ||
| 42 | return X_CommandLine.Parse(commandLineArguments, null, parseArgument); | ||
| 43 | } | ||
| 44 | |||
| 45 | public static X_CommandLine Parse(string[] commandLineArguments, Func<X_CommandLine, string, bool> parseCommand, Func<X_CommandLine, string, bool> parseArgument) | ||
| 46 | { | ||
| 47 | var cmdline = new X_CommandLine(); | ||
| 48 | |||
| 49 | cmdline.FlattenArgumentsWithResponseFilesIntoOriginalArguments(commandLineArguments); | ||
| 50 | |||
| 51 | cmdline.QueueArgumentsAndLoadExtensions(cmdline.OriginalArguments); | ||
| 52 | |||
| 53 | cmdline.ProcessRemainingArguments(parseArgument, parseCommand); | ||
| 54 | |||
| 55 | return cmdline; | ||
| 56 | } | ||
| 57 | |||
| 58 | /// <summary> | ||
| 59 | /// Get a set of files that possibly have a search pattern in the path (such as '*'). | ||
| 60 | /// </summary> | ||
| 61 | /// <param name="searchPath">Search path to find files in.</param> | ||
| 62 | /// <param name="fileType">Type of file; typically "Source".</param> | ||
| 63 | /// <returns>An array of files matching the search path.</returns> | ||
| 64 | /// <remarks> | ||
| 65 | /// This method is written in this verbose way because it needs to support ".." in the path. | ||
| 66 | /// It needs the directory path isolated from the file name in order to use Directory.GetFiles | ||
| 67 | /// or DirectoryInfo.GetFiles. The only way to get this directory path is manually since | ||
| 68 | /// Path.GetDirectoryName does not support ".." in the path. | ||
| 69 | /// </remarks> | ||
| 70 | /// <exception cref="WixFileNotFoundException">Throws WixFileNotFoundException if no file matching the pattern can be found.</exception> | ||
| 71 | public string[] GetFiles(string searchPath, string fileType) | ||
| 72 | { | ||
| 73 | if (null == searchPath) | ||
| 74 | { | ||
| 75 | throw new ArgumentNullException(nameof(searchPath)); | ||
| 76 | } | ||
| 77 | |||
| 78 | // Convert alternate directory separators to the standard one. | ||
| 79 | string filePath = searchPath.Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar); | ||
| 80 | int lastSeparator = filePath.LastIndexOf(Path.DirectorySeparatorChar); | ||
| 81 | string[] files = null; | ||
| 82 | |||
| 83 | try | ||
| 84 | { | ||
| 85 | if (0 > lastSeparator) | ||
| 86 | { | ||
| 87 | files = Directory.GetFiles(".", filePath); | ||
| 88 | } | ||
| 89 | else // found directory separator | ||
| 90 | { | ||
| 91 | files = Directory.GetFiles(filePath.Substring(0, lastSeparator + 1), filePath.Substring(lastSeparator + 1)); | ||
| 92 | } | ||
| 93 | } | ||
| 94 | catch (DirectoryNotFoundException) | ||
| 95 | { | ||
| 96 | // Don't let this function throw the DirectoryNotFoundException. This exception | ||
| 97 | // occurs for non-existant directories and invalid characters in the searchPattern. | ||
| 98 | } | ||
| 99 | catch (ArgumentException) | ||
| 100 | { | ||
| 101 | // Don't let this function throw the ArgumentException. This exception | ||
| 102 | // occurs in certain situations such as when passing a malformed UNC path. | ||
| 103 | } | ||
| 104 | catch (IOException) | ||
| 105 | { | ||
| 106 | throw new WixFileNotFoundException(searchPath, fileType); | ||
| 107 | } | ||
| 108 | |||
| 109 | if (null == files || 0 == files.Length) | ||
| 110 | { | ||
| 111 | throw new WixFileNotFoundException(searchPath, fileType); | ||
| 112 | } | ||
| 113 | |||
| 114 | return files; | ||
| 115 | } | ||
| 116 | |||
| 117 | /// <summary> | ||
| 118 | /// Validates that a valid switch (starts with "/" or "-"), and returns a bool indicating its validity | ||
| 119 | /// </summary> | ||
| 120 | /// <param name="args">The list of strings to check.</param> | ||
| 121 | /// <param name="index">The index (in args) of the commandline parameter to be validated.</param> | ||
| 122 | /// <returns>True if a valid switch exists there, false if not.</returns> | ||
| 123 | public bool IsSwitch(string arg) | ||
| 124 | { | ||
| 125 | return arg != null && ('/' == arg[0] || '-' == arg[0]); | ||
| 126 | } | ||
| 127 | |||
| 128 | /// <summary> | ||
| 129 | /// Validates that a valid switch (starts with "/" or "-"), and returns a bool indicating its validity | ||
| 130 | /// </summary> | ||
| 131 | /// <param name="args">The list of strings to check.</param> | ||
| 132 | /// <param name="index">The index (in args) of the commandline parameter to be validated.</param> | ||
| 133 | /// <returns>True if a valid switch exists there, false if not.</returns> | ||
| 134 | public bool IsSwitchAt(IEnumerable<string> args, int index) | ||
| 135 | { | ||
| 136 | var arg = args.ElementAtOrDefault(index); | ||
| 137 | return IsSwitch(arg); | ||
| 138 | } | ||
| 139 | |||
| 140 | public void GetNextArgumentOrError(ref string arg) | ||
| 141 | { | ||
| 142 | this.TryGetNextArgumentOrError(out arg); | ||
| 143 | } | ||
| 144 | |||
| 145 | public void GetNextArgumentOrError(IList<string> args) | ||
| 146 | { | ||
| 147 | if (this.TryGetNextArgumentOrError(out var arg)) | ||
| 148 | { | ||
| 149 | args.Add(arg); | ||
| 150 | } | ||
| 151 | } | ||
| 152 | |||
| 153 | public void GetNextArgumentAsFilePathOrError(IList<string> args, string fileType) | ||
| 154 | { | ||
| 155 | if (this.TryGetNextArgumentOrError(out var arg)) | ||
| 156 | { | ||
| 157 | foreach (var path in this.GetFiles(arg, fileType)) | ||
| 158 | { | ||
| 159 | args.Add(path); | ||
| 160 | } | ||
| 161 | } | ||
| 162 | } | ||
| 163 | |||
| 164 | public bool TryGetNextArgumentOrError(out string arg) | ||
| 165 | { | ||
| 166 | if (this.RemainingArguments.TryDequeue(out arg) && !this.IsSwitch(arg)) | ||
| 167 | { | ||
| 168 | return true; | ||
| 169 | } | ||
| 170 | |||
| 171 | this.ErrorArgument = arg ?? X_CommandLine.ExpectedArgument; | ||
| 172 | |||
| 173 | return false; | ||
| 174 | } | ||
| 175 | |||
| 176 | private void FlattenArgumentsWithResponseFilesIntoOriginalArguments(string[] commandLineArguments) | ||
| 177 | { | ||
| 178 | List<string> args = new List<string>(); | ||
| 179 | |||
| 180 | foreach (var arg in commandLineArguments) | ||
| 181 | { | ||
| 182 | if ('@' == arg[0]) | ||
| 183 | { | ||
| 184 | var responseFileArguments = X_CommandLine.ParseResponseFile(arg.Substring(1)); | ||
| 185 | args.AddRange(responseFileArguments); | ||
| 186 | } | ||
| 187 | else | ||
| 188 | { | ||
| 189 | args.Add(arg); | ||
| 190 | } | ||
| 191 | } | ||
| 192 | |||
| 193 | this.OriginalArguments = args.ToArray(); | ||
| 194 | } | ||
| 195 | |||
| 196 | private void QueueArgumentsAndLoadExtensions(string[] args) | ||
| 197 | { | ||
| 198 | for (var i = 0; i < args.Length; ++i) | ||
| 199 | { | ||
| 200 | var arg = args[i]; | ||
| 201 | |||
| 202 | if ("-ext" == arg || "/ext" == arg) | ||
| 203 | { | ||
| 204 | if (!this.IsSwitchAt(args, ++i)) | ||
| 205 | { | ||
| 206 | this.ExtensionManager.Load(args[i]); | ||
| 207 | } | ||
| 208 | else | ||
| 209 | { | ||
| 210 | this.ErrorArgument = arg; | ||
| 211 | break; | ||
| 212 | } | ||
| 213 | } | ||
| 214 | else | ||
| 215 | { | ||
| 216 | this.RemainingArguments.Enqueue(arg); | ||
| 217 | } | ||
| 218 | } | ||
| 219 | } | ||
| 220 | |||
| 221 | private void ProcessRemainingArguments(Func<X_CommandLine, string, bool> parseArgument, Func<X_CommandLine, string, bool> parseCommand) | ||
| 222 | { | ||
| 223 | var extensions = this.ExtensionManager.Create<IExtensionCommandLine>(); | ||
| 224 | |||
| 225 | while (!this.ShowHelp && | ||
| 226 | String.IsNullOrEmpty(this.ErrorArgument) && | ||
| 227 | this.RemainingArguments.TryDequeue(out var arg)) | ||
| 228 | { | ||
| 229 | if (String.IsNullOrWhiteSpace(arg)) // skip blank arguments. | ||
| 230 | { | ||
| 231 | continue; | ||
| 232 | } | ||
| 233 | |||
| 234 | if ('-' == arg[0] || '/' == arg[0]) | ||
| 235 | { | ||
| 236 | if (!parseArgument(this, arg) && | ||
| 237 | !this.TryParseCommandLineArgumentWithExtension(arg, extensions)) | ||
| 238 | { | ||
| 239 | this.ErrorArgument = arg; | ||
| 240 | } | ||
| 241 | } | ||
| 242 | else if (String.IsNullOrEmpty(this.ActiveCommand) && parseCommand != null) // First non-switch must be the command, if commands are supported. | ||
| 243 | { | ||
| 244 | if (parseCommand(this, arg)) | ||
| 245 | { | ||
| 246 | this.ActiveCommand = arg; | ||
| 247 | } | ||
| 248 | else | ||
| 249 | { | ||
| 250 | this.ErrorArgument = arg; | ||
| 251 | } | ||
| 252 | } | ||
| 253 | else if (!this.TryParseCommandLineArgumentWithExtension(arg, extensions) && | ||
| 254 | !parseArgument(this, arg)) | ||
| 255 | { | ||
| 256 | this.ErrorArgument = arg; | ||
| 257 | } | ||
| 258 | } | ||
| 259 | } | ||
| 260 | |||
| 261 | private bool TryParseCommandLineArgumentWithExtension(string arg, IEnumerable<IExtensionCommandLine> extensions) | ||
| 262 | { | ||
| 263 | foreach (var extension in extensions) | ||
| 264 | { | ||
| 265 | //if (extension.ParseArgument(this, arg)) | ||
| 266 | //{ | ||
| 267 | // return true; | ||
| 268 | //} | ||
| 269 | } | ||
| 270 | |||
| 271 | return false; | ||
| 272 | } | ||
| 273 | |||
| 274 | /// <summary> | ||
| 275 | /// Parses a response file. | ||
| 276 | /// </summary> | ||
| 277 | /// <param name="responseFile">The file to parse.</param> | ||
| 278 | /// <returns>The array of arguments.</returns> | ||
| 279 | private static List<string> ParseResponseFile(string responseFile) | ||
| 280 | { | ||
| 281 | string arguments; | ||
| 282 | |||
| 283 | using (StreamReader reader = new StreamReader(responseFile)) | ||
| 284 | { | ||
| 285 | arguments = reader.ReadToEnd(); | ||
| 286 | } | ||
| 287 | |||
| 288 | return X_CommandLine.ParseArgumentsToArray(arguments); | ||
| 289 | } | ||
| 290 | |||
| 291 | /// <summary> | ||
| 292 | /// Parses an argument string into an argument array based on whitespace and quoting. | ||
| 293 | /// </summary> | ||
| 294 | /// <param name="arguments">Argument string.</param> | ||
| 295 | /// <returns>Argument array.</returns> | ||
| 296 | private static List<string> ParseArgumentsToArray(string arguments) | ||
| 297 | { | ||
| 298 | // Scan and parse the arguments string, dividing up the arguments based on whitespace. | ||
| 299 | // Unescaped quotes cause whitespace to be ignored, while the quotes themselves are removed. | ||
| 300 | // Quotes may begin and end inside arguments; they don't necessarily just surround whole arguments. | ||
| 301 | // Escaped quotes and escaped backslashes also need to be unescaped by this process. | ||
| 302 | |||
| 303 | // Collects the final list of arguments to be returned. | ||
| 304 | var argsList = new List<string>(); | ||
| 305 | |||
| 306 | // True if we are inside an unescaped quote, meaning whitespace should be ignored. | ||
| 307 | var insideQuote = false; | ||
| 308 | |||
| 309 | // Index of the start of the current argument substring; either the start of the argument | ||
| 310 | // or the start of a quoted or unquoted sequence within it. | ||
| 311 | var partStart = 0; | ||
| 312 | |||
| 313 | // The current argument string being built; when completed it will be added to the list. | ||
| 314 | var arg = new StringBuilder(); | ||
| 315 | |||
| 316 | for (int i = 0; i <= arguments.Length; i++) | ||
| 317 | { | ||
| 318 | if (i == arguments.Length || (Char.IsWhiteSpace(arguments[i]) && !insideQuote)) | ||
| 319 | { | ||
| 320 | // Reached a whitespace separator or the end of the string. | ||
| 321 | |||
| 322 | // Finish building the current argument. | ||
| 323 | arg.Append(arguments.Substring(partStart, i - partStart)); | ||
| 324 | |||
| 325 | // Skip over the whitespace character. | ||
| 326 | partStart = i + 1; | ||
| 327 | |||
| 328 | // Add the argument to the list if it's not empty. | ||
| 329 | if (arg.Length > 0) | ||
| 330 | { | ||
| 331 | argsList.Add(X_CommandLine.ExpandEnvVars(arg.ToString())); | ||
| 332 | arg.Length = 0; | ||
| 333 | } | ||
| 334 | } | ||
| 335 | else if (i > partStart && arguments[i - 1] == '\\') | ||
| 336 | { | ||
| 337 | // Check the character following an unprocessed backslash. | ||
| 338 | // Unescape quotes, and backslashes followed by a quote. | ||
| 339 | if (arguments[i] == '"' || (arguments[i] == '\\' && arguments.Length > i + 1 && arguments[i + 1] == '"')) | ||
| 340 | { | ||
| 341 | // Unescape the quote or backslash by skipping the preceeding backslash. | ||
| 342 | arg.Append(arguments.Substring(partStart, i - 1 - partStart)); | ||
| 343 | arg.Append(arguments[i]); | ||
| 344 | partStart = i + 1; | ||
| 345 | } | ||
| 346 | } | ||
| 347 | else if (arguments[i] == '"') | ||
| 348 | { | ||
| 349 | // Add the quoted or unquoted section to the argument string. | ||
| 350 | arg.Append(arguments.Substring(partStart, i - partStart)); | ||
| 351 | |||
| 352 | // And skip over the quote character. | ||
| 353 | partStart = i + 1; | ||
| 354 | |||
| 355 | insideQuote = !insideQuote; | ||
| 356 | } | ||
| 357 | } | ||
| 358 | |||
| 359 | return argsList; | ||
| 360 | } | ||
| 361 | |||
| 362 | /// <summary> | ||
| 363 | /// Expand enxironment variables contained in the passed string | ||
| 364 | /// </summary> | ||
| 365 | /// <param name="arguments"></param> | ||
| 366 | /// <returns></returns> | ||
| 367 | private static string ExpandEnvVars(string arguments) | ||
| 368 | { | ||
| 369 | var id = Environment.GetEnvironmentVariables(); | ||
| 370 | |||
| 371 | var regex = new Regex("(?<=\\%)(?:[\\w\\.]+)(?=\\%)"); | ||
| 372 | MatchCollection matches = regex.Matches(arguments); | ||
| 373 | |||
| 374 | string value = String.Empty; | ||
| 375 | for (int i = 0; i <= (matches.Count - 1); i++) | ||
| 376 | { | ||
| 377 | try | ||
| 378 | { | ||
| 379 | var key = matches[i].Value; | ||
| 380 | regex = new Regex(String.Concat("(?i)(?:\\%)(?:", key, ")(?:\\%)")); | ||
| 381 | value = id[key].ToString(); | ||
| 382 | arguments = regex.Replace(arguments, value); | ||
| 383 | } | ||
| 384 | catch (NullReferenceException) | ||
| 385 | { | ||
| 386 | // Collapse unresolved environment variables. | ||
| 387 | arguments = regex.Replace(arguments, value); | ||
| 388 | } | ||
| 389 | } | ||
| 390 | |||
| 391 | return arguments; | ||
| 392 | } | ||
| 393 | } | ||
| 394 | } | ||
