aboutsummaryrefslogtreecommitdiff
path: root/src/light/LightCommandLine.cs
diff options
context:
space:
mode:
Diffstat (limited to 'src/light/LightCommandLine.cs')
-rw-r--r--src/light/LightCommandLine.cs485
1 files changed, 485 insertions, 0 deletions
diff --git a/src/light/LightCommandLine.cs b/src/light/LightCommandLine.cs
new file mode 100644
index 00000000..9a90b9ce
--- /dev/null
+++ b/src/light/LightCommandLine.cs
@@ -0,0 +1,485 @@
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.Tools
4{
5 using System;
6 using System.Collections.Generic;
7 using System.Globalization;
8 using System.IO;
9 using WixToolset.Core.CommandLine;
10 using WixToolset.Data;
11 using WixToolset.Extensibility.Services;
12
13 public class LightCommandLine
14 {
15 public LightCommandLine(IMessaging messaging)
16 {
17 this.Messaging = messaging;
18 this.ShowLogo = true;
19 this.Tidy = true;
20
21 this.CubeFiles = new List<string>();
22 this.SuppressIces = new List<string>();
23 this.Ices = new List<string>();
24 this.BindPaths = new List<BindPath>();
25 this.Extensions = new List<string>();
26 this.Files = new List<string>();
27 this.LocalizationFiles = new List<string>();
28 this.Variables = new Dictionary<string, string>();
29 }
30
31 public IMessaging Messaging { get; }
32
33 public string PdbFile { get; private set; }
34
35 public CompressionLevel? DefaultCompressionLevel { get; set; }
36
37 public bool SuppressAclReset { get; private set; }
38
39 public bool SuppressLayout { get; private set; }
40
41 public bool SuppressWixPdb { get; private set; }
42
43 public bool SuppressValidation { get; private set; }
44
45 public string IntermediateFolder { get; private set; }
46
47 public string OutputsFile { get; private set; }
48
49 public string BuiltOutputsFile { get; private set; }
50
51 public string WixprojectFile { get; private set; }
52
53 public string ContentsFile { get; private set; }
54
55 public List<string> Ices { get; private set; }
56
57 public string CabCachePath { get; private set; }
58
59 public int CabbingThreadCount { get; private set; }
60
61 public List<string> CubeFiles { get; private set; }
62
63 public List<string> SuppressIces { get; private set; }
64
65 public bool ShowLogo { get; private set; }
66
67 public bool ShowHelp { get; private set; }
68
69 public bool ShowPedanticMessages { get; private set; }
70
71 public bool SuppressLocalization { get; private set; }
72
73 public bool SuppressVersionCheck { get; private set; }
74
75 public string[] Cultures { get; private set; }
76
77 public string OutputFile { get; private set; }
78
79 public bool OutputXml { get; private set; }
80
81 public List<BindPath> BindPaths { get; private set; }
82
83 public List<string> Extensions { get; private set; }
84
85 public List<string> Files { get; private set; }
86
87 public List<string> LocalizationFiles { get; private set; }
88
89 public bool Tidy { get; private set; }
90
91 public string UnreferencedSymbolsFile { get; private set; }
92
93 public IDictionary<string, string> Variables { get; private set; }
94
95 /// <summary>
96 /// Parse the commandline arguments.
97 /// </summary>
98 /// <param name="args">Commandline arguments.</param>
99 public string[] Parse(string[] args)
100 {
101 List<string> unprocessed = new List<string>();
102
103 for (int i = 0; i < args.Length; ++i)
104 {
105 string arg = args[i];
106 if (String.IsNullOrEmpty(arg)) // skip blank arguments
107 {
108 continue;
109 }
110
111 if (1 == arg.Length) // treat '-' and '@' as filenames when by themselves.
112 {
113 unprocessed.Add(arg);
114 }
115 else if ('-' == arg[0] || '/' == arg[0])
116 {
117 string parameter = arg.Substring(1);
118 if (parameter.Equals("b", StringComparison.Ordinal))
119 {
120 if (!CommandLineHelper.IsValidArg(args, ++i))
121 {
122 break;
123 }
124
125 var bindPath = BindPath.Parse(args[i]);
126
127 this.BindPaths.Add(bindPath);
128 }
129 else if (parameter.StartsWith("cultures:", StringComparison.Ordinal))
130 {
131 string culturesString = arg.Substring(10).ToLower(CultureInfo.InvariantCulture);
132
133 // When null is used treat it as if cultures wasn't specified.
134 // This is needed for batching over the light task when using MSBuild which doesn't
135 // support empty items
136 if (culturesString.Equals("null", StringComparison.OrdinalIgnoreCase))
137 {
138 this.Cultures = null;
139 }
140 else
141 {
142 this.Cultures = culturesString.Split(';', ',');
143
144 for (int c = 0; c < this.Cultures.Length; ++c)
145 {
146 // Neutral is different from null. For neutral we still want to do WXL filtering.
147 // Set the culture to the empty string = identifier for the invariant culture
148 if (this.Cultures[c].Equals("neutral", StringComparison.OrdinalIgnoreCase))
149 {
150 this.Cultures[c] = String.Empty;
151 }
152 }
153 }
154 }
155 else if (parameter.StartsWith("dcl:", StringComparison.Ordinal))
156 {
157 string defaultCompressionLevel = arg.Substring(5);
158
159 if (String.IsNullOrEmpty(defaultCompressionLevel))
160 {
161 break;
162 }
163 else if (Enum.TryParse(defaultCompressionLevel, true, out CompressionLevel compressionLevel))
164 {
165 this.DefaultCompressionLevel = compressionLevel;
166 }
167 }
168 else if (parameter.StartsWith("d", StringComparison.Ordinal))
169 {
170 parameter = arg.Substring(2);
171 string[] value = parameter.Split("=".ToCharArray(), 2);
172
173 string preexisting;
174 if (1 == value.Length)
175 {
176 this.Messaging.Write(ErrorMessages.ExpectedWixVariableValue(value[0]));
177 }
178 else if (this.Variables.TryGetValue(value[0], out preexisting))
179 {
180 this.Messaging.Write(ErrorMessages.WixVariableCollision(null, value[0]));
181 }
182 else
183 {
184 this.Variables.Add(value[0], value[1]);
185 }
186 }
187 else if (parameter.Equals("ext", StringComparison.Ordinal))
188 {
189 if (!CommandLineHelper.IsValidArg(args, ++i))
190 {
191 this.Messaging.Write(ErrorMessages.TypeSpecificationForExtensionRequired("-ext"));
192 break;
193 }
194
195 this.Extensions.Add(args[i]);
196 }
197 else if (parameter.Equals("loc", StringComparison.Ordinal))
198 {
199 string locFile = CommandLineHelper.GetFile(parameter, this.Messaging, args, ++i);
200 if (String.IsNullOrEmpty(locFile))
201 {
202 break;
203 }
204
205 this.LocalizationFiles.Add(locFile);
206 }
207 else if (parameter.Equals("nologo", StringComparison.Ordinal))
208 {
209 this.ShowLogo = false;
210 }
211 else if (parameter.Equals("notidy", StringComparison.Ordinal))
212 {
213 this.Tidy = false;
214 }
215 else if ("o" == parameter || "out" == parameter)
216 {
217 this.OutputFile = CommandLineHelper.GetFile(parameter, this.Messaging, args, ++i);
218 if (String.IsNullOrEmpty(this.OutputFile))
219 {
220 break;
221 }
222 }
223 else if (parameter.Equals("pedantic", StringComparison.Ordinal))
224 {
225 this.ShowPedanticMessages = true;
226 }
227 else if (parameter.Equals("sloc", StringComparison.Ordinal))
228 {
229 this.SuppressLocalization = true;
230 }
231 else if (parameter.Equals("usf", StringComparison.Ordinal))
232 {
233 this.UnreferencedSymbolsFile = CommandLineHelper.GetFile(parameter, this.Messaging, args, ++i);
234
235 if (String.IsNullOrEmpty(this.UnreferencedSymbolsFile))
236 {
237 break;
238 }
239 }
240 else if (parameter.Equals("xo", StringComparison.Ordinal))
241 {
242 this.OutputXml = true;
243 }
244 else if (parameter.Equals("cc", StringComparison.Ordinal))
245 {
246 this.CabCachePath = CommandLineHelper.GetDirectory(parameter, this.Messaging, args, ++i);
247
248 if (String.IsNullOrEmpty(this.CabCachePath))
249 {
250 break;
251 }
252 }
253 else if (parameter.Equals("ct", StringComparison.Ordinal))
254 {
255 if (!CommandLineHelper.IsValidArg(args, ++i))
256 {
257 this.Messaging.Write(ErrorMessages.IllegalCabbingThreadCount(String.Empty));
258 break;
259 }
260
261 int ct = 0;
262 if (!Int32.TryParse(args[i], out ct) || 0 >= ct)
263 {
264 this.Messaging.Write(ErrorMessages.IllegalCabbingThreadCount(args[i]));
265 break;
266 }
267
268 this.CabbingThreadCount = ct;
269 this.Messaging.Write(VerboseMessages.SetCabbingThreadCount(this.CabbingThreadCount.ToString()));
270 }
271 else if (parameter.Equals("cub", StringComparison.Ordinal))
272 {
273 string cubeFile = CommandLineHelper.GetFile(parameter, this.Messaging, args, ++i);
274
275 if (String.IsNullOrEmpty(cubeFile))
276 {
277 break;
278 }
279
280 this.CubeFiles.Add(cubeFile);
281 }
282 else if (parameter.StartsWith("ice:", StringComparison.Ordinal))
283 {
284 this.Ices.Add(parameter.Substring(4));
285 }
286 else if (parameter.Equals("intermediatefolder", StringComparison.OrdinalIgnoreCase))
287 {
288 this.IntermediateFolder = CommandLineHelper.GetDirectory(parameter, this.Messaging, args, ++i);
289
290 if (String.IsNullOrEmpty(this.IntermediateFolder))
291 {
292 break;
293 }
294 }
295 else if (parameter.Equals("contentsfile", StringComparison.Ordinal))
296 {
297 this.ContentsFile = CommandLineHelper.GetFile(parameter, this.Messaging, args, ++i);
298
299 if (String.IsNullOrEmpty(this.ContentsFile))
300 {
301 break;
302 }
303 }
304 else if (parameter.Equals("outputsfile", StringComparison.Ordinal))
305 {
306 this.OutputsFile = CommandLineHelper.GetFile(parameter, this.Messaging, args, ++i);
307
308 if (String.IsNullOrEmpty(this.OutputsFile))
309 {
310 break;
311 }
312 }
313 else if (parameter.Equals("builtoutputsfile", StringComparison.Ordinal))
314 {
315 this.BuiltOutputsFile = CommandLineHelper.GetFile(parameter, this.Messaging, args, ++i);
316
317 if (String.IsNullOrEmpty(this.BuiltOutputsFile))
318 {
319 break;
320 }
321 }
322 else if (parameter.Equals("wixprojectfile", StringComparison.Ordinal))
323 {
324 this.WixprojectFile = CommandLineHelper.GetFile(parameter, this.Messaging, args, ++i);
325
326 if (String.IsNullOrEmpty(this.WixprojectFile))
327 {
328 break;
329 }
330 }
331 else if (parameter.Equals("pdbout", StringComparison.Ordinal))
332 {
333 this.PdbFile = CommandLineHelper.GetFile(parameter, this.Messaging, args, ++i);
334
335 if (String.IsNullOrEmpty(this.PdbFile))
336 {
337 break;
338 }
339 }
340 else if (parameter.StartsWith("sice:", StringComparison.Ordinal))
341 {
342 this.SuppressIces.Add(parameter.Substring(5));
343 }
344 else if (parameter.Equals("sl", StringComparison.Ordinal))
345 {
346 this.SuppressLayout = true;
347 }
348 else if (parameter.Equals("spdb", StringComparison.Ordinal))
349 {
350 this.SuppressWixPdb = true;
351 }
352 else if (parameter.Equals("sacl", StringComparison.Ordinal))
353 {
354 this.SuppressAclReset = true;
355 }
356 else if (parameter.Equals("sval", StringComparison.Ordinal))
357 {
358 this.SuppressValidation = true;
359 }
360 else if ("sv" == parameter)
361 {
362 this.SuppressVersionCheck = true;
363 }
364 else if (parameter.StartsWith("sw", StringComparison.Ordinal))
365 {
366 string paramArg = parameter.Substring(2);
367 if (0 == paramArg.Length)
368 {
369 this.Messaging.SuppressAllWarnings = true;
370 }
371 else
372 {
373 int suppressWarning = 0;
374 if (!Int32.TryParse(paramArg, out suppressWarning) || 0 >= suppressWarning)
375 {
376 this.Messaging.Write(ErrorMessages.IllegalSuppressWarningId(paramArg));
377 }
378 else
379 {
380 this.Messaging.SuppressWarningMessage(suppressWarning);
381 }
382 }
383 }
384 else if (parameter.StartsWith("wx", StringComparison.Ordinal))
385 {
386 string paramArg = parameter.Substring(2);
387 if (0 == paramArg.Length)
388 {
389 this.Messaging.WarningsAsError = true;
390 }
391 else
392 {
393 int elevateWarning = 0;
394 if (!Int32.TryParse(paramArg, out elevateWarning) || 0 >= elevateWarning)
395 {
396 this.Messaging.Write(ErrorMessages.IllegalWarningIdAsError(paramArg));
397 }
398 else
399 {
400 this.Messaging.ElevateWarningMessage(elevateWarning);
401 }
402 }
403 }
404 else if ("v" == parameter)
405 {
406 this.Messaging.ShowVerboseMessages = true;
407 }
408 else if ("?" == parameter || "help" == parameter)
409 {
410 this.ShowHelp = true;
411 break;
412 }
413 else
414 {
415 unprocessed.Add(arg);
416 }
417 }
418 else if ('@' == arg[0])
419 {
420 string[] parsedArgs = CommandLineResponseFile.Parse(arg.Substring(1));
421 string[] unparsedArgs = this.Parse(parsedArgs);
422 unprocessed.AddRange(unparsedArgs);
423 }
424 else
425 {
426 unprocessed.Add(arg);
427 }
428 }
429
430 return unprocessed.ToArray();
431 }
432
433 public string[] ParsePostExtensions(string[] remaining)
434 {
435 List<string> unprocessed = new List<string>();
436
437 for (int i = 0; i < remaining.Length; ++i)
438 {
439 string arg = remaining[i];
440 if (String.IsNullOrEmpty(arg)) // skip blank arguments
441 {
442 continue;
443 }
444
445 if (1 < arg.Length && ('-' == arg[0] || '/' == arg[0]))
446 {
447 unprocessed.Add(arg);
448 }
449 else
450 {
451 this.Files.AddRange(CommandLineHelper.GetFiles(arg, "Source"));
452 }
453 }
454
455 if (0 == this.Files.Count)
456 {
457 this.ShowHelp = true;
458 }
459 else if (String.IsNullOrEmpty(this.OutputFile))
460 {
461 if (1 < this.Files.Count)
462 {
463 this.Messaging.Write(ErrorMessages.MustSpecifyOutputWithMoreThanOneInput());
464 }
465
466 // After the linker tells us what the output type actually is, we'll change the ".wix" to the correct extension.
467 this.OutputFile = Path.ChangeExtension(Path.GetFileName(this.Files[0]), ".wix");
468
469 // Add the directories of the input files as unnamed bind paths.
470 foreach (string file in this.Files)
471 {
472 BindPath bindPath = new BindPath(Path.GetDirectoryName(Path.GetFullPath(file)));
473 this.BindPaths.Add(bindPath);
474 }
475 }
476
477 if (!this.SuppressWixPdb && String.IsNullOrEmpty(this.PdbFile) && !String.IsNullOrEmpty(this.OutputFile))
478 {
479 this.PdbFile = Path.ChangeExtension(this.OutputFile, ".wixpdb");
480 }
481
482 return unprocessed.ToArray();
483 }
484 }
485}