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