aboutsummaryrefslogtreecommitdiff
path: root/src/WixToolset.Core/CommandLine/ParseCommandLine.cs
diff options
context:
space:
mode:
Diffstat (limited to 'src/WixToolset.Core/CommandLine/ParseCommandLine.cs')
-rw-r--r--src/WixToolset.Core/CommandLine/ParseCommandLine.cs263
1 files changed, 0 insertions, 263 deletions
diff --git a/src/WixToolset.Core/CommandLine/ParseCommandLine.cs b/src/WixToolset.Core/CommandLine/ParseCommandLine.cs
deleted file mode 100644
index 3cf6e032..00000000
--- a/src/WixToolset.Core/CommandLine/ParseCommandLine.cs
+++ /dev/null
@@ -1,263 +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
3namespace WixToolset.Core.CommandLine
4{
5 using System;
6 using System.Collections.Generic;
7 using System.IO;
8 using WixToolset.Data;
9 using WixToolset.Extensibility.Services;
10
11 internal class ParseCommandLine : IParseCommandLine
12 {
13 private const string ExpectedArgument = "expected argument";
14
15 public string ErrorArgument { get; set; }
16
17 private Queue<string> RemainingArguments { get; }
18
19 private IMessaging Messaging { get; }
20
21 public ParseCommandLine(IMessaging messaging, string[] arguments, string errorArgument)
22 {
23 this.Messaging = messaging;
24 this.RemainingArguments = new Queue<string>(arguments);
25 this.ErrorArgument = errorArgument;
26 }
27
28 public bool IsSwitch(string arg)
29 {
30 return !String.IsNullOrEmpty(arg) && ('/' == arg[0] || '-' == arg[0]);
31 }
32
33 public void GetArgumentAsFilePathOrError(string argument, string fileType, IList<string> paths)
34 {
35 foreach (var path in this.GetFiles(argument, fileType))
36 {
37 paths.Add(path);
38 }
39 }
40
41 public string GetNextArgumentOrError(string commandLineSwitch)
42 {
43 if (this.TryGetNextNonSwitchArgumentOrError(out var argument))
44 {
45 return argument;
46 }
47
48 this.Messaging.Write(ErrorMessages.ExpectedArgument(commandLineSwitch));
49 return null;
50 }
51
52 public bool GetNextArgumentOrError(string commandLineSwitch, IList<string> args)
53 {
54 if (this.TryGetNextNonSwitchArgumentOrError(out var arg))
55 {
56 args.Add(arg);
57 return true;
58 }
59
60 this.Messaging.Write(ErrorMessages.ExpectedArgument(commandLineSwitch));
61 return false;
62 }
63
64 public string GetNextArgumentAsDirectoryOrError(string commandLineSwitch)
65 {
66 if (this.TryGetNextNonSwitchArgumentOrError(out var arg) && this.TryGetDirectory(commandLineSwitch, this.Messaging, arg, out var directory))
67 {
68 return directory;
69 }
70
71 this.Messaging.Write(ErrorMessages.ExpectedArgument(commandLineSwitch));
72 return null;
73 }
74
75 public bool GetNextArgumentAsDirectoryOrError(string commandLineSwitch, IList<string> directories)
76 {
77 if (this.TryGetNextNonSwitchArgumentOrError(out var arg) && this.TryGetDirectory(commandLineSwitch, this.Messaging, arg, out var directory))
78 {
79 directories.Add(directory);
80 return true;
81 }
82
83 this.Messaging.Write(ErrorMessages.ExpectedArgument(commandLineSwitch));
84 return false;
85 }
86
87 public string GetNextArgumentAsFilePathOrError(string commandLineSwitch)
88 {
89 if (this.TryGetNextNonSwitchArgumentOrError(out var arg) && this.TryGetFile(commandLineSwitch, arg, out var path))
90 {
91 return path;
92 }
93
94 this.Messaging.Write(ErrorMessages.ExpectedArgument(commandLineSwitch));
95 return null;
96 }
97
98 public bool GetNextArgumentAsFilePathOrError(string commandLineSwitch, string fileType, IList<string> paths)
99 {
100 if (this.TryGetNextNonSwitchArgumentOrError(out var arg))
101 {
102 foreach (var path in this.GetFiles(arg, fileType))
103 {
104 paths.Add(path);
105 }
106
107 return true;
108 }
109
110 this.Messaging.Write(ErrorMessages.ExpectedArgument(commandLineSwitch));
111 return false;
112 }
113
114 public bool TryGetNextSwitchOrArgument(out string arg)
115 {
116 return TryDequeue(this.RemainingArguments, out arg);
117 }
118
119 private bool TryGetNextNonSwitchArgumentOrError(out string arg)
120 {
121 var result = this.TryGetNextSwitchOrArgument(out arg);
122
123 if (!result && !this.IsSwitch(arg))
124 {
125 this.ErrorArgument = arg ?? ParseCommandLine.ExpectedArgument;
126 }
127
128 return result;
129 }
130
131 private static bool IsValidArg(string arg)
132 {
133 return !(String.IsNullOrEmpty(arg) || '/' == arg[0] || '-' == arg[0]);
134 }
135
136 private static bool TryDequeue(Queue<string> q, out string arg)
137 {
138 if (q.Count > 0)
139 {
140 arg = q.Dequeue();
141 return true;
142 }
143
144 arg = null;
145 return false;
146 }
147
148 private bool TryGetDirectory(string commandlineSwitch, IMessaging messageHandler, string arg, out string directory)
149 {
150 directory = null;
151
152 if (File.Exists(arg))
153 {
154 this.Messaging.Write(ErrorMessages.ExpectedDirectoryGotFile(commandlineSwitch, arg));
155 return false;
156 }
157
158 directory = this.VerifyPath(arg);
159 return directory != null;
160 }
161
162 private bool TryGetFile(string commandlineSwitch, string arg, out string path)
163 {
164 path = null;
165
166 if (!IsValidArg(arg))
167 {
168 this.Messaging.Write(ErrorMessages.FilePathRequired(commandlineSwitch));
169 }
170 else if (Directory.Exists(arg))
171 {
172 this.Messaging.Write(ErrorMessages.ExpectedFileGotDirectory(commandlineSwitch, arg));
173 }
174 else
175 {
176 path = this.VerifyPath(arg);
177 }
178
179 return path != null;
180 }
181
182 /// <summary>
183 /// Get a set of files that possibly have a search pattern in the path (such as '*').
184 /// </summary>
185 /// <param name="searchPath">Search path to find files in.</param>
186 /// <param name="fileType">Type of file; typically "Source".</param>
187 /// <returns>An array of files matching the search path.</returns>
188 /// <remarks>
189 /// This method is written in this verbose way because it needs to support ".." in the path.
190 /// It needs the directory path isolated from the file name in order to use Directory.GetFiles
191 /// or DirectoryInfo.GetFiles. The only way to get this directory path is manually since
192 /// Path.GetDirectoryName does not support ".." in the path.
193 /// </remarks>
194 /// <exception cref="WixFileNotFoundException">Throws WixFileNotFoundException if no file matching the pattern can be found.</exception>
195 private string[] GetFiles(string searchPath, string fileType)
196 {
197 if (null == searchPath)
198 {
199 throw new ArgumentNullException(nameof(searchPath));
200 }
201
202 // Convert alternate directory separators to the standard one.
203 var filePath = searchPath.Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar);
204 var lastSeparator = filePath.LastIndexOf(Path.DirectorySeparatorChar);
205 var files = new string[0];
206
207 try
208 {
209 if (0 > lastSeparator)
210 {
211 files = Directory.GetFiles(".", filePath);
212 }
213 else // found directory separator
214 {
215 files = Directory.GetFiles(filePath.Substring(0, lastSeparator + 1), filePath.Substring(lastSeparator + 1));
216 }
217 }
218 catch (DirectoryNotFoundException)
219 {
220 // Don't let this function throw the DirectoryNotFoundException. This exception
221 // occurs for non-existant directories and invalid characters in the searchPattern.
222 }
223 catch (ArgumentException)
224 {
225 // Don't let this function throw the ArgumentException. This exception
226 // occurs in certain situations such as when passing a malformed UNC path.
227 }
228 catch (IOException)
229 {
230 }
231
232 if (0 == files.Length)
233 {
234 this.Messaging.Write(ErrorMessages.FileNotFound(null, searchPath, fileType));
235 }
236
237 return files;
238 }
239
240 private string VerifyPath(string path)
241 {
242 string fullPath;
243
244 if (0 <= path.IndexOf('\"'))
245 {
246 this.Messaging.Write(ErrorMessages.PathCannotContainQuote(path));
247 return null;
248 }
249
250 try
251 {
252 fullPath = Path.GetFullPath(path);
253 }
254 catch (Exception e)
255 {
256 this.Messaging.Write(ErrorMessages.InvalidCommandLineFileName(path, e.Message));
257 return null;
258 }
259
260 return fullPath;
261 }
262 }
263}