aboutsummaryrefslogtreecommitdiff
path: root/src/WixToolset.Core
diff options
context:
space:
mode:
Diffstat (limited to 'src/WixToolset.Core')
-rw-r--r--src/WixToolset.Core/BindContext.cs14
-rw-r--r--src/WixToolset.Core/Binder.cs461
-rw-r--r--src/WixToolset.Core/CommandLine/BuildCommand.cs62
-rw-r--r--src/WixToolset.Core/CommandLine/CommandLineContext.cs2
-rw-r--r--src/WixToolset.Core/CommandLine/CommandLineHelper.cs216
-rw-r--r--src/WixToolset.Core/CommandLine/CommandLineParser.cs (renamed from src/WixToolset.Core/CommandLine/CommandLine.cs)92
-rw-r--r--src/WixToolset.Core/CommandLine/CommandLineResponseFile.cs2
-rw-r--r--src/WixToolset.Core/CommandLine/CompileCommand.cs2
-rw-r--r--src/WixToolset.Core/CommandLine/HelpCommand.cs2
-rw-r--r--src/WixToolset.Core/CommandLine/VersionCommand.cs2
-rw-r--r--src/WixToolset.Core/Layout.cs26
-rw-r--r--src/WixToolset.Core/Resolver.cs29
-rw-r--r--src/WixToolset.Core/WixToolsetServiceProvider.cs3
13 files changed, 358 insertions, 555 deletions
diff --git a/src/WixToolset.Core/BindContext.cs b/src/WixToolset.Core/BindContext.cs
index 8bdacf75..f423b731 100644
--- a/src/WixToolset.Core/BindContext.cs
+++ b/src/WixToolset.Core/BindContext.cs
@@ -27,13 +27,13 @@ namespace WixToolset.Core
27 27
28 public int Codepage { get; set; } 28 public int Codepage { get; set; }
29 29
30 public CompressionLevel DefaultCompressionLevel { get; set; } 30 public CompressionLevel? DefaultCompressionLevel { get; set; }
31 31
32 public IEnumerable<IDelayedField> DelayedFields { get; set; } 32 public IEnumerable<IDelayedField> DelayedFields { get; set; }
33 33
34 public IEnumerable<IExpectedExtractFile> ExpectedEmbeddedFiles { get; set; } 34 public IEnumerable<IExpectedExtractFile> ExpectedEmbeddedFiles { get; set; }
35 35
36 public IExtensionManager ExtensionManager { get; set; } 36 public IEnumerable<IBinderExtension> Extensions { get; set; }
37 37
38 public IEnumerable<IFileSystemExtension> FileSystemExtensions { get; set; } 38 public IEnumerable<IFileSystemExtension> FileSystemExtensions { get; set; }
39 39
@@ -50,15 +50,5 @@ namespace WixToolset.Core
50 public IEnumerable<string> SuppressIces { get; set; } 50 public IEnumerable<string> SuppressIces { get; set; }
51 51
52 public bool SuppressValidation { get; set; } 52 public bool SuppressValidation { get; set; }
53
54 public IBindVariableResolver WixVariableResolver { get; set; }
55
56 public string ContentsFile { get; set; }
57
58 public string OutputsFile { get; set; }
59
60 public string BuiltOutputsFile { get; set; }
61
62 public string WixprojectFile { get; set; }
63 } 53 }
64} 54}
diff --git a/src/WixToolset.Core/Binder.cs b/src/WixToolset.Core/Binder.cs
index 9db27fec..c442c94d 100644
--- a/src/WixToolset.Core/Binder.cs
+++ b/src/WixToolset.Core/Binder.cs
@@ -5,10 +5,8 @@ namespace WixToolset.Core
5 using System; 5 using System;
6 using System.Collections.Generic; 6 using System.Collections.Generic;
7 using System.Diagnostics; 7 using System.Diagnostics;
8 using System.IO;
9 using System.Linq; 8 using System.Linq;
10 using System.Reflection; 9 using System.Reflection;
11 using WixToolset.Core.Bind;
12 using WixToolset.Data; 10 using WixToolset.Data;
13 using WixToolset.Data.Bind; 11 using WixToolset.Data.Bind;
14 using WixToolset.Data.Tuples; 12 using WixToolset.Data.Tuples;
@@ -20,334 +18,110 @@ namespace WixToolset.Core
20 /// </summary> 18 /// </summary>
21 public sealed class Binder 19 public sealed class Binder
22 { 20 {
23 //private BinderCore core; 21 public Binder(IServiceProvider serviceProvider)
24 //private List<IBinderExtension> extensions;
25 //private List<IBinderFileManager> fileManagers;
26
27 public Binder()
28 { 22 {
29 //this.DefaultCompressionLevel = CompressionLevel.High; 23 this.ServiceProvider = serviceProvider;
30
31 //this.BindPaths = new List<BindPath>();
32 //this.TargetBindPaths = new List<BindPath>();
33 //this.UpdatedBindPaths = new List<BindPath>();
34
35 //this.extensions = new List<IBinderExtension>();
36 //this.fileManagers = new List<IBinderFileManager>();
37 //this.inspectorExtensions = new List<InspectorExtension>();
38
39 //this.Ices = new List<string>();
40 //this.SuppressIces = new List<string>();
41 } 24 }
42 25
43 private IBindContext Context { get; set; } 26 public int CabbingThreadCount { get; set; }
44
45 //private TableDefinitionCollection TableDefinitions { get; }
46 27
47 //public IEnumerable<IBackendFactory> BackendFactories { get; set; } 28 public string CabCachePath { get; set; }
48 29
49 //public string ContentsFile { private get; set; } 30 public int Codepage { get; set; }
50 31
51 //public string OutputsFile { private get; set; } 32 public CompressionLevel? DefaultCompressionLevel { get; set; }
52 33
53 //public string BuiltOutputsFile { private get; set; } 34 public IEnumerable<IDelayedField> DelayedFields { get; set; }
54 35
55 //public string WixprojectFile { private get; set; } 36 public IEnumerable<IExpectedExtractFile> ExpectedEmbeddedFiles { get; set; }
56 37
57 /// <summary> 38 public IEnumerable<string> Ices { get; set; }
58 /// Gets the list of bindpaths.
59 /// </summary>
60 //public List<BindPath> BindPaths { get; private set; }
61 39
62 /// <summary> 40 public string IntermediateFolder { get; set; }
63 /// Gets the list of target bindpaths.
64 /// </summary>
65 //public List<BindPath> TargetBindPaths { get; private set; }
66 41
67 /// <summary> 42 public Intermediate IntermediateRepresentation { get; set; }
68 /// Gets the list of updated bindpaths.
69 /// </summary>
70 //public List<BindPath> UpdatedBindPaths { get; private set; }
71 43
72 /// <summary> 44 public string OutputPath { get; set; }
73 /// Gets or sets the option to enable building binary delta patches.
74 /// </summary>
75 /// <value>The option to enable building binary delta patches.</value>
76 public bool DeltaBinaryPatch { get; set; }
77 45
78 /// <summary> 46 public string OutputPdbPath { get; set; }
79 /// Gets or sets the cabinet cache location.
80 /// </summary>
81 public string CabCachePath { get; set; }
82 47
83 /// <summary> 48 public IEnumerable<string> SuppressIces { get; set; }
84 /// Gets or sets the number of threads to use for cabinet creation.
85 /// </summary>
86 /// <value>The number of threads to use for cabinet creation.</value>
87 public int CabbingThreadCount { get; set; }
88 49
89 /// <summary>
90 /// Gets or sets the default compression level to use for cabinets
91 /// that don't have their compression level explicitly set.
92 /// </summary>
93 //public CompressionLevel DefaultCompressionLevel { get; set; }
94
95 /// <summary>
96 /// Gets and sets the location to save the WixPdb.
97 /// </summary>
98 /// <value>The location in which to save the WixPdb. Null if the the WixPdb should not be output.</value>
99 //public string PdbFile { get; set; }
100
101 //public List<string> Ices { get; private set; }
102
103 //public List<string> SuppressIces { get; private set; }
104
105 /// <summary>
106 /// Gets and sets the option to suppress resetting ACLs by the binder.
107 /// </summary>
108 /// <value>The option to suppress resetting ACLs by the binder.</value>
109 public bool SuppressAclReset { get; set; }
110
111 /// <summary>
112 /// Gets and sets the option to suppress creating an image for MSI/MSM.
113 /// </summary>
114 /// <value>The option to suppress creating an image for MSI/MSM.</value>
115 public bool SuppressLayout { get; set; }
116
117 /// <summary>
118 /// Gets and sets the option to suppress MSI/MSM validation.
119 /// </summary>
120 /// <value>The option to suppress MSI/MSM validation.</value>
121 /// <remarks>This must be set before calling Bind.</remarks>
122 public bool SuppressValidation { get; set; } 50 public bool SuppressValidation { get; set; }
123 51
124 /// <summary> 52 public bool DeltaBinaryPatch { get; set; }
125 /// Gets and sets the option to suppress adding _Validation table rows.
126 /// </summary>
127 public bool SuppressAddingValidationRows { get; set; }
128
129 /// <summary>
130 /// Gets or sets the localizer.
131 /// </summary>
132 /// <value>The localizer.</value>
133 public Localizer Localizer { get; set; }
134
135 /// <summary>
136 /// Gets or sets the temporary path for the Binder. If left null, the binder
137 /// will use %TEMP% environment variable.
138 /// </summary>
139 /// <value>Path to temp files.</value>
140 public string TempFilesLocation { get; set; }
141
142 /// <summary>
143 /// Gets or sets the Wix variable resolver.
144 /// </summary>
145 /// <value>The Wix variable resolver.</value>
146 internal WixVariableResolver WixVariableResolver { get; set; }
147
148 public BindResult Bind(IBindContext context)
149 {
150 this.Context = context;
151 53
152 this.WriteBuildInfoTable(this.Context.IntermediateRepresentation, this.Context.OutputPath); 54 public IServiceProvider ServiceProvider { get; }
153 55
154 var bindResult = this.BackendBind(); 56 public BindResult Execute()
155 return bindResult;
156 }
157
158//// private ResolveResult Resolve()
159//// {
160//// var buildingPatch = this.Context.IntermediateRepresentation.Sections.Any(s => s.Type == SectionType.Patch);
161
162//// var filesWithEmbeddedFiles = new ExtractEmbeddedFiles();
163
164//// IEnumerable<DelayedField> delayedFields;
165//// {
166//// var command = new ResolveFieldsCommand();
167//// command.Messaging = this.Context.Messaging;
168//// command.BuildingPatch = buildingPatch;
169//// command.BindVariableResolver = this.Context.WixVariableResolver;
170//// command.BindPaths = this.Context.BindPaths;
171//// command.Extensions = this.Context.Extensions;
172//// command.FilesWithEmbeddedFiles = filesWithEmbeddedFiles;
173//// command.IntermediateFolder = this.Context.IntermediateFolder;
174//// command.Intermediate = this.Context.IntermediateRepresentation;
175//// command.SupportDelayedResolution = true;
176//// command.Execute();
177
178//// delayedFields = command.DelayedFields;
179//// }
180
181////#if REVISIT_FOR_PATCHING
182//// if (this.Context.IntermediateRepresentation.SubStorages != null)
183//// {
184//// foreach (SubStorage transform in this.Context.IntermediateRepresentation.SubStorages)
185//// {
186//// var command = new ResolveFieldsCommand();
187//// command.BuildingPatch = buildingPatch;
188//// command.BindVariableResolver = this.Context.WixVariableResolver;
189//// command.BindPaths = this.Context.BindPaths;
190//// command.Extensions = this.Context.Extensions;
191//// command.FilesWithEmbeddedFiles = filesWithEmbeddedFiles;
192//// command.IntermediateFolder = this.Context.IntermediateFolder;
193//// command.Intermediate = this.Context.IntermediateRepresentation;
194//// command.SupportDelayedResolution = false;
195//// command.Execute();
196//// }
197//// }
198////#endif
199
200//// var expectedEmbeddedFiles = filesWithEmbeddedFiles.GetExpectedEmbeddedFiles();
201
202//// return new ResolveResult
203//// {
204//// ExpectedEmbeddedFiles = expectedEmbeddedFiles,
205//// DelayedFields = delayedFields,
206//// };
207//// }
208
209 private BindResult BackendBind()
210 { 57 {
211 var extensionManager = this.Context.ServiceProvider.GetService<IExtensionManager>(); 58 var context = this.ServiceProvider.GetService<IBindContext>();
59 context.Messaging = this.ServiceProvider.GetService<IMessaging>();
60 context.CabbingThreadCount = this.CabbingThreadCount;
61 context.CabCachePath = this.CabCachePath;
62 context.Codepage = this.Codepage;
63 context.DefaultCompressionLevel = this.DefaultCompressionLevel;
64 context.DelayedFields = this.DelayedFields;
65 context.ExpectedEmbeddedFiles = this.ExpectedEmbeddedFiles;
66 context.Extensions = this.ServiceProvider.GetService<IExtensionManager>().Create<IBinderExtension>();
67 context.Ices = this.Ices;
68 context.IntermediateFolder = this.IntermediateFolder;
69 context.IntermediateRepresentation = this.IntermediateRepresentation;
70 context.OutputPath = this.OutputPath;
71 context.OutputPdbPath = this.OutputPdbPath;
72 context.SuppressIces = this.SuppressIces;
73 context.SuppressValidation = this.SuppressValidation;
74
75
76 // Prebind.
77 //
78 foreach (var extension in context.Extensions)
79 {
80 extension.PreBind(context);
81 }
212 82
213 var backendFactories = extensionManager.Create<IBackendFactory>(); 83 // Bind.
84 //
85 this.WriteBuildInfoTable(context.IntermediateRepresentation, context.OutputPath, context.OutputPdbPath);
214 86
215 var entrySection = this.Context.IntermediateRepresentation.Sections[0]; 87 var bindResult = this.BackendBind(context);
216 88
217 foreach (var factory in backendFactories) 89 if (bindResult != null)
218 { 90 {
219 if (factory.TryCreateBackend(entrySection.Type.ToString(), this.Context.OutputPath, null, out var backend)) 91 // Postbind.
92 //
93 foreach (var extension in context.Extensions)
220 { 94 {
221 var result = backend.Bind(this.Context); 95 extension.PostBind(bindResult);
222 return result;
223 } 96 }
224 } 97 }
225 98
226 // TODO: messaging that a backend could not be found to bind the output type? 99 return bindResult;
227
228 return null;
229 } 100 }
230 101
231 /// <summary> 102 private BindResult BackendBind(IBindContext context)
232 /// Binds an output.
233 /// </summary>
234 /// <param name="output">The output to bind.</param>
235 /// <param name="file">The Windows Installer file to create.</param>
236 /// <remarks>The Binder.DeleteTempFiles method should be called after calling this method.</remarks>
237 /// <returns>true if binding completed successfully; false otherwise</returns>
238#if false
239 public bool Bind(Output output, string file)
240 { 103 {
241 // Ensure the cabinet cache path exists if we are going to use it. 104 var extensionManager = context.ServiceProvider.GetService<IExtensionManager>();
242 if (!String.IsNullOrEmpty(this.CabCachePath))
243 {
244 Directory.CreateDirectory(this.CabCachePath);
245 }
246
247 //var fileManagerCore = new BinderFileManagerCore();
248 //fileManagerCore.CabCachePath = this.CabCachePath;
249 //fileManagerCore.Output = output;
250 //fileManagerCore.TempFilesLocation = this.TempFilesLocation;
251 //fileManagerCore.AddBindPaths(this.BindPaths, BindStage.Normal);
252 //fileManagerCore.AddBindPaths(this.TargetBindPaths, BindStage.Target);
253 //fileManagerCore.AddBindPaths(this.UpdatedBindPaths, BindStage.Updated);
254 //foreach (IBinderFileManager fileManager in this.fileManagers)
255 //{
256 // fileManager.Core = fileManagerCore;
257 //}
258
259 this.core = new BinderCore();
260 this.core.FileManagerCore = fileManagerCore;
261
262 this.WriteBuildInfoTable(output, file);
263
264 // Initialize extensions.
265 foreach (IBinderExtension extension in this.extensions)
266 {
267 extension.Core = this.core;
268
269 extension.Initialize(output);
270 }
271
272 // Gather all the wix variables.
273 //Table wixVariableTable = output.Tables["WixVariable"];
274 //if (null != wixVariableTable)
275 //{
276 // foreach (WixVariableRow wixVariableRow in wixVariableTable.Rows)
277 // {
278 // this.WixVariableResolver.AddVariable(wixVariableRow);
279 // }
280 //}
281
282 //BindContext context = new BindContext();
283 //context.CabbingThreadCount = this.CabbingThreadCount;
284 //context.DefaultCompressionLevel = this.DefaultCompressionLevel;
285 //context.Extensions = this.extensions;
286 //context.FileManagerCore = fileManagerCore;
287 //context.FileManagers = this.fileManagers;
288 //context.Ices = this.Ices;
289 //context.IntermediateFolder = this.TempFilesLocation;
290 //context.IntermediateRepresentation = output;
291 //context.Localizer = this.Localizer;
292 //context.OutputPath = file;
293 //context.OutputPdbPath = this.PdbFile;
294 //context.SuppressIces = this.SuppressIces;
295 //context.SuppressValidation = this.SuppressValidation;
296 //context.WixVariableResolver = this.WixVariableResolver;
297
298 BindResult result = null;
299
300 foreach (var factory in this.BackendFactories)
301 {
302 if (factory.TryCreateBackend(output.Type.ToString(), file, null, out var backend))
303 {
304 result = backend.Bind(context);
305 break;
306 }
307 }
308 105
309 if (result == null) 106 var backendFactories = extensionManager.Create<IBackendFactory>();
310 {
311 // TODO: messaging that a backend could not be found to bind the output type?
312 107
313 return false; 108 var entrySection = context.IntermediateRepresentation.Sections[0];
314 }
315 109
316 // Layout media 110 foreach (var factory in backendFactories)
317 try
318 {
319 this.LayoutMedia(result.FileTransfers);
320 }
321 finally
322 { 111 {
323 if (!String.IsNullOrEmpty(this.ContentsFile) && result.ContentFilePaths != null) 112 if (factory.TryCreateBackend(entrySection.Type.ToString(), context.OutputPath, null, out var backend))
324 {
325 this.CreateContentsFile(this.ContentsFile, result.ContentFilePaths);
326 }
327
328 if (!String.IsNullOrEmpty(this.OutputsFile) && result.FileTransfers != null)
329 { 113 {
330 this.CreateOutputsFile(this.OutputsFile, result.FileTransfers, this.PdbFile); 114 var result = backend.Bind(context);
331 } 115 return result;
332
333 if (!String.IsNullOrEmpty(this.BuiltOutputsFile) && result.FileTransfers != null)
334 {
335 this.CreateBuiltOutputsFile(this.BuiltOutputsFile, result.FileTransfers, this.PdbFile);
336 } 116 }
337 } 117 }
338 118
339 this.core = null; 119 // TODO: messaging that a backend could not be found to bind the output type?
340 120
341 return Messaging.Instance.EncounteredError; 121 return null;
342 } 122 }
343#endif 123
344 124 private void WriteBuildInfoTable(Intermediate output, string outputFile, string outputPdbPath)
345 /// <summary>
346 /// Populates the WixBuildInfo table in an output.
347 /// </summary>
348 /// <param name="output">The output.</param>
349 /// <param name="databaseFile">The output file if OutputFile not set.</param>
350 private void WriteBuildInfoTable(Intermediate output, string outputFile)
351 { 125 {
352 var entrySection = output.Sections.First(s => s.Type != SectionType.Fragment); 126 var entrySection = output.Sections.First(s => s.Type != SectionType.Fragment);
353 127
@@ -358,117 +132,12 @@ namespace WixToolset.Core
358 buildInfoRow.WixVersion = fileVersion.FileVersion; 132 buildInfoRow.WixVersion = fileVersion.FileVersion;
359 buildInfoRow.WixOutputFile = outputFile; 133 buildInfoRow.WixOutputFile = outputFile;
360 134
361 if (!String.IsNullOrEmpty(this.Context.WixprojectFile)) 135 if (!String.IsNullOrEmpty(outputPdbPath))
362 {
363 buildInfoRow.WixProjectFile = this.Context.WixprojectFile;
364 }
365
366 if (!String.IsNullOrEmpty(this.Context.OutputPdbPath))
367 { 136 {
368 buildInfoRow.WixPdbFile = this.Context.OutputPdbPath; 137 buildInfoRow.WixPdbFile = outputPdbPath;
369 } 138 }
370 139
371 entrySection.Tuples.Add(buildInfoRow); 140 entrySection.Tuples.Add(buildInfoRow);
372 } 141 }
373
374#if DELETE_THIS_CODE
375 /// <summary>
376 /// Binds a bundle.
377 /// </summary>
378 /// <param name="bundle">The bundle to bind.</param>
379 /// <param name="bundleFile">The bundle to create.</param>
380 private void BindBundle(Output bundle, string bundleFile, out IEnumerable<FileTransfer> fileTransfers, out IEnumerable<string> contentPaths)
381 {
382 BindBundleCommand command = new BindBundleCommand();
383 command.DefaultCompressionLevel = this.DefaultCompressionLevel;
384 command.Extensions = this.extensions;
385 command.FileManagerCore = this.fileManagerCore;
386 command.FileManagers = this.fileManagers;
387 command.Output = bundle;
388 command.OutputPath = bundleFile;
389 command.PdbFile = this.PdbFile;
390 command.TableDefinitions = this.core.TableDefinitions;
391 command.TempFilesLocation = this.TempFilesLocation;
392 command.WixVariableResolver = this.WixVariableResolver;
393 command.Execute();
394
395 fileTransfers = command.FileTransfers;
396 contentPaths = command.ContentFilePaths;
397 }
398
399 /// <summary>
400 /// Binds a databse.
401 /// </summary>
402 /// <param name="output">The output to bind.</param>
403 /// <param name="databaseFile">The database file to create.</param>
404 private void BindDatabase(Output output, string databaseFile, out IEnumerable<FileTransfer> fileTransfers, out IEnumerable<string> contentPaths)
405 {
406 Validator validator = null;
407
408 // tell the binder about the validator if validation isn't suppressed
409 if (!this.SuppressValidation && (OutputType.Module == output.Type || OutputType.Product == output.Type))
410 {
411 validator = new Validator();
412 validator.TempFilesLocation = Path.Combine(this.TempFilesLocation, "validate");
413
414 // set the default cube file
415 string lightDirectory = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
416 string cubePath = (OutputType.Module == output.Type) ? Path.Combine(lightDirectory, "mergemod.cub") : Path.Combine(lightDirectory, "darice.cub");
417 validator.AddCubeFile(cubePath);
418
419 // by default, disable ICEs that have equivalent-or-better checks in WiX
420 this.SuppressIces.Add("ICE08");
421 this.SuppressIces.Add("ICE33");
422 this.SuppressIces.Add("ICE47");
423 this.SuppressIces.Add("ICE66");
424
425 // set the ICEs
426 validator.ICEs = this.Ices.ToArray();
427
428 // set the suppressed ICEs
429 validator.SuppressedICEs = this.SuppressIces.ToArray();
430 }
431
432 BindDatabaseCommand command = new BindDatabaseCommand();
433 command.CabbingThreadCount = this.CabbingThreadCount;
434 command.Codepage = this.Localizer == null ? -1 : this.Localizer.Codepage;
435 command.DefaultCompressionLevel = this.DefaultCompressionLevel;
436 command.Extensions = this.extensions;
437 command.FileManagerCore = this.fileManagerCore;
438 command.FileManagers = this.fileManagers;
439 command.InspectorExtensions = this.inspectorExtensions;
440 command.Localizer = this.Localizer;
441 command.PdbFile = this.PdbFile;
442 command.Output = output;
443 command.OutputPath = databaseFile;
444 command.SuppressAddingValidationRows = this.SuppressAddingValidationRows;
445 command.SuppressLayout = this.SuppressLayout;
446 command.TableDefinitions = this.core.TableDefinitions;
447 command.TempFilesLocation = this.TempFilesLocation;
448 command.Validator = validator;
449 command.WixVariableResolver = this.WixVariableResolver;
450 command.Execute();
451
452 fileTransfers = command.FileTransfers;
453 contentPaths = command.ContentFilePaths;
454 }
455
456 /// <summary>
457 /// Binds a transform.
458 /// </summary>
459 /// <param name="transform">The transform to bind.</param>
460 /// <param name="outputPath">The transform to create.</param>
461 private void BindTransform(Output transform, string outputPath)
462 {
463 BindTransformCommand command = new BindTransformCommand();
464 command.Extensions = this.extensions;
465 command.FileManagers = this.fileManagers;
466 command.TableDefinitions = this.core.TableDefinitions;
467 command.TempFilesLocation = this.TempFilesLocation;
468 command.Transform = transform;
469 command.OutputPath = outputPath;
470 command.Execute();
471 }
472#endif
473 } 142 }
474} 143}
diff --git a/src/WixToolset.Core/CommandLine/BuildCommand.cs b/src/WixToolset.Core/CommandLine/BuildCommand.cs
index 92aa3343..5653afca 100644
--- a/src/WixToolset.Core/CommandLine/BuildCommand.cs
+++ b/src/WixToolset.Core/CommandLine/BuildCommand.cs
@@ -1,6 +1,6 @@
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. 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 2
3namespace WixToolset.Core 3namespace WixToolset.Core.CommandLine
4{ 4{
5 using System; 5 using System;
6 using System.Collections.Generic; 6 using System.Collections.Generic;
@@ -13,7 +13,7 @@ namespace WixToolset.Core
13 13
14 internal class BuildCommand : ICommandLineCommand 14 internal class BuildCommand : ICommandLineCommand
15 { 15 {
16 public BuildCommand(IServiceProvider serviceProvider, IMessaging messaging, IExtensionManager extensions, IEnumerable<SourceFile> sources, IDictionary<string, string> preprocessorVariables, IEnumerable<string> locFiles, IEnumerable<string> libraryFiles, string outputPath, OutputType outputType, string cabCachePath, IEnumerable<string> cultures, bool bindFiles, IEnumerable<BindPath> bindPaths, string intermediateFolder, string contentsFile, string outputsFile, string builtOutputsFile, string wixProjectFile) 16 public BuildCommand(IServiceProvider serviceProvider, IMessaging messaging, IExtensionManager extensions, IEnumerable<SourceFile> sources, IDictionary<string, string> preprocessorVariables, IEnumerable<string> locFiles, IEnumerable<string> libraryFiles, string outputPath, OutputType outputType, string cabCachePath, IEnumerable<string> cultures, bool bindFiles, IEnumerable<BindPath> bindPaths, string intermediateFolder, string contentsFile, string outputsFile, string builtOutputsFile)
17 { 17 {
18 this.ServiceProvider = serviceProvider; 18 this.ServiceProvider = serviceProvider;
19 this.Messaging = messaging; 19 this.Messaging = messaging;
@@ -34,7 +34,6 @@ namespace WixToolset.Core
34 this.ContentsFile = contentsFile; 34 this.ContentsFile = contentsFile;
35 this.OutputsFile = outputsFile; 35 this.OutputsFile = outputsFile;
36 this.BuiltOutputsFile = builtOutputsFile; 36 this.BuiltOutputsFile = builtOutputsFile;
37 this.WixProjectFile = wixProjectFile;
38 } 37 }
39 38
40 public IServiceProvider ServiceProvider { get; } 39 public IServiceProvider ServiceProvider { get; }
@@ -73,8 +72,6 @@ namespace WixToolset.Core
73 72
74 public string BuiltOutputsFile { get; } 73 public string BuiltOutputsFile { get; }
75 74
76 public string WixProjectFile { get; }
77
78 public int Execute() 75 public int Execute()
79 { 76 {
80 var intermediates = this.CompilePhase(); 77 var intermediates = this.CompilePhase();
@@ -207,7 +204,12 @@ namespace WixToolset.Core
207 204
208 ResolveResult resolveResult; 205 ResolveResult resolveResult;
209 { 206 {
210 var resolver = new Resolver(this.ServiceProvider, this.BindPaths, output, this.IntermediateFolder, localizations); 207 var resolver = new Resolver(this.ServiceProvider);
208 resolver.BindPaths = this.BindPaths;
209 resolver.IntermediateFolder = this.IntermediateFolder;
210 resolver.IntermediateRepresentation = output;
211 resolver.Localizations = localizations;
212
211 resolveResult = resolver.Execute(); 213 resolveResult = resolver.Execute();
212 } 214 }
213 215
@@ -224,28 +226,22 @@ namespace WixToolset.Core
224 intermediateFolder = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName()); 226 intermediateFolder = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());
225 } 227 }
226 228
227 var context = this.ServiceProvider.GetService<IBindContext>(); 229 var binder = new Binder(this.ServiceProvider);
228 context.Messaging = this.Messaging; 230 //binder.CabbingThreadCount = this.CabbingThreadCount;
229 //context.CabbingThreadCount = this.CabbingThreadCount; 231 binder.CabCachePath = this.CabCachePath;
230 context.CabCachePath = this.CabCachePath; 232 binder.Codepage = resolveResult.Codepage;
231 context.Codepage = resolveResult.Codepage; 233 //binder.DefaultCompressionLevel = this.DefaultCompressionLevel;
232 //context.DefaultCompressionLevel = this.DefaultCompressionLevel; 234 binder.DelayedFields = resolveResult.DelayedFields;
233 context.DelayedFields = resolveResult.DelayedFields; 235 binder.ExpectedEmbeddedFiles = resolveResult.ExpectedEmbeddedFiles;
234 context.ExpectedEmbeddedFiles = resolveResult.ExpectedEmbeddedFiles; 236 binder.Ices = Array.Empty<string>(); // TODO: set this correctly
235 //context.Ices = this.Ices; 237 binder.IntermediateFolder = intermediateFolder;
236 context.IntermediateFolder = intermediateFolder; 238 binder.IntermediateRepresentation = resolveResult.IntermediateRepresentation;
237 context.IntermediateRepresentation = resolveResult.IntermediateRepresentation; 239 binder.OutputPath = this.OutputPath;
238 context.OutputPath = this.OutputPath; 240 binder.OutputPdbPath = Path.ChangeExtension(this.OutputPath, ".wixpdb");
239 context.OutputPdbPath = Path.ChangeExtension(this.OutputPath, ".wixpdb"); 241 binder.SuppressIces = Array.Empty<string>(); // TODO: set this correctly
240 //context.SuppressIces = this.SuppressIces; 242 binder.SuppressValidation = true; // TODO: set this correctly
241 context.SuppressValidation = true; // TODO: set this correctly 243
242 context.ContentsFile = this.ContentsFile; 244 bindResult = binder.Execute();
243 context.OutputsFile = this.OutputsFile;
244 context.BuiltOutputsFile = this.BuiltOutputsFile;
245 context.WixprojectFile = this.WixProjectFile;
246
247 var binder = new Binder();
248 bindResult = binder.Bind(context);
249 } 245 }
250 246
251 if (this.Messaging.EncounteredError) 247 if (this.Messaging.EncounteredError)
@@ -254,8 +250,14 @@ namespace WixToolset.Core
254 } 250 }
255 251
256 { 252 {
257 // TODO: correctly set SuppressAclReset bool at the end. 253 var layout = new Layout(this.ServiceProvider);
258 var layout = new Layout(this.ServiceProvider, bindResult.FileTransfers, bindResult.ContentFilePaths, this.ContentsFile, this.OutputsFile, this.BuiltOutputsFile, false); 254 layout.FileTransfers = bindResult.FileTransfers;
255 layout.ContentFilePaths = bindResult.ContentFilePaths;
256 layout.ContentsFile = this.ContentsFile;
257 layout.OutputsFile = this.OutputsFile;
258 layout.BuiltOutputsFile = this.BuiltOutputsFile;
259 layout.SuppressAclReset = false; // TODO: correctly set SuppressAclReset
260
259 layout.Execute(); 261 layout.Execute();
260 } 262 }
261 } 263 }
diff --git a/src/WixToolset.Core/CommandLine/CommandLineContext.cs b/src/WixToolset.Core/CommandLine/CommandLineContext.cs
index cbb9af53..2ff2c1fd 100644
--- a/src/WixToolset.Core/CommandLine/CommandLineContext.cs
+++ b/src/WixToolset.Core/CommandLine/CommandLineContext.cs
@@ -1,6 +1,6 @@
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. 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 2
3namespace WixToolset.Core 3namespace WixToolset.Core.CommandLine
4{ 4{
5 using System; 5 using System;
6 using WixToolset.Extensibility.Services; 6 using WixToolset.Extensibility.Services;
diff --git a/src/WixToolset.Core/CommandLine/CommandLineHelper.cs b/src/WixToolset.Core/CommandLine/CommandLineHelper.cs
new file mode 100644
index 00000000..51ece0f7
--- /dev/null
+++ b/src/WixToolset.Core/CommandLine/CommandLineHelper.cs
@@ -0,0 +1,216 @@
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.Core.CommandLine
4{
5 using System;
6 using System.IO;
7 using WixToolset.Data;
8 using WixToolset.Extensibility.Services;
9
10 public class CommandLineHelper
11 {
12 /// <summary>
13 /// Validates that a string is a valid directory name, and throws appropriate warnings/errors if not
14 /// </summary>
15 /// <param name="commandlineSwitch">The commandline switch we're parsing (for error display purposes).</param>
16 /// <param name="messageHandler">The messagehandler to report warnings/errors to.</param>
17 /// <param name="args">The list of strings to check.</param>
18 /// <param name="index">The index (in args) of the commandline parameter to be parsed.</param>
19 /// <returns>The string if it is valid, null if it is invalid.</returns>
20 public static string GetDirectory(string commandlineSwitch, IMessaging messageHandler, string[] args, int index)
21 {
22 return GetDirectory(commandlineSwitch, messageHandler, args, index, false);
23 }
24
25 /// <summary>
26 /// Validates that a string is a valid directory name, and throws appropriate warnings/errors if not
27 /// </summary>
28 /// <param name="commandlineSwitch">The commandline switch we're parsing (for error display purposes).</param>
29 /// <param name="messageHandler">The messagehandler to report warnings/errors to.</param>
30 /// <param name="args">The list of strings to check.</param>
31 /// <param name="index">The index (in args) of the commandline parameter to be parsed.</param>
32 /// <param name="allowPrefix">Indicates if a colon-delimited prefix is allowed.</param>
33 /// <returns>The string if it is valid, null if it is invalid.</returns>
34 public static string GetDirectory(string commandlineSwitch, IMessaging messageHandler, string[] args, int index, bool allowPrefix)
35 {
36 commandlineSwitch = String.Concat("-", commandlineSwitch);
37
38 if (!IsValidArg(args, index))
39 {
40 messageHandler.Write(ErrorMessages.DirectoryPathRequired(commandlineSwitch));
41 return null;
42 }
43
44 if (File.Exists(args[index]))
45 {
46 messageHandler.Write(ErrorMessages.ExpectedDirectoryGotFile(commandlineSwitch, args[index]));
47 return null;
48 }
49
50 return VerifyPath(messageHandler, args[index], allowPrefix);
51 }
52
53 /// <summary>
54 /// Validates that a string is a valid filename, and throws appropriate warnings/errors if not
55 /// </summary>
56 /// <param name="commandlineSwitch">The commandline switch we're parsing (for error display purposes).</param>
57 /// <param name="messageHandler">The messagehandler to report warnings/errors to.</param>
58 /// <param name="args">The list of strings to check.</param>
59 /// <param name="index">The index (in args) of the commandline parameter to be parsed.</param>
60 /// <returns>The string if it is valid, null if it is invalid.</returns>
61 public static string GetFile(string commandlineSwitch, IMessaging messageHandler, string[] args, int index)
62 {
63 commandlineSwitch = String.Concat("-", commandlineSwitch);
64
65 if (!IsValidArg(args, index))
66 {
67 messageHandler.Write(ErrorMessages.FilePathRequired(commandlineSwitch));
68 return null;
69 }
70
71 if (Directory.Exists(args[index]))
72 {
73 messageHandler.Write(ErrorMessages.ExpectedFileGotDirectory(commandlineSwitch, args[index]));
74 return null;
75 }
76
77 return VerifyPath(messageHandler, args[index]);
78 }
79
80 /// <summary>
81 /// Get a set of files that possibly have a search pattern in the path (such as '*').
82 /// </summary>
83 /// <param name="searchPath">Search path to find files in.</param>
84 /// <param name="fileType">Type of file; typically "Source".</param>
85 /// <returns>An array of files matching the search path.</returns>
86 /// <remarks>
87 /// This method is written in this verbose way because it needs to support ".." in the path.
88 /// It needs the directory path isolated from the file name in order to use Directory.GetFiles
89 /// or DirectoryInfo.GetFiles. The only way to get this directory path is manually since
90 /// Path.GetDirectoryName does not support ".." in the path.
91 /// </remarks>
92 /// <exception cref="WixFileNotFoundException">Throws WixFileNotFoundException if no file matching the pattern can be found.</exception>
93 public static string[] GetFiles(string searchPath, string fileType)
94 {
95 if (null == searchPath)
96 {
97 throw new ArgumentNullException(nameof(searchPath));
98 }
99
100 // Convert alternate directory separators to the standard one.
101 string filePath = searchPath.Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar);
102 int lastSeparator = filePath.LastIndexOf(Path.DirectorySeparatorChar);
103 string[] files = null;
104
105 try
106 {
107 if (0 > lastSeparator)
108 {
109 files = Directory.GetFiles(".", filePath);
110 }
111 else // found directory separator
112 {
113 files = Directory.GetFiles(filePath.Substring(0, lastSeparator + 1), filePath.Substring(lastSeparator + 1));
114 }
115 }
116 catch (DirectoryNotFoundException)
117 {
118 // Don't let this function throw the DirectoryNotFoundException. This exception
119 // occurs for non-existant directories and invalid characters in the searchPattern.
120 }
121 catch (ArgumentException)
122 {
123 // Don't let this function throw the ArgumentException. This exception
124 // occurs in certain situations such as when passing a malformed UNC path.
125 }
126 catch (IOException)
127 {
128 throw new WixFileNotFoundException(searchPath, fileType);
129 }
130
131 if (null == files || 0 == files.Length)
132 {
133 throw new WixFileNotFoundException(searchPath, fileType);
134 }
135
136 return files;
137 }
138
139 /// <summary>
140 /// Validates that a valid string parameter (without "/" or "-"), and returns a bool indicating its validity
141 /// </summary>
142 /// <param name="args">The list of strings to check.</param>
143 /// <param name="index">The index (in args) of the commandline parameter to be validated.</param>
144 /// <returns>True if a valid string parameter exists there, false if not.</returns>
145 public static bool IsValidArg(string[] args, int index)
146 {
147 if (args.Length <= index || String.IsNullOrEmpty(args[index]) || '/' == args[index][0] || '-' == args[index][0])
148 {
149 return false;
150 }
151 else
152 {
153 return true;
154 }
155 }
156
157 /// <summary>
158 /// Validates that a commandline parameter is a valid file or directory name, and throws appropriate warnings/errors if not
159 /// </summary>
160 /// <param name="messageHandler">The messagehandler to report warnings/errors to.</param>
161 /// <param name="path">The path to test.</param>
162 /// <returns>The string if it is valid, null if it is invalid.</returns>
163 public static string VerifyPath(IMessaging messageHandler, string path)
164 {
165 return VerifyPath(messageHandler, path, false);
166 }
167
168 /// <summary>
169 /// Validates that a commandline parameter is a valid file or directory name, and throws appropriate warnings/errors if not
170 /// </summary>
171 /// <param name="messageHandler">The messagehandler to report warnings/errors to.</param>
172 /// <param name="path">The path to test.</param>
173 /// <param name="allowPrefix">Indicates if a colon-delimited prefix is allowed.</param>
174 /// <returns>The full path if it is valid, null if it is invalid.</returns>
175 public static string VerifyPath(IMessaging messageHandler, string path, bool allowPrefix)
176 {
177 string fullPath;
178
179 if (0 <= path.IndexOf('\"'))
180 {
181 messageHandler.Write(ErrorMessages.PathCannotContainQuote(path));
182 return null;
183 }
184
185 try
186 {
187 string prefix = null;
188 if (allowPrefix)
189 {
190 int prefixLength = path.IndexOf('=') + 1;
191 if (0 != prefixLength)
192 {
193 prefix = path.Substring(0, prefixLength);
194 path = path.Substring(prefixLength);
195 }
196 }
197
198 if (String.IsNullOrEmpty(prefix))
199 {
200 fullPath = Path.GetFullPath(path);
201 }
202 else
203 {
204 fullPath = String.Concat(prefix, Path.GetFullPath(path));
205 }
206 }
207 catch (Exception e)
208 {
209 messageHandler.Write(ErrorMessages.InvalidCommandLineFileName(path, e.Message));
210 return null;
211 }
212
213 return fullPath;
214 }
215 }
216}
diff --git a/src/WixToolset.Core/CommandLine/CommandLine.cs b/src/WixToolset.Core/CommandLine/CommandLineParser.cs
index 97f79755..0e7da42a 100644
--- a/src/WixToolset.Core/CommandLine/CommandLine.cs
+++ b/src/WixToolset.Core/CommandLine/CommandLineParser.cs
@@ -1,6 +1,6 @@
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. 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 2
3namespace WixToolset.Core 3namespace WixToolset.Core.CommandLine
4{ 4{
5 using System; 5 using System;
6 using System.Collections.Generic; 6 using System.Collections.Generic;
@@ -22,7 +22,7 @@ namespace WixToolset.Core
22 Bind, 22 Bind,
23 } 23 }
24 24
25 internal class CommandLine : ICommandLine, IParseCommandLine 25 internal class CommandLineParser : ICommandLine, IParseCommandLine
26 { 26 {
27 private IServiceProvider ServiceProvider { get; set; } 27 private IServiceProvider ServiceProvider { get; set; }
28 28
@@ -54,7 +54,7 @@ namespace WixToolset.Core
54 54
55 if (!String.IsNullOrEmpty(context.Arguments)) 55 if (!String.IsNullOrEmpty(context.Arguments))
56 { 56 {
57 args = CommandLine.ParseArgumentsToArray(context.Arguments).Union(args).ToArray(); 57 args = CommandLineParser.ParseArgumentsToArray(context.Arguments).Union(args).ToArray();
58 } 58 }
59 59
60 return this.ParseStandardCommandLine(context, args); 60 return this.ParseStandardCommandLine(context, args);
@@ -88,13 +88,12 @@ namespace WixToolset.Core
88 var contentsFile = String.Empty; 88 var contentsFile = String.Empty;
89 var outputsFile = String.Empty; 89 var outputsFile = String.Empty;
90 var builtOutputsFile = String.Empty; 90 var builtOutputsFile = String.Empty;
91 var wixProjectFile = String.Empty;
92 91
93 this.Parse(context, args, (cmdline, arg) => Enum.TryParse(arg, true, out command), (cmdline, arg) => 92 this.Parse(context, args, (cmdline, arg) => Enum.TryParse(arg, true, out command), (cmdline, arg) =>
94 { 93 {
95 if (cmdline.IsSwitch(arg)) 94 if (cmdline.IsSwitch(arg))
96 { 95 {
97 var parameter = arg.TrimStart(new[] { '-', '/' }); 96 var parameter = arg.Substring(1);
98 switch (parameter.ToLowerInvariant()) 97 switch (parameter.ToLowerInvariant())
99 { 98 {
100 case "?": 99 case "?":
@@ -127,9 +126,6 @@ namespace WixToolset.Core
127 case "builtoutputsfile": 126 case "builtoutputsfile":
128 cmdline.GetNextArgumentOrError(ref builtOutputsFile); 127 cmdline.GetNextArgumentOrError(ref builtOutputsFile);
129 return true; 128 return true;
130 case "wixprojectfile":
131 cmdline.GetNextArgumentOrError(ref wixProjectFile);
132 return true;
133 129
134 case "d": 130 case "d":
135 case "define": 131 case "define":
@@ -181,7 +177,7 @@ namespace WixToolset.Core
181 } 177 }
182 else 178 else
183 { 179 {
184 files.AddRange(cmdline.GetFiles(arg, "source code")); 180 files.AddRange(CommandLineHelper.GetFiles(arg, "source code"));
185 return true; 181 return true;
186 } 182 }
187 }); 183 });
@@ -211,7 +207,7 @@ namespace WixToolset.Core
211 var variables = this.GatherPreprocessorVariables(defines); 207 var variables = this.GatherPreprocessorVariables(defines);
212 var bindPathList = this.GatherBindPaths(bindPaths); 208 var bindPathList = this.GatherBindPaths(bindPaths);
213 var type = CalculateOutputType(outputType, outputFile); 209 var type = CalculateOutputType(outputType, outputFile);
214 return new BuildCommand(this.ServiceProvider, this.Messaging, this.ExtensionManager, sourceFiles, variables, locFiles, libraryFiles, outputFile, type, cabCachePath, cultures, bindFiles, bindPathList, intermediateFolder, contentsFile, outputsFile, builtOutputsFile, wixProjectFile); 210 return new BuildCommand(this.ServiceProvider, this.Messaging, this.ExtensionManager, sourceFiles, variables, locFiles, libraryFiles, outputFile, type, cabCachePath, cultures, bindFiles, bindPathList, intermediateFolder, contentsFile, outputsFile, builtOutputsFile);
215 } 211 }
216 212
217 case Commands.Compile: 213 case Commands.Compile:
@@ -283,7 +279,7 @@ namespace WixToolset.Core
283 } 279 }
284#endif 280#endif
285 281
286 private ICommandLine Parse(ICommandLineContext context, string[] commandLineArguments, Func<CommandLine, string, bool> parseCommand, Func<CommandLine, string, bool> parseArgument) 282 private ICommandLine Parse(ICommandLineContext context, string[] commandLineArguments, Func<CommandLineParser, string, bool> parseCommand, Func<CommandLineParser, string, bool> parseArgument)
287 { 283 {
288 this.FlattenArgumentsWithResponseFilesIntoOriginalArguments(commandLineArguments); 284 this.FlattenArgumentsWithResponseFilesIntoOriginalArguments(commandLineArguments);
289 285
@@ -335,7 +331,7 @@ namespace WixToolset.Core
335 331
336 foreach (var bindPath in bindPaths) 332 foreach (var bindPath in bindPaths)
337 { 333 {
338 BindPath bp = BindPath.Parse(bindPath); 334 var bp = BindPath.Parse(bindPath);
339 335
340 if (Directory.Exists(bp.Path)) 336 if (Directory.Exists(bp.Path))
341 { 337 {
@@ -351,65 +347,6 @@ namespace WixToolset.Core
351 } 347 }
352 348
353 /// <summary> 349 /// <summary>
354 /// Get a set of files that possibly have a search pattern in the path (such as '*').
355 /// </summary>
356 /// <param name="searchPath">Search path to find files in.</param>
357 /// <param name="fileType">Type of file; typically "Source".</param>
358 /// <returns>An array of files matching the search path.</returns>
359 /// <remarks>
360 /// This method is written in this verbose way because it needs to support ".." in the path.
361 /// It needs the directory path isolated from the file name in order to use Directory.GetFiles
362 /// or DirectoryInfo.GetFiles. The only way to get this directory path is manually since
363 /// Path.GetDirectoryName does not support ".." in the path.
364 /// </remarks>
365 /// <exception cref="WixFileNotFoundException">Throws WixFileNotFoundException if no file matching the pattern can be found.</exception>
366 public string[] GetFiles(string searchPath, string fileType)
367 {
368 if (null == searchPath)
369 {
370 throw new ArgumentNullException(nameof(searchPath));
371 }
372
373 // Convert alternate directory separators to the standard one.
374 string filePath = searchPath.Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar);
375 int lastSeparator = filePath.LastIndexOf(Path.DirectorySeparatorChar);
376 string[] files = null;
377
378 try
379 {
380 if (0 > lastSeparator)
381 {
382 files = Directory.GetFiles(".", filePath);
383 }
384 else // found directory separator
385 {
386 files = Directory.GetFiles(filePath.Substring(0, lastSeparator + 1), filePath.Substring(lastSeparator + 1));
387 }
388 }
389 catch (DirectoryNotFoundException)
390 {
391 // Don't let this function throw the DirectoryNotFoundException. This exception
392 // occurs for non-existant directories and invalid characters in the searchPattern.
393 }
394 catch (ArgumentException)
395 {
396 // Don't let this function throw the ArgumentException. This exception
397 // occurs in certain situations such as when passing a malformed UNC path.
398 }
399 catch (IOException)
400 {
401 throw new WixFileNotFoundException(searchPath, fileType);
402 }
403
404 if (null == files || 0 == files.Length)
405 {
406 throw new WixFileNotFoundException(searchPath, fileType);
407 }
408
409 return files;
410 }
411
412 /// <summary>
413 /// Validates that a valid switch (starts with "/" or "-"), and returns a bool indicating its validity 350 /// Validates that a valid switch (starts with "/" or "-"), and returns a bool indicating its validity
414 /// </summary> 351 /// </summary>
415 /// <param name="args">The list of strings to check.</param> 352 /// <param name="args">The list of strings to check.</param>
@@ -449,7 +386,7 @@ namespace WixToolset.Core
449 { 386 {
450 if (this.TryGetNextArgumentOrError(out var arg)) 387 if (this.TryGetNextArgumentOrError(out var arg))
451 { 388 {
452 foreach (var path in this.GetFiles(arg, fileType)) 389 foreach (var path in CommandLineHelper.GetFiles(arg, fileType))
453 { 390 {
454 args.Add(path); 391 args.Add(path);
455 } 392 }
@@ -458,13 +395,12 @@ namespace WixToolset.Core
458 395
459 public bool TryGetNextArgumentOrError(out string arg) 396 public bool TryGetNextArgumentOrError(out string arg)
460 { 397 {
461 //if (this.RemainingArguments.TryDequeue(out arg) && !this.IsSwitch(arg))
462 if (TryDequeue(this.RemainingArguments, out arg) && !this.IsSwitch(arg)) 398 if (TryDequeue(this.RemainingArguments, out arg) && !this.IsSwitch(arg))
463 { 399 {
464 return true; 400 return true;
465 } 401 }
466 402
467 this.ErrorArgument = arg ?? CommandLine.ExpectedArgument; 403 this.ErrorArgument = arg ?? CommandLineParser.ExpectedArgument;
468 404
469 return false; 405 return false;
470 } 406 }
@@ -489,7 +425,7 @@ namespace WixToolset.Core
489 { 425 {
490 if ('@' == arg[0]) 426 if ('@' == arg[0])
491 { 427 {
492 var responseFileArguments = CommandLine.ParseResponseFile(arg.Substring(1)); 428 var responseFileArguments = CommandLineParser.ParseResponseFile(arg.Substring(1));
493 args.AddRange(responseFileArguments); 429 args.AddRange(responseFileArguments);
494 } 430 }
495 else 431 else
@@ -526,7 +462,7 @@ namespace WixToolset.Core
526 } 462 }
527 } 463 }
528 464
529 private void ProcessRemainingArguments(ICommandLineContext context, Func<CommandLine, string, bool> parseArgument, Func<CommandLine, string, bool> parseCommand) 465 private void ProcessRemainingArguments(ICommandLineContext context, Func<CommandLineParser, string, bool> parseArgument, Func<CommandLineParser, string, bool> parseCommand)
530 { 466 {
531 var extensions = this.ExtensionManager.Create<IExtensionCommandLine>(); 467 var extensions = this.ExtensionManager.Create<IExtensionCommandLine>();
532 468
@@ -593,7 +529,7 @@ namespace WixToolset.Core
593 arguments = reader.ReadToEnd(); 529 arguments = reader.ReadToEnd();
594 } 530 }
595 531
596 return CommandLine.ParseArgumentsToArray(arguments); 532 return CommandLineParser.ParseArgumentsToArray(arguments);
597 } 533 }
598 534
599 private static List<string> ParseArgumentsToArray(string arguments) 535 private static List<string> ParseArgumentsToArray(string arguments)
@@ -631,7 +567,7 @@ namespace WixToolset.Core
631 // Add the argument to the list if it's not empty. 567 // Add the argument to the list if it's not empty.
632 if (arg.Length > 0) 568 if (arg.Length > 0)
633 { 569 {
634 argsList.Add(CommandLine.ExpandEnvironmentVariables(arg.ToString())); 570 argsList.Add(CommandLineParser.ExpandEnvironmentVariables(arg.ToString()));
635 arg.Length = 0; 571 arg.Length = 0;
636 } 572 }
637 } 573 }
diff --git a/src/WixToolset.Core/CommandLine/CommandLineResponseFile.cs b/src/WixToolset.Core/CommandLine/CommandLineResponseFile.cs
index 578c3b22..6922b246 100644
--- a/src/WixToolset.Core/CommandLine/CommandLineResponseFile.cs
+++ b/src/WixToolset.Core/CommandLine/CommandLineResponseFile.cs
@@ -1,6 +1,6 @@
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. 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 2
3namespace WixToolset 3namespace WixToolset.Core.CommandLine
4{ 4{
5 using System; 5 using System;
6 using System.Collections; 6 using System.Collections;
diff --git a/src/WixToolset.Core/CommandLine/CompileCommand.cs b/src/WixToolset.Core/CommandLine/CompileCommand.cs
index 856dd29f..f0ff5b1a 100644
--- a/src/WixToolset.Core/CommandLine/CompileCommand.cs
+++ b/src/WixToolset.Core/CommandLine/CompileCommand.cs
@@ -1,6 +1,6 @@
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. 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 2
3namespace WixToolset.Core 3namespace WixToolset.Core.CommandLine
4{ 4{
5 using System; 5 using System;
6 using System.Collections.Generic; 6 using System.Collections.Generic;
diff --git a/src/WixToolset.Core/CommandLine/HelpCommand.cs b/src/WixToolset.Core/CommandLine/HelpCommand.cs
index 2a2eab24..6e547d60 100644
--- a/src/WixToolset.Core/CommandLine/HelpCommand.cs
+++ b/src/WixToolset.Core/CommandLine/HelpCommand.cs
@@ -1,6 +1,6 @@
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. 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 2
3namespace WixToolset.Core 3namespace WixToolset.Core.CommandLine
4{ 4{
5 using System; 5 using System;
6 using WixToolset.Extensibility.Services; 6 using WixToolset.Extensibility.Services;
diff --git a/src/WixToolset.Core/CommandLine/VersionCommand.cs b/src/WixToolset.Core/CommandLine/VersionCommand.cs
index 12941bdc..a04aac31 100644
--- a/src/WixToolset.Core/CommandLine/VersionCommand.cs
+++ b/src/WixToolset.Core/CommandLine/VersionCommand.cs
@@ -1,6 +1,6 @@
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. 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 2
3namespace WixToolset.Core 3namespace WixToolset.Core.CommandLine
4{ 4{
5 using System; 5 using System;
6 using WixToolset.Extensibility.Services; 6 using WixToolset.Extensibility.Services;
diff --git a/src/WixToolset.Core/Layout.cs b/src/WixToolset.Core/Layout.cs
index d7322a12..b2957fb9 100644
--- a/src/WixToolset.Core/Layout.cs
+++ b/src/WixToolset.Core/Layout.cs
@@ -9,7 +9,6 @@ namespace WixToolset.Core
9 using WixToolset.Core.Bind; 9 using WixToolset.Core.Bind;
10 using WixToolset.Data; 10 using WixToolset.Data;
11 using WixToolset.Data.Bind; 11 using WixToolset.Data.Bind;
12 using WixToolset.Data.Tuples;
13 using WixToolset.Extensibility; 12 using WixToolset.Extensibility;
14 using WixToolset.Extensibility.Services; 13 using WixToolset.Extensibility.Services;
15 14
@@ -18,36 +17,31 @@ namespace WixToolset.Core
18 /// </summary> 17 /// </summary>
19 public sealed class Layout 18 public sealed class Layout
20 { 19 {
21 public Layout(IServiceProvider serviceProvider, IEnumerable<FileTransfer> fileTransfers, IEnumerable<string> contentFilePaths, string contentsFile, string outputsFile, string builtOutputsFile, bool suppressAclReset) 20 public Layout(IServiceProvider serviceProvider)
22 { 21 {
23 this.ServiceProvider = serviceProvider; 22 this.ServiceProvider = serviceProvider;
24 this.FileTransfers = fileTransfers;
25 this.ContentFilePaths = contentFilePaths;
26 this.ContentsFile = contentsFile;
27 this.OutputsFile = outputsFile;
28 this.BuiltOutputsFile = builtOutputsFile;
29 this.SuppressAclReset = suppressAclReset;
30 this.Messaging = this.ServiceProvider.GetService<IMessaging>();
31 } 23 }
32 24
33 private IServiceProvider ServiceProvider { get; } 25 private IServiceProvider ServiceProvider { get; }
34 26
35 private IEnumerable<FileTransfer> FileTransfers { get; } 27 public IEnumerable<FileTransfer> FileTransfers { get; set; }
36 28
37 private IEnumerable<string> ContentFilePaths { get; } 29 public IEnumerable<string> ContentFilePaths { get; set; }
38 30
39 private string ContentsFile { get; } 31 public string ContentsFile { get; set; }
40 32
41 private string OutputsFile { get; } 33 public string OutputsFile { get; set; }
42 34
43 private string BuiltOutputsFile { get; } 35 public string BuiltOutputsFile { get; set; }
44 36
45 private bool SuppressAclReset { get; } 37 public bool SuppressAclReset { get; set; }
46 38
47 private IMessaging Messaging { get; } 39 private IMessaging Messaging { get; set; }
48 40
49 public void Execute() 41 public void Execute()
50 { 42 {
43 this.Messaging = this.ServiceProvider.GetService<IMessaging>();
44
51 var extensionManager = this.ServiceProvider.GetService<IExtensionManager>(); 45 var extensionManager = this.ServiceProvider.GetService<IExtensionManager>();
52 46
53 var context = this.ServiceProvider.GetService<ILayoutContext>(); 47 var context = this.ServiceProvider.GetService<ILayoutContext>();
diff --git a/src/WixToolset.Core/Resolver.cs b/src/WixToolset.Core/Resolver.cs
index b0d3a189..1b72e3d0 100644
--- a/src/WixToolset.Core/Resolver.cs
+++ b/src/WixToolset.Core/Resolver.cs
@@ -16,34 +16,31 @@ namespace WixToolset.Core
16 /// </summary> 16 /// </summary>
17 public sealed class Resolver 17 public sealed class Resolver
18 { 18 {
19 public Resolver(IServiceProvider serviceProvider, IEnumerable<BindPath> bindPaths, Intermediate intermediateRepresentation, string intermediateFolder, IEnumerable<Localization> localizations) 19 public Resolver(IServiceProvider serviceProvider)
20 { 20 {
21 this.ServiceProvider = serviceProvider; 21 this.ServiceProvider = serviceProvider;
22 this.BindPaths = bindPaths;
23 this.IntermediateRepresentation = intermediateRepresentation;
24 this.IntermediateFolder = intermediateFolder;
25 this.Localizations = localizations;
26
27 this.Messaging = this.ServiceProvider.GetService<IMessaging>();
28 } 22 }
29 23
30 private IServiceProvider ServiceProvider { get; } 24 private IServiceProvider ServiceProvider { get; set; }
31 25
32 private IEnumerable<BindPath> BindPaths { get; } 26 public IEnumerable<BindPath> BindPaths { get; set; }
33 27
34 private Intermediate IntermediateRepresentation { get; } 28 public Intermediate IntermediateRepresentation { get; set; }
35 29
36 private string IntermediateFolder { get; } 30 public string IntermediateFolder { get; set; }
37 31
38 private IEnumerable<Localization> Localizations { get; } 32 public IEnumerable<Localization> Localizations { get; set; }
39 33
40 private IMessaging Messaging { get; } 34 private IMessaging Messaging { get; set; }
41 35
42 public ResolveResult Execute() 36 public ResolveResult Execute()
43 { 37 {
38 this.Messaging = this.ServiceProvider.GetService<IMessaging>();
39
44 var localizer = new Localizer(this.Messaging, this.Localizations); 40 var localizer = new Localizer(this.Messaging, this.Localizations);
45 41
46 var variableResolver = new WixVariableResolver(this.Messaging, localizer); 42 var variableResolver = new WixVariableResolver(this.Messaging, localizer);
43 this.PopulateVariableResolver(variableResolver);
47 44
48 var context = this.ServiceProvider.GetService<IResolveContext>(); 45 var context = this.ServiceProvider.GetService<IResolveContext>();
49 context.Messaging = this.Messaging; 46 context.Messaging = this.Messaging;
@@ -51,7 +48,7 @@ namespace WixToolset.Core
51 context.Extensions = this.ServiceProvider.GetService<IExtensionManager>().Create<IResolverExtension>(); 48 context.Extensions = this.ServiceProvider.GetService<IExtensionManager>().Create<IResolverExtension>();
52 context.IntermediateFolder = this.IntermediateFolder; 49 context.IntermediateFolder = this.IntermediateFolder;
53 context.IntermediateRepresentation = this.IntermediateRepresentation; 50 context.IntermediateRepresentation = this.IntermediateRepresentation;
54 context.WixVariableResolver = this.PopulateVariableResolver(variableResolver); 51 context.WixVariableResolver = variableResolver;
55 52
56 // Preresolve. 53 // Preresolve.
57 // 54 //
@@ -212,7 +209,7 @@ namespace WixToolset.Core
212 } 209 }
213 } 210 }
214 211
215 private WixVariableResolver PopulateVariableResolver(WixVariableResolver resolver) 212 private void PopulateVariableResolver(WixVariableResolver resolver)
216 { 213 {
217 // Gather all the wix variables. 214 // Gather all the wix variables.
218 var wixVariableTuples = this.IntermediateRepresentation.Sections.SelectMany(s => s.Tuples).OfType<WixVariableTuple>(); 215 var wixVariableTuples = this.IntermediateRepresentation.Sections.SelectMany(s => s.Tuples).OfType<WixVariableTuple>();
@@ -227,8 +224,6 @@ namespace WixToolset.Core
227 this.Messaging.Write(ErrorMessages.WixVariableCollision(tuple.SourceLineNumbers, tuple.WixVariable)); 224 this.Messaging.Write(ErrorMessages.WixVariableCollision(tuple.SourceLineNumbers, tuple.WixVariable));
228 } 225 }
229 } 226 }
230
231 return resolver;
232 } 227 }
233 } 228 }
234} 229}
diff --git a/src/WixToolset.Core/WixToolsetServiceProvider.cs b/src/WixToolset.Core/WixToolsetServiceProvider.cs
index 74b312c6..a018b8dc 100644
--- a/src/WixToolset.Core/WixToolsetServiceProvider.cs
+++ b/src/WixToolset.Core/WixToolsetServiceProvider.cs
@@ -3,6 +3,7 @@
3namespace WixToolset.Core 3namespace WixToolset.Core
4{ 4{
5 using System; 5 using System;
6 using WixToolset.Core.CommandLine;
6 using WixToolset.Core.ExtensibilityServices; 7 using WixToolset.Core.ExtensibilityServices;
7 using WixToolset.Data; 8 using WixToolset.Data;
8 using WixToolset.Extensibility; 9 using WixToolset.Extensibility;
@@ -64,7 +65,7 @@ namespace WixToolset.Core
64 65
65 if (serviceType == typeof(ICommandLine)) 66 if (serviceType == typeof(ICommandLine))
66 { 67 {
67 return new CommandLine(); 68 return new CommandLineParser();
68 } 69 }
69 70
70 // Singletons. 71 // Singletons.