@joebigelow / wix-1 / commits / c08fd0ae

Introduce WixToolsetServiceProvider

Using a service provider allows all of WixToolset.Core's internal functionality to be abstracted behind interfaces in WixToolset.Extensibility. The service provide can also control what interfaces are singletons.

Rob Mensching committed Oct 17, 2017 at 02:47 UTC c08fd0aefeea1628fe93c818ca4dde63fd6ac2e1
29 files changed +242 -82
src/Directory.Build.props
+2 -1
@@ -5,7 +5,8 @@
5 <PropertyGroup>
6 <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
7 <BaseIntermediateOutputPath>$(MSBuildThisFileDirectory)..\build\obj\$(MSBuildProjectName)\</BaseIntermediateOutputPath>
8 - <OutputPath>$(MSBuildThisFileDirectory)..\build\$(Configuration)\</OutputPath>
8 + <BaseOutputPath>$(MSBuildThisFileDirectory)..\build\$(Configuration)\</BaseOutputPath>
9 + <OutputPath>$(BaseOutputPath)</OutputPath>
10
11 <Authors>WiX Toolset Team</Authors>
12 <Company>WiX Toolset</Company>
src/WixToolset.BuildTasks/DoIt.cs
+22 -1
@@ -9,6 +9,7 @@ namespace WixToolset.BuildTasks
9 using Microsoft.Build.Utilities;
10 using WixToolset.Core;
11 using WixToolset.Data;
12 + using WixToolset.Extensibility.Services;
13
14 /// <summary>
15 /// An MSBuild task to run the WiX compiler.
@@ -164,10 +165,30 @@ namespace WixToolset.BuildTasks
165
166 this.Log.LogMessage(MessageImportance.Normal, "wix.exe " + commandLineString);
167
167 - var command = CommandLine.ParseStandardCommandLine(commandLineString);
168 + var serviceProvider = new WixToolsetServiceProvider();
169 +
170 + var context = serviceProvider.GetService<ICommandLineContext>();
171 + context.Messaging = Messaging.Instance;
172 + context.ExtensionManager = this.CreateExtensionManagerWithStandardBackends(serviceProvider);
173 + context.Arguments = commandLineString;
174 +
175 + var commandLine = serviceProvider.GetService<ICommandLine>();
176 + var command = commandLine.ParseStandardCommandLine(context);
177 command?.Execute();
178 }
179
180 + private IExtensionManager CreateExtensionManagerWithStandardBackends(IServiceProvider serviceProvider)
181 + {
182 + var extensionManager = serviceProvider.GetService<IExtensionManager>();
183 +
184 + foreach (var type in new[] { typeof(WixToolset.Core.Burn.StandardBackend), typeof(WixToolset.Core.WindowsInstaller.StandardBackend) })
185 + {
186 + extensionManager.Add(type.Assembly);
187 + }
188 +
189 + return extensionManager;
190 + }
191 +
192 private void DisplayMessage(object sender, DisplayEventArgs e)
193 {
194 this.Log.LogMessageFromText(e.Message, MessageImportance.Normal);
src/WixToolset.Core.Burn/BackendFactory.cs
+1
@@ -5,6 +5,7 @@ namespace WixToolset.Core.Burn
5 using System;
6 using System.IO;
7 using WixToolset.Extensibility;
8 + using WixToolset.Extensibility.Services;
9
10 internal class BackendFactory : IBackendFactory
11 {
src/WixToolset.Core.Burn/Bind/BindBundleCommand.cs
+1
@@ -16,6 +16,7 @@ namespace WixToolset.Core.Burn
16 using WixToolset.Data.Bind;
17 using WixToolset.Data.Rows;
18 using WixToolset.Extensibility;
19 + using WixToolset.Extensibility.Services;
20
21 // TODO: (4.0) Refactor so that these don't need to be copied.
22 // Copied verbatim from ext\UtilExtension\wixext\UtilCompiler.cs
src/WixToolset.Core.Burn/BundleBackend.cs
+1
@@ -9,6 +9,7 @@ namespace WixToolset.Core.Burn
9 using WixToolset.Data;
10 using WixToolset.Data.Bind;
11 using WixToolset.Extensibility;
12 + using WixToolset.Extensibility.Services;
13
14 internal class BundleBackend : IBackend
15 {
src/WixToolset.Core.Burn/StandardBackend.cs new
+12
@@ -0,0 +1,12 @@
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.Burn
4 +{
5 + /// <summary>
6 + /// Denotes this assembly contains a backend that is considered
7 + /// a standard part of the WiX Toolset.
8 + /// </summary>
9 + public static class StandardBackend
10 + {
11 + }
12 +}
src/WixToolset.Core.WindowsInstaller/Bind/BindDatabaseCommand.cs
+1
@@ -16,6 +16,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
16 using WixToolset.Data.Bind;
17 using WixToolset.Data.Rows;
18 using WixToolset.Extensibility;
19 + using WixToolset.Extensibility.Services;
20 using WixToolset.Msi;
21
22 /// <summary>
src/WixToolset.Core.WindowsInstaller/MsiBackend.cs
+1
@@ -8,6 +8,7 @@ namespace WixToolset.Core.WindowsInstaller
8 using WixToolset.Data;
9 using WixToolset.Data.Bind;
10 using WixToolset.Extensibility;
11 + using WixToolset.Extensibility.Services;
12
13 internal class MsiBackend : IBackend
14 {
src/WixToolset.Core.WindowsInstaller/MsmBackend.cs
+1
@@ -7,6 +7,7 @@ namespace WixToolset.Core.WindowsInstaller
7 using WixToolset.Data;
8 using WixToolset.Data.Bind;
9 using WixToolset.Extensibility;
10 + using WixToolset.Extensibility.Services;
11
12 internal class MsmBackend : IBackend
13 {
src/WixToolset.Core.WindowsInstaller/MspBackend.cs
+1
@@ -10,6 +10,7 @@ namespace WixToolset.Core.WindowsInstaller
10 using WixToolset.Data;
11 using WixToolset.Data.Bind;
12 using WixToolset.Extensibility;
13 + using WixToolset.Extensibility.Services;
14 using WixToolset.Msi;
15 using WixToolset.Ole32;
16
src/WixToolset.Core.WindowsInstaller/MstBackend.cs
+1
@@ -8,6 +8,7 @@ namespace WixToolset.Core.WindowsInstaller
8 using WixToolset.Data;
9 using WixToolset.Data.Bind;
10 using WixToolset.Extensibility;
11 + using WixToolset.Extensibility.Services;
12
13 internal class MstBackend : IBackend
14 {
src/WixToolset.Core.WindowsInstaller/StandardBackend.cs new
+12
@@ -0,0 +1,12 @@
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.WindowsInstaller
4 +{
5 + /// <summary>
6 + /// Denotes this assembly contains a backend that is considered
7 + /// a standard part of the WiX Toolset.
8 + /// </summary>
9 + public static class StandardBackend
10 + {
11 + }
12 +}
src/WixToolset.Core.WindowsInstaller/Validator.cs
+1
@@ -16,6 +16,7 @@ namespace WixToolset.Core.WindowsInstaller
16 using WixToolset.Msi;
17 using System.Linq;
18 using System.Reflection;
19 + using WixToolset.Extensibility.Services;
20
21 /// <summary>
22 /// Runs internal consistency evaluators (ICEs) from cub files against a database.
src/WixToolset.Core.WindowsInstaller/WindowsInstallerBackendFactory.cs
+1
@@ -5,6 +5,7 @@ namespace WixToolset.Core.WindowsInstaller
5 using System;
6 using System.IO;
7 using WixToolset.Extensibility;
8 + using WixToolset.Extensibility.Services;
9
10 internal class WindowsInstallerBackendFactory : IBackendFactory
11 {
src/WixToolset.Core/BindContext.cs
+9
@@ -2,12 +2,21 @@
2
3 namespace WixToolset.Core
4 {
5 + using System;
6 using System.Collections.Generic;
7 using WixToolset.Data;
8 using WixToolset.Extensibility;
9 + using WixToolset.Extensibility.Services;
10
11 public class BindContext : IBindContext
12 {
13 + internal BindContext(IServiceProvider serviceProvider)
14 + {
15 + this.ServiceProvider = serviceProvider;
16 + }
17 +
18 + public IServiceProvider ServiceProvider { get; }
19 +
20 public Messaging Messaging { get; set; }
21
22 public IEnumerable<BindPath> BindPaths { get; set; }
src/WixToolset.Core/Binder.cs
+3 -2
@@ -16,6 +16,7 @@ namespace WixToolset.Core
16 using WixToolset.Data.Bind;
17 using WixToolset.Data.Rows;
18 using WixToolset.Extensibility;
19 + using WixToolset.Extensibility.Services;
20
21 /// <summary>
22 /// Binder of the WiX toolset.
@@ -42,14 +43,14 @@ namespace WixToolset.Core
43 //this.SuppressIces = new List<string>();
44 }
45
45 - public Binder(BindContext context)
46 + public Binder(IBindContext context)
47 {
48 this.Context = context;
49
50 this.TableDefinitions = WindowsInstallerStandard.GetTableDefinitions();
51 }
52
52 - private BindContext Context { get; }
53 + private IBindContext Context { get; }
54
55 private TableDefinitionCollection TableDefinitions { get; }
56
src/WixToolset.Core/CommandLine/BuildCommand.cs
+7 -3
@@ -9,11 +9,13 @@ namespace WixToolset.Core
9 using WixToolset.Data;
10 using WixToolset.Data.Rows;
11 using WixToolset.Extensibility;
12 + using WixToolset.Extensibility.Services;
13
14 internal class BuildCommand : ICommandLineCommand
15 {
15 - public BuildCommand(ExtensionManager 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, 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)
17 {
18 + this.ServiceProvider = serviceProvider;
19 this.ExtensionManager = extensions;
20 this.LocFiles = locFiles;
21 this.LibraryFiles = libraryFiles;
@@ -34,7 +36,9 @@ namespace WixToolset.Core
36 this.WixProjectFile = wixProjectFile;
37 }
38
37 - public ExtensionManager ExtensionManager { get; }
39 + public IServiceProvider ServiceProvider { get; }
40 +
41 + public IExtensionManager ExtensionManager { get; }
42
43 public IEnumerable<string> LocFiles { get; }
44
@@ -173,7 +177,7 @@ namespace WixToolset.Core
177 intermediateFolder = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());
178 }
179
176 - var context = new BindContext();
180 + var context = this.ServiceProvider.GetService<IBindContext>();
181 context.Messaging = Messaging.Instance;
182 context.ExtensionManager = this.ExtensionManager;
183 context.BindPaths = this.BindPaths ?? Array.Empty<BindPath>();
src/WixToolset.Core/CommandLine/CommandLine.cs
+30 -34
@@ -6,11 +6,11 @@ namespace WixToolset.Core
6 using System.Collections.Generic;
7 using System.IO;
8 using System.Linq;
9 - using System.Reflection;
9 using System.Text;
10 using System.Text.RegularExpressions;
11 using WixToolset.Data;
12 using WixToolset.Extensibility;
13 + using WixToolset.Extensibility.Services;
14
15 internal enum Commands
16 {
@@ -22,12 +22,14 @@ namespace WixToolset.Core
22 Bind,
23 }
24
25 - public class CommandLine
25 + internal class CommandLine : ICommandLine
26 {
27 - private CommandLine()
27 + public CommandLine()
28 {
29 }
30
31 + private IServiceProvider ServiceProvider { get; set; }
32 +
33 public static string ExpectedArgument { get; } = "expected argument";
34
35 public string ActiveCommand { get; private set; }
@@ -36,20 +38,29 @@ namespace WixToolset.Core
38
39 public Queue<string> RemainingArguments { get; } = new Queue<string>();
40
39 - public ExtensionManager ExtensionManager { get; } = new ExtensionManager();
41 + public IExtensionManager ExtensionManager { get; private set; }
42
43 public string ErrorArgument { get; set; }
44
45 public bool ShowHelp { get; set; }
46
45 - public static ICommandLineCommand ParseStandardCommandLine(string commandLineString)
47 + public ICommandLineCommand ParseStandardCommandLine(ICommandLineContext context)
48 {
47 - var args = CommandLine.ParseArgumentsToArray(commandLineString).ToArray();
49 + this.ServiceProvider = context.ServiceProvider;
50 +
51 + this.ExtensionManager = context.ExtensionManager ?? this.ServiceProvider.GetService<IExtensionManager>();
52 +
53 + var args = context.ParsedArguments ?? Array.Empty<string>();
54 +
55 + if (!String.IsNullOrEmpty(context.Arguments))
56 + {
57 + args = CommandLine.ParseArgumentsToArray(context.Arguments).Union(args).ToArray();
58 + }
59
49 - return ParseStandardCommandLine(args);
60 + return this.ParseStandardCommandLine(args);
61 }
62
52 - public static ICommandLineCommand ParseStandardCommandLine(string[] args)
63 + private ICommandLineCommand ParseStandardCommandLine(string[] args)
64 {
65 var next = String.Empty;
66
@@ -79,7 +90,7 @@ namespace WixToolset.Core
90 var builtOutputsFile = String.Empty;
91 var wixProjectFile = String.Empty;
92
82 - var cli = CommandLine.Parse(args, (cmdline, arg) => Enum.TryParse(arg, true, out command), (cmdline, arg) =>
93 + this.Parse(args, (cmdline, arg) => Enum.TryParse(arg, true, out command), (cmdline, arg) =>
94 {
95 if (cmdline.IsSwitch(arg))
96 {
@@ -103,7 +114,7 @@ namespace WixToolset.Core
114 case "cc":
115 cmdline.GetNextArgumentOrError(ref cabCachePath);
116 return true;
106 -
117 +
118 case "cultures":
119 cmdline.GetNextArgumentOrError(cultures);
120 return true;
@@ -187,7 +198,7 @@ namespace WixToolset.Core
198 AppCommon.DisplayToolHeader();
199 }
200
190 - if (cli.ShowHelp)
201 + if (this.ShowHelp)
202 {
203 return new HelpCommand(command);
204 }
@@ -196,14 +207,11 @@ namespace WixToolset.Core
207 {
208 case Commands.Build:
209 {
199 - LoadStandardBackends(cli.ExtensionManager);
200 -
210 var sourceFiles = GatherSourceFiles(files, outputFolder);
211 var variables = GatherPreprocessorVariables(defines);
212 var bindPathList = GatherBindPaths(bindPaths);
204 - var extensions = cli.ExtensionManager;
213 var type = CalculateOutputType(outputType, outputFile);
206 - return new BuildCommand(extensions, sourceFiles, variables, locFiles, libraryFiles, outputFile, type, cabCachePath, cultures, bindFiles, bindPathList, intermediateFolder, contentsFile, outputsFile, builtOutputsFile, wixProjectFile);
214 + return new BuildCommand(this.ServiceProvider, this.ExtensionManager, sourceFiles, variables, locFiles, libraryFiles, outputFile, type, cabCachePath, cultures, bindFiles, bindPathList, intermediateFolder, contentsFile, outputsFile, builtOutputsFile, wixProjectFile);
215 }
216
217 case Commands.Compile:
@@ -217,18 +225,6 @@ namespace WixToolset.Core
225 return null;
226 }
227
220 - private static void LoadStandardBackends(ExtensionManager extensionManager)
221 - {
222 - var folder = Path.GetDirectoryName(new Uri(Assembly.GetExecutingAssembly().CodeBase).LocalPath);
223 -
224 - foreach (var backendAssemblyName in new[] { "WixToolset.Core.Burn.dll", "WixToolset.Core.WindowsInstaller.dll" })
225 - {
226 - var path = Path.Combine(folder, backendAssemblyName);
227 -
228 - extensionManager.Load(path);
229 - }
230 - }
231 -
228 private static OutputType CalculateOutputType(string outputType, string outputFile)
229 {
230 if (String.IsNullOrEmpty(outputType))
@@ -269,6 +265,7 @@ namespace WixToolset.Core
265 return OutputType.Unknown;
266 }
267
268 +#if UNUSED
269 private static CommandLine Parse(string commandLineString, Func<CommandLine, string, bool> parseArgument)
270 {
271 var arguments = CommandLine.ParseArgumentsToArray(commandLineString).ToArray();
@@ -280,18 +277,17 @@ namespace WixToolset.Core
277 {
278 return CommandLine.Parse(commandLineArguments, null, parseArgument);
279 }
280 +#endif
281
284 - private static CommandLine Parse(string[] commandLineArguments, Func<CommandLine, string, bool> parseCommand, Func<CommandLine, string, bool> parseArgument)
282 + private ICommandLine Parse(string[] commandLineArguments, Func<CommandLine, string, bool> parseCommand, Func<CommandLine, string, bool> parseArgument)
283 {
286 - var cmdline = new CommandLine();
287 -
288 - cmdline.FlattenArgumentsWithResponseFilesIntoOriginalArguments(commandLineArguments);
284 + this.FlattenArgumentsWithResponseFilesIntoOriginalArguments(commandLineArguments);
285
290 - cmdline.QueueArgumentsAndLoadExtensions(cmdline.OriginalArguments);
286 + this.QueueArgumentsAndLoadExtensions(this.OriginalArguments);
287
292 - cmdline.ProcessRemainingArguments(parseArgument, parseCommand);
288 + this.ProcessRemainingArguments(parseArgument, parseCommand);
289
294 - return cmdline;
290 + return this;
291 }
292
293 private static IEnumerable<SourceFile> GatherSourceFiles(IEnumerable<string> sourceFiles, string intermediateDirectory)
src/WixToolset.Core/CommandLine/CommandLineContext.cs new
+26
@@ -0,0 +1,26 @@
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
4 +{
5 + using System;
6 + using WixToolset.Data;
7 + using WixToolset.Extensibility.Services;
8 +
9 + internal class CommandLineContext : ICommandLineContext
10 + {
11 + public CommandLineContext(IServiceProvider serviceProvider)
12 + {
13 + this.ServiceProvider = serviceProvider;
14 + }
15 +
16 + public IServiceProvider ServiceProvider { get; }
17 +
18 + public Messaging Messaging { get; set; }
19 +
20 + public IExtensionManager ExtensionManager { get; set; }
21 +
22 + public string Arguments { get; set; }
23 +
24 + public string[] ParsedArguments { get; set; }
25 + }
26 +}
src/WixToolset.Core/CommandLine/CompileCommand.cs
+1 -2
@@ -2,9 +2,8 @@
2
3 namespace WixToolset.Core
4 {
5 - using System;
5 using System.Collections.Generic;
7 - using WixToolset.Data;
6 + using WixToolset.Extensibility.Services;
7
8 internal class CompileCommand : ICommandLineCommand
9 {
src/WixToolset.Core/CommandLine/HelpCommand.cs
+1
@@ -3,6 +3,7 @@
3 namespace WixToolset.Core
4 {
5 using System;
6 + using WixToolset.Extensibility.Services;
7
8 internal class HelpCommand : ICommandLineCommand
9 {
src/WixToolset.Core/CommandLine/ICommandLineCommand.cs deleted
-9
@@ -1,9 +0,0 @@
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
4 -{
5 - public interface ICommandLineCommand
6 - {
7 - int Execute();
8 - }
9 -}
src/WixToolset.Core/CommandLine/VersionCommand.cs
+3 -2
@@ -1,9 +1,10 @@
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 -
3 namespace WixToolset.Core
4 {
5 + using System;
6 + using WixToolset.Extensibility.Services;
7 +
8 internal class VersionCommand : ICommandLineCommand
9 {
10 public int Execute()
src/WixToolset.Core/ExtensionManager.cs
+14 -4
@@ -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.
2
3 -namespace WixToolset
3 +namespace WixToolset.Core
4 {
5 using System;
6 using System.Collections.Generic;
@@ -8,12 +8,23 @@ namespace WixToolset
8 using System.Linq;
9 using System.Reflection;
10 using WixToolset.Data;
11 - using WixToolset.Extensibility;
11 + using WixToolset.Extensibility.Services;
12
13 public class ExtensionManager : IExtensionManager
14 {
15 private List<Assembly> extensionAssemblies = new List<Assembly>();
16
17 + /// <summary>
18 + /// Adds an assembly.
19 + /// </summary>
20 + /// <param name="assembly">Assembly to add to the extension manager.</param>
21 + /// <returns>The assembly added.</returns>
22 + public Assembly Add(Assembly assembly)
23 + {
24 + this.extensionAssemblies.Add(assembly);
25 + return assembly;
26 + }
27 +
28 /// <summary>
29 /// Loads an assembly from a type description string.
30 /// </summary>
@@ -57,8 +68,7 @@ namespace WixToolset
68 assembly = ExtensionManager.ExtensionLoadFrom(assemblyName);
69 }
70
60 - this.extensionAssemblies.Add(assembly);
61 - return assembly;
71 + return this.Add(assembly);
72 }
73
74 /// <summary>
src/WixToolset.Core/IncribeContext.cs
+8
@@ -2,11 +2,19 @@
2
3 namespace WixToolset.Core
4 {
5 + using System;
6 using WixToolset.Data;
7 using WixToolset.Extensibility;
8
9 internal class InscribeContext : IInscribeContext
10 {
11 + public InscribeContext(IServiceProvider serviceProvider)
12 + {
13 + this.ServiceProvider = serviceProvider;
14 + }
15 +
16 + public IServiceProvider ServiceProvider { get; }
17 +
18 public Messaging Messaging { get; } = Messaging.Instance;
19
20 public string IntermediateFolder { get; set; }
src/WixToolset.Core/WixToolsetServiceProvider.cs new
+47
@@ -0,0 +1,47 @@
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
4 +{
5 + using System;
6 + using WixToolset.Extensibility;
7 + using WixToolset.Extensibility.Services;
8 +
9 + public class WixToolsetServiceProvider : IServiceProvider
10 + {
11 + private ExtensionManager extensionManager;
12 +
13 + public object GetService(Type serviceType)
14 + {
15 + if (serviceType == null) throw new ArgumentNullException(nameof(serviceType));
16 +
17 + // Transients.
18 + if (serviceType == typeof(IBindContext))
19 + {
20 + return new BindContext(this);
21 + }
22 +
23 + if (serviceType == typeof(IInscribeContext))
24 + {
25 + return new InscribeContext(this);
26 + }
27 +
28 + if (serviceType == typeof(ICommandLineContext))
29 + {
30 + return new CommandLineContext(this);
31 + }
32 +
33 + if (serviceType == typeof(ICommandLine))
34 + {
35 + return new CommandLine();
36 + }
37 +
38 + // Singletons.
39 + if (serviceType == typeof(IExtensionManager))
40 + {
41 + return extensionManager = extensionManager ?? new ExtensionManager();
42 + }
43 +
44 + throw new ArgumentException($"Unknown service type: {serviceType.Name}", nameof(serviceType));
45 + }
46 + }
47 +}
src/test/WixToolsetTest.CoreIntegrationFixture/ProgramFixture.cs
+1 -1
@@ -20,7 +20,7 @@ namespace WixToolsetTest.CoreIntegrationFixture
20 var intermediateFolder = fs.GetFolder();
21
22 var program = new Program();
23 - var result = program.Run(new[] { "build", "Package.wxs", "PackageComponents.wxs", "-loc", "Package.en-us.wxl", "-bindpath", "data", "-intermediateFolder", intermediateFolder, "-o", $@"{intermediateFolder}\bin\test.msi" });
23 + var result = program.Run(new WixToolsetServiceProvider(), new[] { "build", "Package.wxs", "PackageComponents.wxs", "-loc", "Package.en-us.wxl", "-bindpath", "data", "-intermediateFolder", intermediateFolder, "-o", $@"{intermediateFolder}\bin\test.msi" });
24
25 Assert.Equal(0, result);
26 Assert.True(File.Exists(Path.Combine(intermediateFolder, @"bin\test.msi")));
src/test/WixToolsetTest.CoreIntegrationFixture/WixToolsetTest.CoreIntegrationFixture.csproj
+5 -20
@@ -12,25 +12,14 @@
12 </PropertyGroup>
13
14 <ItemGroup>
15 - <None Remove="TestData\SingleFile\data\test.txt" />
16 - <None Remove="TestData\SingleFile\Package.en-us.wxl" />
17 - <None Remove="TestData\SingleFile\Package.wxs" />
18 - <None Remove="TestData\SingleFile\PackageComponents.wxs" />
15 + <Content Include="TestData\SingleFile\data\test.txt" CopyToOutputDirectory="PreserveNewest" />
16 + <Content Include="TestData\SingleFile\Package.en-us.wxl" CopyToOutputDirectory="PreserveNewest" />
17 + <Content Include="TestData\SingleFile\Package.wxs" CopyToOutputDirectory="PreserveNewest" />
18 + <Content Include="TestData\SingleFile\PackageComponents.wxs" CopyToOutputDirectory="PreserveNewest" />
19 </ItemGroup>
20
21 <ItemGroup>
22 - <Content Include="TestData\SingleFile\data\test.txt">
23 - <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
24 - </Content>
25 - <Content Include="TestData\SingleFile\Package.en-us.wxl">
26 - <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
27 - </Content>
28 - <Content Include="TestData\SingleFile\Package.wxs">
29 - <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
30 - </Content>
31 - <Content Include="TestData\SingleFile\PackageComponents.wxs">
32 - <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
33 - </Content>
22 + <ProjectReference Include="..\..\wix\wix.csproj" />
23 </ItemGroup>
24
25 <ItemGroup>
@@ -38,8 +27,4 @@
27 <PackageReference Include="xunit" Version="2.2.0" />
28 <PackageReference Include="xunit.runner.visualstudio" Version="2.2.0" />
29 </ItemGroup>
41 -
42 - <ItemGroup>
43 - <ProjectReference Include="..\..\wix\wix.csproj" />
44 - </ItemGroup>
30 </Project>
src/wix/Program.cs
+29 -3
@@ -4,6 +4,7 @@ namespace WixToolset.Core
4 {
5 using System;
6 using WixToolset.Data;
7 + using WixToolset.Extensibility.Services;
8
9 /// <summary>
10 /// Wix Toolset Command-Line Interface.
@@ -21,16 +22,41 @@ namespace WixToolset.Core
22 Messaging.Instance.InitializeAppName("WIX", "wix.exe");
23 Messaging.Instance.Display += DisplayMessage;
24
25 + var serviceProvider = new WixToolsetServiceProvider();
26 var program = new Program();
25 - return program.Run(args);
27 + return program.Run(serviceProvider, args);
28 }
29
28 - public int Run(string[] args)
30 + /// <summary>
31 + /// Executes the wix command-line interface.
32 + /// </summary>
33 + /// <param name="serviceProvider">Service provider to use throughout this execution.</param>
34 + /// <param name="args">Command-line arguments to execute.</param>
35 + /// <returns>Returns the application error code.</returns>
36 + public int Run(IServiceProvider serviceProvider, string[] args)
37 {
30 - var command = CommandLine.ParseStandardCommandLine(args);
38 + var context = serviceProvider.GetService<ICommandLineContext>();
39 + context.Messaging = Messaging.Instance;
40 + context.ExtensionManager = CreateExtensionManagerWithStandardBackends(serviceProvider);
41 + context.ParsedArguments = args;
42 +
43 + var commandLine = serviceProvider.GetService<ICommandLine>();
44 + var command = commandLine.ParseStandardCommandLine(context);
45 return command?.Execute() ?? 1;
46 }
47
48 + private static IExtensionManager CreateExtensionManagerWithStandardBackends(IServiceProvider serviceProvider)
49 + {
50 + var extensionManager = serviceProvider.GetService<IExtensionManager>();
51 +
52 + foreach (var type in new[] { typeof(WixToolset.Core.Burn.StandardBackend), typeof(WixToolset.Core.WindowsInstaller.StandardBackend) })
53 + {
54 + extensionManager.Add(type.Assembly);
55 + }
56 +
57 + return extensionManager;
58 + }
59 +
60 private static void DisplayMessage(object sender, DisplayEventArgs e)
61 {
62 switch (e.Level)