diff options
author | Rob Mensching <rob@firegiant.com> | 2017-12-22 15:53:01 -0800 |
---|---|---|
committer | Rob Mensching <rob@firegiant.com> | 2017-12-22 15:53:01 -0800 |
commit | ecf3a0cca5a424a91ab98557d963d2535963d582 (patch) | |
tree | 06355e906e5c404480dc6eac342b9b4d2ec9d122 | |
parent | dc9f4c329e6f55ce7595970463e0caf148096f4b (diff) | |
download | wix-ecf3a0cca5a424a91ab98557d963d2535963d582.tar.gz wix-ecf3a0cca5a424a91ab98557d963d2535963d582.tar.bz2 wix-ecf3a0cca5a424a91ab98557d963d2535963d582.zip |
Reintroduce binder extensions and light.exe for binding .wixouts
31 files changed, 1956 insertions, 560 deletions
diff --git a/src/WixToolset.BuildTasks/WixToolTask.cs b/src/WixToolset.BuildTasks/WixToolTask.cs index 7ccf0327..60305e00 100644 --- a/src/WixToolset.BuildTasks/WixToolTask.cs +++ b/src/WixToolset.BuildTasks/WixToolTask.cs | |||
@@ -4,7 +4,6 @@ namespace WixToolset.BuildTasks | |||
4 | { | 4 | { |
5 | using System; | 5 | using System; |
6 | using System.Collections.Generic; | 6 | using System.Collections.Generic; |
7 | using System.Diagnostics; | ||
8 | using System.Diagnostics.CodeAnalysis; | 7 | using System.Diagnostics.CodeAnalysis; |
9 | using System.Globalization; | 8 | using System.Globalization; |
10 | using System.IO; | 9 | using System.IO; |
@@ -14,6 +13,7 @@ namespace WixToolset.BuildTasks | |||
14 | 13 | ||
15 | using Microsoft.Build.Framework; | 14 | using Microsoft.Build.Framework; |
16 | using Microsoft.Build.Utilities; | 15 | using Microsoft.Build.Utilities; |
16 | using WixToolset.Core.CommandLine; | ||
17 | 17 | ||
18 | /// <summary> | 18 | /// <summary> |
19 | /// Base class for WiX tool tasks; executes tools in-process | 19 | /// Base class for WiX tool tasks; executes tools in-process |
diff --git a/src/WixToolset.Core.WindowsInstaller/Bind/BindDatabaseCommand.cs b/src/WixToolset.Core.WindowsInstaller/Bind/BindDatabaseCommand.cs index 2f161305..c47a1e56 100644 --- a/src/WixToolset.Core.WindowsInstaller/Bind/BindDatabaseCommand.cs +++ b/src/WixToolset.Core.WindowsInstaller/Bind/BindDatabaseCommand.cs | |||
@@ -22,7 +22,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
22 | // As outlined in RFC 4122, this is our namespace for generating name-based (version 3) UUIDs. | 22 | // As outlined in RFC 4122, this is our namespace for generating name-based (version 3) UUIDs. |
23 | internal static readonly Guid WixComponentGuidNamespace = new Guid("{3064E5C6-FB63-4FE9-AC49-E446A792EFA5}"); | 23 | internal static readonly Guid WixComponentGuidNamespace = new Guid("{3064E5C6-FB63-4FE9-AC49-E446A792EFA5}"); |
24 | 24 | ||
25 | public BindDatabaseCommand(WixToolset.Extensibility.IBindContext context, IEnumerable<IWindowsInstallerBackendExtension> backendExtension, Validator validator) | 25 | public BindDatabaseCommand(IBindContext context, IEnumerable<IWindowsInstallerBackendExtension> backendExtension, Validator validator) |
26 | { | 26 | { |
27 | this.TableDefinitions = WindowsInstallerStandardInternal.GetTableDefinitions(); | 27 | this.TableDefinitions = WindowsInstallerStandardInternal.GetTableDefinitions(); |
28 | 28 | ||
@@ -49,7 +49,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
49 | 49 | ||
50 | private string CabCachePath { get; } | 50 | private string CabCachePath { get; } |
51 | 51 | ||
52 | private CompressionLevel DefaultCompressionLevel { get; } | 52 | private CompressionLevel? DefaultCompressionLevel { get; } |
53 | 53 | ||
54 | public IEnumerable<IDelayedField> DelayedFields { get; } | 54 | public IEnumerable<IDelayedField> DelayedFields { get; } |
55 | 55 | ||
diff --git a/src/WixToolset.Core.WindowsInstaller/Bind/CreateCabinetsCommand.cs b/src/WixToolset.Core.WindowsInstaller/Bind/CreateCabinetsCommand.cs index 28e7f6df..997ffa09 100644 --- a/src/WixToolset.Core.WindowsInstaller/Bind/CreateCabinetsCommand.cs +++ b/src/WixToolset.Core.WindowsInstaller/Bind/CreateCabinetsCommand.cs | |||
@@ -54,7 +54,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
54 | /// Sets the default compression level to use for cabinets | 54 | /// Sets the default compression level to use for cabinets |
55 | /// that don't have their compression level explicitly set. | 55 | /// that don't have their compression level explicitly set. |
56 | /// </summary> | 56 | /// </summary> |
57 | public CompressionLevel DefaultCompressionLevel { private get; set; } | 57 | public CompressionLevel? DefaultCompressionLevel { private get; set; } |
58 | 58 | ||
59 | public IEnumerable<IWindowsInstallerBackendExtension> BackendExtensions { private get; set; } | 59 | public IEnumerable<IWindowsInstallerBackendExtension> BackendExtensions { private get; set; } |
60 | 60 | ||
@@ -99,7 +99,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
99 | { | 99 | { |
100 | var mediaTuple = entry.Key; | 100 | var mediaTuple = entry.Key; |
101 | IEnumerable<FileFacade> files = entry.Value; | 101 | IEnumerable<FileFacade> files = entry.Value; |
102 | CompressionLevel compressionLevel = this.DefaultCompressionLevel; | 102 | CompressionLevel compressionLevel = this.DefaultCompressionLevel ?? CompressionLevel.Medium; |
103 | 103 | ||
104 | string mediaLayoutFolder = null; | 104 | string mediaLayoutFolder = null; |
105 | 105 | ||
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 | ||
3 | namespace WixToolset.Core | 3 | namespace 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 | ||
3 | namespace WixToolset.Core | 3 | namespace 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 | |||
3 | namespace 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 | ||
3 | namespace WixToolset.Core | 3 | namespace 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 | ||
3 | namespace WixToolset | 3 | namespace 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 | ||
3 | namespace WixToolset.Core | 3 | namespace 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 | ||
3 | namespace WixToolset.Core | 3 | namespace 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 | ||
3 | namespace WixToolset.Core | 3 | namespace 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 @@ | |||
3 | namespace WixToolset.Core | 3 | namespace 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. |
diff --git a/src/light/App.ico b/src/light/App.ico new file mode 100644 index 00000000..3a5525fd --- /dev/null +++ b/src/light/App.ico | |||
Binary files differ | |||
diff --git a/src/light/AssemblyInfo.cs b/src/light/AssemblyInfo.cs new file mode 100644 index 00000000..ab2fc0ab --- /dev/null +++ b/src/light/AssemblyInfo.cs | |||
@@ -0,0 +1,9 @@ | |||
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 | |||
3 | using System; | ||
4 | using System.Reflection; | ||
5 | using System.Runtime.CompilerServices; | ||
6 | using System.Runtime.InteropServices; | ||
7 | |||
8 | [assembly: AssemblyCulture("")] | ||
9 | [assembly: ComVisible(false)] | ||
diff --git a/src/light/LightCommandLine.cs b/src/light/LightCommandLine.cs new file mode 100644 index 00000000..9a90b9ce --- /dev/null +++ b/src/light/LightCommandLine.cs | |||
@@ -0,0 +1,485 @@ | |||
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 | |||
3 | namespace WixToolset.Tools | ||
4 | { | ||
5 | using System; | ||
6 | using System.Collections.Generic; | ||
7 | using System.Globalization; | ||
8 | using System.IO; | ||
9 | using WixToolset.Core.CommandLine; | ||
10 | using WixToolset.Data; | ||
11 | using WixToolset.Extensibility.Services; | ||
12 | |||
13 | public class LightCommandLine | ||
14 | { | ||
15 | public LightCommandLine(IMessaging messaging) | ||
16 | { | ||
17 | this.Messaging = messaging; | ||
18 | this.ShowLogo = true; | ||
19 | this.Tidy = true; | ||
20 | |||
21 | this.CubeFiles = new List<string>(); | ||
22 | this.SuppressIces = new List<string>(); | ||
23 | this.Ices = new List<string>(); | ||
24 | this.BindPaths = new List<BindPath>(); | ||
25 | this.Extensions = new List<string>(); | ||
26 | this.Files = new List<string>(); | ||
27 | this.LocalizationFiles = new List<string>(); | ||
28 | this.Variables = new Dictionary<string, string>(); | ||
29 | } | ||
30 | |||
31 | public IMessaging Messaging { get; } | ||
32 | |||
33 | public string PdbFile { get; private set; } | ||
34 | |||
35 | public CompressionLevel? DefaultCompressionLevel { get; set; } | ||
36 | |||
37 | public bool SuppressAclReset { get; private set; } | ||
38 | |||
39 | public bool SuppressLayout { get; private set; } | ||
40 | |||
41 | public bool SuppressWixPdb { get; private set; } | ||
42 | |||
43 | public bool SuppressValidation { get; private set; } | ||
44 | |||
45 | public string IntermediateFolder { get; private set; } | ||
46 | |||
47 | public string OutputsFile { get; private set; } | ||
48 | |||
49 | public string BuiltOutputsFile { get; private set; } | ||
50 | |||
51 | public string WixprojectFile { get; private set; } | ||
52 | |||
53 | public string ContentsFile { get; private set; } | ||
54 | |||
55 | public List<string> Ices { get; private set; } | ||
56 | |||
57 | public string CabCachePath { get; private set; } | ||
58 | |||
59 | public int CabbingThreadCount { get; private set; } | ||
60 | |||
61 | public List<string> CubeFiles { get; private set; } | ||
62 | |||
63 | public List<string> SuppressIces { get; private set; } | ||
64 | |||
65 | public bool ShowLogo { get; private set; } | ||
66 | |||
67 | public bool ShowHelp { get; private set; } | ||
68 | |||
69 | public bool ShowPedanticMessages { get; private set; } | ||
70 | |||
71 | public bool SuppressLocalization { get; private set; } | ||
72 | |||
73 | public bool SuppressVersionCheck { get; private set; } | ||
74 | |||
75 | public string[] Cultures { get; private set; } | ||
76 | |||
77 | public string OutputFile { get; private set; } | ||
78 | |||
79 | public bool OutputXml { get; private set; } | ||
80 | |||
81 | public List<BindPath> BindPaths { get; private set; } | ||
82 | |||
83 | public List<string> Extensions { get; private set; } | ||
84 | |||
85 | public List<string> Files { get; private set; } | ||
86 | |||
87 | public List<string> LocalizationFiles { get; private set; } | ||
88 | |||
89 | public bool Tidy { get; private set; } | ||
90 | |||
91 | public string UnreferencedSymbolsFile { get; private set; } | ||
92 | |||
93 | public IDictionary<string, string> Variables { get; private set; } | ||
94 | |||
95 | /// <summary> | ||
96 | /// Parse the commandline arguments. | ||
97 | /// </summary> | ||
98 | /// <param name="args">Commandline arguments.</param> | ||
99 | public string[] Parse(string[] args) | ||
100 | { | ||
101 | List<string> unprocessed = new List<string>(); | ||
102 | |||
103 | for (int i = 0; i < args.Length; ++i) | ||
104 | { | ||
105 | string arg = args[i]; | ||
106 | if (String.IsNullOrEmpty(arg)) // skip blank arguments | ||
107 | { | ||
108 | continue; | ||
109 | } | ||
110 | |||
111 | if (1 == arg.Length) // treat '-' and '@' as filenames when by themselves. | ||
112 | { | ||
113 | unprocessed.Add(arg); | ||
114 | } | ||
115 | else if ('-' == arg[0] || '/' == arg[0]) | ||
116 | { | ||
117 | string parameter = arg.Substring(1); | ||
118 | if (parameter.Equals("b", StringComparison.Ordinal)) | ||
119 | { | ||
120 | if (!CommandLineHelper.IsValidArg(args, ++i)) | ||
121 | { | ||
122 | break; | ||
123 | } | ||
124 | |||
125 | var bindPath = BindPath.Parse(args[i]); | ||
126 | |||
127 | this.BindPaths.Add(bindPath); | ||
128 | } | ||
129 | else if (parameter.StartsWith("cultures:", StringComparison.Ordinal)) | ||
130 | { | ||
131 | string culturesString = arg.Substring(10).ToLower(CultureInfo.InvariantCulture); | ||
132 | |||
133 | // When null is used treat it as if cultures wasn't specified. | ||
134 | // This is needed for batching over the light task when using MSBuild which doesn't | ||
135 | // support empty items | ||
136 | if (culturesString.Equals("null", StringComparison.OrdinalIgnoreCase)) | ||
137 | { | ||
138 | this.Cultures = null; | ||
139 | } | ||
140 | else | ||
141 | { | ||
142 | this.Cultures = culturesString.Split(';', ','); | ||
143 | |||
144 | for (int c = 0; c < this.Cultures.Length; ++c) | ||
145 | { | ||
146 | // Neutral is different from null. For neutral we still want to do WXL filtering. | ||
147 | // Set the culture to the empty string = identifier for the invariant culture | ||
148 | if (this.Cultures[c].Equals("neutral", StringComparison.OrdinalIgnoreCase)) | ||
149 | { | ||
150 | this.Cultures[c] = String.Empty; | ||
151 | } | ||
152 | } | ||
153 | } | ||
154 | } | ||
155 | else if (parameter.StartsWith("dcl:", StringComparison.Ordinal)) | ||
156 | { | ||
157 | string defaultCompressionLevel = arg.Substring(5); | ||
158 | |||
159 | if (String.IsNullOrEmpty(defaultCompressionLevel)) | ||
160 | { | ||
161 | break; | ||
162 | } | ||
163 | else if (Enum.TryParse(defaultCompressionLevel, true, out CompressionLevel compressionLevel)) | ||
164 | { | ||
165 | this.DefaultCompressionLevel = compressionLevel; | ||
166 | } | ||
167 | } | ||
168 | else if (parameter.StartsWith("d", StringComparison.Ordinal)) | ||
169 | { | ||
170 | parameter = arg.Substring(2); | ||
171 | string[] value = parameter.Split("=".ToCharArray(), 2); | ||
172 | |||
173 | string preexisting; | ||
174 | if (1 == value.Length) | ||
175 | { | ||
176 | this.Messaging.Write(ErrorMessages.ExpectedWixVariableValue(value[0])); | ||
177 | } | ||
178 | else if (this.Variables.TryGetValue(value[0], out preexisting)) | ||
179 | { | ||
180 | this.Messaging.Write(ErrorMessages.WixVariableCollision(null, value[0])); | ||
181 | } | ||
182 | else | ||
183 | { | ||
184 | this.Variables.Add(value[0], value[1]); | ||
185 | } | ||
186 | } | ||
187 | else if (parameter.Equals("ext", StringComparison.Ordinal)) | ||
188 | { | ||
189 | if (!CommandLineHelper.IsValidArg(args, ++i)) | ||
190 | { | ||
191 | this.Messaging.Write(ErrorMessages.TypeSpecificationForExtensionRequired("-ext")); | ||
192 | break; | ||
193 | } | ||
194 | |||
195 | this.Extensions.Add(args[i]); | ||
196 | } | ||
197 | else if (parameter.Equals("loc", StringComparison.Ordinal)) | ||
198 | { | ||
199 | string locFile = CommandLineHelper.GetFile(parameter, this.Messaging, args, ++i); | ||
200 | if (String.IsNullOrEmpty(locFile)) | ||
201 | { | ||
202 | break; | ||
203 | } | ||
204 | |||
205 | this.LocalizationFiles.Add(locFile); | ||
206 | } | ||
207 | else if (parameter.Equals("nologo", StringComparison.Ordinal)) | ||
208 | { | ||
209 | this.ShowLogo = false; | ||
210 | } | ||
211 | else if (parameter.Equals("notidy", StringComparison.Ordinal)) | ||
212 | { | ||
213 | this.Tidy = false; | ||
214 | } | ||
215 | else if ("o" == parameter || "out" == parameter) | ||
216 | { | ||
217 | this.OutputFile = CommandLineHelper.GetFile(parameter, this.Messaging, args, ++i); | ||
218 | if (String.IsNullOrEmpty(this.OutputFile)) | ||
219 | { | ||
220 | break; | ||
221 | } | ||
222 | } | ||
223 | else if (parameter.Equals("pedantic", StringComparison.Ordinal)) | ||
224 | { | ||
225 | this.ShowPedanticMessages = true; | ||
226 | } | ||
227 | else if (parameter.Equals("sloc", StringComparison.Ordinal)) | ||
228 | { | ||
229 | this.SuppressLocalization = true; | ||
230 | } | ||
231 | else if (parameter.Equals("usf", StringComparison.Ordinal)) | ||
232 | { | ||
233 | this.UnreferencedSymbolsFile = CommandLineHelper.GetFile(parameter, this.Messaging, args, ++i); | ||
234 | |||
235 | if (String.IsNullOrEmpty(this.UnreferencedSymbolsFile)) | ||
236 | { | ||
237 | break; | ||
238 | } | ||
239 | } | ||
240 | else if (parameter.Equals("xo", StringComparison.Ordinal)) | ||
241 | { | ||
242 | this.OutputXml = true; | ||
243 | } | ||
244 | else if (parameter.Equals("cc", StringComparison.Ordinal)) | ||
245 | { | ||
246 | this.CabCachePath = CommandLineHelper.GetDirectory(parameter, this.Messaging, args, ++i); | ||
247 | |||
248 | if (String.IsNullOrEmpty(this.CabCachePath)) | ||
249 | { | ||
250 | break; | ||
251 | } | ||
252 | } | ||
253 | else if (parameter.Equals("ct", StringComparison.Ordinal)) | ||
254 | { | ||
255 | if (!CommandLineHelper.IsValidArg(args, ++i)) | ||
256 | { | ||
257 | this.Messaging.Write(ErrorMessages.IllegalCabbingThreadCount(String.Empty)); | ||
258 | break; | ||
259 | } | ||
260 | |||
261 | int ct = 0; | ||
262 | if (!Int32.TryParse(args[i], out ct) || 0 >= ct) | ||
263 | { | ||
264 | this.Messaging.Write(ErrorMessages.IllegalCabbingThreadCount(args[i])); | ||
265 | break; | ||
266 | } | ||
267 | |||
268 | this.CabbingThreadCount = ct; | ||
269 | this.Messaging.Write(VerboseMessages.SetCabbingThreadCount(this.CabbingThreadCount.ToString())); | ||
270 | } | ||
271 | else if (parameter.Equals("cub", StringComparison.Ordinal)) | ||
272 | { | ||
273 | string cubeFile = CommandLineHelper.GetFile(parameter, this.Messaging, args, ++i); | ||
274 | |||
275 | if (String.IsNullOrEmpty(cubeFile)) | ||
276 | { | ||
277 | break; | ||
278 | } | ||
279 | |||
280 | this.CubeFiles.Add(cubeFile); | ||
281 | } | ||
282 | else if (parameter.StartsWith("ice:", StringComparison.Ordinal)) | ||
283 | { | ||
284 | this.Ices.Add(parameter.Substring(4)); | ||
285 | } | ||
286 | else if (parameter.Equals("intermediatefolder", StringComparison.OrdinalIgnoreCase)) | ||
287 | { | ||
288 | this.IntermediateFolder = CommandLineHelper.GetDirectory(parameter, this.Messaging, args, ++i); | ||
289 | |||
290 | if (String.IsNullOrEmpty(this.IntermediateFolder)) | ||
291 | { | ||
292 | break; | ||
293 | } | ||
294 | } | ||
295 | else if (parameter.Equals("contentsfile", StringComparison.Ordinal)) | ||
296 | { | ||
297 | this.ContentsFile = CommandLineHelper.GetFile(parameter, this.Messaging, args, ++i); | ||
298 | |||
299 | if (String.IsNullOrEmpty(this.ContentsFile)) | ||
300 | { | ||
301 | break; | ||
302 | } | ||
303 | } | ||
304 | else if (parameter.Equals("outputsfile", StringComparison.Ordinal)) | ||
305 | { | ||
306 | this.OutputsFile = CommandLineHelper.GetFile(parameter, this.Messaging, args, ++i); | ||
307 | |||
308 | if (String.IsNullOrEmpty(this.OutputsFile)) | ||
309 | { | ||
310 | break; | ||
311 | } | ||
312 | } | ||
313 | else if (parameter.Equals("builtoutputsfile", StringComparison.Ordinal)) | ||
314 | { | ||
315 | this.BuiltOutputsFile = CommandLineHelper.GetFile(parameter, this.Messaging, args, ++i); | ||
316 | |||
317 | if (String.IsNullOrEmpty(this.BuiltOutputsFile)) | ||
318 | { | ||
319 | break; | ||
320 | } | ||
321 | } | ||
322 | else if (parameter.Equals("wixprojectfile", StringComparison.Ordinal)) | ||
323 | { | ||
324 | this.WixprojectFile = CommandLineHelper.GetFile(parameter, this.Messaging, args, ++i); | ||
325 | |||
326 | if (String.IsNullOrEmpty(this.WixprojectFile)) | ||
327 | { | ||
328 | break; | ||
329 | } | ||
330 | } | ||
331 | else if (parameter.Equals("pdbout", StringComparison.Ordinal)) | ||
332 | { | ||
333 | this.PdbFile = CommandLineHelper.GetFile(parameter, this.Messaging, args, ++i); | ||
334 | |||
335 | if (String.IsNullOrEmpty(this.PdbFile)) | ||
336 | { | ||
337 | break; | ||
338 | } | ||
339 | } | ||
340 | else if (parameter.StartsWith("sice:", StringComparison.Ordinal)) | ||
341 | { | ||
342 | this.SuppressIces.Add(parameter.Substring(5)); | ||
343 | } | ||
344 | else if (parameter.Equals("sl", StringComparison.Ordinal)) | ||
345 | { | ||
346 | this.SuppressLayout = true; | ||
347 | } | ||
348 | else if (parameter.Equals("spdb", StringComparison.Ordinal)) | ||
349 | { | ||
350 | this.SuppressWixPdb = true; | ||
351 | } | ||
352 | else if (parameter.Equals("sacl", StringComparison.Ordinal)) | ||
353 | { | ||
354 | this.SuppressAclReset = true; | ||
355 | } | ||
356 | else if (parameter.Equals("sval", StringComparison.Ordinal)) | ||
357 | { | ||
358 | this.SuppressValidation = true; | ||
359 | } | ||
360 | else if ("sv" == parameter) | ||
361 | { | ||
362 | this.SuppressVersionCheck = true; | ||
363 | } | ||
364 | else if (parameter.StartsWith("sw", StringComparison.Ordinal)) | ||
365 | { | ||
366 | string paramArg = parameter.Substring(2); | ||
367 | if (0 == paramArg.Length) | ||
368 | { | ||
369 | this.Messaging.SuppressAllWarnings = true; | ||
370 | } | ||
371 | else | ||
372 | { | ||
373 | int suppressWarning = 0; | ||
374 | if (!Int32.TryParse(paramArg, out suppressWarning) || 0 >= suppressWarning) | ||
375 | { | ||
376 | this.Messaging.Write(ErrorMessages.IllegalSuppressWarningId(paramArg)); | ||
377 | } | ||
378 | else | ||
379 | { | ||
380 | this.Messaging.SuppressWarningMessage(suppressWarning); | ||
381 | } | ||
382 | } | ||
383 | } | ||
384 | else if (parameter.StartsWith("wx", StringComparison.Ordinal)) | ||
385 | { | ||
386 | string paramArg = parameter.Substring(2); | ||
387 | if (0 == paramArg.Length) | ||
388 | { | ||
389 | this.Messaging.WarningsAsError = true; | ||
390 | } | ||
391 | else | ||
392 | { | ||
393 | int elevateWarning = 0; | ||
394 | if (!Int32.TryParse(paramArg, out elevateWarning) || 0 >= elevateWarning) | ||
395 | { | ||
396 | this.Messaging.Write(ErrorMessages.IllegalWarningIdAsError(paramArg)); | ||
397 | } | ||
398 | else | ||
399 | { | ||
400 | this.Messaging.ElevateWarningMessage(elevateWarning); | ||
401 | } | ||
402 | } | ||
403 | } | ||
404 | else if ("v" == parameter) | ||
405 | { | ||
406 | this.Messaging.ShowVerboseMessages = true; | ||
407 | } | ||
408 | else if ("?" == parameter || "help" == parameter) | ||
409 | { | ||
410 | this.ShowHelp = true; | ||
411 | break; | ||
412 | } | ||
413 | else | ||
414 | { | ||
415 | unprocessed.Add(arg); | ||
416 | } | ||
417 | } | ||
418 | else if ('@' == arg[0]) | ||
419 | { | ||
420 | string[] parsedArgs = CommandLineResponseFile.Parse(arg.Substring(1)); | ||
421 | string[] unparsedArgs = this.Parse(parsedArgs); | ||
422 | unprocessed.AddRange(unparsedArgs); | ||
423 | } | ||
424 | else | ||
425 | { | ||
426 | unprocessed.Add(arg); | ||
427 | } | ||
428 | } | ||
429 | |||
430 | return unprocessed.ToArray(); | ||
431 | } | ||
432 | |||
433 | public string[] ParsePostExtensions(string[] remaining) | ||
434 | { | ||
435 | List<string> unprocessed = new List<string>(); | ||
436 | |||
437 | for (int i = 0; i < remaining.Length; ++i) | ||
438 | { | ||
439 | string arg = remaining[i]; | ||
440 | if (String.IsNullOrEmpty(arg)) // skip blank arguments | ||
441 | { | ||
442 | continue; | ||
443 | } | ||
444 | |||
445 | if (1 < arg.Length && ('-' == arg[0] || '/' == arg[0])) | ||
446 | { | ||
447 | unprocessed.Add(arg); | ||
448 | } | ||
449 | else | ||
450 | { | ||
451 | this.Files.AddRange(CommandLineHelper.GetFiles(arg, "Source")); | ||
452 | } | ||
453 | } | ||
454 | |||
455 | if (0 == this.Files.Count) | ||
456 | { | ||
457 | this.ShowHelp = true; | ||
458 | } | ||
459 | else if (String.IsNullOrEmpty(this.OutputFile)) | ||
460 | { | ||
461 | if (1 < this.Files.Count) | ||
462 | { | ||
463 | this.Messaging.Write(ErrorMessages.MustSpecifyOutputWithMoreThanOneInput()); | ||
464 | } | ||
465 | |||
466 | // After the linker tells us what the output type actually is, we'll change the ".wix" to the correct extension. | ||
467 | this.OutputFile = Path.ChangeExtension(Path.GetFileName(this.Files[0]), ".wix"); | ||
468 | |||
469 | // Add the directories of the input files as unnamed bind paths. | ||
470 | foreach (string file in this.Files) | ||
471 | { | ||
472 | BindPath bindPath = new BindPath(Path.GetDirectoryName(Path.GetFullPath(file))); | ||
473 | this.BindPaths.Add(bindPath); | ||
474 | } | ||
475 | } | ||
476 | |||
477 | if (!this.SuppressWixPdb && String.IsNullOrEmpty(this.PdbFile) && !String.IsNullOrEmpty(this.OutputFile)) | ||
478 | { | ||
479 | this.PdbFile = Path.ChangeExtension(this.OutputFile, ".wixpdb"); | ||
480 | } | ||
481 | |||
482 | return unprocessed.ToArray(); | ||
483 | } | ||
484 | } | ||
485 | } | ||
diff --git a/src/light/LightStrings.Designer.cs b/src/light/LightStrings.Designer.cs new file mode 100644 index 00000000..50e271fd --- /dev/null +++ b/src/light/LightStrings.Designer.cs | |||
@@ -0,0 +1,104 @@ | |||
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 | |||
3 | namespace WixToolset.Tools { | ||
4 | using System; | ||
5 | |||
6 | |||
7 | /// <summary> | ||
8 | /// A strongly-typed resource class, for looking up localized strings, etc. | ||
9 | /// </summary> | ||
10 | // This class was auto-generated by the StronglyTypedResourceBuilder | ||
11 | // class via a tool like ResGen or Visual Studio. | ||
12 | // To add or remove a member, edit your .ResX file then rerun ResGen | ||
13 | // with the /str option, or rebuild your VS project. | ||
14 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] | ||
15 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] | ||
16 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] | ||
17 | internal class LightStrings { | ||
18 | |||
19 | private static global::System.Resources.ResourceManager resourceMan; | ||
20 | |||
21 | private static global::System.Globalization.CultureInfo resourceCulture; | ||
22 | |||
23 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] | ||
24 | internal LightStrings() { | ||
25 | } | ||
26 | |||
27 | /// <summary> | ||
28 | /// Returns the cached ResourceManager instance used by this class. | ||
29 | /// </summary> | ||
30 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] | ||
31 | internal static global::System.Resources.ResourceManager ResourceManager { | ||
32 | get { | ||
33 | if (object.ReferenceEquals(resourceMan, null)) { | ||
34 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("WixToolset.Tools.LightStrings", typeof(LightStrings).Assembly); | ||
35 | resourceMan = temp; | ||
36 | } | ||
37 | return resourceMan; | ||
38 | } | ||
39 | } | ||
40 | |||
41 | /// <summary> | ||
42 | /// Overrides the current thread's CurrentUICulture property for all | ||
43 | /// resource lookups using this strongly typed resource class. | ||
44 | /// </summary> | ||
45 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] | ||
46 | internal static global::System.Globalization.CultureInfo Culture { | ||
47 | get { | ||
48 | return resourceCulture; | ||
49 | } | ||
50 | set { | ||
51 | resourceCulture = value; | ||
52 | } | ||
53 | } | ||
54 | |||
55 | /// <summary> | ||
56 | /// Looks up a localized string similar to -b <path> specify a binder path to locate all files | ||
57 | /// (default: current directory) | ||
58 | /// prefix the path with 'name=' where 'name' is the name of your | ||
59 | /// named bindpath. | ||
60 | /// -cc <path> path to cache built cabinets (will not be deleted after linking) | ||
61 | /// -ct <N> number of threads to use when creating cabinets | ||
62 | /// (default: %NUMBER_OF_PROCESSORS%) | ||
63 | /// -cub <file.cub> additional .cub file containing ICEs to run | ||
64 | /// -dcl:level set default cabinet compression l [rest of string was truncated]";. | ||
65 | /// </summary> | ||
66 | internal static string CommandLineArguments { | ||
67 | get { | ||
68 | return ResourceManager.GetString("CommandLineArguments", resourceCulture); | ||
69 | } | ||
70 | } | ||
71 | |||
72 | /// <summary> | ||
73 | /// Looks up a localized string similar to The -bf (bind files) option is only applicable with the -xo option.. | ||
74 | /// </summary> | ||
75 | internal static string EXP_BindFileOptionNotApplicable { | ||
76 | get { | ||
77 | return ResourceManager.GetString("EXP_BindFileOptionNotApplicable", resourceCulture); | ||
78 | } | ||
79 | } | ||
80 | |||
81 | /// <summary> | ||
82 | /// Looks up a localized string similar to Cannot link object files (.wixobj) files with an output file (.wixout). | ||
83 | /// </summary> | ||
84 | internal static string EXP_CannotLinkObjFilesWithOutpuFile { | ||
85 | get { | ||
86 | return ResourceManager.GetString("EXP_CannotLinkObjFilesWithOutpuFile", resourceCulture); | ||
87 | } | ||
88 | } | ||
89 | |||
90 | /// <summary> | ||
91 | /// Looks up a localized string similar to usage: light.exe [-?] [-b bindPath] [-nologo] [-out outputFile] objectFile [objectFile ...] [@responseFile] | ||
92 | /// | ||
93 | ///{0} | ||
94 | /// | ||
95 | ///Environment variables: | ||
96 | /// WIX_TEMP overrides the temporary directory used for cab creation, msm exploding, .... | ||
97 | /// </summary> | ||
98 | internal static string HelpMessage { | ||
99 | get { | ||
100 | return ResourceManager.GetString("HelpMessage", resourceCulture); | ||
101 | } | ||
102 | } | ||
103 | } | ||
104 | } | ||
diff --git a/src/light/LightStrings.resx b/src/light/LightStrings.resx new file mode 100644 index 00000000..3f586a5d --- /dev/null +++ b/src/light/LightStrings.resx | |||
@@ -0,0 +1,174 @@ | |||
1 | <?xml version="1.0" encoding="utf-8"?> | ||
2 | <root> | ||
3 | <!-- | ||
4 | Microsoft ResX Schema | ||
5 | |||
6 | Version 2.0 | ||
7 | |||
8 | The primary goals of this format is to allow a simple XML format | ||
9 | that is mostly human readable. The generation and parsing of the | ||
10 | various data types are done through the TypeConverter classes | ||
11 | associated with the data types. | ||
12 | |||
13 | Example: | ||
14 | |||
15 | ... ado.net/XML headers & schema ... | ||
16 | <resheader name="resmimetype">text/microsoft-resx</resheader> | ||
17 | <resheader name="version">2.0</resheader> | ||
18 | <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader> | ||
19 | <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader> | ||
20 | <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data> | ||
21 | <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data> | ||
22 | <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64"> | ||
23 | <value>[base64 mime encoded serialized .NET Framework object]</value> | ||
24 | </data> | ||
25 | <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64"> | ||
26 | <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value> | ||
27 | <comment>This is a comment</comment> | ||
28 | </data> | ||
29 | |||
30 | There are any number of "resheader" rows that contain simple | ||
31 | name/value pairs. | ||
32 | |||
33 | Each data row contains a name, and value. The row also contains a | ||
34 | type or mimetype. Type corresponds to a .NET class that support | ||
35 | text/value conversion through the TypeConverter architecture. | ||
36 | Classes that don't support this are serialized and stored with the | ||
37 | mimetype set. | ||
38 | |||
39 | The mimetype is used for serialized objects, and tells the | ||
40 | ResXResourceReader how to depersist the object. This is currently not | ||
41 | extensible. For a given mimetype the value must be set accordingly: | ||
42 | |||
43 | Note - application/x-microsoft.net.object.binary.base64 is the format | ||
44 | that the ResXResourceWriter will generate, however the reader can | ||
45 | read any of the formats listed below. | ||
46 | |||
47 | mimetype: application/x-microsoft.net.object.binary.base64 | ||
48 | value : The object must be serialized with | ||
49 | : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter | ||
50 | : and then encoded with base64 encoding. | ||
51 | |||
52 | mimetype: application/x-microsoft.net.object.soap.base64 | ||
53 | value : The object must be serialized with | ||
54 | : System.Runtime.Serialization.Formatters.Soap.SoapFormatter | ||
55 | : and then encoded with base64 encoding. | ||
56 | |||
57 | mimetype: application/x-microsoft.net.object.bytearray.base64 | ||
58 | value : The object must be serialized into a byte array | ||
59 | : using a System.ComponentModel.TypeConverter | ||
60 | : and then encoded with base64 encoding. | ||
61 | --> | ||
62 | <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata"> | ||
63 | <xsd:import namespace="http://www.w3.org/XML/1998/namespace" /> | ||
64 | <xsd:element name="root" msdata:IsDataSet="true"> | ||
65 | <xsd:complexType> | ||
66 | <xsd:choice maxOccurs="unbounded"> | ||
67 | <xsd:element name="metadata"> | ||
68 | <xsd:complexType> | ||
69 | <xsd:sequence> | ||
70 | <xsd:element name="value" type="xsd:string" minOccurs="0" /> | ||
71 | </xsd:sequence> | ||
72 | <xsd:attribute name="name" use="required" type="xsd:string" /> | ||
73 | <xsd:attribute name="type" type="xsd:string" /> | ||
74 | <xsd:attribute name="mimetype" type="xsd:string" /> | ||
75 | <xsd:attribute ref="xml:space" /> | ||
76 | </xsd:complexType> | ||
77 | </xsd:element> | ||
78 | <xsd:element name="assembly"> | ||
79 | <xsd:complexType> | ||
80 | <xsd:attribute name="alias" type="xsd:string" /> | ||
81 | <xsd:attribute name="name" type="xsd:string" /> | ||
82 | </xsd:complexType> | ||
83 | </xsd:element> | ||
84 | <xsd:element name="data"> | ||
85 | <xsd:complexType> | ||
86 | <xsd:sequence> | ||
87 | <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" /> | ||
88 | <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" /> | ||
89 | </xsd:sequence> | ||
90 | <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" /> | ||
91 | <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" /> | ||
92 | <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" /> | ||
93 | <xsd:attribute ref="xml:space" /> | ||
94 | </xsd:complexType> | ||
95 | </xsd:element> | ||
96 | <xsd:element name="resheader"> | ||
97 | <xsd:complexType> | ||
98 | <xsd:sequence> | ||
99 | <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" /> | ||
100 | </xsd:sequence> | ||
101 | <xsd:attribute name="name" type="xsd:string" use="required" /> | ||
102 | </xsd:complexType> | ||
103 | </xsd:element> | ||
104 | </xsd:choice> | ||
105 | </xsd:complexType> | ||
106 | </xsd:element> | ||
107 | </xsd:schema> | ||
108 | <resheader name="resmimetype"> | ||
109 | <value>text/microsoft-resx</value> | ||
110 | </resheader> | ||
111 | <resheader name="version"> | ||
112 | <value>2.0</value> | ||
113 | </resheader> | ||
114 | <resheader name="reader"> | ||
115 | <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> | ||
116 | </resheader> | ||
117 | <resheader name="writer"> | ||
118 | <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> | ||
119 | </resheader> | ||
120 | <data name="CommandLineArguments" xml:space="preserve"> | ||
121 | <value> -b <path> specify a binder path to locate all files | ||
122 | (default: current directory) | ||
123 | prefix the path with 'name=' where 'name' is the name of your | ||
124 | named bindpath. | ||
125 | -cc <path> path to cache built cabinets (will not be deleted after linking) | ||
126 | -ct <N> number of threads to use when creating cabinets | ||
127 | (default: %NUMBER_OF_PROCESSORS%) | ||
128 | -cub <file.cub> additional .cub file containing ICEs to run | ||
129 | -dcl:level set default cabinet compression level | ||
130 | (low, medium, high, none, mszip; mszip default) | ||
131 | -eav exact assembly versions (breaks .NET 1.1 RTM compatibility) | ||
132 | -ice:<ICE> run a specific internal consistency evaluator (ICE) | ||
133 | -pdbout <output.wixpdb> save the WixPdb to a specific file | ||
134 | (default: same name as output with wixpdb extension) | ||
135 | -reusecab reuse cabinets from cabinet cache | ||
136 | -sacl suppress resetting ACLs | ||
137 | (useful when laying out image to a network share) | ||
138 | -sice:<ICE> suppress an internal consistency evaluator (ICE) | ||
139 | -sl suppress layout | ||
140 | -spdb suppress outputting the WixPdb | ||
141 | -sval suppress MSI/MSM validation | ||
142 | -cultures:<cultures> semicolon or comma delimited list of localized | ||
143 | string cultures to load from .wxl files and libraries. | ||
144 | Precedence of cultures is from left to right. | ||
145 | -d<name>[=<value>] define a wix variable, with or without a value. | ||
146 | -ext <extension> extension assembly or "class, assembly" | ||
147 | -loc <loc.wxl> read localization strings from .wxl file | ||
148 | -nologo skip printing light logo information | ||
149 | -notidy do not delete temporary files (useful for debugging) | ||
150 | -o[ut] specify output file (default: write to current directory) | ||
151 | -pedantic show pedantic messages | ||
152 | -sloc suppress localization | ||
153 | -sw[N] suppress all warnings or a specific message ID | ||
154 | (example: -sw1009 -sw1103) | ||
155 | -usf <output.xml> unreferenced symbols file | ||
156 | -v verbose output | ||
157 | -wx[N] treat all warnings or a specific message ID as an error | ||
158 | (example: -wx1009 -wx1103) | ||
159 | -xo output wixout format instead of MSI format | ||
160 | -? | -help this help information</value> | ||
161 | </data> | ||
162 | <data name="EXP_CannotLinkObjFilesWithOutpuFile" xml:space="preserve"> | ||
163 | <value>Cannot link object files (.wixobj) files with an output file (.wixout)</value> | ||
164 | </data> | ||
165 | <data name="HelpMessage" xml:space="preserve"> | ||
166 | <value> usage: light.exe [-?] [-b bindPath] [-nologo] [-out outputFile] objectFile [objectFile ...] [@responseFile] | ||
167 | |||
168 | {0} | ||
169 | |||
170 | Environment variables: | ||
171 | WIX_TEMP overrides the temporary directory used for cab creation, msm exploding, ...</value> | ||
172 | <comment>{0} is replaced by a list of light's arguments.</comment> | ||
173 | </data> | ||
174 | </root> | ||
diff --git a/src/light/app.config b/src/light/app.config new file mode 100644 index 00000000..71c529fb --- /dev/null +++ b/src/light/app.config | |||
@@ -0,0 +1,9 @@ | |||
1 | <?xml version="1.0" encoding="utf-8" ?> | ||
2 | <!-- 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. --> | ||
3 | |||
4 | |||
5 | <configuration> | ||
6 | <runtime> | ||
7 | <loadFromRemoteSources enabled="true"/> | ||
8 | </runtime> | ||
9 | </configuration> | ||
diff --git a/src/light/light.cs b/src/light/light.cs new file mode 100644 index 00000000..c0967caa --- /dev/null +++ b/src/light/light.cs | |||
@@ -0,0 +1,595 @@ | |||
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 | |||
3 | namespace WixToolset.Tools | ||
4 | { | ||
5 | using System; | ||
6 | using System.Collections.Generic; | ||
7 | using System.Globalization; | ||
8 | using System.IO; | ||
9 | using System.Linq; | ||
10 | using System.Runtime.InteropServices; | ||
11 | using System.Text; | ||
12 | using System.Threading; | ||
13 | using WixToolset.Core; | ||
14 | using WixToolset.Data; | ||
15 | using WixToolset.Data.Bind; | ||
16 | using WixToolset.Extensibility; | ||
17 | using WixToolset.Extensibility.Services; | ||
18 | |||
19 | /// <summary> | ||
20 | /// The main entry point for light. | ||
21 | /// </summary> | ||
22 | public sealed class Light | ||
23 | { | ||
24 | LightCommandLine commandLine; | ||
25 | private IEnumerable<IExtensionData> extensionData; | ||
26 | //private IEnumerable<IBinderExtension> binderExtensions; | ||
27 | //private IEnumerable<IBinderFileManager> fileManagers; | ||
28 | |||
29 | /// <summary> | ||
30 | /// The main entry point for light. | ||
31 | /// </summary> | ||
32 | /// <param name="args">Commandline arguments for the application.</param> | ||
33 | /// <returns>Returns the application error code.</returns> | ||
34 | [MTAThread] | ||
35 | public static int Main(string[] args) | ||
36 | { | ||
37 | var serviceProvider = new WixToolsetServiceProvider(); | ||
38 | |||
39 | var listener = new ConsoleMessageListener("WIX", "light.exe"); | ||
40 | |||
41 | Light light = new Light(); | ||
42 | return light.Run(serviceProvider, listener, args); | ||
43 | } | ||
44 | |||
45 | /// <summary> | ||
46 | /// Main running method for the application. | ||
47 | /// </summary> | ||
48 | /// <param name="args">Commandline arguments to the application.</param> | ||
49 | /// <returns>Returns the application error code.</returns> | ||
50 | public int Run(IServiceProvider serviceProvider, IMessageListener listener, string[] args) | ||
51 | { | ||
52 | var messaging = serviceProvider.GetService<IMessaging>(); | ||
53 | messaging.SetListener(listener); | ||
54 | |||
55 | try | ||
56 | { | ||
57 | var unparsed = this.ParseCommandLineAndLoadExtensions(serviceProvider, messaging, args); | ||
58 | |||
59 | if (!messaging.EncounteredError) | ||
60 | { | ||
61 | if (this.commandLine.ShowLogo) | ||
62 | { | ||
63 | AppCommon.DisplayToolHeader(); | ||
64 | } | ||
65 | |||
66 | if (this.commandLine.ShowHelp) | ||
67 | { | ||
68 | PrintHelp(); | ||
69 | AppCommon.DisplayToolFooter(); | ||
70 | } | ||
71 | else | ||
72 | { | ||
73 | foreach (string arg in unparsed) | ||
74 | { | ||
75 | messaging.Write(WarningMessages.UnsupportedCommandLineArgument(arg)); | ||
76 | } | ||
77 | |||
78 | this.Bind(serviceProvider, messaging); | ||
79 | } | ||
80 | } | ||
81 | } | ||
82 | catch (WixException we) | ||
83 | { | ||
84 | messaging.Write(we.Error); | ||
85 | } | ||
86 | catch (Exception e) | ||
87 | { | ||
88 | messaging.Write(ErrorMessages.UnexpectedException(e.Message, e.GetType().ToString(), e.StackTrace)); | ||
89 | if (e is NullReferenceException || e is SEHException) | ||
90 | { | ||
91 | throw; | ||
92 | } | ||
93 | } | ||
94 | |||
95 | return messaging.LastErrorNumber; | ||
96 | } | ||
97 | |||
98 | /// <summary> | ||
99 | /// Parse command line and load all the extensions. | ||
100 | /// </summary> | ||
101 | /// <param name="args">Command line arguments to be parsed.</param> | ||
102 | private IEnumerable<string> ParseCommandLineAndLoadExtensions(IServiceProvider serviceProvider, IMessaging messaging, string[] args) | ||
103 | { | ||
104 | this.commandLine = new LightCommandLine(messaging); | ||
105 | |||
106 | string[] unprocessed = this.commandLine.Parse(args); | ||
107 | if (messaging.EncounteredError) | ||
108 | { | ||
109 | return unprocessed; | ||
110 | } | ||
111 | |||
112 | // Load extensions. | ||
113 | var extensionManager = CreateExtensionManagerWithStandardBackends(serviceProvider); | ||
114 | foreach (string extension in this.commandLine.Extensions) | ||
115 | { | ||
116 | extensionManager.Load(extension); | ||
117 | } | ||
118 | |||
119 | // Extension data command line processing. | ||
120 | var context = serviceProvider.GetService<ICommandLineContext>(); | ||
121 | context.Arguments = null; | ||
122 | context.ExtensionManager = extensionManager; | ||
123 | context.Messaging = messaging; | ||
124 | context.ParsedArguments = args; | ||
125 | |||
126 | var commandLineExtensions = extensionManager.Create<IExtensionCommandLine>(); | ||
127 | foreach (var extension in commandLineExtensions) | ||
128 | { | ||
129 | extension.PreParse(context); | ||
130 | } | ||
131 | |||
132 | // Process unproccessed arguments. | ||
133 | List<string> actuallyUnprocessed = new List<string>(); | ||
134 | foreach (var arg in unprocessed) | ||
135 | { | ||
136 | if (!this.TryParseCommandLineArgumentWithExtension(arg, commandLineExtensions)) | ||
137 | { | ||
138 | actuallyUnprocessed.Add(arg); | ||
139 | } | ||
140 | } | ||
141 | |||
142 | return this.commandLine.ParsePostExtensions(actuallyUnprocessed.ToArray()); | ||
143 | } | ||
144 | |||
145 | private void Bind(IServiceProvider serviceProvider, IMessaging messaging) | ||
146 | { | ||
147 | var output = this.LoadWixout(messaging); | ||
148 | |||
149 | if (messaging.EncounteredError) | ||
150 | { | ||
151 | return; | ||
152 | } | ||
153 | |||
154 | var intermediateFolder = this.commandLine.IntermediateFolder; | ||
155 | if (String.IsNullOrEmpty(intermediateFolder)) | ||
156 | { | ||
157 | intermediateFolder = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName()); | ||
158 | } | ||
159 | |||
160 | var localizations = this.LoadLocalizationFiles(messaging, this.commandLine.LocalizationFiles); | ||
161 | |||
162 | if (messaging.EncounteredError) | ||
163 | { | ||
164 | return; | ||
165 | } | ||
166 | |||
167 | ResolveResult resolveResult; | ||
168 | { | ||
169 | var resolver = new Resolver(serviceProvider); | ||
170 | resolver.BindPaths = this.commandLine.BindPaths; | ||
171 | resolver.IntermediateFolder = intermediateFolder; | ||
172 | resolver.IntermediateRepresentation = output; | ||
173 | resolver.Localizations = localizations; | ||
174 | |||
175 | resolveResult = resolver.Execute(); | ||
176 | } | ||
177 | |||
178 | if (messaging.EncounteredError) | ||
179 | { | ||
180 | return; | ||
181 | } | ||
182 | |||
183 | BindResult bindResult; | ||
184 | { | ||
185 | var binder = new Binder(serviceProvider); | ||
186 | binder.CabbingThreadCount = this.commandLine.CabbingThreadCount; | ||
187 | binder.CabCachePath = this.commandLine.CabCachePath; | ||
188 | binder.Codepage = resolveResult.Codepage; | ||
189 | binder.DefaultCompressionLevel = this.commandLine.DefaultCompressionLevel; | ||
190 | binder.DelayedFields = resolveResult.DelayedFields; | ||
191 | binder.ExpectedEmbeddedFiles = resolveResult.ExpectedEmbeddedFiles; | ||
192 | binder.Ices = this.commandLine.Ices; | ||
193 | binder.IntermediateFolder = intermediateFolder; | ||
194 | binder.IntermediateRepresentation = resolveResult.IntermediateRepresentation; | ||
195 | binder.OutputPath = this.commandLine.OutputFile; | ||
196 | binder.OutputPdbPath = Path.ChangeExtension(this.commandLine.OutputFile, ".wixpdb"); | ||
197 | binder.SuppressIces = this.commandLine.SuppressIces; | ||
198 | binder.SuppressValidation = this.commandLine.SuppressValidation; | ||
199 | |||
200 | bindResult = binder.Execute(); | ||
201 | } | ||
202 | |||
203 | if (messaging.EncounteredError) | ||
204 | { | ||
205 | return; | ||
206 | } | ||
207 | |||
208 | { | ||
209 | var layout = new Layout(serviceProvider); | ||
210 | layout.FileTransfers = bindResult.FileTransfers; | ||
211 | layout.ContentFilePaths = bindResult.ContentFilePaths; | ||
212 | layout.ContentsFile = this.commandLine.ContentsFile; | ||
213 | layout.OutputsFile = this.commandLine.OutputsFile; | ||
214 | layout.BuiltOutputsFile = this.commandLine.BuiltOutputsFile; | ||
215 | layout.SuppressAclReset = this.commandLine.SuppressAclReset; | ||
216 | |||
217 | layout.Execute(); | ||
218 | } | ||
219 | } | ||
220 | |||
221 | private void Run(IMessaging messaging) | ||
222 | { | ||
223 | #if false | ||
224 | // Initialize the variable resolver from the command line. | ||
225 | WixVariableResolver wixVariableResolver = new WixVariableResolver(); | ||
226 | foreach (var wixVar in this.commandLine.Variables) | ||
227 | { | ||
228 | wixVariableResolver.AddVariable(wixVar.Key, wixVar.Value); | ||
229 | } | ||
230 | |||
231 | // Initialize the linker from the command line. | ||
232 | Linker linker = new Linker(); | ||
233 | linker.UnreferencedSymbolsFile = this.commandLine.UnreferencedSymbolsFile; | ||
234 | linker.ShowPedanticMessages = this.commandLine.ShowPedanticMessages; | ||
235 | linker.WixVariableResolver = wixVariableResolver; | ||
236 | |||
237 | foreach (IExtensionData data in this.extensionData) | ||
238 | { | ||
239 | linker.AddExtensionData(data); | ||
240 | } | ||
241 | |||
242 | // Initialize the binder from the command line. | ||
243 | WixToolset.Binder binder = new WixToolset.Binder(); | ||
244 | binder.CabCachePath = this.commandLine.CabCachePath; | ||
245 | binder.ContentsFile = this.commandLine.ContentsFile; | ||
246 | binder.BuiltOutputsFile = this.commandLine.BuiltOutputsFile; | ||
247 | binder.OutputsFile = this.commandLine.OutputsFile; | ||
248 | binder.WixprojectFile = this.commandLine.WixprojectFile; | ||
249 | binder.BindPaths.AddRange(this.commandLine.BindPaths); | ||
250 | binder.CabbingThreadCount = this.commandLine.CabbingThreadCount; | ||
251 | if (this.commandLine.DefaultCompressionLevel.HasValue) | ||
252 | { | ||
253 | binder.DefaultCompressionLevel = this.commandLine.DefaultCompressionLevel.Value; | ||
254 | } | ||
255 | binder.Ices.AddRange(this.commandLine.Ices); | ||
256 | binder.SuppressIces.AddRange(this.commandLine.SuppressIces); | ||
257 | binder.SuppressAclReset = this.commandLine.SuppressAclReset; | ||
258 | binder.SuppressLayout = this.commandLine.SuppressLayout; | ||
259 | binder.SuppressValidation = this.commandLine.SuppressValidation; | ||
260 | binder.PdbFile = this.commandLine.SuppressWixPdb ? null : this.commandLine.PdbFile; | ||
261 | binder.TempFilesLocation = AppCommon.GetTempLocation(); | ||
262 | binder.WixVariableResolver = wixVariableResolver; | ||
263 | |||
264 | foreach (IBinderExtension extension in this.binderExtensions) | ||
265 | { | ||
266 | binder.AddExtension(extension); | ||
267 | } | ||
268 | |||
269 | foreach (IBinderFileManager fileManager in this.fileManagers) | ||
270 | { | ||
271 | binder.AddExtension(fileManager); | ||
272 | } | ||
273 | |||
274 | // Initialize the localizer. | ||
275 | Localizer localizer = this.InitializeLocalization(linker.TableDefinitions); | ||
276 | if (messaging.EncounteredError) | ||
277 | { | ||
278 | return; | ||
279 | } | ||
280 | |||
281 | wixVariableResolver.Localizer = localizer; | ||
282 | linker.Localizer = localizer; | ||
283 | binder.Localizer = localizer; | ||
284 | |||
285 | // Loop through all the believed object files. | ||
286 | List<Section> sections = new List<Section>(); | ||
287 | Output output = null; | ||
288 | foreach (string inputFile in this.commandLine.Files) | ||
289 | { | ||
290 | string inputFileFullPath = Path.GetFullPath(inputFile); | ||
291 | FileFormat format = FileStructure.GuessFileFormatFromExtension(Path.GetExtension(inputFileFullPath)); | ||
292 | bool retry; | ||
293 | do | ||
294 | { | ||
295 | retry = false; | ||
296 | |||
297 | try | ||
298 | { | ||
299 | switch (format) | ||
300 | { | ||
301 | case FileFormat.Wixobj: | ||
302 | Intermediate intermediate = Intermediate.Load(inputFileFullPath, linker.TableDefinitions, this.commandLine.SuppressVersionCheck); | ||
303 | sections.AddRange(intermediate.Sections); | ||
304 | break; | ||
305 | |||
306 | case FileFormat.Wixlib: | ||
307 | Library library = Library.Load(inputFileFullPath, linker.TableDefinitions, this.commandLine.SuppressVersionCheck); | ||
308 | AddLibraryLocalizationsToLocalizer(library, this.commandLine.Cultures, localizer); | ||
309 | sections.AddRange(library.Sections); | ||
310 | break; | ||
311 | |||
312 | default: | ||
313 | output = Output.Load(inputFileFullPath, this.commandLine.SuppressVersionCheck); | ||
314 | break; | ||
315 | } | ||
316 | } | ||
317 | catch (WixUnexpectedFileFormatException e) | ||
318 | { | ||
319 | format = e.FileFormat; | ||
320 | retry = (FileFormat.Wixobj == format || FileFormat.Wixlib == format || FileFormat.Wixout == format); // .wixobj, .wixout and .wixout are supported by light. | ||
321 | if (!retry) | ||
322 | { | ||
323 | messaging.OnMessage(e.Error); | ||
324 | } | ||
325 | } | ||
326 | } while (retry); | ||
327 | } | ||
328 | |||
329 | // Stop processing if any errors were found loading object files. | ||
330 | if (messaging.EncounteredError) | ||
331 | { | ||
332 | return; | ||
333 | } | ||
334 | |||
335 | // and now for the fun part | ||
336 | if (null == output) | ||
337 | { | ||
338 | OutputType expectedOutputType = OutputType.Unknown; | ||
339 | if (!String.IsNullOrEmpty(this.commandLine.OutputFile)) | ||
340 | { | ||
341 | expectedOutputType = Output.GetOutputType(Path.GetExtension(this.commandLine.OutputFile)); | ||
342 | } | ||
343 | |||
344 | output = linker.Link(sections, expectedOutputType); | ||
345 | |||
346 | // If an error occurred during linking, stop processing. | ||
347 | if (null == output) | ||
348 | { | ||
349 | return; | ||
350 | } | ||
351 | } | ||
352 | else if (0 != sections.Count) | ||
353 | { | ||
354 | throw new InvalidOperationException(LightStrings.EXP_CannotLinkObjFilesWithOutpuFile); | ||
355 | } | ||
356 | |||
357 | bool tidy = true; // clean up after ourselves by default. | ||
358 | try | ||
359 | { | ||
360 | // only output the xml if its a patch build or user specfied to only output wixout | ||
361 | string outputFile = this.commandLine.OutputFile; | ||
362 | string outputExtension = Path.GetExtension(outputFile); | ||
363 | if (this.commandLine.OutputXml || OutputType.Patch == output.Type) | ||
364 | { | ||
365 | if (String.IsNullOrEmpty(outputExtension) || outputExtension.Equals(".wix", StringComparison.Ordinal)) | ||
366 | { | ||
367 | outputExtension = (OutputType.Patch == output.Type) ? ".wixmsp" : ".wixout"; | ||
368 | outputFile = Path.ChangeExtension(outputFile, outputExtension); | ||
369 | } | ||
370 | |||
371 | output.Save(outputFile); | ||
372 | } | ||
373 | else // finish creating the MSI/MSM | ||
374 | { | ||
375 | if (String.IsNullOrEmpty(outputExtension) || outputExtension.Equals(".wix", StringComparison.Ordinal)) | ||
376 | { | ||
377 | outputExtension = Output.GetExtension(output.Type); | ||
378 | outputFile = Path.ChangeExtension(outputFile, outputExtension); | ||
379 | } | ||
380 | |||
381 | binder.Bind(output, outputFile); | ||
382 | } | ||
383 | } | ||
384 | catch (WixException we) // keep files around for debugging IDT issues. | ||
385 | { | ||
386 | if (we is WixInvalidIdtException) | ||
387 | { | ||
388 | tidy = false; | ||
389 | } | ||
390 | |||
391 | throw; | ||
392 | } | ||
393 | catch (Exception) // keep files around for debugging unexpected exceptions. | ||
394 | { | ||
395 | tidy = false; | ||
396 | throw; | ||
397 | } | ||
398 | finally | ||
399 | { | ||
400 | if (null != binder) | ||
401 | { | ||
402 | binder.Cleanup(tidy); | ||
403 | } | ||
404 | } | ||
405 | |||
406 | return; | ||
407 | #endif | ||
408 | } | ||
409 | |||
410 | #if false | ||
411 | private Localizer InitializeLocalization(TableDefinitionCollection tableDefinitions) | ||
412 | { | ||
413 | Localizer localizer = null; | ||
414 | |||
415 | // Instantiate the localizer and load any localization files. | ||
416 | if (!this.commandLine.SuppressLocalization || 0 < this.commandLine.LocalizationFiles.Count || null != this.commandLine.Cultures || !this.commandLine.OutputXml) | ||
417 | { | ||
418 | List<Localization> localizations = new List<Localization>(); | ||
419 | |||
420 | // Load each localization file. | ||
421 | foreach (string localizationFile in this.commandLine.LocalizationFiles) | ||
422 | { | ||
423 | Localization localization = Localizer.ParseLocalizationFile(localizationFile, tableDefinitions); | ||
424 | if (null != localization) | ||
425 | { | ||
426 | localizations.Add(localization); | ||
427 | } | ||
428 | } | ||
429 | |||
430 | localizer = new Localizer(); | ||
431 | if (null != this.commandLine.Cultures) | ||
432 | { | ||
433 | // Alocalizations in order specified in cultures. | ||
434 | foreach (string culture in this.commandLine.Cultures) | ||
435 | { | ||
436 | foreach (Localization localization in localizations) | ||
437 | { | ||
438 | if (culture.Equals(localization.Culture, StringComparison.OrdinalIgnoreCase)) | ||
439 | { | ||
440 | localizer.AddLocalization(localization); | ||
441 | } | ||
442 | } | ||
443 | } | ||
444 | } | ||
445 | else // no cultures specified, so try neutral culture and if none of those add all loc files. | ||
446 | { | ||
447 | bool neutralFound = false; | ||
448 | foreach (Localization localization in localizations) | ||
449 | { | ||
450 | if (String.IsNullOrEmpty(localization.Culture)) | ||
451 | { | ||
452 | // If a neutral wxl was provided use it. | ||
453 | localizer.AddLocalization(localization); | ||
454 | neutralFound = true; | ||
455 | } | ||
456 | } | ||
457 | |||
458 | if (!neutralFound) | ||
459 | { | ||
460 | // No cultures were specified and no neutral wxl are available, include all of the loc files. | ||
461 | foreach (Localization localization in localizations) | ||
462 | { | ||
463 | localizer.AddLocalization(localization); | ||
464 | } | ||
465 | } | ||
466 | } | ||
467 | |||
468 | // Load localizations provided by extensions with data. | ||
469 | foreach (IExtensionData data in this.extensionData) | ||
470 | { | ||
471 | Library library = data.GetLibrary(tableDefinitions); | ||
472 | if (null != library) | ||
473 | { | ||
474 | // Load the extension's default culture if it provides one and no cultures were specified. | ||
475 | string[] extensionCultures = this.commandLine.Cultures; | ||
476 | if (null == extensionCultures && null != data.DefaultCulture) | ||
477 | { | ||
478 | extensionCultures = new string[] { data.DefaultCulture }; | ||
479 | } | ||
480 | |||
481 | AddLibraryLocalizationsToLocalizer(library, extensionCultures, localizer); | ||
482 | } | ||
483 | } | ||
484 | } | ||
485 | |||
486 | return localizer; | ||
487 | } | ||
488 | |||
489 | private void AddLibraryLocalizationsToLocalizer(Library library, string[] cultures, Localizer localizer) | ||
490 | { | ||
491 | foreach (Localization localization in library.GetLocalizations(cultures)) | ||
492 | { | ||
493 | localizer.AddLocalization(localization); | ||
494 | } | ||
495 | } | ||
496 | #endif | ||
497 | |||
498 | private bool TryParseCommandLineArgumentWithExtension(string arg, IEnumerable<IExtensionCommandLine> extensions) | ||
499 | { | ||
500 | foreach (var extension in extensions) | ||
501 | { | ||
502 | // TODO: decide what to do with "IParseCommandLine" argument. | ||
503 | if (extension.TryParseArgument(null, arg)) | ||
504 | { | ||
505 | return true; | ||
506 | } | ||
507 | } | ||
508 | |||
509 | return false; | ||
510 | } | ||
511 | |||
512 | private IEnumerable<Localization> LoadLocalizationFiles(IMessaging messaging, IEnumerable<string> locFiles) | ||
513 | { | ||
514 | foreach (var loc in locFiles) | ||
515 | { | ||
516 | var localization = Localizer.ParseLocalizationFile(messaging, loc); | ||
517 | |||
518 | yield return localization; | ||
519 | } | ||
520 | } | ||
521 | |||
522 | private Intermediate LoadWixout(IMessaging messaging) | ||
523 | { | ||
524 | var path = this.commandLine.Files.Single(); | ||
525 | |||
526 | return Intermediate.Load(path); | ||
527 | } | ||
528 | |||
529 | private static IExtensionManager CreateExtensionManagerWithStandardBackends(IServiceProvider serviceProvider) | ||
530 | { | ||
531 | var extensionManager = serviceProvider.GetService<IExtensionManager>(); | ||
532 | |||
533 | foreach (var type in new[] { typeof(WixToolset.Core.Burn.WixToolsetStandardBackend), typeof(WixToolset.Core.WindowsInstaller.WixToolsetStandardBackend) }) | ||
534 | { | ||
535 | extensionManager.Add(type.Assembly); | ||
536 | } | ||
537 | |||
538 | return extensionManager; | ||
539 | } | ||
540 | |||
541 | private static void PrintHelp() | ||
542 | { | ||
543 | string lightArgs = LightStrings.CommandLineArguments; | ||
544 | |||
545 | Console.WriteLine(String.Format(LightStrings.HelpMessage, lightArgs)); | ||
546 | } | ||
547 | |||
548 | private class ConsoleMessageListener : IMessageListener | ||
549 | { | ||
550 | public ConsoleMessageListener(string shortName, string longName) | ||
551 | { | ||
552 | this.ShortAppName = shortName; | ||
553 | this.LongAppName = longName; | ||
554 | |||
555 | PrepareConsoleForLocalization(); | ||
556 | } | ||
557 | |||
558 | public string LongAppName { get; } | ||
559 | |||
560 | public string ShortAppName { get; } | ||
561 | |||
562 | public void Write(Message message) | ||
563 | { | ||
564 | var filename = message.SourceLineNumbers?.FileName ?? this.LongAppName; | ||
565 | var line = message.SourceLineNumbers?.LineNumber ?? -1; | ||
566 | var type = message.Level.ToString().ToLowerInvariant(); | ||
567 | var output = message.Level >= MessageLevel.Warning ? Console.Out : Console.Error; | ||
568 | |||
569 | if (line > 0) | ||
570 | { | ||
571 | filename = String.Concat(filename, "(", line, ")"); | ||
572 | } | ||
573 | |||
574 | output.WriteLine("{0} : {1} {2}{3:0000}: {4}", filename, type, this.ShortAppName, message.Id, message.ToString()); | ||
575 | } | ||
576 | |||
577 | public void Write(string message) | ||
578 | { | ||
579 | Console.Out.WriteLine(message); | ||
580 | } | ||
581 | |||
582 | private static void PrepareConsoleForLocalization() | ||
583 | { | ||
584 | Thread.CurrentThread.CurrentUICulture = CultureInfo.CurrentUICulture.GetConsoleFallbackUICulture(); | ||
585 | |||
586 | if (Console.OutputEncoding.CodePage != Encoding.UTF8.CodePage && | ||
587 | Console.OutputEncoding.CodePage != Thread.CurrentThread.CurrentUICulture.TextInfo.OEMCodePage && | ||
588 | Console.OutputEncoding.CodePage != Thread.CurrentThread.CurrentUICulture.TextInfo.ANSICodePage) | ||
589 | { | ||
590 | Thread.CurrentThread.CurrentUICulture = new CultureInfo("en-US"); | ||
591 | } | ||
592 | } | ||
593 | } | ||
594 | } | ||
595 | } | ||
diff --git a/src/light/light.csproj b/src/light/light.csproj new file mode 100644 index 00000000..20e10b11 --- /dev/null +++ b/src/light/light.csproj | |||
@@ -0,0 +1,21 @@ | |||
1 | <?xml version="1.0" encoding="utf-8"?> | ||
2 | <!-- 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. --> | ||
3 | |||
4 | <Project Sdk="Microsoft.NET.Sdk"> | ||
5 | <PropertyGroup> | ||
6 | <TargetFramework>net461</TargetFramework> | ||
7 | <OutputType>Exe</OutputType> | ||
8 | <Description>Linker</Description> | ||
9 | <Title>WiX Toolset Linker</Title> | ||
10 | </PropertyGroup> | ||
11 | |||
12 | <ItemGroup> | ||
13 | <ProjectReference Include="..\WixToolset.Core\WixToolset.Core.csproj" /> | ||
14 | <ProjectReference Include="..\WixToolset.Core.Burn\WixToolset.Core.Burn.csproj" /> | ||
15 | <ProjectReference Include="..\WixToolset.Core.WindowsInstaller\WixToolset.Core.WindowsInstaller.csproj" /> | ||
16 | </ItemGroup> | ||
17 | |||
18 | <ItemGroup> | ||
19 | <PackageReference Include="Nerdbank.GitVersioning" Version="2.0.41" PrivateAssets="all" /> | ||
20 | </ItemGroup> | ||
21 | </Project> | ||
diff --git a/src/test/WixToolsetTest.LightIntegration/LightFixture.cs b/src/test/WixToolsetTest.LightIntegration/LightFixture.cs new file mode 100644 index 00000000..21c10be9 --- /dev/null +++ b/src/test/WixToolsetTest.LightIntegration/LightFixture.cs | |||
@@ -0,0 +1,48 @@ | |||
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 | |||
3 | namespace WixToolsetTest.LightIntegration | ||
4 | { | ||
5 | using System.IO; | ||
6 | using System.Linq; | ||
7 | using WixToolset.Core; | ||
8 | using WixToolset.Tools; | ||
9 | using WixToolsetTest.LightIntegration.Utility; | ||
10 | using Xunit; | ||
11 | |||
12 | public class LightFixture | ||
13 | { | ||
14 | [Fact] | ||
15 | public void CanBuildFromWixout() | ||
16 | { | ||
17 | var folder = TestData.Get(@"TestData\Wixout"); | ||
18 | |||
19 | using (var fs = new DisposableFileSystem()) | ||
20 | { | ||
21 | var baseFolder = fs.GetFolder(); | ||
22 | var intermediateFolder = Path.Combine(baseFolder, "obj"); | ||
23 | |||
24 | var program = new Light(); | ||
25 | var result = program.Run(new WixToolsetServiceProvider(), null, new[] | ||
26 | { | ||
27 | Path.Combine(folder, "test.wixout"), | ||
28 | "-loc", Path.Combine(folder, "Package.en-us.wxl"), | ||
29 | "-b", Path.Combine(folder, "data"), | ||
30 | "-intermediateFolder", intermediateFolder, | ||
31 | "-o", Path.Combine(baseFolder, @"bin\test.msi") | ||
32 | }); | ||
33 | |||
34 | Assert.Equal(0, result); | ||
35 | |||
36 | var binFolder = Path.Combine(baseFolder, @"bin\"); | ||
37 | var builtFiles = Directory.GetFiles(binFolder, "*", SearchOption.AllDirectories); | ||
38 | |||
39 | Assert.Equal(new[]{ | ||
40 | "MsiPackage\\test.txt", | ||
41 | "test.msi", | ||
42 | "test.wir", | ||
43 | "test.wixpdb", | ||
44 | }, builtFiles.Select(f => f.Substring(binFolder.Length)).OrderBy(s => s).ToArray()); | ||
45 | } | ||
46 | } | ||
47 | } | ||
48 | } | ||
diff --git a/src/test/WixToolsetTest.LightIntegration/TestData/Wixout/Package.en-us.wxl b/src/test/WixToolsetTest.LightIntegration/TestData/Wixout/Package.en-us.wxl new file mode 100644 index 00000000..38c12ac1 --- /dev/null +++ b/src/test/WixToolsetTest.LightIntegration/TestData/Wixout/Package.en-us.wxl | |||
@@ -0,0 +1,11 @@ | |||
1 | <?xml version="1.0" encoding="utf-8"?> | ||
2 | |||
3 | <!-- | ||
4 | This file contains the declaration of all the localizable strings. | ||
5 | --> | ||
6 | <WixLocalization xmlns="http://wixtoolset.org/schemas/v4/wxl" Culture="en-US"> | ||
7 | |||
8 | <String Id="DowngradeError">A newer version of [ProductName] is already installed.</String> | ||
9 | <String Id="FeatureTitle">MsiPackage</String> | ||
10 | |||
11 | </WixLocalization> | ||
diff --git a/src/test/WixToolsetTest.LightIntegration/TestData/Wixout/data/test.txt b/src/test/WixToolsetTest.LightIntegration/TestData/Wixout/data/test.txt new file mode 100644 index 00000000..cd0db0e1 --- /dev/null +++ b/src/test/WixToolsetTest.LightIntegration/TestData/Wixout/data/test.txt | |||
@@ -0,0 +1 @@ | |||
This is test.txt. \ No newline at end of file | |||
diff --git a/src/test/WixToolsetTest.LightIntegration/TestData/Wixout/test.wixout b/src/test/WixToolsetTest.LightIntegration/TestData/Wixout/test.wixout new file mode 100644 index 00000000..009b625f --- /dev/null +++ b/src/test/WixToolsetTest.LightIntegration/TestData/Wixout/test.wixout | |||
Binary files differ | |||
diff --git a/src/test/WixToolsetTest.LightIntegration/Utility/DisposableFileSystem.cs b/src/test/WixToolsetTest.LightIntegration/Utility/DisposableFileSystem.cs new file mode 100644 index 00000000..3b8c0e19 --- /dev/null +++ b/src/test/WixToolsetTest.LightIntegration/Utility/DisposableFileSystem.cs | |||
@@ -0,0 +1,86 @@ | |||
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 | |||
3 | namespace WixToolsetTest.LightIntegration.Utility | ||
4 | { | ||
5 | using System; | ||
6 | using System.Collections.Generic; | ||
7 | using System.IO; | ||
8 | |||
9 | public class DisposableFileSystem : IDisposable | ||
10 | { | ||
11 | protected bool Disposed { get; private set; } | ||
12 | |||
13 | private List<string> CleanupPaths { get; } = new List<string>(); | ||
14 | |||
15 | protected string GetFile(bool create = false) | ||
16 | { | ||
17 | var path = Path.GetTempFileName(); | ||
18 | |||
19 | if (!create) | ||
20 | { | ||
21 | File.Delete(path); | ||
22 | } | ||
23 | |||
24 | this.CleanupPaths.Add(path); | ||
25 | |||
26 | return path; | ||
27 | } | ||
28 | |||
29 | public string GetFolder(bool create = false) | ||
30 | { | ||
31 | var path = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName()); | ||
32 | |||
33 | if (create) | ||
34 | { | ||
35 | Directory.CreateDirectory(path); | ||
36 | } | ||
37 | |||
38 | this.CleanupPaths.Add(path); | ||
39 | |||
40 | return path; | ||
41 | } | ||
42 | |||
43 | |||
44 | #region // IDisposable | ||
45 | |||
46 | public void Dispose() | ||
47 | { | ||
48 | this.Dispose(true); | ||
49 | GC.SuppressFinalize(this); | ||
50 | } | ||
51 | |||
52 | protected virtual void Dispose(bool disposing) | ||
53 | { | ||
54 | if (this.Disposed) | ||
55 | { | ||
56 | return; | ||
57 | } | ||
58 | |||
59 | if (disposing) | ||
60 | { | ||
61 | foreach (var path in this.CleanupPaths) | ||
62 | { | ||
63 | try | ||
64 | { | ||
65 | if (File.Exists(path)) | ||
66 | { | ||
67 | File.Delete(path); | ||
68 | } | ||
69 | else if (Directory.Exists(path)) | ||
70 | { | ||
71 | Directory.Delete(path, true); | ||
72 | } | ||
73 | } | ||
74 | catch | ||
75 | { | ||
76 | // Best effort delete, so ignore any failures. | ||
77 | } | ||
78 | } | ||
79 | } | ||
80 | |||
81 | this.Disposed = true; | ||
82 | } | ||
83 | |||
84 | #endregion | ||
85 | } | ||
86 | } | ||
diff --git a/src/test/WixToolsetTest.LightIntegration/Utility/TestData.cs b/src/test/WixToolsetTest.LightIntegration/Utility/TestData.cs new file mode 100644 index 00000000..c13e9d6d --- /dev/null +++ b/src/test/WixToolsetTest.LightIntegration/Utility/TestData.cs | |||
@@ -0,0 +1,17 @@ | |||
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 | |||
3 | namespace WixToolsetTest.LightIntegration.Utility | ||
4 | { | ||
5 | using System; | ||
6 | using System.IO; | ||
7 | |||
8 | public class TestData | ||
9 | { | ||
10 | public static string LocalPath => Path.GetDirectoryName(new Uri(System.Reflection.Assembly.GetExecutingAssembly().CodeBase).LocalPath); | ||
11 | |||
12 | public static string Get(params string[] paths) | ||
13 | { | ||
14 | return Path.Combine(LocalPath, Path.Combine(paths)); | ||
15 | } | ||
16 | } | ||
17 | } | ||
diff --git a/src/test/WixToolsetTest.LightIntegration/WixToolsetTest.LightIntegration.csproj b/src/test/WixToolsetTest.LightIntegration/WixToolsetTest.LightIntegration.csproj new file mode 100644 index 00000000..ef303868 --- /dev/null +++ b/src/test/WixToolsetTest.LightIntegration/WixToolsetTest.LightIntegration.csproj | |||
@@ -0,0 +1,33 @@ | |||
1 | <?xml version="1.0" encoding="utf-8"?> | ||
2 | <!-- 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. --> | ||
3 | |||
4 | <Project Sdk="Microsoft.NET.Sdk"> | ||
5 | <PropertyGroup> | ||
6 | <TargetFramework>net461</TargetFramework> | ||
7 | <IsPackable>false</IsPackable> | ||
8 | </PropertyGroup> | ||
9 | <ItemGroup> | ||
10 | <None Remove="TestData\Wixout\Package.en-us.wxl" /> | ||
11 | <None Remove="TestData\Wixout\test.wixout" /> | ||
12 | </ItemGroup> | ||
13 | |||
14 | <ItemGroup> | ||
15 | <Content Include="TestData\Wixout\data\test.txt" CopyToOutputDirectory="PreserveNewest" /> | ||
16 | <Content Include="TestData\Wixout\Package.en-us.wxl"> | ||
17 | <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> | ||
18 | </Content> | ||
19 | <Content Include="TestData\Wixout\test.wixout"> | ||
20 | <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> | ||
21 | </Content> | ||
22 | </ItemGroup> | ||
23 | |||
24 | <ItemGroup> | ||
25 | <ProjectReference Include="..\..\light\light.csproj" /> | ||
26 | </ItemGroup> | ||
27 | |||
28 | <ItemGroup> | ||
29 | <PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.3.0-preview-20170628-02" /> | ||
30 | <PackageReference Include="xunit" Version="2.2.0" /> | ||
31 | <PackageReference Include="xunit.runner.visualstudio" Version="2.2.0" /> | ||
32 | </ItemGroup> | ||
33 | </Project> | ||