main
cs 166 lines 6.33 KB
Raw
1 // Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2
3 namespace WixToolset.Core
4 {
5 using System;
6 using System.Collections.Generic;
7 using System.Linq;
8 using WixToolset.Core.Link;
9 using WixToolset.Data;
10 using WixToolset.Extensibility.Data;
11 using WixToolset.Extensibility.Services;
12
13 /// <summary>
14 /// Core librarian tool.
15 /// </summary>
16 internal class Librarian : ILibrarian
17 {
18 internal Librarian(IServiceProvider serviceProvider)
19 {
20 this.ServiceProvider = serviceProvider;
21
22 this.Messaging = this.ServiceProvider.GetService<IMessaging>();
23 this.FileResolver = this.ServiceProvider.GetService<IFileResolver>();
24 this.LayoutServices = this.ServiceProvider.GetService<ILayoutServices>();
25 }
26
27 private IServiceProvider ServiceProvider { get; }
28
29 private IMessaging Messaging { get; }
30
31 private IFileResolver FileResolver { get; }
32
33 private ILayoutServices LayoutServices { get; }
34
35 /// <summary>
36 /// Create a library by combining several intermediates (objects).
37 /// </summary>
38 /// <returns>Returns tracked input files and the new library.</returns>
39 public ILibraryResult Combine(ILibraryContext context)
40 {
41 if (String.IsNullOrEmpty(context.LibraryId))
42 {
43 context.LibraryId = Convert.ToBase64String(Guid.NewGuid().ToByteArray()).TrimEnd('=').Replace('+', '.').Replace('/', '_');
44 }
45
46 foreach (var extension in context.Extensions)
47 {
48 extension.PreCombine(context);
49 }
50
51 ILibraryResult result = this.ServiceProvider.GetService<ILibraryResult>();
52 Intermediate library = null;
53 IReadOnlyCollection<ITrackedFile> trackedFiles = null;
54 try
55 {
56 var sections = context.Intermediates.SelectMany(i => i.Sections).ToList();
57
58 var collate = new CollateLocalizationsCommand(this.Messaging, context.Localizations);
59 var localizationsByCulture = collate.Execute();
60
61 if (this.Messaging.EncounteredError)
62 {
63 return null;
64 }
65
66 foreach (var localization in localizationsByCulture.Values)
67 {
68 localization.UpdateLocation(LocalizationLocation.Library);
69 }
70
71 trackedFiles = this.ResolveFilePathsToEmbed(context, sections);
72
73 if (this.Messaging.EncounteredError)
74 {
75 return null;
76 }
77
78 foreach (var section in sections)
79 {
80 section.AssignToLibrary(context.LibraryId);
81 }
82
83 library = new Intermediate(context.LibraryId, IntermediateLevels.Compiled, sections, localizationsByCulture);
84
85 library.UpdateLevel(IntermediateLevels.Combined);
86
87 this.Validate(library);
88 }
89 finally
90 {
91 result.Library = library;
92 result.TrackedFiles = trackedFiles;
93
94 foreach (var extension in context.Extensions)
95 {
96 extension.PostCombine(result);
97 }
98 }
99
100 return result;
101 }
102
103 private IReadOnlyCollection<ITrackedFile> ResolveFilePathsToEmbed(ILibraryContext context, IEnumerable<IntermediateSection> sections)
104 {
105 var trackedFiles = new List<ITrackedFile>();
106
107 // Resolve paths to files that are to be embedded in the library.
108 if (context.BindFiles)
109 {
110 var variableResolver = this.ServiceProvider.GetService<IVariableResolver>();
111
112 foreach (var bindVariable in context.BindVariables)
113 {
114 variableResolver.AddVariable(null, bindVariable.Key, bindVariable.Value, false);
115 }
116
117 var bindPaths = context.BindPaths.Where(b => b.Stage == BindStage.Normal).ToList();
118
119 foreach (var symbol in sections.SelectMany(s => s.Symbols))
120 {
121 foreach (var field in symbol.Fields.Where(f => f?.Type == IntermediateFieldType.Path))
122 {
123 var pathField = field.AsPath();
124
125 if (pathField != null && !String.IsNullOrEmpty(pathField.Path))
126 {
127 var resolution = variableResolver.ResolveVariables(symbol.SourceLineNumbers, pathField.Path);
128
129 try
130 {
131 var file = this.FileResolver.ResolveFile(resolution.Value, context.Extensions, bindPaths, symbol.SourceLineNumbers, symbol.Definition);
132
133 // File was successfully resolved so track the embedded index as the embedded file index.
134 field.Set(new IntermediateFieldPathValue { Embed = true, Path = file });
135
136 trackedFiles.Add(this.LayoutServices.TrackFile(file, TrackedFileType.Input, symbol.SourceLineNumbers));
137 }
138 catch (WixException e)
139 {
140 this.Messaging.Write(e.Error);
141 }
142 }
143 }
144 }
145 }
146
147 return trackedFiles;
148 }
149
150 private void Validate(Intermediate library)
151 {
152 var find = new FindEntrySectionAndLoadSymbolsCommand(this.Messaging, library.Sections, OutputType.Library);
153 find.Execute();
154
155 // TODO: Consider bringing this sort of verification back.
156 // foreach (Section section in library.Sections)
157 // {
158 // ResolveReferencesCommand resolve = new ResolveReferencesCommand(find.EntrySection, find.Symbols);
159 // resolve.Execute();
160 //
161 // ReportDuplicateResolvedSymbolErrorsCommand reportDupes = new ReportDuplicateResolvedSymbolErrorsCommand(find.SymbolsWithDuplicates, resolve.ResolvedSections);
162 // reportDupes.Execute();
163 // }
164 }
165 }
166 }