aboutsummaryrefslogtreecommitdiff
path: root/src/heat/UtilHeatExtension.cs
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/heat/UtilHeatExtension.cs405
1 files changed, 405 insertions, 0 deletions
diff --git a/src/heat/UtilHeatExtension.cs b/src/heat/UtilHeatExtension.cs
new file mode 100644
index 00000000..7296a3b3
--- /dev/null
+++ b/src/heat/UtilHeatExtension.cs
@@ -0,0 +1,405 @@
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.Harvesters
4{
5 using System;
6 using System.Collections.Generic;
7 using System.IO;
8 using WixToolset.Core.Burn.Interfaces;
9 using WixToolset.Data;
10 using WixToolset.Data.Symbols;
11 using WixToolset.Extensibility.Services;
12 using WixToolset.Harvesters.Data;
13 using WixToolset.Harvesters.Extensibility;
14
15 /// <summary>
16 /// A utility heat extension for the WiX Toolset Harvester application.
17 /// </summary>
18 internal class UtilHeatExtension : BaseHeatExtension
19 {
20 public UtilHeatExtension(IServiceProvider serviceProvider)
21 {
22 this.PayloadHarvester = serviceProvider.GetService<IPayloadHarvester>();
23 }
24
25 private IPayloadHarvester PayloadHarvester { get; }
26
27 /// <summary>
28 /// Gets the supported command line types for this extension.
29 /// </summary>
30 /// <value>The supported command line types for this extension.</value>
31 public override HeatCommandLineOption[] CommandLineTypes
32 {
33 get
34 {
35 return new HeatCommandLineOption[]
36 {
37 new HeatCommandLineOption("dir", "harvest a directory"),
38 new HeatCommandLineOption("file", "harvest a file"),
39 new HeatCommandLineOption("exepackagepayload", "harvest a bundle payload as ExePackagePayload"),
40 new HeatCommandLineOption("msupackagepayload", "harvest a bundle payload as MsuPackagePayload"),
41 new HeatCommandLineOption("perf", "harvest performance counters"),
42 new HeatCommandLineOption("reg", "harvest a .reg file"),
43 new HeatCommandLineOption("-ag", "autogenerate component guids at compile time"),
44 new HeatCommandLineOption("-cg <ComponentGroupName>", "component group name (cannot contain spaces e.g -cg MyComponentGroup)"),
45 new HeatCommandLineOption("-dr <DirectoryName>", "directory reference to root directories (cannot contain spaces e.g. -dr MyAppDirRef)"),
46 new HeatCommandLineOption("-var <VariableName>", "substitute File/@Source=\"SourceDir\" with a preprocessor or a wix variable" + Environment.NewLine +
47 "(e.g. -var var.MySource will become File/@Source=\"$(var.MySource)\\myfile.txt\" and " + Environment.NewLine +
48 "-var wix.MySource will become File/@Source=\"!(wix.MySource)\\myfile.txt\""),
49 new HeatCommandLineOption("-gg", "generate guids now"),
50 new HeatCommandLineOption("-g1", "generated guids are not in brackets"),
51 new HeatCommandLineOption("-ke", "keep empty directories"),
52 new HeatCommandLineOption("-scom", "suppress COM elements"),
53 new HeatCommandLineOption("-sfrag", "suppress fragments"),
54 new HeatCommandLineOption("-srd", "suppress harvesting the root directory as an element"),
55 new HeatCommandLineOption("-svb6", "suppress VB6 COM elements"),
56 new HeatCommandLineOption("-sreg", "suppress registry harvesting"),
57 new HeatCommandLineOption("-suid", "suppress unique identifiers for files, components, & directories"),
58 new HeatCommandLineOption("-t", "transform harvested output with XSL file"),
59 new HeatCommandLineOption("-template", "use template, one of: fragment,module,product"),
60 };
61 }
62 }
63
64 /// <summary>
65 /// Parse the command line options for this extension.
66 /// </summary>
67 /// <param name="type">The active harvester type.</param>
68 /// <param name="args">The option arguments.</param>
69 public override void ParseOptions(string type, string[] args)
70 {
71 bool active = false;
72 IHarvesterExtension harvesterExtension = null;
73 bool suppressHarvestingRegistryValues = false;
74 UtilFinalizeHarvesterMutator utilFinalizeHarvesterMutator = new UtilFinalizeHarvesterMutator();
75 UtilMutator utilMutator = new UtilMutator();
76 List<UtilTransformMutator> transformMutators = new List<UtilTransformMutator>();
77 GenerateType generateType = GenerateType.Components;
78
79 // select the harvester
80 switch (type)
81 {
82 case "dir":
83 harvesterExtension = new DirectoryHarvester();
84 active = true;
85 break;
86 case "file":
87 harvesterExtension = new FileHarvester();
88 active = true;
89 break;
90 case "exepackagepayload":
91 harvesterExtension = new PayloadHarvester(this.PayloadHarvester, WixBundlePackageType.Exe);
92 active = true;
93 break;
94 case "msupackagepayload":
95 harvesterExtension = new PayloadHarvester(this.PayloadHarvester, WixBundlePackageType.Msu);
96 active = true;
97 break;
98 case "perf":
99 harvesterExtension = new PerformanceCategoryHarvester();
100 active = true;
101 break;
102 case "reg":
103 harvesterExtension = new RegFileHarvester();
104 active = true;
105 break;
106 }
107
108 // set default settings
109 utilMutator.CreateFragments = true;
110 utilMutator.SetUniqueIdentifiers = true;
111
112 // parse the options
113 for (int i = 0; i < args.Length; i++)
114 {
115 string commandSwitch = args[i];
116
117 if (null == commandSwitch || 0 == commandSwitch.Length) // skip blank arguments
118 {
119 continue;
120 }
121
122 if ('-' == commandSwitch[0] || '/' == commandSwitch[0])
123 {
124 string truncatedCommandSwitch = commandSwitch.Substring(1);
125
126 if ("ag" == truncatedCommandSwitch)
127 {
128 utilMutator.AutogenerateGuids = true;
129 }
130 else if ("cg" == truncatedCommandSwitch)
131 {
132 utilMutator.ComponentGroupName = this.GetArgumentParameter(args, i);
133
134 if (this.Core.Messaging.EncounteredError)
135 {
136 return;
137 }
138 }
139 else if ("dr" == truncatedCommandSwitch)
140 {
141 string dr = this.GetArgumentParameter(args, i);
142
143 if (this.Core.Messaging.EncounteredError)
144 {
145 return;
146 }
147
148 if (harvesterExtension is DirectoryHarvester)
149 {
150 ((DirectoryHarvester)harvesterExtension).RootedDirectoryRef = dr;
151 }
152 else if (harvesterExtension is FileHarvester)
153 {
154 ((FileHarvester)harvesterExtension).RootedDirectoryRef = dr;
155 }
156 }
157 else if ("gg" == truncatedCommandSwitch)
158 {
159 utilMutator.GenerateGuids = true;
160 }
161 else if ("g1" == truncatedCommandSwitch)
162 {
163 utilMutator.GuidFormat = "D";
164 }
165 else if ("ke" == truncatedCommandSwitch)
166 {
167 if (harvesterExtension is DirectoryHarvester)
168 {
169 ((DirectoryHarvester)harvesterExtension).KeepEmptyDirectories = true;
170 }
171 else if (active)
172 {
173 // TODO: error message - not applicable to file harvester
174 }
175 }
176 else if ("scom" == truncatedCommandSwitch)
177 {
178 if (active)
179 {
180 utilFinalizeHarvesterMutator.SuppressCOMElements = true;
181 }
182 else
183 {
184 // TODO: error message - not applicable
185 }
186 }
187 else if ("svb6" == truncatedCommandSwitch)
188 {
189 if (active)
190 {
191 utilFinalizeHarvesterMutator.SuppressVB6COMElements = true;
192 }
193 else
194 {
195 // TODO: error message - not applicable
196 }
197 }
198 else if ("sfrag" == truncatedCommandSwitch)
199 {
200 utilMutator.CreateFragments = false;
201 }
202 else if ("srd" == truncatedCommandSwitch)
203 {
204 if (harvesterExtension is DirectoryHarvester)
205 {
206 ((DirectoryHarvester)harvesterExtension).SuppressRootDirectory = true;
207 }
208 else if (harvesterExtension is FileHarvester)
209 {
210 ((FileHarvester)harvesterExtension).SuppressRootDirectory = true;
211 }
212 }
213 else if ("sreg" == truncatedCommandSwitch)
214 {
215 suppressHarvestingRegistryValues = true;
216 }
217 else if ("suid" == truncatedCommandSwitch)
218 {
219 utilMutator.SetUniqueIdentifiers = false;
220
221 if (harvesterExtension is DirectoryHarvester)
222 {
223 ((DirectoryHarvester)harvesterExtension).SetUniqueIdentifiers = false;
224 }
225 else if (harvesterExtension is FileHarvester)
226 {
227 ((FileHarvester)harvesterExtension).SetUniqueIdentifiers = false;
228 }
229 }
230 else if (truncatedCommandSwitch.StartsWith("t:", StringComparison.Ordinal) || "t" == truncatedCommandSwitch)
231 {
232 string xslFile;
233 if (truncatedCommandSwitch.StartsWith("t:", StringComparison.Ordinal))
234 {
235 this.Core.Messaging.Write(WarningMessages.DeprecatedCommandLineSwitch("t:", "t"));
236 xslFile = truncatedCommandSwitch.Substring(2);
237 }
238 else
239 {
240 xslFile = this.GetArgumentParameter(args, i, true);
241 }
242
243 if (0 <= xslFile.IndexOf('\"'))
244 {
245 this.Core.Messaging.Write(ErrorMessages.PathCannotContainQuote(xslFile));
246 return;
247 }
248
249 try
250 {
251 xslFile = Path.GetFullPath(xslFile);
252 }
253 catch (Exception e)
254 {
255 this.Core.Messaging.Write(ErrorMessages.InvalidCommandLineFileName(xslFile, e.Message));
256 return;
257 }
258
259 transformMutators.Add(new UtilTransformMutator(xslFile, transformMutators.Count));
260 }
261 else if (truncatedCommandSwitch.StartsWith("template:", StringComparison.Ordinal) || "template" == truncatedCommandSwitch)
262 {
263 string template;
264 if(truncatedCommandSwitch.StartsWith("template:", StringComparison.Ordinal))
265 {
266 this.Core.Messaging.Write(WarningMessages.DeprecatedCommandLineSwitch("template:", "template"));
267 template = truncatedCommandSwitch.Substring(9);
268 }
269 else
270 {
271 template = this.GetArgumentParameter(args, i);
272 }
273
274 switch (template)
275 {
276 case "fragment":
277 utilMutator.TemplateType = TemplateType.Fragment;
278 break;
279 case "module":
280 utilMutator.TemplateType = TemplateType.Module;
281 break;
282 case "product":
283 utilMutator.TemplateType = TemplateType.Package ;
284 break;
285 default:
286 // TODO: error
287 break;
288 }
289 }
290 else if ("var" == truncatedCommandSwitch)
291 {
292 if (active)
293 {
294 utilFinalizeHarvesterMutator.PreprocessorVariable = this.GetArgumentParameter(args, i);
295
296 if (this.Core.Messaging.EncounteredError)
297 {
298 return;
299 }
300 }
301 }
302 else if ("generate" == truncatedCommandSwitch)
303 {
304 if (harvesterExtension is DirectoryHarvester)
305 {
306 string genType = this.GetArgumentParameter(args, i).ToUpperInvariant();
307 switch (genType)
308 {
309 case "COMPONENTS":
310 generateType = GenerateType.Components;
311 break;
312 case "PAYLOADGROUP":
313 generateType = GenerateType.PayloadGroup;
314 break;
315 default:
316 throw new WixException(HarvesterErrors.InvalidDirectoryOutputType(genType));
317 }
318 }
319 else
320 {
321 // TODO: error message - not applicable
322 }
323 }
324 }
325 }
326
327 // set the appropriate harvester extension
328 if (active)
329 {
330 this.Core.Harvester.Extension = harvesterExtension;
331
332 if (!suppressHarvestingRegistryValues)
333 {
334 this.Core.Mutator.AddExtension(new UtilHarvesterMutator());
335 }
336
337 this.Core.Mutator.AddExtension(utilFinalizeHarvesterMutator);
338
339 if (harvesterExtension is DirectoryHarvester directoryHarvester)
340 {
341 directoryHarvester.GenerateType = generateType;
342 this.Core.Harvester.Core.RootDirectory = this.Core.Harvester.Core.ExtensionArgument;
343 }
344 else if (harvesterExtension is FileHarvester)
345 {
346 if (((FileHarvester)harvesterExtension).SuppressRootDirectory)
347 {
348 this.Core.Harvester.Core.RootDirectory = Path.GetDirectoryName(Path.GetFullPath(this.Core.Harvester.Core.ExtensionArgument));
349 }
350 else
351 {
352 this.Core.Harvester.Core.RootDirectory = Path.GetDirectoryName(Path.GetDirectoryName(Path.GetFullPath(this.Core.Harvester.Core.ExtensionArgument)));
353
354 // GetDirectoryName() returns null for root paths such as "c:\", so make sure to support that as well
355 if (null == this.Core.Harvester.Core.RootDirectory)
356 {
357 this.Core.Harvester.Core.RootDirectory = Path.GetPathRoot(Path.GetDirectoryName(Path.GetFullPath(this.Core.Harvester.Core.ExtensionArgument)));
358 }
359 }
360 }
361 }
362
363 // set the mutator
364 this.Core.Mutator.AddExtension(utilMutator);
365
366 // add the transforms
367 foreach (UtilTransformMutator transformMutator in transformMutators)
368 {
369 this.Core.Mutator.AddExtension(transformMutator);
370 }
371 }
372
373 private string GetArgumentParameter(string[] args, int index)
374 {
375 return this.GetArgumentParameter(args, index, false);
376 }
377
378 private string GetArgumentParameter(string[] args, int index, bool allowSpaces)
379 {
380 string truncatedCommandSwitch = args[index];
381 string commandSwitchValue = args[index + 1];
382
383 //increment the index to the switch value
384 index++;
385
386 if (IsValidArg(args, index) && !String.IsNullOrEmpty(commandSwitchValue.Trim()))
387 {
388 if (!allowSpaces && commandSwitchValue.Contains(" "))
389 {
390 this.Core.Messaging.Write(HarvesterErrors.SpacesNotAllowedInArgumentValue(truncatedCommandSwitch, commandSwitchValue));
391 }
392 else
393 {
394 return commandSwitchValue;
395 }
396 }
397 else
398 {
399 this.Core.Messaging.Write(HarvesterErrors.ArgumentRequiresValue(truncatedCommandSwitch));
400 }
401
402 return null;
403 }
404 }
405}