diff options
Diffstat (limited to 'src')
8 files changed, 208 insertions, 126 deletions
diff --git a/src/WixToolset.Core.WindowsInstaller/Bind/AssignMediaCommand.cs b/src/WixToolset.Core.WindowsInstaller/Bind/AssignMediaCommand.cs index 1d677a70..b75956b4 100644 --- a/src/WixToolset.Core.WindowsInstaller/Bind/AssignMediaCommand.cs +++ b/src/WixToolset.Core.WindowsInstaller/Bind/AssignMediaCommand.cs | |||
@@ -35,7 +35,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
35 | 35 | ||
36 | private bool FilesCompressed { get; } | 36 | private bool FilesCompressed { get; } |
37 | 37 | ||
38 | public string CabinetNameTemplate { private get; set; } | 38 | private string CabinetNameTemplate { get; set; } |
39 | 39 | ||
40 | /// <summary> | 40 | /// <summary> |
41 | /// Gets cabinets with their file rows. | 41 | /// Gets cabinets with their file rows. |
@@ -43,11 +43,6 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
43 | public Dictionary<MediaTuple, IEnumerable<FileFacade>> FileFacadesByCabinetMedia { get; private set; } | 43 | public Dictionary<MediaTuple, IEnumerable<FileFacade>> FileFacadesByCabinetMedia { get; private set; } |
44 | 44 | ||
45 | /// <summary> | 45 | /// <summary> |
46 | /// Get media rows. | ||
47 | /// </summary> | ||
48 | public Dictionary<int, MediaTuple> MediaRows { get; private set; } | ||
49 | |||
50 | /// <summary> | ||
51 | /// Get uncompressed file rows. This will contain file rows of File elements that are marked with compression=no. | 46 | /// Get uncompressed file rows. This will contain file rows of File elements that are marked with compression=no. |
52 | /// This contains all the files when Package element is marked with compression=no | 47 | /// This contains all the files when Package element is marked with compression=no |
53 | /// </summary> | 48 | /// </summary> |
@@ -55,17 +50,11 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
55 | 50 | ||
56 | public void Execute() | 51 | public void Execute() |
57 | { | 52 | { |
58 | var filesByCabinetMedia = new Dictionary<MediaTuple, List<FileFacade>>(); | 53 | var mediaTuples = this.Section.Tuples.OfType<MediaTuple>().ToList(); |
59 | 54 | var mediaTemplateTuples = this.Section.Tuples.OfType<WixMediaTemplateTuple>().ToList(); | |
60 | var mediaRows = new Dictionary<int, MediaTuple>(); | ||
61 | |||
62 | var uncompressedFiles = new List<FileFacade>(); | ||
63 | |||
64 | var mediaTable = this.Section.Tuples.OfType<MediaTuple>().ToList(); | ||
65 | var mediaTemplateTable = this.Section.Tuples.OfType<WixMediaTemplateTuple>().ToList(); | ||
66 | 55 | ||
67 | // If both tables are authored, it is an error. | 56 | // If both tuples are authored, it is an error. |
68 | if (mediaTemplateTable.Count > 0 && mediaTable.Count > 1) | 57 | if (mediaTemplateTuples.Count > 0 && mediaTuples.Count > 1) |
69 | { | 58 | { |
70 | throw new WixException(ErrorMessages.MediaTableCollision(null)); | 59 | throw new WixException(ErrorMessages.MediaTableCollision(null)); |
71 | } | 60 | } |
@@ -78,34 +67,44 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
78 | Cabinet = "#MergeModule.CABinet", | 67 | Cabinet = "#MergeModule.CABinet", |
79 | }); | 68 | }); |
80 | 69 | ||
81 | filesByCabinetMedia.Add(mergeModuleMediaTuple, new List<FileFacade>(this.FileFacades)); | 70 | this.FileFacadesByCabinetMedia = new Dictionary<MediaTuple, IEnumerable<FileFacade>> |
71 | { | ||
72 | { mergeModuleMediaTuple, this.FileFacades } | ||
73 | }; | ||
74 | |||
75 | this.UncompressedFileFacades = Array.Empty<FileFacade>(); | ||
82 | } | 76 | } |
83 | else if (mediaTemplateTable.Count == 0) | 77 | else if (mediaTemplateTuples.Count == 0) |
84 | { | 78 | { |
85 | this.ManuallyAssignFiles(mediaTable, this.FileFacades, filesByCabinetMedia, mediaRows, uncompressedFiles); | 79 | var filesByCabinetMedia = new Dictionary<MediaTuple, List<FileFacade>>(); |
80 | |||
81 | var uncompressedFiles = new List<FileFacade>(); | ||
82 | |||
83 | this.ManuallyAssignFiles(mediaTuples, filesByCabinetMedia, uncompressedFiles); | ||
84 | |||
85 | this.FileFacadesByCabinetMedia = filesByCabinetMedia.ToDictionary(kvp => kvp.Key, kvp => (IEnumerable<FileFacade>)kvp.Value); | ||
86 | |||
87 | this.UncompressedFileFacades = uncompressedFiles; | ||
86 | } | 88 | } |
87 | else | 89 | else |
88 | { | 90 | { |
89 | this.AutoAssignFiles(mediaTable, filesByCabinetMedia, mediaRows, uncompressedFiles); | 91 | var filesByCabinetMedia = new Dictionary<MediaTuple, List<FileFacade>>(); |
90 | } | ||
91 | 92 | ||
92 | this.FileFacadesByCabinetMedia = new Dictionary<MediaTuple, IEnumerable<FileFacade>>(); | 93 | var uncompressedFiles = new List<FileFacade>(); |
93 | 94 | ||
94 | foreach (var mediaRowWithFiles in filesByCabinetMedia) | 95 | this.AutoAssignFiles(mediaTuples, filesByCabinetMedia, uncompressedFiles); |
95 | { | ||
96 | this.FileFacadesByCabinetMedia.Add(mediaRowWithFiles.Key, mediaRowWithFiles.Value); | ||
97 | } | ||
98 | 96 | ||
99 | this.MediaRows = mediaRows; | 97 | this.FileFacadesByCabinetMedia = filesByCabinetMedia.ToDictionary(kvp => kvp.Key, kvp => (IEnumerable<FileFacade>)kvp.Value); |
100 | 98 | ||
101 | this.UncompressedFileFacades = uncompressedFiles; | 99 | this.UncompressedFileFacades = uncompressedFiles; |
100 | } | ||
102 | } | 101 | } |
103 | 102 | ||
104 | /// <summary> | 103 | /// <summary> |
105 | /// Assign files to cabinets based on MediaTemplate authoring. | 104 | /// Assign files to cabinets based on MediaTemplate authoring. |
106 | /// </summary> | 105 | /// </summary> |
107 | /// <param name="fileFacades">FileRowCollection</param> | 106 | /// <param name="fileFacades">FileRowCollection</param> |
108 | private void AutoAssignFiles(List<MediaTuple> mediaTable, Dictionary<MediaTuple, List<FileFacade>> filesByCabinetMedia, Dictionary<int, MediaTuple> mediaRows, List<FileFacade> uncompressedFiles) | 107 | private void AutoAssignFiles(List<MediaTuple> mediaTable, Dictionary<MediaTuple, List<FileFacade>> filesByCabinetMedia, List<FileFacade> uncompressedFiles) |
109 | { | 108 | { |
110 | const int MaxCabIndex = 999; | 109 | const int MaxCabIndex = 999; |
111 | 110 | ||
@@ -158,6 +157,8 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
158 | throw new WixException(ErrorMessages.MaximumUncompressedMediaSizeTooLarge(null, maxPreCabSizeInMB)); | 157 | throw new WixException(ErrorMessages.MaximumUncompressedMediaSizeTooLarge(null, maxPreCabSizeInMB)); |
159 | } | 158 | } |
160 | 159 | ||
160 | var mediaTuplesByDiskId = new Dictionary<int, MediaTuple>(); | ||
161 | |||
161 | foreach (var facade in this.FileFacades) | 162 | foreach (var facade in this.FileFacades) |
162 | { | 163 | { |
163 | // When building a product, if the current file is not to be compressed or if | 164 | // When building a product, if the current file is not to be compressed or if |
@@ -171,44 +172,38 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
171 | if (currentCabIndex == MaxCabIndex) | 172 | if (currentCabIndex == MaxCabIndex) |
172 | { | 173 | { |
173 | // Associate current file with last cab (irrespective of the size) and cab index is not incremented anymore. | 174 | // Associate current file with last cab (irrespective of the size) and cab index is not incremented anymore. |
174 | var cabinetFiles = filesByCabinetMedia[currentMediaRow]; | ||
175 | facade.DiskId = currentCabIndex; | ||
176 | cabinetFiles.Add(facade); | ||
177 | continue; | ||
178 | } | ||
179 | |||
180 | // Update current cab size. | ||
181 | currentPreCabSize += (ulong)facade.FileSize; | ||
182 | |||
183 | if (currentPreCabSize > maxPreCabSizeInBytes) | ||
184 | { | ||
185 | // Overflow due to current file | ||
186 | currentMediaRow = this.AddMediaRow(mediaTemplateRow, ++currentCabIndex); | ||
187 | mediaRows.Add(currentMediaRow.DiskId, currentMediaRow); | ||
188 | filesByCabinetMedia.Add(currentMediaRow, new List<FileFacade>()); | ||
189 | |||
190 | var cabinetFileRows = filesByCabinetMedia[currentMediaRow]; | ||
191 | facade.DiskId = currentCabIndex; | ||
192 | cabinetFileRows.Add(facade); | ||
193 | // Now files larger than MaxUncompressedMediaSize will be the only file in its cabinet so as to respect MaxUncompressedMediaSize | ||
194 | currentPreCabSize = (ulong)facade.FileSize; | ||
195 | } | 175 | } |
196 | else | 176 | else |
197 | { | 177 | { |
198 | // File fits in the current cab. | 178 | // Update current cab size. |
199 | if (currentMediaRow == null) | 179 | currentPreCabSize += (ulong)facade.FileSize; |
180 | |||
181 | // Overflow due to current file | ||
182 | if (currentPreCabSize > maxPreCabSizeInBytes) | ||
200 | { | 183 | { |
201 | // Create new cab and MediaRow | 184 | currentMediaRow = this.AddMediaTuple(mediaTemplateRow, ++currentCabIndex); |
202 | currentMediaRow = this.AddMediaRow(mediaTemplateRow, ++currentCabIndex); | 185 | mediaTuplesByDiskId.Add(currentMediaRow.DiskId, currentMediaRow); |
203 | mediaRows.Add(currentMediaRow.DiskId, currentMediaRow); | ||
204 | filesByCabinetMedia.Add(currentMediaRow, new List<FileFacade>()); | 186 | filesByCabinetMedia.Add(currentMediaRow, new List<FileFacade>()); |
205 | } | ||
206 | 187 | ||
207 | // Associate current file with current cab. | 188 | // Now files larger than MaxUncompressedMediaSize will be the only file in its cabinet so as to respect MaxUncompressedMediaSize |
208 | var cabinetFiles = filesByCabinetMedia[currentMediaRow]; | 189 | currentPreCabSize = (ulong)facade.FileSize; |
209 | facade.DiskId = currentCabIndex; | 190 | } |
210 | cabinetFiles.Add(facade); | 191 | else // file fits in the current cab. |
192 | { | ||
193 | if (currentMediaRow == null) | ||
194 | { | ||
195 | // Create new cab and MediaRow | ||
196 | currentMediaRow = this.AddMediaTuple(mediaTemplateRow, ++currentCabIndex); | ||
197 | mediaTuplesByDiskId.Add(currentMediaRow.DiskId, currentMediaRow); | ||
198 | filesByCabinetMedia.Add(currentMediaRow, new List<FileFacade>()); | ||
199 | } | ||
200 | } | ||
211 | } | 201 | } |
202 | |||
203 | // Associate current file with current cab. | ||
204 | var cabinetFiles = filesByCabinetMedia[currentMediaRow]; | ||
205 | facade.DiskId = currentCabIndex; | ||
206 | cabinetFiles.Add(facade); | ||
212 | } | 207 | } |
213 | 208 | ||
214 | // If there are uncompressed files and no MediaRow, create a default one. | 209 | // If there are uncompressed files and no MediaRow, create a default one. |
@@ -219,51 +214,45 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
219 | DiskId = 1, | 214 | DiskId = 1, |
220 | }); | 215 | }); |
221 | 216 | ||
222 | mediaRows.Add(1, defaultMediaRow); | 217 | mediaTuplesByDiskId.Add(1, defaultMediaRow); |
223 | } | 218 | } |
224 | } | 219 | } |
225 | 220 | ||
226 | /// <summary> | 221 | /// <summary> |
227 | /// Assign files to cabinets based on Media authoring. | 222 | /// Assign files to cabinets based on Media authoring. |
228 | /// </summary> | 223 | /// </summary> |
229 | /// <param name="mediaTable"></param> | 224 | private void ManuallyAssignFiles(List<MediaTuple> mediaTuples, Dictionary<MediaTuple, List<FileFacade>> filesByCabinetMedia, List<FileFacade> uncompressedFiles) |
230 | /// <param name="fileFacades"></param> | ||
231 | private void ManuallyAssignFiles(List<MediaTuple> mediaTable, IEnumerable<FileFacade> fileFacades, Dictionary<MediaTuple, List<FileFacade>> filesByCabinetMedia, Dictionary<int, MediaTuple> mediaRows, List<FileFacade> uncompressedFiles) | ||
232 | { | 225 | { |
233 | if (mediaTable.Any()) | 226 | var mediaTuplesByDiskId = new Dictionary<int, MediaTuple>(); |
227 | |||
228 | if (mediaTuples.Any()) | ||
234 | { | 229 | { |
235 | var cabinetMediaRows = new Dictionary<string, MediaTuple>(StringComparer.OrdinalIgnoreCase); | 230 | var cabinetMediaTuples = new Dictionary<string, MediaTuple>(StringComparer.OrdinalIgnoreCase); |
236 | foreach (var mediaRow in mediaTable) | 231 | foreach (var mediaTuple in mediaTuples) |
237 | { | 232 | { |
238 | // If the Media row has a cabinet, make sure it is unique across all Media rows. | 233 | // If the Media row has a cabinet, make sure it is unique across all Media rows. |
239 | if (!String.IsNullOrEmpty(mediaRow.Cabinet)) | 234 | if (!String.IsNullOrEmpty(mediaTuple.Cabinet)) |
240 | { | 235 | { |
241 | if (cabinetMediaRows.TryGetValue(mediaRow.Cabinet, out var existingRow)) | 236 | if (cabinetMediaTuples.TryGetValue(mediaTuple.Cabinet, out var existingRow)) |
242 | { | 237 | { |
243 | this.Messaging.Write(ErrorMessages.DuplicateCabinetName(mediaRow.SourceLineNumbers, mediaRow.Cabinet)); | 238 | this.Messaging.Write(ErrorMessages.DuplicateCabinetName(mediaTuple.SourceLineNumbers, mediaTuple.Cabinet)); |
244 | this.Messaging.Write(ErrorMessages.DuplicateCabinetName2(existingRow.SourceLineNumbers, existingRow.Cabinet)); | 239 | this.Messaging.Write(ErrorMessages.DuplicateCabinetName2(existingRow.SourceLineNumbers, existingRow.Cabinet)); |
245 | } | 240 | } |
246 | else | 241 | else |
247 | { | 242 | { |
248 | cabinetMediaRows.Add(mediaRow.Cabinet, mediaRow); | 243 | cabinetMediaTuples.Add(mediaTuple.Cabinet, mediaTuple); |
249 | } | 244 | } |
250 | } | ||
251 | 245 | ||
252 | mediaRows.Add(mediaRow.DiskId, mediaRow); | 246 | filesByCabinetMedia.Add(mediaTuple, new List<FileFacade>()); |
253 | } | 247 | } |
254 | } | ||
255 | 248 | ||
256 | foreach (var mediaRow in mediaRows.Values) | 249 | mediaTuplesByDiskId.Add(mediaTuple.DiskId, mediaTuple); |
257 | { | ||
258 | if (null != mediaRow.Cabinet) | ||
259 | { | ||
260 | filesByCabinetMedia.Add(mediaRow, new List<FileFacade>()); | ||
261 | } | 250 | } |
262 | } | 251 | } |
263 | 252 | ||
264 | foreach (var facade in fileFacades) | 253 | foreach (var facade in this.FileFacades) |
265 | { | 254 | { |
266 | if (!mediaRows.TryGetValue(facade.DiskId, out var mediaRow)) | 255 | if (!mediaTuplesByDiskId.TryGetValue(facade.DiskId, out var mediaTuple)) |
267 | { | 256 | { |
268 | this.Messaging.Write(ErrorMessages.MissingMedia(facade.SourceLineNumber, facade.DiskId)); | 257 | this.Messaging.Write(ErrorMessages.MissingMedia(facade.SourceLineNumber, facade.DiskId)); |
269 | continue; | 258 | continue; |
@@ -279,7 +268,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
279 | } | 268 | } |
280 | else // file is marked compressed. | 269 | else // file is marked compressed. |
281 | { | 270 | { |
282 | if (filesByCabinetMedia.TryGetValue(mediaRow, out var cabinetFiles)) | 271 | if (filesByCabinetMedia.TryGetValue(mediaTuple, out var cabinetFiles)) |
283 | { | 272 | { |
284 | cabinetFiles.Add(facade); | 273 | cabinetFiles.Add(facade); |
285 | } | 274 | } |
@@ -292,12 +281,12 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
292 | } | 281 | } |
293 | 282 | ||
294 | /// <summary> | 283 | /// <summary> |
295 | /// Adds a row to the media table with cab name template filled in. | 284 | /// Adds a tuple to the section with cab name template filled in. |
296 | /// </summary> | 285 | /// </summary> |
297 | /// <param name="mediaTable"></param> | 286 | /// <param name="mediaTable"></param> |
298 | /// <param name="cabIndex"></param> | 287 | /// <param name="cabIndex"></param> |
299 | /// <returns></returns> | 288 | /// <returns></returns> |
300 | private MediaTuple AddMediaRow(WixMediaTemplateTuple mediaTemplateTuple, int cabIndex) | 289 | private MediaTuple AddMediaTuple(WixMediaTemplateTuple mediaTemplateTuple, int cabIndex) |
301 | { | 290 | { |
302 | return this.Section.AddTuple(new MediaTuple(mediaTemplateTuple.SourceLineNumbers, new Identifier(AccessModifier.Private, cabIndex)) | 291 | return this.Section.AddTuple(new MediaTuple(mediaTemplateTuple.SourceLineNumbers, new Identifier(AccessModifier.Private, cabIndex)) |
303 | { | 292 | { |
diff --git a/src/WixToolset.Core.WindowsInstaller/Bind/BindDatabaseCommand.cs b/src/WixToolset.Core.WindowsInstaller/Bind/BindDatabaseCommand.cs index 6c2968ec..da92be69 100644 --- a/src/WixToolset.Core.WindowsInstaller/Bind/BindDatabaseCommand.cs +++ b/src/WixToolset.Core.WindowsInstaller/Bind/BindDatabaseCommand.cs | |||
@@ -281,19 +281,6 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
281 | command.Execute(); | 281 | command.Execute(); |
282 | } | 282 | } |
283 | 283 | ||
284 | // Assign files to media. | ||
285 | Dictionary<int, MediaTuple> assignedMediaRows; | ||
286 | Dictionary<MediaTuple, IEnumerable<FileFacade>> filesByCabinetMedia; | ||
287 | IEnumerable<FileFacade> uncompressedFiles; | ||
288 | { | ||
289 | var command = new AssignMediaCommand(section, this.Messaging, fileFacades, compressed); | ||
290 | command.Execute(); | ||
291 | |||
292 | assignedMediaRows = command.MediaRows; | ||
293 | filesByCabinetMedia = command.FileFacadesByCabinetMedia; | ||
294 | uncompressedFiles = command.UncompressedFileFacades; | ||
295 | } | ||
296 | |||
297 | // stop processing if an error previously occurred | 284 | // stop processing if an error previously occurred |
298 | if (this.Messaging.EncounteredError) | 285 | if (this.Messaging.EncounteredError) |
299 | { | 286 | { |
@@ -366,10 +353,23 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
366 | command.Execute(); | 353 | command.Execute(); |
367 | } | 354 | } |
368 | 355 | ||
369 | // Update file sequence. | 356 | // Assign files to media and update file sequences. |
357 | Dictionary<MediaTuple, IEnumerable<FileFacade>> filesByCabinetMedia; | ||
358 | IEnumerable<FileFacade> uncompressedFiles; | ||
370 | { | 359 | { |
371 | var command = new UpdateMediaSequencesCommand(section, fileFacades); | 360 | var order = new OptimizeFileFacadesOrderCommand(fileFacades); |
372 | command.Execute(); | 361 | order.Execute(); |
362 | |||
363 | fileFacades = order.FileFacades; | ||
364 | |||
365 | var assign = new AssignMediaCommand(section, this.Messaging, fileFacades, compressed); | ||
366 | assign.Execute(); | ||
367 | |||
368 | filesByCabinetMedia = assign.FileFacadesByCabinetMedia; | ||
369 | uncompressedFiles = assign.UncompressedFileFacades; | ||
370 | |||
371 | var update = new UpdateMediaSequencesCommand(section, fileFacades); | ||
372 | update.Execute(); | ||
373 | } | 373 | } |
374 | 374 | ||
375 | // stop processing if an error previously occurred | 375 | // stop processing if an error previously occurred |
diff --git a/src/WixToolset.Core.WindowsInstaller/Bind/CabinetBuilder.cs b/src/WixToolset.Core.WindowsInstaller/Bind/CabinetBuilder.cs index 486ee67a..dce89f78 100644 --- a/src/WixToolset.Core.WindowsInstaller/Bind/CabinetBuilder.cs +++ b/src/WixToolset.Core.WindowsInstaller/Bind/CabinetBuilder.cs | |||
@@ -7,7 +7,6 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
7 | using System.IO; | 7 | using System.IO; |
8 | using System.Linq; | 8 | using System.Linq; |
9 | using System.Threading; | 9 | using System.Threading; |
10 | using WixToolset.Core.Bind; | ||
11 | using WixToolset.Core.Native; | 10 | using WixToolset.Core.Native; |
12 | using WixToolset.Data; | 11 | using WixToolset.Data; |
13 | using WixToolset.Extensibility.Services; | 12 | using WixToolset.Extensibility.Services; |
@@ -18,12 +17,13 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
18 | /// </summary> | 17 | /// </summary> |
19 | internal sealed class CabinetBuilder | 18 | internal sealed class CabinetBuilder |
20 | { | 19 | { |
21 | private Queue cabinetWorkItems; | 20 | private readonly object lockObject = new object(); |
22 | private object lockObject; | 21 | |
22 | private readonly Queue cabinetWorkItems; | ||
23 | private int threadCount; | 23 | private int threadCount; |
24 | 24 | ||
25 | // Address of Binder's callback function for Cabinet Splitting | 25 | // Address of Binder's callback function for Cabinet Splitting |
26 | private IntPtr newCabNamesCallBackAddress; | 26 | private readonly IntPtr newCabNamesCallBackAddress; |
27 | 27 | ||
28 | /// <summary> | 28 | /// <summary> |
29 | /// Instantiate a new CabinetBuilder. | 29 | /// Instantiate a new CabinetBuilder. |
@@ -38,7 +38,6 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
38 | } | 38 | } |
39 | 39 | ||
40 | this.cabinetWorkItems = new Queue(); | 40 | this.cabinetWorkItems = new Queue(); |
41 | this.lockObject = new object(); | ||
42 | this.Messaging = messaging; | 41 | this.Messaging = messaging; |
43 | this.threadCount = threadCount; | 42 | this.threadCount = threadCount; |
44 | 43 | ||
@@ -56,10 +55,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
56 | /// Enqueues a CabinetWorkItem to the queue. | 55 | /// Enqueues a CabinetWorkItem to the queue. |
57 | /// </summary> | 56 | /// </summary> |
58 | /// <param name="cabinetWorkItem">cabinet work item</param> | 57 | /// <param name="cabinetWorkItem">cabinet work item</param> |
59 | public void Enqueue(CabinetWorkItem cabinetWorkItem) | 58 | public void Enqueue(CabinetWorkItem cabinetWorkItem) => this.cabinetWorkItems.Enqueue(cabinetWorkItem); |
60 | { | ||
61 | this.cabinetWorkItems.Enqueue(cabinetWorkItem); | ||
62 | } | ||
63 | 59 | ||
64 | /// <summary> | 60 | /// <summary> |
65 | /// Create the queued cabinets. | 61 | /// Create the queued cabinets. |
diff --git a/src/WixToolset.Core.WindowsInstaller/Bind/CreateCabinetsCommand.cs b/src/WixToolset.Core.WindowsInstaller/Bind/CreateCabinetsCommand.cs index de357e53..9741fcd9 100644 --- a/src/WixToolset.Core.WindowsInstaller/Bind/CreateCabinetsCommand.cs +++ b/src/WixToolset.Core.WindowsInstaller/Bind/CreateCabinetsCommand.cs | |||
@@ -171,7 +171,6 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
171 | return cabbingThreadCount; | 171 | return cabbingThreadCount; |
172 | } | 172 | } |
173 | 173 | ||
174 | |||
175 | /// <summary> | 174 | /// <summary> |
176 | /// Creates a work item to create a cabinet. | 175 | /// Creates a work item to create a cabinet. |
177 | /// </summary> | 176 | /// </summary> |
diff --git a/src/WixToolset.Core.WindowsInstaller/Bind/OptimizeFileFacadesOrderCommand.cs b/src/WixToolset.Core.WindowsInstaller/Bind/OptimizeFileFacadesOrderCommand.cs new file mode 100644 index 00000000..6943d345 --- /dev/null +++ b/src/WixToolset.Core.WindowsInstaller/Bind/OptimizeFileFacadesOrderCommand.cs | |||
@@ -0,0 +1,38 @@ | |||
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.WindowsInstaller.Bind | ||
4 | { | ||
5 | using System; | ||
6 | using System.Collections.Generic; | ||
7 | using WixToolset.Core.Bind; | ||
8 | |||
9 | internal class OptimizeFileFacadesOrderCommand | ||
10 | { | ||
11 | public OptimizeFileFacadesOrderCommand(List<FileFacade> fileFacades) | ||
12 | { | ||
13 | this.FileFacades = fileFacades; | ||
14 | } | ||
15 | |||
16 | public List<FileFacade> FileFacades { get; private set; } | ||
17 | |||
18 | public List<FileFacade> Execute() | ||
19 | { | ||
20 | this.FileFacades.Sort(FileFacadeOptimizer.Instance); | ||
21 | |||
22 | return this.FileFacades; | ||
23 | } | ||
24 | |||
25 | private class FileFacadeOptimizer : IComparer<FileFacade> | ||
26 | { | ||
27 | public static readonly FileFacadeOptimizer Instance = new FileFacadeOptimizer(); | ||
28 | |||
29 | public int Compare(FileFacade x, FileFacade y) | ||
30 | { | ||
31 | // TODO: Sort these facades even smarter by directory path and component id | ||
32 | // and maybe file size or file extension and other creative ideas to | ||
33 | // get optimal install speed out of MSI. | ||
34 | return String.Compare(x.ComponentRef, y.ComponentRef, StringComparison.Ordinal); | ||
35 | } | ||
36 | } | ||
37 | } | ||
38 | } | ||
diff --git a/src/WixToolset.Core.WindowsInstaller/Bind/UpdateMediaSequencesCommand.cs b/src/WixToolset.Core.WindowsInstaller/Bind/UpdateMediaSequencesCommand.cs index 9aab7b98..bf28b279 100644 --- a/src/WixToolset.Core.WindowsInstaller/Bind/UpdateMediaSequencesCommand.cs +++ b/src/WixToolset.Core.WindowsInstaller/Bind/UpdateMediaSequencesCommand.cs | |||
@@ -29,9 +29,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
29 | { | 29 | { |
30 | var lastSequence = 0; | 30 | var lastSequence = 0; |
31 | 31 | ||
32 | // Order by Component to group the files by directory. | 32 | foreach (var facade in this.FileFacades) |
33 | var optimized = this.OptimizedFileFacades(); | ||
34 | foreach (var facade in optimized) | ||
35 | { | 33 | { |
36 | facade.Sequence = ++lastSequence; | 34 | facade.Sequence = ++lastSequence; |
37 | } | 35 | } |
@@ -43,8 +41,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
43 | var patchGroups = new Dictionary<int, List<FileFacade>>(); | 41 | var patchGroups = new Dictionary<int, List<FileFacade>>(); |
44 | 42 | ||
45 | // sequence the non-patch-added files | 43 | // sequence the non-patch-added files |
46 | var optimized = this.OptimizedFileFacades(); | 44 | foreach (var facade in this.FileFacades) |
47 | foreach (var facade in optimized) | ||
48 | { | 45 | { |
49 | if (null == mediaTuple) | 46 | if (null == mediaTuple) |
50 | { | 47 | { |
@@ -108,13 +105,5 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
108 | } | 105 | } |
109 | } | 106 | } |
110 | } | 107 | } |
111 | |||
112 | private IEnumerable<FileFacade> OptimizedFileFacades() | ||
113 | { | ||
114 | // TODO: Sort these facades even smarter by directory path and component id | ||
115 | // and maybe file size or file extension and other creative ideas to | ||
116 | // get optimal install speed out of MSI. | ||
117 | return this.FileFacades.OrderBy(f => f.ComponentRef); | ||
118 | } | ||
119 | } | 108 | } |
120 | } | 109 | } |
diff --git a/src/test/WixToolsetTest.CoreIntegration/CabFixture.cs b/src/test/WixToolsetTest.CoreIntegration/CabFixture.cs new file mode 100644 index 00000000..79471554 --- /dev/null +++ b/src/test/WixToolsetTest.CoreIntegration/CabFixture.cs | |||
@@ -0,0 +1,71 @@ | |||
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 WixToolsetTest.CoreIntegration | ||
4 | { | ||
5 | using System; | ||
6 | using System.IO; | ||
7 | using System.Linq; | ||
8 | using WixBuildTools.TestSupport; | ||
9 | using WixToolset.Core.TestPackage; | ||
10 | using Xunit; | ||
11 | |||
12 | public class CabFixture | ||
13 | { | ||
14 | [Fact] | ||
15 | public void CabinetFilesSequencedCorrectly() | ||
16 | { | ||
17 | var folder = TestData.Get(@"TestData\MultiFileCompressed"); | ||
18 | |||
19 | using (var fs = new DisposableFileSystem()) | ||
20 | { | ||
21 | var baseFolder = fs.GetFolder(); | ||
22 | var intermediateFolder = Path.Combine(baseFolder, "obj"); | ||
23 | var msiPath = Path.Combine(baseFolder, @"bin\test.msi"); | ||
24 | var cabPath = Path.Combine(baseFolder, @"bin\cab1.cab"); | ||
25 | |||
26 | var result = WixRunner.Execute(new[] | ||
27 | { | ||
28 | "build", | ||
29 | Path.Combine(folder, "Package.wxs"), | ||
30 | Path.Combine(folder, "PackageComponents.wxs"), | ||
31 | "-d", "MediaTemplateCompressionLevel", | ||
32 | "-loc", Path.Combine(folder, "Package.en-us.wxl"), | ||
33 | "-bindpath", Path.Combine(folder, "data"), | ||
34 | "-intermediateFolder", intermediateFolder, | ||
35 | "-o", msiPath | ||
36 | }); | ||
37 | |||
38 | result.AssertSuccess(); | ||
39 | Assert.True(File.Exists(cabPath)); | ||
40 | |||
41 | var fileTable = Query.QueryDatabase(msiPath, new[] { "File" }); | ||
42 | var fileRows = fileTable.Select(r => new FileRow(r)).OrderBy(f => f.Sequence).ToList(); | ||
43 | |||
44 | Assert.Equal(new[] { 1, 2 }, fileRows.Select(f => f.Sequence).ToArray()); | ||
45 | Assert.Equal(new[] { "test.txt", "Notepad.exe" }, fileRows.Select(f => f.Name).ToArray()); | ||
46 | |||
47 | var files = Query.GetCabinetFiles(cabPath); | ||
48 | Assert.Equal(fileRows.Select(f => f.Id).ToArray(), files.Select(f => f.Name).ToArray()); | ||
49 | } | ||
50 | } | ||
51 | |||
52 | private class FileRow | ||
53 | { | ||
54 | public FileRow(string row) | ||
55 | { | ||
56 | row = row.Substring("File:".Length); | ||
57 | |||
58 | var split = row.Split('\t'); | ||
59 | this.Id = split[0]; | ||
60 | this.Name = split[2]; | ||
61 | this.Sequence = Convert.ToInt32(split[7]); | ||
62 | } | ||
63 | |||
64 | public string Id { get; set; } | ||
65 | |||
66 | public string Name { get; set; } | ||
67 | |||
68 | public int Sequence { get; set; } | ||
69 | } | ||
70 | } | ||
71 | } | ||
diff --git a/src/test/WixToolsetTest.CoreIntegration/TestData/MultiFileCompressed/PackageComponents.wxs b/src/test/WixToolsetTest.CoreIntegration/TestData/MultiFileCompressed/PackageComponents.wxs index d65a07df..82797ebe 100644 --- a/src/test/WixToolsetTest.CoreIntegration/TestData/MultiFileCompressed/PackageComponents.wxs +++ b/src/test/WixToolsetTest.CoreIntegration/TestData/MultiFileCompressed/PackageComponents.wxs | |||
@@ -3,10 +3,10 @@ | |||
3 | <Fragment> | 3 | <Fragment> |
4 | <ComponentGroup Id="ProductComponents" Directory="INSTALLFOLDER"> | 4 | <ComponentGroup Id="ProductComponents" Directory="INSTALLFOLDER"> |
5 | <Component> | 5 | <Component> |
6 | <File Source="test.txt" /> | 6 | <File Source="$(env.WINDIR)\Notepad.exe" /> |
7 | </Component> | 7 | </Component> |
8 | <Component> | 8 | <Component> |
9 | <File Source="$(env.WINDIR)\Notepad.exe" /> | 9 | <File Source="test.txt" /> |
10 | </Component> | 10 | </Component> |
11 | </ComponentGroup> | 11 | </ComponentGroup> |
12 | </Fragment> | 12 | </Fragment> |