summaryrefslogtreecommitdiff
path: root/src/tools/heat/HeatCommand.cs
diff options
context:
space:
mode:
authorRob Mensching <rob@firegiant.com>2022-07-26 17:20:39 -0700
committerRob Mensching <rob@firegiant.com>2022-08-01 20:25:19 -0700
commita627ca9b720047e633a8fe72003ab9bee31006c5 (patch)
tree2bc8a924bb4141ab718e74d08f6459a0ffe8d573 /src/tools/heat/HeatCommand.cs
parent521eb3c9cf38823a2c4019abb85dc0b3200b92cb (diff)
downloadwix-a627ca9b720047e633a8fe72003ab9bee31006c5.tar.gz
wix-a627ca9b720047e633a8fe72003ab9bee31006c5.tar.bz2
wix-a627ca9b720047e633a8fe72003ab9bee31006c5.zip
Create WixToolset.Heat.nupkg to distribute heat.exe and Heat targets
Moves Heat functionality to the "tools" layer and packages it all up in WixToolset.Heat.nupkg for distribution in WiX v4. Completes 6838
Diffstat (limited to 'src/tools/heat/HeatCommand.cs')
-rw-r--r--src/tools/heat/HeatCommand.cs277
1 files changed, 277 insertions, 0 deletions
diff --git a/src/tools/heat/HeatCommand.cs b/src/tools/heat/HeatCommand.cs
new file mode 100644
index 00000000..56277004
--- /dev/null
+++ b/src/tools/heat/HeatCommand.cs
@@ -0,0 +1,277 @@
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.Globalization;
8 using System.IO;
9 using System.Runtime.InteropServices;
10 using System.Threading;
11 using System.Threading.Tasks;
12 using System.Xml;
13 using WixToolset.Data;
14 using WixToolset.Extensibility.Data;
15 using WixToolset.Extensibility.Services;
16 using WixToolset.Harvesters.Extensibility;
17 using Wix = WixToolset.Harvesters.Serialize;
18
19 internal class HeatCommand : ICommandLineCommand
20 {
21 public HeatCommand(string harvestType, IList<IHeatExtension> extensions, IServiceProvider serviceProvider)
22 {
23 this.Extensions = extensions;
24 this.Messaging = serviceProvider.GetService<IMessaging>();
25 this.ServiceProvider = serviceProvider;
26
27 this.ExtensionType = harvestType;
28 this.ExtensionOptions.Add(harvestType);
29 }
30
31 public bool ShowHelp { get; set; }
32
33 public bool ShowLogo { get; set; }
34
35 public bool StopParsing { get; private set; }
36
37 private string ExtensionArgument { get; set; }
38
39 private List<string> ExtensionOptions { get; } = new List<string>();
40
41 private string ExtensionType { get; }
42
43 private IList<IHeatExtension> Extensions { get; }
44
45 private int Indent { get; set; } = 4;
46
47 private IMessaging Messaging { get; }
48
49 private string OutputFile { get; set; }
50
51 private IServiceProvider ServiceProvider { get; }
52
53 public Task<int> ExecuteAsync(CancellationToken cancellationToken)
54 {
55 var exitCode = this.Harvest();
56 return Task.FromResult(exitCode);
57 }
58
59 public bool TryParseArgument(ICommandLineParser parser, string arg)
60 {
61 if (this.ExtensionArgument == null)
62 {
63 this.ExtensionArgument = arg;
64 }
65 else if ('-' == arg[0] || '/' == arg[0])
66 {
67 string parameter = arg.Substring(1);
68 if ("nologo" == parameter)
69 {
70 this.ShowLogo = false;
71 }
72 else if ("o" == parameter || "out" == parameter)
73 {
74 this.OutputFile = parser.GetNextArgumentAsFilePathOrError(arg);
75
76 if (String.IsNullOrEmpty(this.OutputFile))
77 {
78 return false;
79 }
80 }
81 else if ("swall" == parameter)
82 {
83 this.Messaging.Write(WarningMessages.DeprecatedCommandLineSwitch("swall", "sw"));
84 this.Messaging.SuppressAllWarnings = true;
85 }
86 else if (parameter.StartsWith("sw"))
87 {
88 string paramArg = parameter.Substring(2);
89 try
90 {
91 if (0 == paramArg.Length)
92 {
93 this.Messaging.SuppressAllWarnings = true;
94 }
95 else
96 {
97 int suppressWarning = Convert.ToInt32(paramArg, CultureInfo.InvariantCulture.NumberFormat);
98 if (0 >= suppressWarning)
99 {
100 this.Messaging.Write(ErrorMessages.IllegalSuppressWarningId(paramArg));
101 }
102
103 this.Messaging.SuppressWarningMessage(suppressWarning);
104 }
105 }
106 catch (FormatException)
107 {
108 this.Messaging.Write(ErrorMessages.IllegalSuppressWarningId(paramArg));
109 }
110 catch (OverflowException)
111 {
112 this.Messaging.Write(ErrorMessages.IllegalSuppressWarningId(paramArg));
113 }
114 }
115 else if ("wxall" == parameter)
116 {
117 this.Messaging.Write(WarningMessages.DeprecatedCommandLineSwitch("wxall", "wx"));
118 this.Messaging.WarningsAsError = true;
119 }
120 else if (parameter.StartsWith("wx"))
121 {
122 string paramArg = parameter.Substring(2);
123 try
124 {
125 if (0 == paramArg.Length)
126 {
127 this.Messaging.WarningsAsError = true;
128 }
129 else
130 {
131 int elevateWarning = Convert.ToInt32(paramArg, CultureInfo.InvariantCulture.NumberFormat);
132 if (0 >= elevateWarning)
133 {
134 this.Messaging.Write(ErrorMessages.IllegalWarningIdAsError(paramArg));
135 }
136
137 this.Messaging.ElevateWarningMessage(elevateWarning);
138 }
139 }
140 catch (FormatException)
141 {
142 this.Messaging.Write(ErrorMessages.IllegalWarningIdAsError(paramArg));
143 }
144 catch (OverflowException)
145 {
146 this.Messaging.Write(ErrorMessages.IllegalWarningIdAsError(paramArg));
147 }
148 }
149 else if ("v" == parameter)
150 {
151 this.Messaging.ShowVerboseMessages = true;
152 }
153 else if ("indent" == parameter)
154 {
155 try
156 {
157 this.Indent = Int32.Parse(parser.GetNextArgumentOrError(arg), CultureInfo.InvariantCulture);
158 }
159 catch
160 {
161 throw new ArgumentException("Invalid numeric argument.", parameter);
162 }
163 }
164 }
165
166 this.ExtensionOptions.Add(arg);
167 return true;
168 }
169
170 private int Harvest()
171 {
172 try
173 {
174 if (String.IsNullOrEmpty(this.ExtensionArgument))
175 {
176 this.Messaging.Write(ErrorMessages.HarvestSourceNotSpecified());
177 }
178 else if (String.IsNullOrEmpty(this.OutputFile))
179 {
180 this.Messaging.Write(ErrorMessages.OutputTargetNotSpecified());
181 }
182
183 // exit if there was an error parsing the core command line
184 if (this.Messaging.EncounteredError)
185 {
186 return this.Messaging.LastErrorNumber;
187 }
188
189 if (this.ShowLogo)
190 {
191 HelpCommand.DisplayToolHeader();
192 }
193
194 var heatCore = new HeatCore(this.ServiceProvider, this.ExtensionArgument);
195
196 // parse the extension's command line arguments
197 var extensionOptionsArray = this.ExtensionOptions.ToArray();
198 foreach (var heatExtension in this.Extensions)
199 {
200 heatExtension.Core = heatCore;
201 heatExtension.ParseOptions(this.ExtensionType, extensionOptionsArray);
202 }
203
204 // exit if there was an error parsing the command line (otherwise the logo appears after error messages)
205 if (this.Messaging.EncounteredError)
206 {
207 return this.Messaging.LastErrorNumber;
208 }
209
210 // harvest the output
211 Wix.Wix wix = heatCore.Harvester.Harvest(this.ExtensionArgument);
212 if (null == wix)
213 {
214 return this.Messaging.LastErrorNumber;
215 }
216
217 // mutate the output
218 if (!heatCore.Mutator.Mutate(wix))
219 {
220 return this.Messaging.LastErrorNumber;
221 }
222
223 XmlWriterSettings xmlSettings = new XmlWriterSettings();
224 xmlSettings.Indent = true;
225 xmlSettings.IndentChars = new string(' ', this.Indent);
226 xmlSettings.OmitXmlDeclaration = true;
227
228 string wixString;
229 using (StringWriter stringWriter = new StringWriter())
230 {
231 using (XmlWriter xmlWriter = XmlWriter.Create(stringWriter, xmlSettings))
232 {
233 wix.OutputXml(xmlWriter);
234 }
235
236 wixString = stringWriter.ToString();
237 }
238
239 string mutatedWixString = heatCore.Mutator.Mutate(wixString);
240 if (String.IsNullOrEmpty(mutatedWixString))
241 {
242 return this.Messaging.LastErrorNumber;
243 }
244
245 Directory.CreateDirectory(Path.GetDirectoryName(this.OutputFile));
246
247 using (StreamWriter streamWriter = new StreamWriter(this.OutputFile, false, System.Text.Encoding.UTF8))
248 {
249 xmlSettings.OmitXmlDeclaration = false;
250 xmlSettings.Encoding = System.Text.Encoding.UTF8;
251 using (XmlWriter xmlWriter = XmlWriter.Create(streamWriter, xmlSettings))
252 {
253 xmlWriter.WriteStartDocument();
254 xmlWriter.Flush();
255 }
256
257 streamWriter.WriteLine();
258 streamWriter.Write(mutatedWixString);
259 }
260 }
261 catch (WixException we)
262 {
263 this.Messaging.Write(we.Error);
264 }
265 catch (Exception e)
266 {
267 this.Messaging.Write(ErrorMessages.UnexpectedException(e));
268 if (e is NullReferenceException || e is SEHException)
269 {
270 throw;
271 }
272 }
273
274 return this.Messaging.LastErrorNumber;
275 }
276 }
277}