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 /src | |
| parent | dc9f4c329e6f55ce7595970463e0caf148096f4b (diff) | |
| download | wix-ecf3a0cca5a424a91ab98557d963d2535963d582.tar.gz wix-ecf3a0cca5a424a91ab98557d963d2535963d582.tar.bz2 wix-ecf3a0cca5a424a91ab98557d963d2535963d582.zip | |
Reintroduce binder extensions and light.exe for binding .wixouts
Diffstat (limited to 'src')
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> | ||
