diff options
author | Rob Mensching <rob@firegiant.com> | 2017-12-22 15:53:01 -0800 |
---|---|---|
committer | Rob Mensching <rob@firegiant.com> | 2017-12-22 15:53:01 -0800 |
commit | ecf3a0cca5a424a91ab98557d963d2535963d582 (patch) | |
tree | 06355e906e5c404480dc6eac342b9b4d2ec9d122 /src/light/light.cs | |
parent | dc9f4c329e6f55ce7595970463e0caf148096f4b (diff) | |
download | wix-ecf3a0cca5a424a91ab98557d963d2535963d582.tar.gz wix-ecf3a0cca5a424a91ab98557d963d2535963d582.tar.bz2 wix-ecf3a0cca5a424a91ab98557d963d2535963d582.zip |
Reintroduce binder extensions and light.exe for binding .wixouts
Diffstat (limited to 'src/light/light.cs')
-rw-r--r-- | src/light/light.cs | 595 |
1 files changed, 595 insertions, 0 deletions
diff --git a/src/light/light.cs b/src/light/light.cs new file mode 100644 index 00000000..c0967caa --- /dev/null +++ b/src/light/light.cs | |||
@@ -0,0 +1,595 @@ | |||
1 | // Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. | ||
2 | |||
3 | namespace WixToolset.Tools | ||
4 | { | ||
5 | using System; | ||
6 | using System.Collections.Generic; | ||
7 | using System.Globalization; | ||
8 | using System.IO; | ||
9 | using System.Linq; | ||
10 | using System.Runtime.InteropServices; | ||
11 | using System.Text; | ||
12 | using System.Threading; | ||
13 | using WixToolset.Core; | ||
14 | using WixToolset.Data; | ||
15 | using WixToolset.Data.Bind; | ||
16 | using WixToolset.Extensibility; | ||
17 | using WixToolset.Extensibility.Services; | ||
18 | |||
19 | /// <summary> | ||
20 | /// The main entry point for light. | ||
21 | /// </summary> | ||
22 | public sealed class Light | ||
23 | { | ||
24 | LightCommandLine commandLine; | ||
25 | private IEnumerable<IExtensionData> extensionData; | ||
26 | //private IEnumerable<IBinderExtension> binderExtensions; | ||
27 | //private IEnumerable<IBinderFileManager> fileManagers; | ||
28 | |||
29 | /// <summary> | ||
30 | /// The main entry point for light. | ||
31 | /// </summary> | ||
32 | /// <param name="args">Commandline arguments for the application.</param> | ||
33 | /// <returns>Returns the application error code.</returns> | ||
34 | [MTAThread] | ||
35 | public static int Main(string[] args) | ||
36 | { | ||
37 | var serviceProvider = new WixToolsetServiceProvider(); | ||
38 | |||
39 | var listener = new ConsoleMessageListener("WIX", "light.exe"); | ||
40 | |||
41 | Light light = new Light(); | ||
42 | return light.Run(serviceProvider, listener, args); | ||
43 | } | ||
44 | |||
45 | /// <summary> | ||
46 | /// Main running method for the application. | ||
47 | /// </summary> | ||
48 | /// <param name="args">Commandline arguments to the application.</param> | ||
49 | /// <returns>Returns the application error code.</returns> | ||
50 | public int Run(IServiceProvider serviceProvider, IMessageListener listener, string[] args) | ||
51 | { | ||
52 | var messaging = serviceProvider.GetService<IMessaging>(); | ||
53 | messaging.SetListener(listener); | ||
54 | |||
55 | try | ||
56 | { | ||
57 | var unparsed = this.ParseCommandLineAndLoadExtensions(serviceProvider, messaging, args); | ||
58 | |||
59 | if (!messaging.EncounteredError) | ||
60 | { | ||
61 | if (this.commandLine.ShowLogo) | ||
62 | { | ||
63 | AppCommon.DisplayToolHeader(); | ||
64 | } | ||
65 | |||
66 | if (this.commandLine.ShowHelp) | ||
67 | { | ||
68 | PrintHelp(); | ||
69 | AppCommon.DisplayToolFooter(); | ||
70 | } | ||
71 | else | ||
72 | { | ||
73 | foreach (string arg in unparsed) | ||
74 | { | ||
75 | messaging.Write(WarningMessages.UnsupportedCommandLineArgument(arg)); | ||
76 | } | ||
77 | |||
78 | this.Bind(serviceProvider, messaging); | ||
79 | } | ||
80 | } | ||
81 | } | ||
82 | catch (WixException we) | ||
83 | { | ||
84 | messaging.Write(we.Error); | ||
85 | } | ||
86 | catch (Exception e) | ||
87 | { | ||
88 | messaging.Write(ErrorMessages.UnexpectedException(e.Message, e.GetType().ToString(), e.StackTrace)); | ||
89 | if (e is NullReferenceException || e is SEHException) | ||
90 | { | ||
91 | throw; | ||
92 | } | ||
93 | } | ||
94 | |||
95 | return messaging.LastErrorNumber; | ||
96 | } | ||
97 | |||
98 | /// <summary> | ||
99 | /// Parse command line and load all the extensions. | ||
100 | /// </summary> | ||
101 | /// <param name="args">Command line arguments to be parsed.</param> | ||
102 | private IEnumerable<string> ParseCommandLineAndLoadExtensions(IServiceProvider serviceProvider, IMessaging messaging, string[] args) | ||
103 | { | ||
104 | this.commandLine = new LightCommandLine(messaging); | ||
105 | |||
106 | string[] unprocessed = this.commandLine.Parse(args); | ||
107 | if (messaging.EncounteredError) | ||
108 | { | ||
109 | return unprocessed; | ||
110 | } | ||
111 | |||
112 | // Load extensions. | ||
113 | var extensionManager = CreateExtensionManagerWithStandardBackends(serviceProvider); | ||
114 | foreach (string extension in this.commandLine.Extensions) | ||
115 | { | ||
116 | extensionManager.Load(extension); | ||
117 | } | ||
118 | |||
119 | // Extension data command line processing. | ||
120 | var context = serviceProvider.GetService<ICommandLineContext>(); | ||
121 | context.Arguments = null; | ||
122 | context.ExtensionManager = extensionManager; | ||
123 | context.Messaging = messaging; | ||
124 | context.ParsedArguments = args; | ||
125 | |||
126 | var commandLineExtensions = extensionManager.Create<IExtensionCommandLine>(); | ||
127 | foreach (var extension in commandLineExtensions) | ||
128 | { | ||
129 | extension.PreParse(context); | ||
130 | } | ||
131 | |||
132 | // Process unproccessed arguments. | ||
133 | List<string> actuallyUnprocessed = new List<string>(); | ||
134 | foreach (var arg in unprocessed) | ||
135 | { | ||
136 | if (!this.TryParseCommandLineArgumentWithExtension(arg, commandLineExtensions)) | ||
137 | { | ||
138 | actuallyUnprocessed.Add(arg); | ||
139 | } | ||
140 | } | ||
141 | |||
142 | return this.commandLine.ParsePostExtensions(actuallyUnprocessed.ToArray()); | ||
143 | } | ||
144 | |||
145 | private void Bind(IServiceProvider serviceProvider, IMessaging messaging) | ||
146 | { | ||
147 | var output = this.LoadWixout(messaging); | ||
148 | |||
149 | if (messaging.EncounteredError) | ||
150 | { | ||
151 | return; | ||
152 | } | ||
153 | |||
154 | var intermediateFolder = this.commandLine.IntermediateFolder; | ||
155 | if (String.IsNullOrEmpty(intermediateFolder)) | ||
156 | { | ||
157 | intermediateFolder = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName()); | ||
158 | } | ||
159 | |||
160 | var localizations = this.LoadLocalizationFiles(messaging, this.commandLine.LocalizationFiles); | ||
161 | |||
162 | if (messaging.EncounteredError) | ||
163 | { | ||
164 | return; | ||
165 | } | ||
166 | |||
167 | ResolveResult resolveResult; | ||
168 | { | ||
169 | var resolver = new Resolver(serviceProvider); | ||
170 | resolver.BindPaths = this.commandLine.BindPaths; | ||
171 | resolver.IntermediateFolder = intermediateFolder; | ||
172 | resolver.IntermediateRepresentation = output; | ||
173 | resolver.Localizations = localizations; | ||
174 | |||
175 | resolveResult = resolver.Execute(); | ||
176 | } | ||
177 | |||
178 | if (messaging.EncounteredError) | ||
179 | { | ||
180 | return; | ||
181 | } | ||
182 | |||
183 | BindResult bindResult; | ||
184 | { | ||
185 | var binder = new Binder(serviceProvider); | ||
186 | binder.CabbingThreadCount = this.commandLine.CabbingThreadCount; | ||
187 | binder.CabCachePath = this.commandLine.CabCachePath; | ||
188 | binder.Codepage = resolveResult.Codepage; | ||
189 | binder.DefaultCompressionLevel = this.commandLine.DefaultCompressionLevel; | ||
190 | binder.DelayedFields = resolveResult.DelayedFields; | ||
191 | binder.ExpectedEmbeddedFiles = resolveResult.ExpectedEmbeddedFiles; | ||
192 | binder.Ices = this.commandLine.Ices; | ||
193 | binder.IntermediateFolder = intermediateFolder; | ||
194 | binder.IntermediateRepresentation = resolveResult.IntermediateRepresentation; | ||
195 | binder.OutputPath = this.commandLine.OutputFile; | ||
196 | binder.OutputPdbPath = Path.ChangeExtension(this.commandLine.OutputFile, ".wixpdb"); | ||
197 | binder.SuppressIces = this.commandLine.SuppressIces; | ||
198 | binder.SuppressValidation = this.commandLine.SuppressValidation; | ||
199 | |||
200 | bindResult = binder.Execute(); | ||
201 | } | ||
202 | |||
203 | if (messaging.EncounteredError) | ||
204 | { | ||
205 | return; | ||
206 | } | ||
207 | |||
208 | { | ||
209 | var layout = new Layout(serviceProvider); | ||
210 | layout.FileTransfers = bindResult.FileTransfers; | ||
211 | layout.ContentFilePaths = bindResult.ContentFilePaths; | ||
212 | layout.ContentsFile = this.commandLine.ContentsFile; | ||
213 | layout.OutputsFile = this.commandLine.OutputsFile; | ||
214 | layout.BuiltOutputsFile = this.commandLine.BuiltOutputsFile; | ||
215 | layout.SuppressAclReset = this.commandLine.SuppressAclReset; | ||
216 | |||
217 | layout.Execute(); | ||
218 | } | ||
219 | } | ||
220 | |||
221 | private void Run(IMessaging messaging) | ||
222 | { | ||
223 | #if false | ||
224 | // Initialize the variable resolver from the command line. | ||
225 | WixVariableResolver wixVariableResolver = new WixVariableResolver(); | ||
226 | foreach (var wixVar in this.commandLine.Variables) | ||
227 | { | ||
228 | wixVariableResolver.AddVariable(wixVar.Key, wixVar.Value); | ||
229 | } | ||
230 | |||
231 | // Initialize the linker from the command line. | ||
232 | Linker linker = new Linker(); | ||
233 | linker.UnreferencedSymbolsFile = this.commandLine.UnreferencedSymbolsFile; | ||
234 | linker.ShowPedanticMessages = this.commandLine.ShowPedanticMessages; | ||
235 | linker.WixVariableResolver = wixVariableResolver; | ||
236 | |||
237 | foreach (IExtensionData data in this.extensionData) | ||
238 | { | ||
239 | linker.AddExtensionData(data); | ||
240 | } | ||
241 | |||
242 | // Initialize the binder from the command line. | ||
243 | WixToolset.Binder binder = new WixToolset.Binder(); | ||
244 | binder.CabCachePath = this.commandLine.CabCachePath; | ||
245 | binder.ContentsFile = this.commandLine.ContentsFile; | ||
246 | binder.BuiltOutputsFile = this.commandLine.BuiltOutputsFile; | ||
247 | binder.OutputsFile = this.commandLine.OutputsFile; | ||
248 | binder.WixprojectFile = this.commandLine.WixprojectFile; | ||
249 | binder.BindPaths.AddRange(this.commandLine.BindPaths); | ||
250 | binder.CabbingThreadCount = this.commandLine.CabbingThreadCount; | ||
251 | if (this.commandLine.DefaultCompressionLevel.HasValue) | ||
252 | { | ||
253 | binder.DefaultCompressionLevel = this.commandLine.DefaultCompressionLevel.Value; | ||
254 | } | ||
255 | binder.Ices.AddRange(this.commandLine.Ices); | ||
256 | binder.SuppressIces.AddRange(this.commandLine.SuppressIces); | ||
257 | binder.SuppressAclReset = this.commandLine.SuppressAclReset; | ||
258 | binder.SuppressLayout = this.commandLine.SuppressLayout; | ||
259 | binder.SuppressValidation = this.commandLine.SuppressValidation; | ||
260 | binder.PdbFile = this.commandLine.SuppressWixPdb ? null : this.commandLine.PdbFile; | ||
261 | binder.TempFilesLocation = AppCommon.GetTempLocation(); | ||
262 | binder.WixVariableResolver = wixVariableResolver; | ||
263 | |||
264 | foreach (IBinderExtension extension in this.binderExtensions) | ||
265 | { | ||
266 | binder.AddExtension(extension); | ||
267 | } | ||
268 | |||
269 | foreach (IBinderFileManager fileManager in this.fileManagers) | ||
270 | { | ||
271 | binder.AddExtension(fileManager); | ||
272 | } | ||
273 | |||
274 | // Initialize the localizer. | ||
275 | Localizer localizer = this.InitializeLocalization(linker.TableDefinitions); | ||
276 | if (messaging.EncounteredError) | ||
277 | { | ||
278 | return; | ||
279 | } | ||
280 | |||
281 | wixVariableResolver.Localizer = localizer; | ||
282 | linker.Localizer = localizer; | ||
283 | binder.Localizer = localizer; | ||
284 | |||
285 | // Loop through all the believed object files. | ||
286 | List<Section> sections = new List<Section>(); | ||
287 | Output output = null; | ||
288 | foreach (string inputFile in this.commandLine.Files) | ||
289 | { | ||
290 | string inputFileFullPath = Path.GetFullPath(inputFile); | ||
291 | FileFormat format = FileStructure.GuessFileFormatFromExtension(Path.GetExtension(inputFileFullPath)); | ||
292 | bool retry; | ||
293 | do | ||
294 | { | ||
295 | retry = false; | ||
296 | |||
297 | try | ||
298 | { | ||
299 | switch (format) | ||
300 | { | ||
301 | case FileFormat.Wixobj: | ||
302 | Intermediate intermediate = Intermediate.Load(inputFileFullPath, linker.TableDefinitions, this.commandLine.SuppressVersionCheck); | ||
303 | sections.AddRange(intermediate.Sections); | ||
304 | break; | ||
305 | |||
306 | case FileFormat.Wixlib: | ||
307 | Library library = Library.Load(inputFileFullPath, linker.TableDefinitions, this.commandLine.SuppressVersionCheck); | ||
308 | AddLibraryLocalizationsToLocalizer(library, this.commandLine.Cultures, localizer); | ||
309 | sections.AddRange(library.Sections); | ||
310 | break; | ||
311 | |||
312 | default: | ||
313 | output = Output.Load(inputFileFullPath, this.commandLine.SuppressVersionCheck); | ||
314 | break; | ||
315 | } | ||
316 | } | ||
317 | catch (WixUnexpectedFileFormatException e) | ||
318 | { | ||
319 | format = e.FileFormat; | ||
320 | retry = (FileFormat.Wixobj == format || FileFormat.Wixlib == format || FileFormat.Wixout == format); // .wixobj, .wixout and .wixout are supported by light. | ||
321 | if (!retry) | ||
322 | { | ||
323 | messaging.OnMessage(e.Error); | ||
324 | } | ||
325 | } | ||
326 | } while (retry); | ||
327 | } | ||
328 | |||
329 | // Stop processing if any errors were found loading object files. | ||
330 | if (messaging.EncounteredError) | ||
331 | { | ||
332 | return; | ||
333 | } | ||
334 | |||
335 | // and now for the fun part | ||
336 | if (null == output) | ||
337 | { | ||
338 | OutputType expectedOutputType = OutputType.Unknown; | ||
339 | if (!String.IsNullOrEmpty(this.commandLine.OutputFile)) | ||
340 | { | ||
341 | expectedOutputType = Output.GetOutputType(Path.GetExtension(this.commandLine.OutputFile)); | ||
342 | } | ||
343 | |||
344 | output = linker.Link(sections, expectedOutputType); | ||
345 | |||
346 | // If an error occurred during linking, stop processing. | ||
347 | if (null == output) | ||
348 | { | ||
349 | return; | ||
350 | } | ||
351 | } | ||
352 | else if (0 != sections.Count) | ||
353 | { | ||
354 | throw new InvalidOperationException(LightStrings.EXP_CannotLinkObjFilesWithOutpuFile); | ||
355 | } | ||
356 | |||
357 | bool tidy = true; // clean up after ourselves by default. | ||
358 | try | ||
359 | { | ||
360 | // only output the xml if its a patch build or user specfied to only output wixout | ||
361 | string outputFile = this.commandLine.OutputFile; | ||
362 | string outputExtension = Path.GetExtension(outputFile); | ||
363 | if (this.commandLine.OutputXml || OutputType.Patch == output.Type) | ||
364 | { | ||
365 | if (String.IsNullOrEmpty(outputExtension) || outputExtension.Equals(".wix", StringComparison.Ordinal)) | ||
366 | { | ||
367 | outputExtension = (OutputType.Patch == output.Type) ? ".wixmsp" : ".wixout"; | ||
368 | outputFile = Path.ChangeExtension(outputFile, outputExtension); | ||
369 | } | ||
370 | |||
371 | output.Save(outputFile); | ||
372 | } | ||
373 | else // finish creating the MSI/MSM | ||
374 | { | ||
375 | if (String.IsNullOrEmpty(outputExtension) || outputExtension.Equals(".wix", StringComparison.Ordinal)) | ||
376 | { | ||
377 | outputExtension = Output.GetExtension(output.Type); | ||
378 | outputFile = Path.ChangeExtension(outputFile, outputExtension); | ||
379 | } | ||
380 | |||
381 | binder.Bind(output, outputFile); | ||
382 | } | ||
383 | } | ||
384 | catch (WixException we) // keep files around for debugging IDT issues. | ||
385 | { | ||
386 | if (we is WixInvalidIdtException) | ||
387 | { | ||
388 | tidy = false; | ||
389 | } | ||
390 | |||
391 | throw; | ||
392 | } | ||
393 | catch (Exception) // keep files around for debugging unexpected exceptions. | ||
394 | { | ||
395 | tidy = false; | ||
396 | throw; | ||
397 | } | ||
398 | finally | ||
399 | { | ||
400 | if (null != binder) | ||
401 | { | ||
402 | binder.Cleanup(tidy); | ||
403 | } | ||
404 | } | ||
405 | |||
406 | return; | ||
407 | #endif | ||
408 | } | ||
409 | |||
410 | #if false | ||
411 | private Localizer InitializeLocalization(TableDefinitionCollection tableDefinitions) | ||
412 | { | ||
413 | Localizer localizer = null; | ||
414 | |||
415 | // Instantiate the localizer and load any localization files. | ||
416 | if (!this.commandLine.SuppressLocalization || 0 < this.commandLine.LocalizationFiles.Count || null != this.commandLine.Cultures || !this.commandLine.OutputXml) | ||
417 | { | ||
418 | List<Localization> localizations = new List<Localization>(); | ||
419 | |||
420 | // Load each localization file. | ||
421 | foreach (string localizationFile in this.commandLine.LocalizationFiles) | ||
422 | { | ||
423 | Localization localization = Localizer.ParseLocalizationFile(localizationFile, tableDefinitions); | ||
424 | if (null != localization) | ||
425 | { | ||
426 | localizations.Add(localization); | ||
427 | } | ||
428 | } | ||
429 | |||
430 | localizer = new Localizer(); | ||
431 | if (null != this.commandLine.Cultures) | ||
432 | { | ||
433 | // Alocalizations in order specified in cultures. | ||
434 | foreach (string culture in this.commandLine.Cultures) | ||
435 | { | ||
436 | foreach (Localization localization in localizations) | ||
437 | { | ||
438 | if (culture.Equals(localization.Culture, StringComparison.OrdinalIgnoreCase)) | ||
439 | { | ||
440 | localizer.AddLocalization(localization); | ||
441 | } | ||
442 | } | ||
443 | } | ||
444 | } | ||
445 | else // no cultures specified, so try neutral culture and if none of those add all loc files. | ||
446 | { | ||
447 | bool neutralFound = false; | ||
448 | foreach (Localization localization in localizations) | ||
449 | { | ||
450 | if (String.IsNullOrEmpty(localization.Culture)) | ||
451 | { | ||
452 | // If a neutral wxl was provided use it. | ||
453 | localizer.AddLocalization(localization); | ||
454 | neutralFound = true; | ||
455 | } | ||
456 | } | ||
457 | |||
458 | if (!neutralFound) | ||
459 | { | ||
460 | // No cultures were specified and no neutral wxl are available, include all of the loc files. | ||
461 | foreach (Localization localization in localizations) | ||
462 | { | ||
463 | localizer.AddLocalization(localization); | ||
464 | } | ||
465 | } | ||
466 | } | ||
467 | |||
468 | // Load localizations provided by extensions with data. | ||
469 | foreach (IExtensionData data in this.extensionData) | ||
470 | { | ||
471 | Library library = data.GetLibrary(tableDefinitions); | ||
472 | if (null != library) | ||
473 | { | ||
474 | // Load the extension's default culture if it provides one and no cultures were specified. | ||
475 | string[] extensionCultures = this.commandLine.Cultures; | ||
476 | if (null == extensionCultures && null != data.DefaultCulture) | ||
477 | { | ||
478 | extensionCultures = new string[] { data.DefaultCulture }; | ||
479 | } | ||
480 | |||
481 | AddLibraryLocalizationsToLocalizer(library, extensionCultures, localizer); | ||
482 | } | ||
483 | } | ||
484 | } | ||
485 | |||
486 | return localizer; | ||
487 | } | ||
488 | |||
489 | private void AddLibraryLocalizationsToLocalizer(Library library, string[] cultures, Localizer localizer) | ||
490 | { | ||
491 | foreach (Localization localization in library.GetLocalizations(cultures)) | ||
492 | { | ||
493 | localizer.AddLocalization(localization); | ||
494 | } | ||
495 | } | ||
496 | #endif | ||
497 | |||
498 | private bool TryParseCommandLineArgumentWithExtension(string arg, IEnumerable<IExtensionCommandLine> extensions) | ||
499 | { | ||
500 | foreach (var extension in extensions) | ||
501 | { | ||
502 | // TODO: decide what to do with "IParseCommandLine" argument. | ||
503 | if (extension.TryParseArgument(null, arg)) | ||
504 | { | ||
505 | return true; | ||
506 | } | ||
507 | } | ||
508 | |||
509 | return false; | ||
510 | } | ||
511 | |||
512 | private IEnumerable<Localization> LoadLocalizationFiles(IMessaging messaging, IEnumerable<string> locFiles) | ||
513 | { | ||
514 | foreach (var loc in locFiles) | ||
515 | { | ||
516 | var localization = Localizer.ParseLocalizationFile(messaging, loc); | ||
517 | |||
518 | yield return localization; | ||
519 | } | ||
520 | } | ||
521 | |||
522 | private Intermediate LoadWixout(IMessaging messaging) | ||
523 | { | ||
524 | var path = this.commandLine.Files.Single(); | ||
525 | |||
526 | return Intermediate.Load(path); | ||
527 | } | ||
528 | |||
529 | private static IExtensionManager CreateExtensionManagerWithStandardBackends(IServiceProvider serviceProvider) | ||
530 | { | ||
531 | var extensionManager = serviceProvider.GetService<IExtensionManager>(); | ||
532 | |||
533 | foreach (var type in new[] { typeof(WixToolset.Core.Burn.WixToolsetStandardBackend), typeof(WixToolset.Core.WindowsInstaller.WixToolsetStandardBackend) }) | ||
534 | { | ||
535 | extensionManager.Add(type.Assembly); | ||
536 | } | ||
537 | |||
538 | return extensionManager; | ||
539 | } | ||
540 | |||
541 | private static void PrintHelp() | ||
542 | { | ||
543 | string lightArgs = LightStrings.CommandLineArguments; | ||
544 | |||
545 | Console.WriteLine(String.Format(LightStrings.HelpMessage, lightArgs)); | ||
546 | } | ||
547 | |||
548 | private class ConsoleMessageListener : IMessageListener | ||
549 | { | ||
550 | public ConsoleMessageListener(string shortName, string longName) | ||
551 | { | ||
552 | this.ShortAppName = shortName; | ||
553 | this.LongAppName = longName; | ||
554 | |||
555 | PrepareConsoleForLocalization(); | ||
556 | } | ||
557 | |||
558 | public string LongAppName { get; } | ||
559 | |||
560 | public string ShortAppName { get; } | ||
561 | |||
562 | public void Write(Message message) | ||
563 | { | ||
564 | var filename = message.SourceLineNumbers?.FileName ?? this.LongAppName; | ||
565 | var line = message.SourceLineNumbers?.LineNumber ?? -1; | ||
566 | var type = message.Level.ToString().ToLowerInvariant(); | ||
567 | var output = message.Level >= MessageLevel.Warning ? Console.Out : Console.Error; | ||
568 | |||
569 | if (line > 0) | ||
570 | { | ||
571 | filename = String.Concat(filename, "(", line, ")"); | ||
572 | } | ||
573 | |||
574 | output.WriteLine("{0} : {1} {2}{3:0000}: {4}", filename, type, this.ShortAppName, message.Id, message.ToString()); | ||
575 | } | ||
576 | |||
577 | public void Write(string message) | ||
578 | { | ||
579 | Console.Out.WriteLine(message); | ||
580 | } | ||
581 | |||
582 | private static void PrepareConsoleForLocalization() | ||
583 | { | ||
584 | Thread.CurrentThread.CurrentUICulture = CultureInfo.CurrentUICulture.GetConsoleFallbackUICulture(); | ||
585 | |||
586 | if (Console.OutputEncoding.CodePage != Encoding.UTF8.CodePage && | ||
587 | Console.OutputEncoding.CodePage != Thread.CurrentThread.CurrentUICulture.TextInfo.OEMCodePage && | ||
588 | Console.OutputEncoding.CodePage != Thread.CurrentThread.CurrentUICulture.TextInfo.ANSICodePage) | ||
589 | { | ||
590 | Thread.CurrentThread.CurrentUICulture = new CultureInfo("en-US"); | ||
591 | } | ||
592 | } | ||
593 | } | ||
594 | } | ||
595 | } | ||