aboutsummaryrefslogtreecommitdiff
path: root/src/WixToolset.Core.WindowsInstaller/Bind/AssignMediaCommand.cs
diff options
context:
space:
mode:
authorRob Mensching <rob@firegiant.com>2020-06-15 16:07:45 -0700
committerRob Mensching <rob@firegiant.com>2020-06-16 12:15:13 -0700
commit678c92c50c6fb7aa9a093f0d74d4f92742abd5e8 (patch)
treeef4d007b74e56734a5258e2235988fbc0ef6996f /src/WixToolset.Core.WindowsInstaller/Bind/AssignMediaCommand.cs
parent3fb3475b278803576badecfbe8015760de2e7414 (diff)
downloadwix-678c92c50c6fb7aa9a093f0d74d4f92742abd5e8.tar.gz
wix-678c92c50c6fb7aa9a093f0d74d4f92742abd5e8.tar.bz2
wix-678c92c50c6fb7aa9a093f0d74d4f92742abd5e8.zip
Reorganize media assignment to correctly place facade order optimization
Diffstat (limited to 'src/WixToolset.Core.WindowsInstaller/Bind/AssignMediaCommand.cs')
-rw-r--r--src/WixToolset.Core.WindowsInstaller/Bind/AssignMediaCommand.cs159
1 files changed, 74 insertions, 85 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 {