aboutsummaryrefslogtreecommitdiff
path: root/src/WixToolset.Core
diff options
context:
space:
mode:
authorRob Mensching <rob@firegiant.com>2017-10-01 14:25:33 -0700
committerRob Mensching <rob@firegiant.com>2017-10-01 14:25:33 -0700
commit39c7e2bb0399802e65a3025c4a73db211e730479 (patch)
treecf53a931796c67b89cb48fb3a7a0cc4f30cb2c22 /src/WixToolset.Core
parente576d34c3f88b5da033d2516d1c16b0df9491523 (diff)
downloadwix-39c7e2bb0399802e65a3025c4a73db211e730479.tar.gz
wix-39c7e2bb0399802e65a3025c4a73db211e730479.tar.bz2
wix-39c7e2bb0399802e65a3025c4a73db211e730479.zip
Add support for BindPaths and building .wixlibs
Diffstat (limited to 'src/WixToolset.Core')
-rw-r--r--src/WixToolset.Core/CommandLine/BuildCommand.cs196
-rw-r--r--src/WixToolset.Core/CommandLine/CommandLine.cs115
-rw-r--r--src/WixToolset.Core/Librarian.cs117
-rw-r--r--src/WixToolset.Core/Localizer.cs53
-rw-r--r--src/WixToolset.Core/WixVariableResolver.cs20
5 files changed, 363 insertions, 138 deletions
diff --git a/src/WixToolset.Core/CommandLine/BuildCommand.cs b/src/WixToolset.Core/CommandLine/BuildCommand.cs
index ffb48305..d8954cb7 100644
--- a/src/WixToolset.Core/CommandLine/BuildCommand.cs
+++ b/src/WixToolset.Core/CommandLine/BuildCommand.cs
@@ -7,17 +7,24 @@ namespace WixToolset.Core
7 using System.IO; 7 using System.IO;
8 using System.Linq; 8 using System.Linq;
9 using WixToolset.Data; 9 using WixToolset.Data;
10 using WixToolset.Extensibility;
10 11
11 internal class BuildCommand : ICommand 12 internal class BuildCommand : ICommand
12 { 13 {
13 public BuildCommand(IEnumerable<SourceFile> sources, IDictionary<string, string> preprocessorVariables, IEnumerable<string> locFiles, string outputPath, IEnumerable<string> cultures, string contentsFile, string outputsFile, string builtOutputsFile, string wixProjectFile) 14 public BuildCommand(IEnumerable<SourceFile> sources, IDictionary<string, string> preprocessorVariables, IEnumerable<string> locFiles, IEnumerable<string> libraryFiles, string outputPath, OutputType outputType, IEnumerable<string> cultures, bool bindFiles, IEnumerable<BindPath> bindPaths, string intermediateFolder, string contentsFile, string outputsFile, string builtOutputsFile, string wixProjectFile)
14 { 15 {
15 this.LocFiles = locFiles; 16 this.LocFiles = locFiles;
17 this.LibraryFiles = libraryFiles;
16 this.PreprocessorVariables = preprocessorVariables; 18 this.PreprocessorVariables = preprocessorVariables;
17 this.SourceFiles = sources; 19 this.SourceFiles = sources;
18 this.OutputPath = outputPath; 20 this.OutputPath = outputPath;
21 this.OutputType = outputType;
19 22
20 this.Cultures = cultures; 23 this.Cultures = cultures;
24 this.BindFiles = bindFiles;
25 this.BindPaths = bindPaths;
26
27 this.IntermediateFolder = intermediateFolder ?? Path.GetTempPath();
21 this.ContentsFile = contentsFile; 28 this.ContentsFile = contentsFile;
22 this.OutputsFile = outputsFile; 29 this.OutputsFile = outputsFile;
23 this.BuiltOutputsFile = builtOutputsFile; 30 this.BuiltOutputsFile = builtOutputsFile;
@@ -26,14 +33,24 @@ namespace WixToolset.Core
26 33
27 public IEnumerable<string> LocFiles { get; } 34 public IEnumerable<string> LocFiles { get; }
28 35
36 public IEnumerable<string> LibraryFiles { get; }
37
29 private IEnumerable<SourceFile> SourceFiles { get; } 38 private IEnumerable<SourceFile> SourceFiles { get; }
30 39
31 private IDictionary<string, string> PreprocessorVariables { get; } 40 private IDictionary<string, string> PreprocessorVariables { get; }
32 41
33 private string OutputPath { get; } 42 private string OutputPath { get; }
34 43
44 private OutputType OutputType { get; }
45
35 public IEnumerable<string> Cultures { get; } 46 public IEnumerable<string> Cultures { get; }
36 47
48 public bool BindFiles { get; }
49
50 public IEnumerable<BindPath> BindPaths { get; }
51
52 public string IntermediateFolder { get; }
53
37 public string ContentsFile { get; } 54 public string ContentsFile { get; }
38 55
39 public string OutputsFile { get; } 56 public string OutputsFile { get; }
@@ -44,21 +61,135 @@ namespace WixToolset.Core
44 61
45 public int Execute() 62 public int Execute()
46 { 63 {
47 var intermediates = CompilePhase(); 64 var intermediates = this.CompilePhase();
65
66 var tableDefinitions = new TableDefinitionCollection(WindowsInstallerStandard.GetTableDefinitions());
67
68 if (this.OutputType == OutputType.Library)
69 {
70 this.LibraryPhase(intermediates, tableDefinitions);
71 }
72 else
73 {
74 var output = this.LinkPhase(intermediates, tableDefinitions);
75
76 if (!Messaging.Instance.EncounteredError)
77 {
78 this.BindPhase(output, tableDefinitions);
79 }
80 }
81
82 return Messaging.Instance.LastErrorNumber;
83 }
84
85 private IEnumerable<Intermediate> CompilePhase()
86 {
87 var intermediates = new List<Intermediate>();
88
89 var preprocessor = new Preprocessor();
90
91 var compiler = new Compiler();
92
93 foreach (var sourceFile in this.SourceFiles)
94 {
95 var document = preprocessor.Process(sourceFile.SourcePath, this.PreprocessorVariables);
96
97 var intermediate = compiler.Compile(document);
98
99 intermediates.Add(intermediate);
100 }
101
102 return intermediates;
103 }
104
105 private void LibraryPhase(IEnumerable<Intermediate> intermediates, TableDefinitionCollection tableDefinitions)
106 {
107 var localizations = this.LoadLocalizationFiles(tableDefinitions).ToList();
108
109 // If there was an error adding localization files, then bail.
110 if (Messaging.Instance.EncounteredError)
111 {
112 return;
113 }
48 114
49 var sections = intermediates.SelectMany(i => i.Sections).ToList(); 115 var sections = intermediates.SelectMany(i => i.Sections).ToList();
50 116
117 LibraryBinaryFileResolver resolver = null;
118
119 if (this.BindFiles)
120 {
121 resolver = new LibraryBinaryFileResolver();
122 resolver.FileManagers = new List<IBinderFileManager> { new BinderFileManager() }; ;
123 resolver.VariableResolver = new WixVariableResolver();
124
125 BinderFileManagerCore core = new BinderFileManagerCore();
126 core.AddBindPaths(this.BindPaths, BindStage.Normal);
127
128 foreach (var fileManager in resolver.FileManagers)
129 {
130 fileManager.Core = core;
131 }
132 }
133
134 var librarian = new Librarian();
135
136 var library = librarian.Combine(sections, localizations, resolver);
137
138 library?.Save(this.OutputPath);
139 }
140
141 private Output LinkPhase(IEnumerable<Intermediate> intermediates, TableDefinitionCollection tableDefinitions)
142 {
143 var sections = intermediates.SelectMany(i => i.Sections).ToList();
144
145 sections.AddRange(SectionsFromLibraries(tableDefinitions));
146
51 var linker = new Linker(); 147 var linker = new Linker();
52 148
53 var output = linker.Link(sections, OutputType.Product); 149 var output = linker.Link(sections, this.OutputType);
150
151 return output;
152 }
153
154 private IEnumerable<Section> SectionsFromLibraries(TableDefinitionCollection tableDefinitions)
155 {
156 var sections = new List<Section>();
157
158 if (this.LibraryFiles != null)
159 {
160 foreach (var libraryFile in this.LibraryFiles)
161 {
162 try
163 {
164 var library = Library.Load(libraryFile, tableDefinitions, false);
165
166 sections.AddRange(library.Sections);
167 }
168 catch (WixCorruptFileException e)
169 {
170 Messaging.Instance.OnMessage(e.Error);
171 }
172 catch (WixUnexpectedFileFormatException e)
173 {
174 Messaging.Instance.OnMessage(e.Error);
175 }
176 }
177 }
54 178
55 var localizer = new Localizer(); 179 return sections;
180 }
181
182 private void BindPhase(Output output, TableDefinitionCollection tableDefinitions)
183 {
184 var localizations = this.LoadLocalizationFiles(tableDefinitions).ToList();
185
186 var localizer = new Localizer(localizations);
187
188 var resolver = new WixVariableResolver(localizer);
56 189
57 var binder = new Binder(); 190 var binder = new Binder();
58 binder.TempFilesLocation = Path.GetTempPath(); 191 binder.TempFilesLocation = this.IntermediateFolder;
59 binder.WixVariableResolver = new WixVariableResolver(); 192 binder.WixVariableResolver = resolver;
60 binder.WixVariableResolver.Localizer = localizer;
61 binder.AddExtension(new BinderFileManager());
62 binder.SuppressValidation = true; 193 binder.SuppressValidation = true;
63 194
64 binder.ContentsFile = this.ContentsFile; 195 binder.ContentsFile = this.ContentsFile;
@@ -66,35 +197,50 @@ namespace WixToolset.Core
66 binder.BuiltOutputsFile = this.BuiltOutputsFile; 197 binder.BuiltOutputsFile = this.BuiltOutputsFile;
67 binder.WixprojectFile = this.WixProjectFile; 198 binder.WixprojectFile = this.WixProjectFile;
68 199
69 foreach (var loc in this.LocFiles) 200 if (this.BindPaths != null)
70 { 201 {
71 var localization = Localizer.ParseLocalizationFile(loc, linker.TableDefinitions); 202 binder.BindPaths.AddRange(this.BindPaths);
72 binder.WixVariableResolver.Localizer.AddLocalization(localization);
73 } 203 }
74 204
75 binder.Bind(output, this.OutputPath); 205 binder.AddExtension(new BinderFileManager());
76 206
77 return 0; 207 binder.Bind(output, this.OutputPath);
78 } 208 }
79 209
80 private IEnumerable<Intermediate> CompilePhase() 210 private IEnumerable<Localization> LoadLocalizationFiles(TableDefinitionCollection tableDefinitions)
81 { 211 {
82 var intermediates = new List<Intermediate>(); 212 foreach (var loc in this.LocFiles)
83 213 {
84 var preprocessor = new Preprocessor(); 214 var localization = Localizer.ParseLocalizationFile(loc, tableDefinitions);
85 215
86 var compiler = new Compiler(); 216 yield return localization;
217 }
218 }
87 219
88 foreach (var sourceFile in this.SourceFiles) 220 /// <summary>
89 { 221 /// File resolution mechanism to create binary library.
90 var document = preprocessor.Process(sourceFile.SourcePath, this.PreprocessorVariables); 222 /// </summary>
223 private class LibraryBinaryFileResolver : ILibraryBinaryFileResolver
224 {
225 public IEnumerable<IBinderFileManager> FileManagers { get; set; }
91 226
92 var intermediate = compiler.Compile(document); 227 public WixVariableResolver VariableResolver { get; set; }
93 228
94 intermediates.Add(intermediate); 229 public string Resolve(SourceLineNumber sourceLineNumber, string table, string path)
230 {
231 string resolvedPath = this.VariableResolver.ResolveVariables(sourceLineNumber, path, false);
232
233 foreach (IBinderFileManager fileManager in this.FileManagers)
234 {
235 string finalPath = fileManager.ResolveFile(resolvedPath, table, sourceLineNumber, BindStage.Normal);
236 if (!String.IsNullOrEmpty(finalPath))
237 {
238 return finalPath;
239 }
240 }
241
242 return null;
95 } 243 }
96
97 return intermediates;
98 } 244 }
99 } 245 }
100} 246}
diff --git a/src/WixToolset.Core/CommandLine/CommandLine.cs b/src/WixToolset.Core/CommandLine/CommandLine.cs
index 440ae9ef..cac54091 100644
--- a/src/WixToolset.Core/CommandLine/CommandLine.cs
+++ b/src/WixToolset.Core/CommandLine/CommandLine.cs
@@ -57,14 +57,20 @@ namespace WixToolset.Core
57 var showVersion = false; 57 var showVersion = false;
58 var outputFolder = String.Empty; 58 var outputFolder = String.Empty;
59 var outputFile = String.Empty; 59 var outputFile = String.Empty;
60 var sourceFile = String.Empty; 60 var outputType = String.Empty;
61 var verbose = false; 61 var verbose = false;
62 var files = new List<string>(); 62 var files = new List<string>();
63 var defines = new List<string>(); 63 var defines = new List<string>();
64 var includePaths = new List<string>(); 64 var includePaths = new List<string>();
65 var locFiles = new List<string>(); 65 var locFiles = new List<string>();
66 var libraryFiles = new List<string>();
66 var suppressedWarnings = new List<int>(); 67 var suppressedWarnings = new List<int>();
67 68
69 var bindFiles = false;
70 var bindPaths = new List<string>();
71
72 var intermediateFolder = String.Empty;
73
68 var cultures = new List<string>(); 74 var cultures = new List<string>();
69 var contentsFile = String.Empty; 75 var contentsFile = String.Empty;
70 var outputsFile = String.Empty; 76 var outputsFile = String.Empty;
@@ -84,6 +90,14 @@ namespace WixToolset.Core
84 cmdline.ShowHelp = true; 90 cmdline.ShowHelp = true;
85 return true; 91 return true;
86 92
93 case "bindfiles":
94 bindFiles = true;
95 return true;
96
97 case "bindpath":
98 cmdline.GetNextArgumentOrError(bindPaths);
99 return true;
100
87 case "cultures": 101 case "cultures":
88 cmdline.GetNextArgumentOrError(cultures); 102 cmdline.GetNextArgumentOrError(cultures);
89 return true; 103 return true;
@@ -110,15 +124,27 @@ namespace WixToolset.Core
110 cmdline.GetNextArgumentOrError(includePaths); 124 cmdline.GetNextArgumentOrError(includePaths);
111 return true; 125 return true;
112 126
127 case "intermediatefolder":
128 cmdline.GetNextArgumentOrError(ref intermediateFolder);
129 return true;
130
113 case "loc": 131 case "loc":
114 cmdline.GetNextArgumentAsFilePathOrError(locFiles, "localization files"); 132 cmdline.GetNextArgumentAsFilePathOrError(locFiles, "localization files");
115 return true; 133 return true;
116 134
135 case "lib":
136 cmdline.GetNextArgumentAsFilePathOrError(libraryFiles, "library files");
137 return true;
138
117 case "o": 139 case "o":
118 case "out": 140 case "out":
119 cmdline.GetNextArgumentOrError(ref outputFile); 141 cmdline.GetNextArgumentOrError(ref outputFile);
120 return true; 142 return true;
121 143
144 case "outputtype":
145 cmdline.GetNextArgumentOrError(ref outputType);
146 return true;
147
122 case "nologo": 148 case "nologo":
123 showLogo = false; 149 showLogo = false;
124 return true; 150 return true;
@@ -143,6 +169,8 @@ namespace WixToolset.Core
143 } 169 }
144 }); 170 });
145 171
172 Messaging.Instance.ShowVerboseMessages = verbose;
173
146 if (showVersion) 174 if (showVersion)
147 { 175 {
148 return new VersionCommand(); 176 return new VersionCommand();
@@ -164,8 +192,10 @@ namespace WixToolset.Core
164 { 192 {
165 var sourceFiles = GatherSourceFiles(files, outputFolder); 193 var sourceFiles = GatherSourceFiles(files, outputFolder);
166 var variables = GatherPreprocessorVariables(defines); 194 var variables = GatherPreprocessorVariables(defines);
195 var bindPathList = GatherBindPaths(bindPaths);
167 var extensions = cli.ExtensionManager; 196 var extensions = cli.ExtensionManager;
168 return new BuildCommand(sourceFiles, variables, locFiles, outputFile, cultures, contentsFile, outputsFile, builtOutputsFile, wixProjectFile); 197 var type = CalculateOutputType(outputType, outputFile);
198 return new BuildCommand(sourceFiles, variables, locFiles, libraryFiles, outputFile, type, cultures, bindFiles, bindPathList, intermediateFolder, contentsFile, outputsFile, builtOutputsFile, wixProjectFile);
169 } 199 }
170 200
171 case Commands.Compile: 201 case Commands.Compile:
@@ -179,6 +209,46 @@ namespace WixToolset.Core
179 return null; 209 return null;
180 } 210 }
181 211
212 private static OutputType CalculateOutputType(string outputType, string outputFile)
213 {
214 if (String.IsNullOrEmpty(outputType))
215 {
216 outputType = Path.GetExtension(outputFile);
217 }
218
219 switch (outputType.ToLowerInvariant())
220 {
221 case "bundle":
222 case ".exe":
223 return OutputType.Bundle;
224
225 case "library":
226 case ".wixlib":
227 return OutputType.Library;
228
229 case "module":
230 case ".msm":
231 return OutputType.Module;
232
233 case "patch":
234 case ".msp":
235 return OutputType.Patch;
236
237 case ".pcp":
238 return OutputType.PatchCreation;
239
240 case "product":
241 case ".msi":
242 return OutputType.Product;
243
244 case "transform":
245 case ".mst":
246 return OutputType.Transform;
247 }
248
249 return OutputType.Unknown;
250 }
251
182 private static CommandLine Parse(string commandLineString, Func<CommandLine, string, bool> parseArgument) 252 private static CommandLine Parse(string commandLineString, Func<CommandLine, string, bool> parseArgument)
183 { 253 {
184 var arguments = CommandLine.ParseArgumentsToArray(commandLineString).ToArray(); 254 var arguments = CommandLine.ParseArgumentsToArray(commandLineString).ToArray();
@@ -239,6 +309,26 @@ namespace WixToolset.Core
239 return variables; 309 return variables;
240 } 310 }
241 311
312 private static IEnumerable<BindPath> GatherBindPaths(IEnumerable<string> bindPaths)
313 {
314 var result = new List<BindPath>();
315
316 foreach (var bindPath in bindPaths)
317 {
318 BindPath bp = BindPath.Parse(bindPath);
319
320 if (Directory.Exists(bp.Path))
321 {
322 result.Add(bp);
323 }
324 else if (File.Exists(bp.Path))
325 {
326 Messaging.Instance.OnMessage(WixErrors.ExpectedDirectoryGotFile("-bindpath", bp.Path));
327 }
328 }
329
330 return result;
331 }
242 332
243 /// <summary> 333 /// <summary>
244 /// Get a set of files that possibly have a search pattern in the path (such as '*'). 334 /// Get a set of files that possibly have a search pattern in the path (such as '*').
@@ -361,7 +451,7 @@ namespace WixToolset.Core
361 451
362 private static bool TryDequeue(Queue<string> q, out string arg) 452 private static bool TryDequeue(Queue<string> q, out string arg)
363 { 453 {
364 if (q.Count> 0) 454 if (q.Count > 0)
365 { 455 {
366 arg = q.Dequeue(); 456 arg = q.Dequeue();
367 return true; 457 return true;
@@ -469,11 +559,6 @@ namespace WixToolset.Core
469 return false; 559 return false;
470 } 560 }
471 561
472 /// <summary>
473 /// Parses a response file.
474 /// </summary>
475 /// <param name="responseFile">The file to parse.</param>
476 /// <returns>The array of arguments.</returns>
477 private static List<string> ParseResponseFile(string responseFile) 562 private static List<string> ParseResponseFile(string responseFile)
478 { 563 {
479 string arguments; 564 string arguments;
@@ -486,11 +571,6 @@ namespace WixToolset.Core
486 return CommandLine.ParseArgumentsToArray(arguments); 571 return CommandLine.ParseArgumentsToArray(arguments);
487 } 572 }
488 573
489 /// <summary>
490 /// Parses an argument string into an argument array based on whitespace and quoting.
491 /// </summary>
492 /// <param name="arguments">Argument string.</param>
493 /// <returns>Argument array.</returns>
494 private static List<string> ParseArgumentsToArray(string arguments) 574 private static List<string> ParseArgumentsToArray(string arguments)
495 { 575 {
496 // Scan and parse the arguments string, dividing up the arguments based on whitespace. 576 // Scan and parse the arguments string, dividing up the arguments based on whitespace.
@@ -526,7 +606,7 @@ namespace WixToolset.Core
526 // Add the argument to the list if it's not empty. 606 // Add the argument to the list if it's not empty.
527 if (arg.Length > 0) 607 if (arg.Length > 0)
528 { 608 {
529 argsList.Add(CommandLine.ExpandEnvVars(arg.ToString())); 609 argsList.Add(CommandLine.ExpandEnvironmentVariables(arg.ToString()));
530 arg.Length = 0; 610 arg.Length = 0;
531 } 611 }
532 } 612 }
@@ -557,12 +637,7 @@ namespace WixToolset.Core
557 return argsList; 637 return argsList;
558 } 638 }
559 639
560 /// <summary> 640 private static string ExpandEnvironmentVariables(string arguments)
561 /// Expand enxironment variables contained in the passed string
562 /// </summary>
563 /// <param name="arguments"></param>
564 /// <returns></returns>
565 private static string ExpandEnvVars(string arguments)
566 { 641 {
567 var id = Environment.GetEnvironmentVariables(); 642 var id = Environment.GetEnvironmentVariables();
568 643
diff --git a/src/WixToolset.Core/Librarian.cs b/src/WixToolset.Core/Librarian.cs
index daf53478..66a8c32d 100644
--- a/src/WixToolset.Core/Librarian.cs
+++ b/src/WixToolset.Core/Librarian.cs
@@ -4,8 +4,8 @@ namespace WixToolset
4{ 4{
5 using System; 5 using System;
6 using System.Collections.Generic; 6 using System.Collections.Generic;
7 using System.Linq;
7 using WixToolset.Data; 8 using WixToolset.Data;
8 using WixToolset.Extensibility;
9 using WixToolset.Link; 9 using WixToolset.Link;
10 10
11 /// <summary> 11 /// <summary>
@@ -14,69 +14,26 @@ namespace WixToolset
14 public sealed class Librarian 14 public sealed class Librarian
15 { 15 {
16 /// <summary> 16 /// <summary>
17 /// Instantiate a new Librarian class.
18 /// </summary>
19 public Librarian()
20 {
21 this.TableDefinitions = new TableDefinitionCollection(WindowsInstallerStandard.GetTableDefinitions());
22 }
23
24 /// <summary>
25 /// Gets table definitions used by this librarian.
26 /// </summary>
27 /// <value>Table definitions.</value>
28 public TableDefinitionCollection TableDefinitions { get; private set; }
29
30 /// <summary>
31 /// Adds an extension's data.
32 /// </summary>
33 /// <param name="extension">The extension data to add.</param>
34 public void AddExtensionData(IExtensionData extension)
35 {
36 if (null != extension.TableDefinitions)
37 {
38 foreach (TableDefinition tableDefinition in extension.TableDefinitions)
39 {
40 try
41 {
42 this.TableDefinitions.Add(tableDefinition);
43 }
44 catch (ArgumentException)
45 {
46 Messaging.Instance.OnMessage(WixErrors.DuplicateExtensionTable(extension.GetType().ToString(), tableDefinition.Name));
47 }
48 }
49 }
50 }
51
52 /// <summary>
53 /// Create a library by combining several intermediates (objects). 17 /// Create a library by combining several intermediates (objects).
54 /// </summary> 18 /// </summary>
55 /// <param name="sections">The sections to combine into a library.</param> 19 /// <param name="sections">The sections to combine into a library.</param>
56 /// <returns>Returns the new library.</returns> 20 /// <returns>Returns the new library.</returns>
57 public Library Combine(IEnumerable<Section> sections) 21 public Library Combine(IEnumerable<Section> sections, IEnumerable<Localization> localizations, ILibraryBinaryFileResolver resolver)
58 { 22 {
59 Library library = new Library(sections); 23 var localizationsByCulture = CollateLocalizations(localizations);
60 24
61 this.Validate(library); 25 var embedFilePaths = ResolveFilePathsToEmbed(sections, resolver);
62 26
63 return (Messaging.Instance.EncounteredError ? null : library); 27 var library = new Library(sections, localizationsByCulture, embedFilePaths);
64 }
65 28
66 /// <summary> 29 return this.Validate(library);
67 /// Sends a message to the message delegate if there is one.
68 /// </summary>
69 /// <param name="mea">Message event arguments.</param>
70 public void OnMessage(MessageEventArgs e)
71 {
72 Messaging.Instance.OnMessage(e);
73 } 30 }
74 31
75 /// <summary> 32 /// <summary>
76 /// Validate that a library contains one entry section and no duplicate symbols. 33 /// Validate that a library contains one entry section and no duplicate symbols.
77 /// </summary> 34 /// </summary>
78 /// <param name="library">Library to validate.</param> 35 /// <param name="library">Library to validate.</param>
79 private void Validate(Library library) 36 private Library Validate(Library library)
80 { 37 {
81 FindEntrySectionAndLoadSymbolsCommand find = new FindEntrySectionAndLoadSymbolsCommand(library.Sections); 38 FindEntrySectionAndLoadSymbolsCommand find = new FindEntrySectionAndLoadSymbolsCommand(library.Sections);
82 find.Execute(); 39 find.Execute();
@@ -90,6 +47,66 @@ namespace WixToolset
90 // ReportDuplicateResolvedSymbolErrorsCommand reportDupes = new ReportDuplicateResolvedSymbolErrorsCommand(find.SymbolsWithDuplicates, resolve.ResolvedSections); 47 // ReportDuplicateResolvedSymbolErrorsCommand reportDupes = new ReportDuplicateResolvedSymbolErrorsCommand(find.SymbolsWithDuplicates, resolve.ResolvedSections);
91 // reportDupes.Execute(); 48 // reportDupes.Execute();
92 // } 49 // }
50
51 return (Messaging.Instance.EncounteredError ? null : library);
52 }
53
54 private static Dictionary<string, Localization> CollateLocalizations(IEnumerable<Localization> localizations)
55 {
56 var localizationsByCulture = new Dictionary<string, Localization>(StringComparer.OrdinalIgnoreCase);
57
58 foreach (var localization in localizations)
59 {
60 if (localizationsByCulture.TryGetValue(localization.Culture, out var existingCulture))
61 {
62 existingCulture.Merge(localization);
63 }
64 else
65 {
66 localizationsByCulture.Add(localization.Culture, localization);
67 }
68 }
69
70 return localizationsByCulture;
71 }
72
73 private static List<string> ResolveFilePathsToEmbed(IEnumerable<Section> sections, ILibraryBinaryFileResolver resolver)
74 {
75 var embedFilePaths = new List<string>();
76
77 // Resolve paths to files that are to be embedded in the library.
78 if (null != resolver)
79 {
80 foreach (Table table in sections.SelectMany(s => s.Tables))
81 {
82 foreach (Row row in table.Rows)
83 {
84 foreach (ObjectField objectField in row.Fields.OfType<ObjectField>())
85 {
86 if (null != objectField.Data)
87 {
88 string file = resolver.Resolve(row.SourceLineNumbers, table.Name, (string)objectField.Data);
89 if (!String.IsNullOrEmpty(file))
90 {
91 // File was successfully resolved so track the embedded index as the embedded file index.
92 objectField.EmbeddedFileIndex = embedFilePaths.Count;
93 embedFilePaths.Add(file);
94 }
95 else
96 {
97 Messaging.Instance.OnMessage(WixDataErrors.FileNotFound(row.SourceLineNumbers, (string)objectField.Data, table.Name));
98 }
99 }
100 else // clear out embedded file id in case there was one there before.
101 {
102 objectField.EmbeddedFileIndex = null;
103 }
104 }
105 }
106 }
107 }
108
109 return embedFilePaths;
93 } 110 }
94 } 111 }
95} 112}
diff --git a/src/WixToolset.Core/Localizer.cs b/src/WixToolset.Core/Localizer.cs
index 3c299896..63ead24a 100644
--- a/src/WixToolset.Core/Localizer.cs
+++ b/src/WixToolset.Core/Localizer.cs
@@ -23,11 +23,32 @@ namespace WixToolset
23 /// <summary> 23 /// <summary>
24 /// Instantiate a new Localizer. 24 /// Instantiate a new Localizer.
25 /// </summary> 25 /// </summary>
26 public Localizer() 26 public Localizer(IEnumerable<Localization> localizations)
27 { 27 {
28 this.Codepage = -1; 28 this.Codepage = -1;
29 this.variables = new Dictionary<string,WixVariableRow>(); 29 this.variables = new Dictionary<string, WixVariableRow>();
30 this.localizedControls = new Dictionary<string, LocalizedControl>(); 30 this.localizedControls = new Dictionary<string, LocalizedControl>();
31
32 foreach (var localization in localizations)
33 {
34 if (-1 == this.Codepage)
35 {
36 this.Codepage = localization.Codepage;
37 }
38
39 foreach (WixVariableRow wixVariableRow in localization.Variables)
40 {
41 Localizer.AddWixVariable(this.variables, wixVariableRow);
42 }
43
44 foreach (KeyValuePair<string, LocalizedControl> localizedControl in localization.LocalizedControls)
45 {
46 if (!this.localizedControls.ContainsKey(localizedControl.Key))
47 {
48 this.localizedControls.Add(localizedControl.Key, localizedControl.Value);
49 }
50 }
51 }
31 } 52 }
32 53
33 /// <summary> 54 /// <summary>
@@ -76,39 +97,13 @@ namespace WixToolset
76 } 97 }
77 98
78 /// <summary> 99 /// <summary>
79 /// Add a localization file.
80 /// </summary>
81 /// <param name="localization">The localization file to add.</param>
82 public void AddLocalization(Localization localization)
83 {
84 if (-1 == this.Codepage)
85 {
86 this.Codepage = localization.Codepage;
87 }
88
89 foreach (WixVariableRow wixVariableRow in localization.Variables)
90 {
91 Localizer.AddWixVariable(this.variables, wixVariableRow);
92 }
93
94 foreach (KeyValuePair<string, LocalizedControl> localizedControl in localization.LocalizedControls)
95 {
96 if (!this.localizedControls.ContainsKey(localizedControl.Key))
97 {
98 this.localizedControls.Add(localizedControl.Key, localizedControl.Value);
99 }
100 }
101 }
102
103 /// <summary>
104 /// Get a localized data value. 100 /// Get a localized data value.
105 /// </summary> 101 /// </summary>
106 /// <param name="id">The name of the localization variable.</param> 102 /// <param name="id">The name of the localization variable.</param>
107 /// <returns>The localized data value or null if it wasn't found.</returns> 103 /// <returns>The localized data value or null if it wasn't found.</returns>
108 public string GetLocalizedValue(string id) 104 public string GetLocalizedValue(string id)
109 { 105 {
110 WixVariableRow wixVariableRow; 106 return this.variables.TryGetValue(id, out var wixVariableRow) ? wixVariableRow.Value : null;
111 return this.variables.TryGetValue(id, out wixVariableRow) ? wixVariableRow.Value : null;
112 } 107 }
113 108
114 /// <summary> 109 /// <summary>
diff --git a/src/WixToolset.Core/WixVariableResolver.cs b/src/WixToolset.Core/WixVariableResolver.cs
index 921ff1e3..d437423c 100644
--- a/src/WixToolset.Core/WixVariableResolver.cs
+++ b/src/WixToolset.Core/WixVariableResolver.cs
@@ -3,7 +3,6 @@
3namespace WixToolset 3namespace WixToolset
4{ 4{
5 using System; 5 using System;
6 using System.Collections;
7 using System.Collections.Generic; 6 using System.Collections.Generic;
8 using System.Diagnostics.CodeAnalysis; 7 using System.Diagnostics.CodeAnalysis;
9 using System.Globalization; 8 using System.Globalization;
@@ -17,34 +16,27 @@ namespace WixToolset
17 /// </summary> 16 /// </summary>
18 public sealed class WixVariableResolver 17 public sealed class WixVariableResolver
19 { 18 {
20 private Localizer localizer;
21 private Dictionary<string, string> wixVariables; 19 private Dictionary<string, string> wixVariables;
22 20
23 /// <summary> 21 /// <summary>
24 /// Instantiate a new WixVariableResolver. 22 /// Instantiate a new WixVariableResolver.
25 /// </summary> 23 /// </summary>
26 public WixVariableResolver() 24 public WixVariableResolver(Localizer localizer = null)
27 { 25 {
28 this.wixVariables = new Dictionary<string, string>(); 26 this.wixVariables = new Dictionary<string, string>();
27 this.Localizer = localizer;
29 } 28 }
30 29
31 /// <summary> 30 /// <summary>
32 /// Gets or sets the localizer. 31 /// Gets or sets the localizer.
33 /// </summary> 32 /// </summary>
34 /// <value>The localizer.</value> 33 /// <value>The localizer.</value>
35 public Localizer Localizer 34 public Localizer Localizer { get; private set; }
36 {
37 get { return this.localizer; }
38 set { this.localizer = value; }
39 }
40 35
41 /// <summary> 36 /// <summary>
42 /// Gets the count of variables added to the resolver. 37 /// Gets the count of variables added to the resolver.
43 /// </summary> 38 /// </summary>
44 public int VariableCount 39 public int VariableCount => this.wixVariables.Count;
45 {
46 get { return this.wixVariables.Count; }
47 }
48 40
49 /// <summary> 41 /// <summary>
50 /// Add a variable. 42 /// Add a variable.
@@ -198,9 +190,9 @@ namespace WixToolset
198 Messaging.Instance.OnMessage(WixWarnings.DeprecatedLocalizationVariablePrefix(sourceLineNumbers, variableId)); 190 Messaging.Instance.OnMessage(WixWarnings.DeprecatedLocalizationVariablePrefix(sourceLineNumbers, variableId));
199 } 191 }
200 192
201 if (null != this.localizer) 193 if (null != this.Localizer)
202 { 194 {
203 resolvedValue = this.localizer.GetLocalizedValue(variableId); 195 resolvedValue = this.Localizer.GetLocalizedValue(variableId);
204 } 196 }
205 } 197 }
206 else if (!localizationOnly && "wix" == variableNamespace) 198 else if (!localizationOnly && "wix" == variableNamespace)