From 651ad904724f32f5e993fa73aa11a611d95a1a10 Mon Sep 17 00:00:00 2001 From: Rob Mensching Date: Sun, 31 Dec 2017 02:17:12 -0800 Subject: Support filtering localizations by culture --- src/WixToolset.Core/CommandLine/BuildCommand.cs | 9 +-- .../CommandLine/CommandLineParser.cs | 32 ++++++++++- src/WixToolset.Core/ResolveContext.cs | 2 + src/WixToolset.Core/Resolver.cs | 66 +++++++++++++++++++--- 4 files changed, 95 insertions(+), 14 deletions(-) diff --git a/src/WixToolset.Core/CommandLine/BuildCommand.cs b/src/WixToolset.Core/CommandLine/BuildCommand.cs index 48f1b214..5097bd9b 100644 --- a/src/WixToolset.Core/CommandLine/BuildCommand.cs +++ b/src/WixToolset.Core/CommandLine/BuildCommand.cs @@ -13,20 +13,20 @@ namespace WixToolset.Core.CommandLine internal class BuildCommand : ICommandLineCommand { - public BuildCommand(IServiceProvider serviceProvider, IEnumerable sources, IDictionary preprocessorVariables, IEnumerable locFiles, IEnumerable libraryFiles, string outputPath, OutputType outputType, string cabCachePath, IEnumerable cultures, bool bindFiles, IEnumerable bindPaths, IEnumerable includeSearchPaths, string intermediateFolder, string contentsFile, string outputsFile, string builtOutputsFile) + public BuildCommand(IServiceProvider serviceProvider, IEnumerable sources, IDictionary preprocessorVariables, IEnumerable locFiles, IEnumerable libraryFiles, IEnumerable filterCultures, string outputPath, OutputType outputType, string cabCachePath, bool bindFiles, IEnumerable bindPaths, IEnumerable includeSearchPaths, string intermediateFolder, string contentsFile, string outputsFile, string builtOutputsFile) { this.ServiceProvider = serviceProvider; this.Messaging = serviceProvider.GetService(); this.ExtensionManager = serviceProvider.GetService(); this.LocFiles = locFiles; this.LibraryFiles = libraryFiles; + this.FilterCultures = filterCultures; this.PreprocessorVariables = preprocessorVariables; this.SourceFiles = sources; this.OutputPath = outputPath; this.OutputType = outputType; this.CabCachePath = cabCachePath; - this.Cultures = cultures; this.BindFiles = bindFiles; this.BindPaths = bindPaths; this.IncludeSearchPaths = includeSearchPaths; @@ -43,6 +43,8 @@ namespace WixToolset.Core.CommandLine public IExtensionManager ExtensionManager { get; } + public IEnumerable FilterCultures { get; } + public IEnumerable IncludeSearchPaths { get; } public IEnumerable LocFiles { get; } @@ -59,8 +61,6 @@ namespace WixToolset.Core.CommandLine public string CabCachePath { get; } - public IEnumerable Cultures { get; } - public bool BindFiles { get; } public IEnumerable BindPaths { get; } @@ -205,6 +205,7 @@ namespace WixToolset.Core.CommandLine { var resolver = new Resolver(this.ServiceProvider); resolver.BindPaths = this.BindPaths; + resolver.FilterCultures = this.FilterCultures; resolver.IntermediateFolder = this.IntermediateFolder; resolver.IntermediateRepresentation = output; resolver.Localizations = localizations; diff --git a/src/WixToolset.Core/CommandLine/CommandLineParser.cs b/src/WixToolset.Core/CommandLine/CommandLineParser.cs index 500bed08..f4bc8ade 100644 --- a/src/WixToolset.Core/CommandLine/CommandLineParser.cs +++ b/src/WixToolset.Core/CommandLine/CommandLineParser.cs @@ -114,7 +114,7 @@ namespace WixToolset.Core.CommandLine cmdline.GetNextArgumentOrError(ref cabCachePath); return true; - case "cultures": + case "culture": cmdline.GetNextArgumentOrError(cultures); return true; case "contentsfile": @@ -210,8 +210,9 @@ namespace WixToolset.Core.CommandLine var sourceFiles = GatherSourceFiles(files, outputFolder); var variables = this.GatherPreprocessorVariables(defines); var bindPathList = this.GatherBindPaths(bindPaths); + var filterCultures = CalculateFilterCultures(cultures); var type = CalculateOutputType(outputType, outputFile); - return new BuildCommand(this.ServiceProvider, sourceFiles, variables, locFiles, libraryFiles, outputFile, type, cabCachePath, cultures, bindFiles, bindPathList, includePaths, intermediateFolder, contentsFile, outputsFile, builtOutputsFile); + return new BuildCommand(this.ServiceProvider, sourceFiles, variables, locFiles, libraryFiles, filterCultures, outputFile, type, cabCachePath, bindFiles, bindPathList, includePaths, intermediateFolder, contentsFile, outputsFile, builtOutputsFile); } case Commands.Compile: @@ -225,6 +226,33 @@ namespace WixToolset.Core.CommandLine return null; } + private static IEnumerable CalculateFilterCultures(List cultures) + { + var result = new List(); + + if (cultures == null) + { + } + else if (cultures.Count == 1 && cultures[0].Equals("null", StringComparison.OrdinalIgnoreCase)) + { + // When null is used treat it as if cultures wasn't specified. This is + // needed for batching in the MSBuild task since MSBuild doesn't support + // empty items. + } + else + { + foreach (var culture in cultures) + { + // Neutral is different from null. For neutral we still want to do culture filtering. + // Set the culture to the empty string = identifier for the invariant culture. + var filter = (culture.Equals("neutral", StringComparison.OrdinalIgnoreCase)) ? String.Empty : culture; + result.Add(filter); + } + } + + return result; + } + private static OutputType CalculateOutputType(string outputType, string outputFile) { if (String.IsNullOrEmpty(outputType)) diff --git a/src/WixToolset.Core/ResolveContext.cs b/src/WixToolset.Core/ResolveContext.cs index ca80d99c..d49a7d4b 100644 --- a/src/WixToolset.Core/ResolveContext.cs +++ b/src/WixToolset.Core/ResolveContext.cs @@ -25,6 +25,8 @@ namespace WixToolset.Core public IEnumerable ExtensionData { get; set; } + public IEnumerable FilterCultures { get; set; } + public string IntermediateFolder { get; set; } public Intermediate IntermediateRepresentation { get; set; } diff --git a/src/WixToolset.Core/Resolver.cs b/src/WixToolset.Core/Resolver.cs index c2d5cc87..03cf344b 100644 --- a/src/WixToolset.Core/Resolver.cs +++ b/src/WixToolset.Core/Resolver.cs @@ -31,6 +31,8 @@ namespace WixToolset.Core public IEnumerable Localizations { get; set; } + public IEnumerable FilterCultures { get; set; } + public ResolveResult Execute() { var extensionManager = this.ServiceProvider.GetService(); @@ -40,6 +42,7 @@ namespace WixToolset.Core context.BindPaths = this.BindPaths; context.Extensions = extensionManager.Create(); context.ExtensionData = extensionManager.Create(); + context.FilterCultures = this.FilterCultures; context.IntermediateFolder = this.IntermediateFolder; context.IntermediateRepresentation = this.IntermediateRepresentation; context.Localizations = this.Localizations; @@ -207,29 +210,76 @@ namespace WixToolset.Core { var creator = context.ServiceProvider.GetService(); + var localizations = FilterLocalizations(context); + + foreach (var localization in localizations) + { + context.VariableResolver.AddLocalization(localization); + } + + // Gather all the wix variables. + var wixVariableTuples = context.IntermediateRepresentation.Sections.SelectMany(s => s.Tuples).OfType(); + foreach (var tuple in wixVariableTuples) + { + context.VariableResolver.AddVariable(tuple.SourceLineNumbers, tuple.WixVariable, tuple.Value, tuple.Overridable); + } + } + + private static IEnumerable FilterLocalizations(IResolveContext context) + { + var result = new List(); + var filter = CalculateCultureFilter(context); + var localizations = context.Localizations.Concat(context.IntermediateRepresentation.Localizations).ToList(); - // Add localizations from the extensions with data. + // If there still is no filter, return all localizations. + AddFilteredLocalizations(result, filter, localizations); + + // Filter localizations provided by extensions with data. + var creator = context.ServiceProvider.GetService(); + foreach (var data in context.ExtensionData) { var library = data.GetLibrary(creator); if (library?.Localizations != null) { - localizations.AddRange(library.Localizations); + var extensionFilter = (!filter.Any() && data.DefaultCulture != null) ? new[] { data.DefaultCulture } : filter; + + AddFilteredLocalizations(result, extensionFilter, library.Localizations); } } - foreach (var localization in localizations) + return result; + } + + private static IEnumerable CalculateCultureFilter(IResolveContext context) + { + var filter = context.FilterCultures ?? Array.Empty(); + + // If no filter was specified, look for a language neutral localization file specified + // from the command-line (not embedded in the intermediate). If found, filter on language + // neutral. + if (!filter.Any() && context.Localizations.Any(l => String.IsNullOrEmpty(l.Culture))) { - context.VariableResolver.AddLocalization(localization); + filter = new[] { String.Empty }; } - // Gather all the wix variables. - var wixVariableTuples = context.IntermediateRepresentation.Sections.SelectMany(s => s.Tuples).OfType(); - foreach (var tuple in wixVariableTuples) + return filter; + } + + private static void AddFilteredLocalizations(List result, IEnumerable filter, IEnumerable localizations) + { + if (!filter.Any()) { - context.VariableResolver.AddVariable(tuple.SourceLineNumbers, tuple.WixVariable, tuple.Value, tuple.Overridable); + result.AddRange(localizations); + } + else // filter localizations in order specified by the filter + { + foreach (var culture in filter) + { + result.AddRange(localizations.Where(l => culture.Equals(l.Culture, StringComparison.OrdinalIgnoreCase))); + } } } } -- cgit v1.2.3-55-g6feb