summaryrefslogtreecommitdiff
path: root/src/tools/heat/HeatCommand.cs
diff options
context:
space:
mode:
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}