aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRob Mensching <rob@firegiant.com>2017-12-26 15:11:40 -0800
committerRob Mensching <rob@firegiant.com>2017-12-26 15:11:40 -0800
commit1d6ff8af3c423ee4622185edc986ae5caad6b122 (patch)
tree0fd320bb2e249da3a2fbebcd3e0aa49879aa27b0
parentecf3a0cca5a424a91ab98557d963d2535963d582 (diff)
downloadwix-1d6ff8af3c423ee4622185edc986ae5caad6b122.tar.gz
wix-1d6ff8af3c423ee4622185edc986ae5caad6b122.tar.bz2
wix-1d6ff8af3c423ee4622185edc986ae5caad6b122.zip
Standardize creation of public objects in move towards interfaces
-rw-r--r--src/WixToolset.BuildTasks/DoIt.cs1
-rw-r--r--src/WixToolset.Core.Burn/Bundles/ProcessPayloadsCommand.cs3
-rw-r--r--src/WixToolset.Core/Binder.cs14
-rw-r--r--src/WixToolset.Core/CommandLine/BuildCommand.cs89
-rw-r--r--src/WixToolset.Core/CommandLine/CommandLineParser.cs4
-rw-r--r--src/WixToolset.Core/CommandLine/CompileCommand.cs42
-rw-r--r--src/WixToolset.Core/Compiler.cs37
-rw-r--r--src/WixToolset.Core/ExtensibilityServices/PreprocessHelper.cs6
-rw-r--r--src/WixToolset.Core/Librarian.cs32
-rw-r--r--src/WixToolset.Core/LibraryContext.cs5
-rw-r--r--src/WixToolset.Core/Linker.cs36
-rw-r--r--src/WixToolset.Core/Preprocessor.cs136
-rw-r--r--src/WixToolset.Core/WixToolsetServiceProvider.cs128
13 files changed, 293 insertions, 240 deletions
diff --git a/src/WixToolset.BuildTasks/DoIt.cs b/src/WixToolset.BuildTasks/DoIt.cs
index aabd92b5..aa01f6ec 100644
--- a/src/WixToolset.BuildTasks/DoIt.cs
+++ b/src/WixToolset.BuildTasks/DoIt.cs
@@ -157,7 +157,6 @@ namespace WixToolset.BuildTasks
157 commandLineBuilder.AppendSwitchIfNotNull("-contentsfile ", this.BindContentsFile); 157 commandLineBuilder.AppendSwitchIfNotNull("-contentsfile ", this.BindContentsFile);
158 commandLineBuilder.AppendSwitchIfNotNull("-outputsfile ", this.BindOutputsFile); 158 commandLineBuilder.AppendSwitchIfNotNull("-outputsfile ", this.BindOutputsFile);
159 commandLineBuilder.AppendSwitchIfNotNull("-builtoutputsfile ", this.BindBuiltOutputsFile); 159 commandLineBuilder.AppendSwitchIfNotNull("-builtoutputsfile ", this.BindBuiltOutputsFile);
160 commandLineBuilder.AppendSwitchIfNotNull("-wixprojectfile ", this.WixProjectFile);
161 160
162 commandLineBuilder.AppendIfTrue("-bindFiles", this.BindFiles); 161 commandLineBuilder.AppendIfTrue("-bindFiles", this.BindFiles);
163 commandLineBuilder.AppendArrayIfNotNull("-bindPath ", this.CalculateBindPathStrings()); 162 commandLineBuilder.AppendArrayIfNotNull("-bindPath ", this.CalculateBindPathStrings());
diff --git a/src/WixToolset.Core.Burn/Bundles/ProcessPayloadsCommand.cs b/src/WixToolset.Core.Burn/Bundles/ProcessPayloadsCommand.cs
index 1d91ddf2..80f3add3 100644
--- a/src/WixToolset.Core.Burn/Bundles/ProcessPayloadsCommand.cs
+++ b/src/WixToolset.Core.Burn/Bundles/ProcessPayloadsCommand.cs
@@ -9,9 +9,6 @@ namespace WixToolset.Core.Burn.Bundles
9 using System.Security.Cryptography; 9 using System.Security.Cryptography;
10 using System.Security.Cryptography.X509Certificates; 10 using System.Security.Cryptography.X509Certificates;
11 using System.Text; 11 using System.Text;
12 using WixToolset.Data;
13 using WixToolset.Data.Bind;
14 using WixToolset.Data.Rows;
15 12
16 internal class ProcessPayloadsCommand 13 internal class ProcessPayloadsCommand
17 { 14 {
diff --git a/src/WixToolset.Core/Binder.cs b/src/WixToolset.Core/Binder.cs
index c442c94d..f112a214 100644
--- a/src/WixToolset.Core/Binder.cs
+++ b/src/WixToolset.Core/Binder.cs
@@ -125,19 +125,19 @@ namespace WixToolset.Core
125 { 125 {
126 var entrySection = output.Sections.First(s => s.Type != SectionType.Fragment); 126 var entrySection = output.Sections.First(s => s.Type != SectionType.Fragment);
127 127
128 Assembly executingAssembly = Assembly.GetExecutingAssembly(); 128 var executingAssembly = Assembly.GetExecutingAssembly();
129 FileVersionInfo fileVersion = FileVersionInfo.GetVersionInfo(executingAssembly.Location); 129 var fileVersion = FileVersionInfo.GetVersionInfo(executingAssembly.Location);
130 130
131 var buildInfoRow = new WixBuildInfoTuple(); 131 var buildInfoTuple = new WixBuildInfoTuple();
132 buildInfoRow.WixVersion = fileVersion.FileVersion; 132 buildInfoTuple.WixVersion = fileVersion.FileVersion;
133 buildInfoRow.WixOutputFile = outputFile; 133 buildInfoTuple.WixOutputFile = outputFile;
134 134
135 if (!String.IsNullOrEmpty(outputPdbPath)) 135 if (!String.IsNullOrEmpty(outputPdbPath))
136 { 136 {
137 buildInfoRow.WixPdbFile = outputPdbPath; 137 buildInfoTuple.WixPdbFile = outputPdbPath;
138 } 138 }
139 139
140 entrySection.Tuples.Add(buildInfoRow); 140 entrySection.Tuples.Add(buildInfoTuple);
141 } 141 }
142 } 142 }
143} 143}
diff --git a/src/WixToolset.Core/CommandLine/BuildCommand.cs b/src/WixToolset.Core/CommandLine/BuildCommand.cs
index 5653afca..b5ad0b0e 100644
--- a/src/WixToolset.Core/CommandLine/BuildCommand.cs
+++ b/src/WixToolset.Core/CommandLine/BuildCommand.cs
@@ -13,11 +13,11 @@ namespace WixToolset.Core.CommandLine
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) 16 public BuildCommand(IServiceProvider serviceProvider, 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 = serviceProvider.GetService<IMessaging>();
20 this.ExtensionManager = extensions; 20 this.ExtensionManager = serviceProvider.GetService<IExtensionManager>();
21 this.LocFiles = locFiles; 21 this.LocFiles = locFiles;
22 this.LibraryFiles = libraryFiles; 22 this.LibraryFiles = libraryFiles;
23 this.PreprocessorVariables = preprocessorVariables; 23 this.PreprocessorVariables = preprocessorVariables;
@@ -76,6 +76,11 @@ namespace WixToolset.Core.CommandLine
76 { 76 {
77 var intermediates = this.CompilePhase(); 77 var intermediates = this.CompilePhase();
78 78
79 if (this.Messaging.EncounteredError)
80 {
81 return this.Messaging.LastErrorNumber;
82 }
83
79 if (!intermediates.Any()) 84 if (!intermediates.Any())
80 { 85 {
81 return 1; 86 return 1;
@@ -112,35 +117,30 @@ namespace WixToolset.Core.CommandLine
112 117
113 foreach (var sourceFile in this.SourceFiles) 118 foreach (var sourceFile in this.SourceFiles)
114 { 119 {
115 var preprocessContext = this.ServiceProvider.GetService<IPreprocessContext>(); 120 var preprocessor = new Preprocessor(this.ServiceProvider);
116 preprocessContext.Messaging = this.Messaging; 121 preprocessor.IncludeSearchPaths = this.IncludeSearchPaths;
117 preprocessContext.Extensions = this.ExtensionManager.Create<IPreprocessorExtension>(); 122 preprocessor.Platform = Platform.X86; // TODO: set this correctly
118 preprocessContext.Platform = Platform.X86; // TODO: set this correctly 123 preprocessor.SourcePath = sourceFile.SourcePath;
119 preprocessContext.IncludeSearchPaths = this.IncludeSearchPaths?.ToList() ?? new List<string>(); 124 preprocessor.Variables = this.PreprocessorVariables;
120 preprocessContext.SourceFile = sourceFile.SourcePath; 125 var document = preprocessor.Execute();
121 preprocessContext.Variables = new Dictionary<string, string>(this.PreprocessorVariables); 126
127 if (this.Messaging.EncounteredError)
128 {
129 continue;
130 }
122 131
123 var preprocessor = new Preprocessor(); 132 var compiler = new Compiler(this.ServiceProvider);
124 var document = preprocessor.Process(preprocessContext); 133 compiler.OutputPath = sourceFile.OutputPath;
134 compiler.Platform = Platform.X86; // TODO: set this correctly
135 compiler.SourceDocument = document;
136 var intermediate = compiler.Execute();
125 137
126 if (!this.Messaging.EncounteredError) 138 if (this.Messaging.EncounteredError)
127 { 139 {
128 var compileContext = this.ServiceProvider.GetService<ICompileContext>(); 140 continue;
129 compileContext.Messaging = this.Messaging;
130 compileContext.CompilationId = Guid.NewGuid().ToString("N");
131 compileContext.Extensions = this.ExtensionManager.Create<ICompilerExtension>();
132 compileContext.OutputPath = sourceFile.OutputPath;
133 compileContext.Platform = Platform.X86; // TODO: set this correctly
134 compileContext.Source = document;
135
136 var compiler = new Compiler();
137 var intermediate = compiler.Compile(compileContext);
138
139 if (!this.Messaging.EncounteredError)
140 {
141 intermediates.Add(intermediate);
142 }
143 } 141 }
142
143 intermediates.Add(intermediate);
144 } 144 }
145 145
146 return intermediates; 146 return intermediates;
@@ -156,17 +156,12 @@ namespace WixToolset.Core.CommandLine
156 return null; 156 return null;
157 } 157 }
158 158
159 var context = new LibraryContext(); 159 var librarian = new Librarian(this.ServiceProvider);
160 context.Messaging = this.Messaging; 160 librarian.BindFiles = this.BindFiles;
161 context.BindFiles = this.BindFiles; 161 librarian.BindPaths = this.BindPaths;
162 context.BindPaths = this.BindPaths; 162 librarian.Intermediates = intermediates;
163 context.Extensions = this.ExtensionManager.Create<ILibrarianExtension>(); 163 librarian.Localizations = localizations;
164 context.Localizations = localizations; 164 return librarian.Execute();
165 context.LibraryId = Guid.NewGuid().ToString("N");
166 context.Intermediates = intermediates;
167
168 var librarian = new Librarian();
169 return librarian.Combine(context);
170 } 165 }
171 166
172 private Intermediate LinkPhase(IEnumerable<Intermediate> intermediates) 167 private Intermediate LinkPhase(IEnumerable<Intermediate> intermediates)
@@ -180,16 +175,12 @@ namespace WixToolset.Core.CommandLine
180 return null; 175 return null;
181 } 176 }
182 177
183 var context = this.ServiceProvider.GetService<ILinkContext>(); 178 var linker = new Linker(this.ServiceProvider);
184 context.Messaging = this.Messaging; 179 linker.OutputType = this.OutputType;
185 context.Extensions = this.ExtensionManager.Create<ILinkerExtension>(); 180 linker.Intermediates = intermediates;
186 context.ExtensionData = this.ExtensionManager.Create<IExtensionData>(); 181 linker.Libraries = libraries;
187 context.ExpectedOutputType = this.OutputType; 182 linker.TupleDefinitionCreator = creator;
188 context.Intermediates = intermediates.Union(libraries).ToList(); 183 return linker.Execute();
189 context.TupleDefinitionCreator = creator;
190
191 var linker = new Linker();
192 return linker.Link(context);
193 } 184 }
194 185
195 private void BindPhase(Intermediate output) 186 private void BindPhase(Intermediate output)
diff --git a/src/WixToolset.Core/CommandLine/CommandLineParser.cs b/src/WixToolset.Core/CommandLine/CommandLineParser.cs
index 0e7da42a..c5d3c03b 100644
--- a/src/WixToolset.Core/CommandLine/CommandLineParser.cs
+++ b/src/WixToolset.Core/CommandLine/CommandLineParser.cs
@@ -207,14 +207,14 @@ namespace WixToolset.Core.CommandLine
207 var variables = this.GatherPreprocessorVariables(defines); 207 var variables = this.GatherPreprocessorVariables(defines);
208 var bindPathList = this.GatherBindPaths(bindPaths); 208 var bindPathList = this.GatherBindPaths(bindPaths);
209 var type = CalculateOutputType(outputType, outputFile); 209 var type = CalculateOutputType(outputType, outputFile);
210 return new BuildCommand(this.ServiceProvider, this.Messaging, this.ExtensionManager, sourceFiles, variables, locFiles, libraryFiles, outputFile, type, cabCachePath, cultures, bindFiles, bindPathList, intermediateFolder, contentsFile, outputsFile, builtOutputsFile); 210 return new BuildCommand(this.ServiceProvider, sourceFiles, variables, locFiles, libraryFiles, outputFile, type, cabCachePath, cultures, bindFiles, bindPathList, intermediateFolder, contentsFile, outputsFile, builtOutputsFile);
211 } 211 }
212 212
213 case Commands.Compile: 213 case Commands.Compile:
214 { 214 {
215 var sourceFiles = GatherSourceFiles(files, outputFolder); 215 var sourceFiles = GatherSourceFiles(files, outputFolder);
216 var variables = GatherPreprocessorVariables(defines); 216 var variables = GatherPreprocessorVariables(defines);
217 return new CompileCommand(this.ServiceProvider, this.Messaging, this.ExtensionManager, sourceFiles, variables); 217 return new CompileCommand(this.ServiceProvider, sourceFiles, variables);
218 } 218 }
219 } 219 }
220 220
diff --git a/src/WixToolset.Core/CommandLine/CompileCommand.cs b/src/WixToolset.Core/CommandLine/CompileCommand.cs
index f0ff5b1a..123318f5 100644
--- a/src/WixToolset.Core/CommandLine/CompileCommand.cs
+++ b/src/WixToolset.Core/CommandLine/CompileCommand.cs
@@ -4,28 +4,21 @@ namespace WixToolset.Core.CommandLine
4{ 4{
5 using System; 5 using System;
6 using System.Collections.Generic; 6 using System.Collections.Generic;
7 using System.Linq;
8 using WixToolset.Data; 7 using WixToolset.Data;
9 using WixToolset.Extensibility; 8 using WixToolset.Extensibility;
10 using WixToolset.Extensibility.Services; 9 using WixToolset.Extensibility.Services;
11 10
12 internal class CompileCommand : ICommandLineCommand 11 internal class CompileCommand : ICommandLineCommand
13 { 12 {
14 public CompileCommand(IServiceProvider serviceProvider, IMessaging messaging, IExtensionManager extensions, IEnumerable<SourceFile> sources, IDictionary<string, string> preprocessorVariables) 13 public CompileCommand(IServiceProvider serviceProvider, IEnumerable<SourceFile> sources, IDictionary<string, string> preprocessorVariables)
15 { 14 {
16 this.PreprocessorVariables = preprocessorVariables; 15 this.PreprocessorVariables = preprocessorVariables;
17 this.ServiceProvider = serviceProvider; 16 this.ServiceProvider = serviceProvider;
18 this.Messaging = messaging;
19 this.ExtensionManager = extensions;
20 this.SourceFiles = sources; 17 this.SourceFiles = sources;
21 } 18 }
22 19
23 private IServiceProvider ServiceProvider { get; } 20 private IServiceProvider ServiceProvider { get; }
24 21
25 private IMessaging Messaging { get; }
26
27 private IExtensionManager ExtensionManager { get; }
28
29 public IEnumerable<string> IncludeSearchPaths { get; } 22 public IEnumerable<string> IncludeSearchPaths { get; }
30 23
31 private IEnumerable<SourceFile> SourceFiles { get; } 24 private IEnumerable<SourceFile> SourceFiles { get; }
@@ -36,27 +29,18 @@ namespace WixToolset.Core.CommandLine
36 { 29 {
37 foreach (var sourceFile in this.SourceFiles) 30 foreach (var sourceFile in this.SourceFiles)
38 { 31 {
39 var preprocessContext = this.ServiceProvider.GetService<IPreprocessContext>(); 32 var preprocessor = new Preprocessor(this.ServiceProvider);
40 preprocessContext.Messaging = this.Messaging; 33 preprocessor.IncludeSearchPaths = this.IncludeSearchPaths;
41 preprocessContext.Extensions = this.ExtensionManager.Create<IPreprocessorExtension>(); 34 preprocessor.Platform = Platform.X86; // TODO: set this correctly
42 preprocessContext.Platform = Platform.X86; // TODO: set this correctly 35 preprocessor.SourcePath = sourceFile.SourcePath;
43 preprocessContext.IncludeSearchPaths = this.IncludeSearchPaths?.ToList() ?? new List<string>(); 36 preprocessor.Variables = new Dictionary<string, string>(this.PreprocessorVariables);
44 preprocessContext.SourceFile = sourceFile.SourcePath; 37 var document = preprocessor.Execute();
45 preprocessContext.Variables = new Dictionary<string, string>(this.PreprocessorVariables); 38
46 39 var compiler = new Compiler(this.ServiceProvider);
47 var preprocessor = new Preprocessor(); 40 compiler.OutputPath = sourceFile.OutputPath;
48 var document = preprocessor.Process(preprocessContext); 41 compiler.Platform = Platform.X86; // TODO: set this correctly
49 42 compiler.SourceDocument = document;
50 var compileContext = this.ServiceProvider.GetService<ICompileContext>(); 43 var intermediate = compiler.Execute();
51 compileContext.Messaging = this.Messaging;
52 compileContext.CompilationId = Guid.NewGuid().ToString("N");
53 compileContext.Extensions = this.ExtensionManager.Create<ICompilerExtension>();
54 compileContext.OutputPath = sourceFile.OutputPath;
55 compileContext.Platform = Platform.X86; // TODO: set this correctly
56 compileContext.Source = document;
57
58 var compiler = new Compiler();
59 var intermediate = compiler.Compile(compileContext);
60 44
61 intermediate.Save(sourceFile.OutputPath); 45 intermediate.Save(sourceFile.OutputPath);
62 } 46 }
diff --git a/src/WixToolset.Core/Compiler.cs b/src/WixToolset.Core/Compiler.cs
index 2dd7da4d..587c24fe 100644
--- a/src/WixToolset.Core/Compiler.cs
+++ b/src/WixToolset.Core/Compiler.cs
@@ -68,10 +68,25 @@ namespace WixToolset.Core
68 Icon, 68 Icon,
69 } 69 }
70 70
71 public Compiler(IServiceProvider serviceProvider)
72 {
73 this.ServiceProvider = serviceProvider;
74 }
75
76 private IServiceProvider ServiceProvider { get; }
77
71 private ICompileContext Context { get; set; } 78 private ICompileContext Context { get; set; }
72 79
73 private CompilerCore Core { get; set; } 80 private CompilerCore Core { get; set; }
74 81
82 public string CompliationId { get; set; }
83
84 public string OutputPath { get; set; }
85
86 public Platform Platform { get; set; }
87
88 public XDocument SourceDocument { get; set; }
89
75 /// <summary> 90 /// <summary>
76 /// Gets or sets the platform which the compiler will use when defaulting 64-bit attributes and elements. 91 /// Gets or sets the platform which the compiler will use when defaulting 64-bit attributes and elements.
77 /// </summary> 92 /// </summary>
@@ -87,17 +102,21 @@ namespace WixToolset.Core
87 /// <summary> 102 /// <summary>
88 /// Compiles the provided Xml document into an intermediate object 103 /// Compiles the provided Xml document into an intermediate object
89 /// </summary> 104 /// </summary>
90 /// <param name="context">Context for the compile. The BaseURI property
91 /// should be properly set to get messages containing source line information.</param>
92 /// <returns>Intermediate object representing compiled source document.</returns> 105 /// <returns>Intermediate object representing compiled source document.</returns>
93 /// <remarks>This method is not thread-safe.</remarks> 106 /// <remarks>This method is not thread-safe.</remarks>
94 public Intermediate Compile(ICompileContext context) 107 public Intermediate Execute()
95 { 108 {
96 this.Context = context ?? throw new ArgumentNullException(nameof(context)); 109 this.Context = this.ServiceProvider.GetService<ICompileContext>();
110 this.Context.Messaging = this.ServiceProvider.GetService<IMessaging>();
111 this.Context.Extensions = this.ServiceProvider.GetService<IExtensionManager>().Create<ICompilerExtension>();
112 this.Context.CompilationId = this.CompliationId;
113 this.Context.OutputPath = this.OutputPath;
114 this.Context.Platform = this.Platform;
115 this.Context.Source = this.SourceDocument;
97 116
98 var target = new Intermediate(); 117 var target = new Intermediate();
99 118
100 if (String.IsNullOrEmpty(context.CompilationId)) 119 if (String.IsNullOrEmpty(this.Context.CompilationId))
101 { 120 {
102 this.Context.CompilationId = target.Id; 121 this.Context.CompilationId = target.Id;
103 } 122 }
@@ -115,20 +134,20 @@ namespace WixToolset.Core
115 this.Context.Messaging.Write(ErrorMessages.DuplicateExtensionXmlSchemaNamespace(extension.GetType().ToString(), extension.Namespace.NamespaceName, collidingExtension.GetType().ToString())); 134 this.Context.Messaging.Write(ErrorMessages.DuplicateExtensionXmlSchemaNamespace(extension.GetType().ToString(), extension.Namespace.NamespaceName, collidingExtension.GetType().ToString()));
116 } 135 }
117 136
118 extension.PreCompile(context); 137 extension.PreCompile(this.Context);
119 } 138 }
120 139
121 // Try to compile it. 140 // Try to compile it.
122 try 141 try
123 { 142 {
124 var parseHelper = context.ServiceProvider.GetService<IParseHelper>(); 143 var parseHelper = this.Context.ServiceProvider.GetService<IParseHelper>();
125 144
126 this.Core = new CompilerCore(target, this.Context.Messaging, parseHelper, extensionsByNamespace); 145 this.Core = new CompilerCore(target, this.Context.Messaging, parseHelper, extensionsByNamespace);
127 this.Core.ShowPedanticMessages = this.ShowPedanticMessages; 146 this.Core.ShowPedanticMessages = this.ShowPedanticMessages;
128 this.componentIdPlaceholdersResolver = new WixVariableResolver(this.Context.Messaging); 147 this.componentIdPlaceholdersResolver = new WixVariableResolver(this.Context.Messaging);
129 148
130 // parse the document 149 // parse the document
131 var source = context.Source; 150 var source = this.Context.Source;
132 var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(source.Root); 151 var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(source.Root);
133 if ("Wix" == source.Root.Name.LocalName) 152 if ("Wix" == source.Root.Name.LocalName)
134 { 153 {
@@ -158,7 +177,7 @@ namespace WixToolset.Core
158 } 177 }
159 finally 178 finally
160 { 179 {
161 foreach (var extension in context.Extensions) 180 foreach (var extension in this.Context.Extensions)
162 { 181 {
163 extension.PostCompile(target); 182 extension.PostCompile(target);
164 } 183 }
diff --git a/src/WixToolset.Core/ExtensibilityServices/PreprocessHelper.cs b/src/WixToolset.Core/ExtensibilityServices/PreprocessHelper.cs
index 0e3e0bfd..0331c815 100644
--- a/src/WixToolset.Core/ExtensibilityServices/PreprocessHelper.cs
+++ b/src/WixToolset.Core/ExtensibilityServices/PreprocessHelper.cs
@@ -458,7 +458,11 @@ namespace WixToolset.Core.ExtensibilityServices
458 { 458 {
459 this.ExtensionsByPrefix = new Dictionary<string, IPreprocessorExtension>(); 459 this.ExtensionsByPrefix = new Dictionary<string, IPreprocessorExtension>();
460 460
461 foreach (var extension in context.Extensions) 461 var extensionManager = this.ServiceProvider.GetService<IExtensionManager>();
462
463 var extensions = extensionManager.Create<IPreprocessorExtension>();
464
465 foreach (var extension in extensions)
462 { 466 {
463 if (null != extension.Prefixes) 467 if (null != extension.Prefixes)
464 { 468 {
diff --git a/src/WixToolset.Core/Librarian.cs b/src/WixToolset.Core/Librarian.cs
index 2efb0f9b..3e843070 100644
--- a/src/WixToolset.Core/Librarian.cs
+++ b/src/WixToolset.Core/Librarian.cs
@@ -9,27 +9,45 @@ namespace WixToolset.Core
9 using WixToolset.Core.Link; 9 using WixToolset.Core.Link;
10 using WixToolset.Data; 10 using WixToolset.Data;
11 using WixToolset.Extensibility; 11 using WixToolset.Extensibility;
12 using WixToolset.Extensibility.Services;
12 13
13 /// <summary> 14 /// <summary>
14 /// Core librarian tool. 15 /// Core librarian tool.
15 /// </summary> 16 /// </summary>
16 public sealed class Librarian 17 public sealed class Librarian
17 { 18 {
19 public Librarian(IServiceProvider serviceProvider)
20 {
21 this.ServiceProvider = serviceProvider;
22 }
23
24 private IServiceProvider ServiceProvider { get; }
25
18 private ILibraryContext Context { get; set; } 26 private ILibraryContext Context { get; set; }
19 27
28 public bool BindFiles { get; set; }
29
30 public IEnumerable<BindPath> BindPaths { get; set; }
31
32 public IEnumerable<Localization> Localizations { get; set; }
33
34 public IEnumerable<Intermediate> Intermediates { get; set; }
35
20 /// <summary> 36 /// <summary>
21 /// Create a library by combining several intermediates (objects). 37 /// Create a library by combining several intermediates (objects).
22 /// </summary> 38 /// </summary>
23 /// <param name="sections">The sections to combine into a library.</param> 39 /// <param name="sections">The sections to combine into a library.</param>
24 /// <returns>Returns the new library.</returns> 40 /// <returns>Returns the new library.</returns>
25 public Intermediate Combine(ILibraryContext context) 41 public Intermediate Execute()
26 { 42 {
27 this.Context = context ?? throw new ArgumentNullException(nameof(context)); 43 this.Context = new LibraryContext(this.ServiceProvider);
28 44 this.Context.Messaging = this.ServiceProvider.GetService<IMessaging>();
29 if (String.IsNullOrEmpty(this.Context.LibraryId)) 45 this.Context.BindFiles = this.BindFiles;
30 { 46 this.Context.BindPaths = this.BindPaths;
31 this.Context.LibraryId = Convert.ToBase64String(Guid.NewGuid().ToByteArray()).TrimEnd('=').Replace('+', '.').Replace('/', '_'); 47 this.Context.Extensions = this.ServiceProvider.GetService<IExtensionManager>().Create<ILibrarianExtension>();
32 } 48 this.Context.Localizations = this.Localizations;
49 this.Context.LibraryId = Convert.ToBase64String(Guid.NewGuid().ToByteArray()).TrimEnd('=').Replace('+', '.').Replace('/', '_');
50 this.Context.Intermediates = this.Intermediates;
33 51
34 foreach (var extension in this.Context.Extensions) 52 foreach (var extension in this.Context.Extensions)
35 { 53 {
diff --git a/src/WixToolset.Core/LibraryContext.cs b/src/WixToolset.Core/LibraryContext.cs
index c1aec5ce..56a9389f 100644
--- a/src/WixToolset.Core/LibraryContext.cs
+++ b/src/WixToolset.Core/LibraryContext.cs
@@ -10,6 +10,11 @@ namespace WixToolset.Core
10 10
11 public class LibraryContext : ILibraryContext 11 public class LibraryContext : ILibraryContext
12 { 12 {
13 public LibraryContext(IServiceProvider serviceProvider)
14 {
15 this.ServiceProvider = serviceProvider;
16 }
17
13 public IServiceProvider ServiceProvider { get; } 18 public IServiceProvider ServiceProvider { get; }
14 19
15 public IMessaging Messaging { get; set; } 20 public IMessaging Messaging { get; set; }
diff --git a/src/WixToolset.Core/Linker.cs b/src/WixToolset.Core/Linker.cs
index 93f50efa..79ddd30a 100644
--- a/src/WixToolset.Core/Linker.cs
+++ b/src/WixToolset.Core/Linker.cs
@@ -12,6 +12,7 @@ namespace WixToolset.Core
12 using WixToolset.Data; 12 using WixToolset.Data;
13 using WixToolset.Data.Tuples; 13 using WixToolset.Data.Tuples;
14 using WixToolset.Extensibility; 14 using WixToolset.Extensibility;
15 using WixToolset.Extensibility.Services;
15 using WixToolset.Link; 16 using WixToolset.Link;
16 17
17 /// <summary> 18 /// <summary>
@@ -27,14 +28,17 @@ namespace WixToolset.Core
27 /// <summary> 28 /// <summary>
28 /// Creates a linker. 29 /// Creates a linker.
29 /// </summary> 30 /// </summary>
30 public Linker() 31 public Linker(IServiceProvider serviceProvider)
31 { 32 {
33 this.ServiceProvider = serviceProvider;
32 this.sectionIdOnRows = true; // TODO: what is the correct value for this? 34 this.sectionIdOnRows = true; // TODO: what is the correct value for this?
33 35
34 //this.extensionData = new List<IExtensionData>(); 36 //this.extensionData = new List<IExtensionData>();
35 //this.inspectorExtensions = new List<InspectorExtension>(); 37 //this.inspectorExtensions = new List<InspectorExtension>();
36 } 38 }
37 39
40 private IServiceProvider ServiceProvider { get; }
41
38 private ILinkContext Context { get; set; } 42 private ILinkContext Context { get; set; }
39 43
40 /// <summary> 44 /// <summary>
@@ -49,11 +53,13 @@ namespace WixToolset.Core
49 /// <value>The option to show pedantic messages.</value> 53 /// <value>The option to show pedantic messages.</value>
50 public bool ShowPedanticMessages { get; set; } 54 public bool ShowPedanticMessages { get; set; }
51 55
52 /// <summary> 56 public OutputType OutputType { get; set; }
53 /// Gets or sets the Wix variable resolver. 57
54 /// </summary> 58 public IEnumerable<Intermediate> Intermediates { get; set; }
55 /// <value>The Wix variable resolver.</value> 59
56 //internal IBindVariableResolver WixVariableResolver { get; set; } 60 public IEnumerable<Intermediate> Libraries { get; set; }
61
62 public ITupleDefinitionCreator TupleDefinitionCreator { get; set; }
57 63
58 /// <summary> 64 /// <summary>
59 /// Links a collection of sections into an output. 65 /// Links a collection of sections into an output.
@@ -61,16 +67,26 @@ namespace WixToolset.Core
61 /// <param name="inputs">The collection of sections to link together.</param> 67 /// <param name="inputs">The collection of sections to link together.</param>
62 /// <param name="expectedOutputType">Expected output type, based on output file extension provided to the linker.</param> 68 /// <param name="expectedOutputType">Expected output type, based on output file extension provided to the linker.</param>
63 /// <returns>Output object from the linking.</returns> 69 /// <returns>Output object from the linking.</returns>
64 public Intermediate Link(ILinkContext context) 70 public Intermediate Execute()
65 { 71 {
66 this.Context = context ?? throw new ArgumentNullException(nameof(context)); 72 var extensionManager = this.ServiceProvider.GetService<IExtensionManager>();
73
74 var creator = this.TupleDefinitionCreator ?? this.ServiceProvider.GetService<ITupleDefinitionCreator>();
75
76 this.Context = this.ServiceProvider.GetService<ILinkContext>();
77 this.Context.Messaging = this.ServiceProvider.GetService<IMessaging>();
78 this.Context.Extensions = extensionManager.Create<ILinkerExtension>();
79 this.Context.ExtensionData = extensionManager.Create<IExtensionData>();
80 this.Context.ExpectedOutputType = this.OutputType;
81 this.Context.Intermediates = this.Intermediates.Union(this.Libraries).ToList();
82 this.Context.TupleDefinitionCreator = creator;
67 83
68 var sections = this.Context.Intermediates.SelectMany(i => i.Sections).ToList(); 84 var sections = this.Context.Intermediates.SelectMany(i => i.Sections).ToList();
69 85
70 // Add sections from the extensions with data. 86 // Add sections from the extensions with data.
71 foreach (var data in context.ExtensionData) 87 foreach (var data in this.Context.ExtensionData)
72 { 88 {
73 var library = data.GetLibrary(context.TupleDefinitionCreator); 89 var library = data.GetLibrary(this.Context.TupleDefinitionCreator);
74 90
75 if (library != null) 91 if (library != null)
76 { 92 {
diff --git a/src/WixToolset.Core/Preprocessor.cs b/src/WixToolset.Core/Preprocessor.cs
index 53d60c87..6733f493 100644
--- a/src/WixToolset.Core/Preprocessor.cs
+++ b/src/WixToolset.Core/Preprocessor.cs
@@ -14,6 +14,7 @@ namespace WixToolset.Core
14 using WixToolset.Extensibility; 14 using WixToolset.Extensibility;
15 using WixToolset.Core.Preprocess; 15 using WixToolset.Core.Preprocess;
16 using WixToolset.Extensibility.Services; 16 using WixToolset.Extensibility.Services;
17 using System.Linq;
17 18
18 /// <summary> 19 /// <summary>
19 /// Preprocessor object 20 /// Preprocessor object
@@ -35,6 +36,21 @@ namespace WixToolset.Core
35 XmlResolver = null, 36 XmlResolver = null,
36 }; 37 };
37 38
39 public Preprocessor(IServiceProvider serviceProvider)
40 {
41 this.ServiceProvider = serviceProvider;
42 }
43
44 public IEnumerable<string> IncludeSearchPaths { get; set; }
45
46 public Platform Platform { get; set; }
47
48 public string SourcePath { get; set; }
49
50 public IDictionary<string, string> Variables { get; set; }
51
52 private IServiceProvider ServiceProvider { get; }
53
38 private IPreprocessContext Context { get; set; } 54 private IPreprocessContext Context { get; set; }
39 55
40 private Stack<string> CurrentFileStack { get; } = new Stack<string>(); 56 private Stack<string> CurrentFileStack { get; } = new Stack<string>();
@@ -87,14 +103,19 @@ namespace WixToolset.Core
87 /// </summary> 103 /// </summary>
88 /// <param name="context">The preprocessing context.</param> 104 /// <param name="context">The preprocessing context.</param>
89 /// <returns>XDocument with the postprocessed data.</returns> 105 /// <returns>XDocument with the postprocessed data.</returns>
90 public XDocument Process(IPreprocessContext context) 106 public XDocument Execute()
91 { 107 {
92 this.Context = context ?? throw new ArgumentNullException(nameof(context)); 108 this.Context = this.CreateContext();
109
110 this.PreProcess();
93 111
94 using (XmlReader reader = XmlReader.Create(context.SourceFile, DocumentXmlReaderSettings)) 112 XDocument document;
113 using (XmlReader reader = XmlReader.Create(this.Context.SourceFile, DocumentXmlReaderSettings))
95 { 114 {
96 return Process(context, reader); 115 document = this.Process(reader);
97 } 116 }
117
118 return PostProcess(document);
98 } 119 }
99 120
100 /// <summary> 121 /// <summary>
@@ -103,46 +124,32 @@ namespace WixToolset.Core
103 /// <param name="context">The preprocessing context.</param> 124 /// <param name="context">The preprocessing context.</param>
104 /// <param name="reader">XmlReader to processing the context.</param> 125 /// <param name="reader">XmlReader to processing the context.</param>
105 /// <returns>XDocument with the postprocessed data.</returns> 126 /// <returns>XDocument with the postprocessed data.</returns>
106 public XDocument Process(IPreprocessContext context, XmlReader reader) 127 public XDocument Execute(XmlReader reader)
107 { 128 {
108 if (this.Context == null) 129 if (String.IsNullOrEmpty(this.SourcePath) && !String.IsNullOrEmpty(reader.BaseURI))
109 {
110 this.Context = context ?? throw new ArgumentNullException(nameof(context));
111 }
112 else if (this.Context != context)
113 {
114 throw new ArgumentException(nameof(context));
115 }
116
117 if (String.IsNullOrEmpty(this.Context.SourceFile) && !String.IsNullOrEmpty(reader.BaseURI))
118 { 130 {
119 var uri = new Uri(reader.BaseURI); 131 var uri = new Uri(reader.BaseURI);
120 this.Context.SourceFile = uri.AbsolutePath; 132 this.SourcePath = uri.AbsolutePath;
121 } 133 }
122 134
123 this.Context.CurrentSourceLineNumber = new SourceLineNumber(this.Context.SourceFile); 135 this.Context = this.CreateContext();
124 136
125 this.Helper = this.Context.ServiceProvider.GetService<IPreprocessHelper>(); 137 this.PreProcess();
126 138
127 foreach (var extension in this.Context.Extensions) 139 var document = this.Process(reader);
128 {
129 if (null != extension.Prefixes)
130 {
131 foreach (string prefix in extension.Prefixes)
132 {
133 if (!this.ExtensionsByPrefix.TryGetValue(prefix, out var collidingExtension))
134 {
135 this.ExtensionsByPrefix.Add(prefix, extension);
136 }
137 else
138 {
139 this.Context.Messaging.Write(ErrorMessages.DuplicateExtensionPreprocessorType(extension.GetType().ToString(), prefix, collidingExtension.GetType().ToString()));
140 }
141 }
142 }
143 140
144 extension.PrePreprocess(context); 141 return PostProcess(document);
145 } 142 }
143
144 /// <summary>
145 /// Preprocesses a file.
146 /// </summary>
147 /// <param name="context">The preprocessing context.</param>
148 /// <param name="reader">XmlReader to processing the context.</param>
149 /// <returns>XDocument with the postprocessed data.</returns>
150 private XDocument Process(XmlReader reader)
151 {
152 this.Helper = this.ServiceProvider.GetService<IPreprocessHelper>();
146 153
147 this.CurrentFileStack.Clear(); 154 this.CurrentFileStack.Clear();
148 this.CurrentFileStack.Push(this.Helper.GetVariableValue(this.Context, "sys", "SOURCEFILEDIR")); 155 this.CurrentFileStack.Push(this.Helper.GetVariableValue(this.Context, "sys", "SOURCEFILEDIR"));
@@ -161,14 +168,6 @@ namespace WixToolset.Core
161 this.UpdateCurrentLineNumber(reader, 0); 168 this.UpdateCurrentLineNumber(reader, 0);
162 throw new WixException(ErrorMessages.InvalidXml(this.Context.CurrentSourceLineNumber, "source", e.Message)); 169 throw new WixException(ErrorMessages.InvalidXml(this.Context.CurrentSourceLineNumber, "source", e.Message));
163 } 170 }
164 finally
165 {
166 // Finalize the preprocessing.
167 foreach (var extension in this.Context.Extensions)
168 {
169 extension.PostPreprocess(output);
170 }
171 }
172 171
173 return this.Context.Messaging.EncounteredError ? null : output; 172 return this.Context.Messaging.EncounteredError ? null : output;
174 } 173 }
@@ -1404,7 +1403,7 @@ namespace WixToolset.Core
1404 { 1403 {
1405 // build a string to test the directory containing the source file first 1404 // build a string to test the directory containing the source file first
1406 var currentFolder = this.CurrentFileStack.Peek(); 1405 var currentFolder = this.CurrentFileStack.Peek();
1407 var includeTestPath = Path.Combine(Path.GetDirectoryName(currentFolder) , includePath); 1406 var includeTestPath = Path.Combine(Path.GetDirectoryName(currentFolder), includePath);
1408 1407
1409 // test the source file directory 1408 // test the source file directory
1410 if (File.Exists(includeTestPath)) 1409 if (File.Exists(includeTestPath))
@@ -1428,5 +1427,52 @@ namespace WixToolset.Core
1428 1427
1429 return finalIncludePath; 1428 return finalIncludePath;
1430 } 1429 }
1430
1431 private IPreprocessContext CreateContext()
1432 {
1433 var context = this.ServiceProvider.GetService<IPreprocessContext>();
1434 context.Messaging = this.ServiceProvider.GetService<IMessaging>();
1435 context.Extensions = this.ServiceProvider.GetService<IExtensionManager>().Create<IPreprocessorExtension>();
1436 context.CurrentSourceLineNumber = new SourceLineNumber(this.SourcePath);
1437 context.Platform = this.Platform;
1438 context.IncludeSearchPaths = this.IncludeSearchPaths?.ToList() ?? new List<string>();
1439 context.SourceFile = this.SourcePath;
1440 context.Variables = new Dictionary<string, string>(this.Variables);
1441
1442 return context;
1443 }
1444
1445 private void PreProcess()
1446 {
1447 foreach (var extension in this.Context.Extensions)
1448 {
1449 if (extension.Prefixes != null)
1450 {
1451 foreach (var prefix in extension.Prefixes)
1452 {
1453 if (!this.ExtensionsByPrefix.TryGetValue(prefix, out var collidingExtension))
1454 {
1455 this.ExtensionsByPrefix.Add(prefix, extension);
1456 }
1457 else
1458 {
1459 this.Context.Messaging.Write(ErrorMessages.DuplicateExtensionPreprocessorType(extension.GetType().ToString(), prefix, collidingExtension.GetType().ToString()));
1460 }
1461 }
1462 }
1463
1464 extension.PrePreprocess(this.Context);
1465 }
1466 }
1467
1468 private XDocument PostProcess(XDocument document)
1469 {
1470 foreach (var extension in this.Context.Extensions)
1471 {
1472 extension.PostPreprocess(document);
1473 }
1474
1475 return document;
1476 }
1431 } 1477 }
1432} 1478}
diff --git a/src/WixToolset.Core/WixToolsetServiceProvider.cs b/src/WixToolset.Core/WixToolsetServiceProvider.cs
index a018b8dc..0c40c56d 100644
--- a/src/WixToolset.Core/WixToolsetServiceProvider.cs
+++ b/src/WixToolset.Core/WixToolsetServiceProvider.cs
@@ -3,6 +3,7 @@
3namespace WixToolset.Core 3namespace WixToolset.Core
4{ 4{
5 using System; 5 using System;
6 using System.Collections.Generic;
6 using WixToolset.Core.CommandLine; 7 using WixToolset.Core.CommandLine;
7 using WixToolset.Core.ExtensibilityServices; 8 using WixToolset.Core.ExtensibilityServices;
8 using WixToolset.Data; 9 using WixToolset.Data;
@@ -11,95 +12,68 @@ namespace WixToolset.Core
11 12
12 public class WixToolsetServiceProvider : IServiceProvider 13 public class WixToolsetServiceProvider : IServiceProvider
13 { 14 {
14 private ExtensionManager extensionManager; 15 public WixToolsetServiceProvider()
15 private Messaging messaging;
16 private ParseHelper parseHelper;
17 private PreprocessHelper preprocessHelper;
18 private TupleDefinitionCreator tupleDefinitionCreator;
19 private WindowsInstallerBackendHelper windowsInstallerBackendHelper;
20
21 public object GetService(Type serviceType)
22 { 16 {
23 if (serviceType == null) throw new ArgumentNullException(nameof(serviceType)); 17 this.CreationFunctions = new Dictionary<Type, Func<IServiceProvider, Dictionary<Type, object>, object>>
24
25 // Transients.
26 if (serviceType == typeof(IPreprocessContext))
27 {
28 return new PreprocessContext(this);
29 }
30
31 if (serviceType == typeof(ICompileContext))
32 {
33 return new CompileContext(this);
34 }
35
36 if (serviceType == typeof(ILinkContext))
37 {
38 return new LinkContext(this);
39 }
40
41 if (serviceType == typeof(IBindContext))
42 {
43 return new BindContext(this);
44 }
45
46 if (serviceType == typeof(ILayoutContext))
47 {
48 return new LayoutContext(this);
49 }
50
51 if (serviceType == typeof(IResolveContext))
52 {
53 return new ResolveContext(this);
54 }
55
56 if (serviceType == typeof(IInscribeContext))
57 {
58 return new InscribeContext(this);
59 }
60
61 if (serviceType == typeof(ICommandLineContext))
62 { 18 {
63 return new CommandLineContext(this); 19 // Singletons.
64 } 20 { typeof(IExtensionManager), (provider, singletons) => AddSingleton(singletons, typeof(IExtensionManager), new ExtensionManager()) },
21 { typeof(IMessaging), (provider, singletons) => AddSingleton(singletons, typeof(IMessaging), new Messaging()) },
22 { typeof(ITupleDefinitionCreator), (provider, singletons) => AddSingleton(singletons, typeof(ITupleDefinitionCreator), new TupleDefinitionCreator(provider)) },
23 { typeof(IParseHelper), (provider, singletons) => AddSingleton(singletons, typeof(IParseHelper), new ParseHelper(provider)) },
24 { typeof(IPreprocessHelper), (provider, singletons) => AddSingleton(singletons, typeof(IPreprocessHelper), new PreprocessHelper(provider)) },
25 { typeof(IWindowsInstallerBackendHelper), (provider, singletons) => AddSingleton(singletons, typeof(IWindowsInstallerBackendHelper), new WindowsInstallerBackendHelper(provider)) },
65 26
66 if (serviceType == typeof(ICommandLine)) 27 // Transients.
67 { 28 { typeof(ICommandLineContext), (provider, singletons) => new CommandLineContext(provider) },
68 return new CommandLineParser(); 29 { typeof(ICommandLine), (provider, singletons) => new CommandLineParser() },
69 } 30 { typeof(IPreprocessContext), (provider, singletons) => new PreprocessContext(provider) },
31 { typeof(ICompileContext), (provider, singletons) => new CompileContext(provider) },
32 { typeof(ILinkContext), (provider, singletons) => new LinkContext(provider) },
33 { typeof(IResolveContext), (provider, singletons) => new ResolveContext(provider) },
34 { typeof(IBindContext), (provider, singletons) => new BindContext(provider) },
35 { typeof(ILayoutContext), (provider, singletons) => new LayoutContext(provider) },
36 { typeof(IInscribeContext), (provider, singletons) => new InscribeContext(provider) },
37 };
38
39 this.Singletons = new Dictionary<Type, object>();
40 }
70 41
71 // Singletons. 42 private Dictionary<Type, Func<IServiceProvider, Dictionary<Type, object>, object>> CreationFunctions { get; }
72 if (serviceType == typeof(IExtensionManager))
73 {
74 return this.extensionManager = this.extensionManager ?? new ExtensionManager();
75 }
76 43
77 if (serviceType == typeof(IMessaging)) 44 private Dictionary<Type, object> Singletons { get; }
78 {
79 return this.messaging = this.messaging ?? new Messaging();
80 }
81 45
82 if (serviceType == typeof(ITupleDefinitionCreator)) 46 public object GetService(Type serviceType)
83 { 47 {
84 return this.tupleDefinitionCreator = this.tupleDefinitionCreator ?? new TupleDefinitionCreator(this); 48 if (serviceType == null) throw new ArgumentNullException(nameof(serviceType));
85 }
86 49
87 if (serviceType == typeof(IParseHelper)) 50 if (!this.Singletons.TryGetValue(serviceType, out var service))
88 { 51 {
89 return this.parseHelper = this.parseHelper ?? new ParseHelper(this); 52 if (this.CreationFunctions.TryGetValue(serviceType, out var creationFunction))
53 {
54 service = creationFunction(this, this.Singletons);
55
56#if DEBUG
57 if (!serviceType.IsAssignableFrom(service?.GetType()))
58 {
59 throw new InvalidOperationException($"Creation function for service type: {serviceType.Name} created incompatible service with type: {service?.GetType()}");
60 }
61#endif
62 }
90 } 63 }
91 64
92 if (serviceType == typeof(IPreprocessHelper)) 65 return service ?? throw new ArgumentException($"Unknown service type: {serviceType.Name}", nameof(serviceType));
93 { 66 }
94 return this.preprocessHelper = this.preprocessHelper ?? new PreprocessHelper(this);
95 }
96 67
97 if (serviceType == typeof(IWindowsInstallerBackendHelper)) 68 public void AddService(Type serviceType, Func<IServiceProvider, Dictionary<Type, object>, object> creationFunction)
98 { 69 {
99 return this.windowsInstallerBackendHelper = this.windowsInstallerBackendHelper ?? new WindowsInstallerBackendHelper(this); 70 this.CreationFunctions[serviceType] = creationFunction;
100 } 71 }
101 72
102 throw new ArgumentException($"Unknown service type: {serviceType.Name}", nameof(serviceType)); 73 private static object AddSingleton(Dictionary<Type, object> singletons, Type type, object service)
74 {
75 singletons.Add(type, service);
76 return service;
103 } 77 }
104 } 78 }
105} 79}