diff options
Diffstat (limited to 'src')
19 files changed, 779 insertions, 986 deletions
diff --git a/src/WixToolset.Core.WindowsInstaller/Bind/AttachPatchTransformsCommand.cs b/src/WixToolset.Core.WindowsInstaller/Bind/AttachPatchTransformsCommand.cs index 214bf617..a16bafd7 100644 --- a/src/WixToolset.Core.WindowsInstaller/Bind/AttachPatchTransformsCommand.cs +++ b/src/WixToolset.Core.WindowsInstaller/Bind/AttachPatchTransformsCommand.cs | |||
@@ -147,7 +147,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
147 | { | 147 | { |
148 | foreach (MediaRow transformMediaRow in transformMediaTable.Rows) | 148 | foreach (MediaRow transformMediaRow in transformMediaTable.Rows) |
149 | { | 149 | { |
150 | if (mediaTuple.LastSequence < transformMediaRow.LastSequence) | 150 | if (!mediaTuple.LastSequence.HasValue || mediaTuple.LastSequence < transformMediaRow.LastSequence) |
151 | { | 151 | { |
152 | // The Binder will pre-increment the sequence. | 152 | // The Binder will pre-increment the sequence. |
153 | mediaTuple.LastSequence = transformMediaRow.LastSequence; | 153 | mediaTuple.LastSequence = transformMediaRow.LastSequence; |
@@ -156,14 +156,13 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
156 | } | 156 | } |
157 | 157 | ||
158 | // Use the Media/@DiskId if greater than the last sequence for backward compatibility. | 158 | // Use the Media/@DiskId if greater than the last sequence for backward compatibility. |
159 | if (mediaTuple.LastSequence < mediaTuple.DiskId) | 159 | if (!mediaTuple.LastSequence.HasValue || mediaTuple.LastSequence < mediaTuple.DiskId) |
160 | { | 160 | { |
161 | mediaTuple.LastSequence = mediaTuple.DiskId; | 161 | mediaTuple.LastSequence = mediaTuple.DiskId; |
162 | } | 162 | } |
163 | 163 | ||
164 | // Ignore media table in the transform. | 164 | // Ignore media table in the transform. |
165 | mainTransform.Transform.Tables.Remove("Media"); | 165 | mainTransform.Transform.Tables.Remove("Media"); |
166 | mainTransform.Transform.Tables.Remove("WixMedia"); | ||
167 | mainTransform.Transform.Tables.Remove("MsiDigitalSignature"); | 166 | mainTransform.Transform.Tables.Remove("MsiDigitalSignature"); |
168 | 167 | ||
169 | var pairedTransform = this.BuildPairedTransform(summaryInfo, patchMetadata, patchIdTuple, mainTransform.Transform, mediaTuple, baselineTuple, out var productCode); | 168 | var pairedTransform = this.BuildPairedTransform(summaryInfo, patchMetadata, patchIdTuple, mainTransform.Transform, mediaTuple, baselineTuple, out var productCode); |
@@ -767,15 +766,15 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
767 | if (transform.TryGetTable("File", out var fileTable)) | 766 | if (transform.TryGetTable("File", out var fileTable)) |
768 | { | 767 | { |
769 | var componentWithChangedKeyPath = new Dictionary<string, string>(); | 768 | var componentWithChangedKeyPath = new Dictionary<string, string>(); |
770 | foreach (var row in fileTable.Rows) | 769 | foreach (FileRow row in fileTable.Rows) |
771 | { | 770 | { |
772 | if (RowOperation.None == row.Operation) | 771 | if (RowOperation.None == row.Operation) |
773 | { | 772 | { |
774 | continue; | 773 | continue; |
775 | } | 774 | } |
776 | 775 | ||
777 | var fileId = row.FieldAsString(0); | 776 | var fileId = row.File; |
778 | var componentId = row.FieldAsString(1); | 777 | var componentId = row.Component; |
779 | 778 | ||
780 | // If this file is the keypath of a component | 779 | // If this file is the keypath of a component |
781 | if (componentKeyPath.TryGetValue(componentId, out var keyPath) && keyPath.Equals(fileId, StringComparison.Ordinal)) | 780 | if (componentKeyPath.TryGetValue(componentId, out var keyPath) && keyPath.Equals(fileId, StringComparison.Ordinal)) |
@@ -972,7 +971,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
972 | 971 | ||
973 | if (row.Operation == RowOperation.None) | 972 | if (row.Operation == RowOperation.None) |
974 | { | 973 | { |
975 | // ignore the rows without section id. | 974 | // Ignore the rows without section id. |
976 | if (isSectionIdEmpty) | 975 | if (isSectionIdEmpty) |
977 | { | 976 | { |
978 | currentTable.Rows.RemoveAt(i); | 977 | currentTable.Rows.RemoveAt(i); |
@@ -1157,47 +1156,33 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
1157 | return null; | 1156 | return null; |
1158 | } | 1157 | } |
1159 | 1158 | ||
1160 | // copy File table | 1159 | // Copy File table |
1161 | if (mainTransform.Tables.TryGetTable("File", out var mainFileTable) && 0 < mainFileTable.Rows.Count) | 1160 | if (mainTransform.Tables.TryGetTable("File", out var mainFileTable) && 0 < mainFileTable.Rows.Count) |
1162 | { | 1161 | { |
1163 | #if TODO_PATCHING | ||
1164 | // We require file source information. | ||
1165 | var mainWixFileTable = mainTransform.Tables["WixFile"]; | ||
1166 | if (null == mainWixFileTable) | ||
1167 | { | ||
1168 | this.Messaging.Write(ErrorMessages.AdminImageRequired(productCode)); | ||
1169 | return null; | ||
1170 | } | ||
1171 | |||
1172 | var mainFileRows = new RowDictionary<FileRow>(mainFileTable); | ||
1173 | |||
1174 | var pairedFileTable = pairedTransform.EnsureTable(mainFileTable.Definition); | 1162 | var pairedFileTable = pairedTransform.EnsureTable(mainFileTable.Definition); |
1175 | { | ||
1176 | var mainFileRow = mainFileRows[mainWixFileRow.File]; | ||
1177 | 1163 | ||
1178 | // set File.Sequence to non null to satisfy transform bind | 1164 | foreach (FileRow mainFileRow in mainFileTable.Rows) |
1165 | { | ||
1166 | // Set File.Sequence to non null to satisfy transform bind. | ||
1179 | mainFileRow.Sequence = 1; | 1167 | mainFileRow.Sequence = 1; |
1180 | 1168 | ||
1181 | // delete's don't need rows in the paired transform | 1169 | // Delete's don't need rows in the paired transform. |
1182 | if (mainFileRow.Operation == RowOperation.Delete) | 1170 | if (mainFileRow.Operation == RowOperation.Delete) |
1183 | { | 1171 | { |
1184 | continue; | 1172 | continue; |
1185 | } | 1173 | } |
1186 | 1174 | ||
1187 | var pairedFileRow = (FileRow)pairedFileTable.CreateRow(null); | 1175 | var pairedFileRow = (FileRow)pairedFileTable.CreateRow(mainFileRow.SourceLineNumbers); |
1188 | pairedFileRow.Operation = RowOperation.Modify; | 1176 | pairedFileRow.Operation = RowOperation.Modify; |
1189 | for (var i = 0; i < mainFileRow.Fields.Length; i++) | 1177 | mainFileRow.CopyTo(pairedFileRow); |
1190 | { | ||
1191 | pairedFileRow[i] = mainFileRow[i]; | ||
1192 | } | ||
1193 | 1178 | ||
1194 | // override authored media for patch bind | 1179 | // Override authored media for patch bind. |
1195 | mainWixFileRow.DiskId = mediaTuple.DiskId; | 1180 | mainFileRow.DiskId = mediaTuple.DiskId; |
1196 | 1181 | ||
1197 | // suppress any change to File.Sequence to avoid bloat | 1182 | // Suppress any change to File.Sequence to avoid bloat. |
1198 | mainFileRow.Fields[7].Modified = false; | 1183 | mainFileRow.Fields[7].Modified = false; |
1199 | 1184 | ||
1200 | // force File row to appear in the transform | 1185 | // Force File row to appear in the transform. |
1201 | switch (mainFileRow.Operation) | 1186 | switch (mainFileRow.Operation) |
1202 | { | 1187 | { |
1203 | case RowOperation.Modify: | 1188 | case RowOperation.Modify: |
@@ -1211,19 +1196,18 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
1211 | break; | 1196 | break; |
1212 | } | 1197 | } |
1213 | } | 1198 | } |
1214 | #endif | ||
1215 | } | 1199 | } |
1216 | 1200 | ||
1217 | // Add Media row to pairedTransform | 1201 | // Add Media row to pairedTransform |
1218 | var pairedMediaTable = pairedTransform.EnsureTable(this.tableDefinitions["Media"]); | 1202 | var pairedMediaTable = pairedTransform.EnsureTable(this.tableDefinitions["Media"]); |
1219 | var pairedMediaRow = pairedMediaTable.CreateRow(mediaTuple.SourceLineNumbers); | 1203 | var pairedMediaRow = (MediaRow)pairedMediaTable.CreateRow(mediaTuple.SourceLineNumbers); |
1220 | pairedMediaRow.Operation = RowOperation.Add; | 1204 | pairedMediaRow.Operation = RowOperation.Add; |
1221 | pairedMediaRow[0] = mediaTuple.DiskId; | 1205 | pairedMediaRow.DiskId = mediaTuple.DiskId; |
1222 | pairedMediaRow[1] = mediaTuple.LastSequence ?? 0; | 1206 | pairedMediaRow.LastSequence = mediaTuple.LastSequence ?? 0; |
1223 | pairedMediaRow[2] = mediaTuple.DiskPrompt; | 1207 | pairedMediaRow.DiskPrompt = mediaTuple.DiskPrompt; |
1224 | pairedMediaRow[3] = mediaTuple.Cabinet; | 1208 | pairedMediaRow.Cabinet = mediaTuple.Cabinet; |
1225 | pairedMediaRow[4] = mediaTuple.VolumeLabel; | 1209 | pairedMediaRow.VolumeLabel = mediaTuple.VolumeLabel; |
1226 | pairedMediaRow[5] = mediaTuple.Source; | 1210 | pairedMediaRow.Source = mediaTuple.Source; |
1227 | 1211 | ||
1228 | // Add PatchPackage for this Media | 1212 | // Add PatchPackage for this Media |
1229 | var pairedPackageTable = pairedTransform.EnsureTable(this.tableDefinitions["PatchPackage"]); | 1213 | var pairedPackageTable = pairedTransform.EnsureTable(this.tableDefinitions["PatchPackage"]); |
@@ -1283,7 +1267,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
1283 | { | 1267 | { |
1284 | var patchTargetTuples = tuples.OfType<WixPatchTargetTuple>().ToList(); | 1268 | var patchTargetTuples = tuples.OfType<WixPatchTargetTuple>().ToList(); |
1285 | 1269 | ||
1286 | if (patchTargetTuples.Count > 0) | 1270 | if (patchTargetTuples.Any()) |
1287 | { | 1271 | { |
1288 | var targets = new SortedSet<string>(); | 1272 | var targets = new SortedSet<string>(); |
1289 | var replace = true; | 1273 | var replace = true; |
diff --git a/src/WixToolset.Core.WindowsInstaller/Bind/BindDatabaseCommand.cs b/src/WixToolset.Core.WindowsInstaller/Bind/BindDatabaseCommand.cs index 8e901d30..d9d246f5 100644 --- a/src/WixToolset.Core.WindowsInstaller/Bind/BindDatabaseCommand.cs +++ b/src/WixToolset.Core.WindowsInstaller/Bind/BindDatabaseCommand.cs | |||
@@ -43,7 +43,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
43 | this.DefaultCompressionLevel = context.DefaultCompressionLevel; | 43 | this.DefaultCompressionLevel = context.DefaultCompressionLevel; |
44 | this.DelayedFields = context.DelayedFields; | 44 | this.DelayedFields = context.DelayedFields; |
45 | this.ExpectedEmbeddedFiles = context.ExpectedEmbeddedFiles; | 45 | this.ExpectedEmbeddedFiles = context.ExpectedEmbeddedFiles; |
46 | this.FileSystemExtensions = context.FileSystemExtensions; | 46 | this.FileSystemManager = new FileSystemManager(context.FileSystemExtensions); |
47 | this.Intermediate = context.IntermediateRepresentation; | 47 | this.Intermediate = context.IntermediateRepresentation; |
48 | this.IntermediateFolder = context.IntermediateFolder; | 48 | this.IntermediateFolder = context.IntermediateFolder; |
49 | this.OutputPath = context.OutputPath; | 49 | this.OutputPath = context.OutputPath; |
@@ -79,7 +79,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
79 | 79 | ||
80 | public IEnumerable<IExpectedExtractFile> ExpectedEmbeddedFiles { get; } | 80 | public IEnumerable<IExpectedExtractFile> ExpectedEmbeddedFiles { get; } |
81 | 81 | ||
82 | public IEnumerable<IFileSystemExtension> FileSystemExtensions { get; } | 82 | public FileSystemManager FileSystemManager { get; } |
83 | 83 | ||
84 | public bool DeltaBinaryPatch { get; set; } | 84 | public bool DeltaBinaryPatch { get; set; } |
85 | 85 | ||
@@ -116,7 +116,6 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
116 | var trackedFiles = new List<ITrackedFile>(); | 116 | var trackedFiles = new List<ITrackedFile>(); |
117 | 117 | ||
118 | var containsMergeModules = false; | 118 | var containsMergeModules = false; |
119 | var suppressedTableNames = new HashSet<string>(); | ||
120 | 119 | ||
121 | // If there are any fields to resolve later, create the cache to populate during bind. | 120 | // If there are any fields to resolve later, create the cache to populate during bind. |
122 | var variableCache = this.DelayedFields.Any() ? new Dictionary<string, string>(StringComparer.InvariantCultureIgnoreCase) : null; | 121 | var variableCache = this.DelayedFields.Any() ? new Dictionary<string, string>(StringComparer.InvariantCultureIgnoreCase) : null; |
@@ -226,7 +225,6 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
226 | return null; | 225 | return null; |
227 | } | 226 | } |
228 | 227 | ||
229 | WindowsInstallerData output; | ||
230 | this.Intermediate.UpdateLevel(Data.WindowsInstaller.IntermediateLevels.FullyBound); | 228 | this.Intermediate.UpdateLevel(Data.WindowsInstaller.IntermediateLevels.FullyBound); |
231 | this.Messaging.Write(VerboseMessages.UpdatingFileInformation()); | 229 | this.Messaging.Write(VerboseMessages.UpdatingFileInformation()); |
232 | 230 | ||
@@ -268,14 +266,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
268 | } | 266 | } |
269 | else if (SectionType.Patch == section.Type) | 267 | else if (SectionType.Patch == section.Type) |
270 | { | 268 | { |
271 | // Merge transform data into the output object. | 269 | var command = new GetFileFacadesFromTransforms(this.Messaging, this.FileSystemManager, this.SubStorages); |
272 | //IEnumerable<FileFacade> filesFromTransform = this.CopyFromTransformData(this.Output); | ||
273 | |||
274 | //var command = new CopyTransformDataCommand(this.Messaging, /*output*/this.SubStorages, tableDefinitions, copyOutFileRows: true); | ||
275 | //command.Output = output; | ||
276 | //command.TableDefinitions = this.TableDefinitions; | ||
277 | //command.CopyOutFileRows = true; | ||
278 | var command = new GetFileFacadesFromTransforms(this.Messaging, this.SubStorages, tableDefinitions); | ||
279 | command.Execute(); | 270 | command.Execute(); |
280 | var filesFromTransforms = command.FileFacades; | 271 | var filesFromTransforms = command.FileFacades; |
281 | 272 | ||
@@ -338,6 +329,12 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
338 | command.Execute(); | 329 | command.Execute(); |
339 | } | 330 | } |
340 | 331 | ||
332 | // Update file sequence. | ||
333 | { | ||
334 | var command = new UpdateMediaSequencesCommand(section, fileFacades); | ||
335 | command.Execute(); | ||
336 | } | ||
337 | |||
341 | // stop processing if an error previously occurred | 338 | // stop processing if an error previously occurred |
342 | if (this.Messaging.EncounteredError) | 339 | if (this.Messaging.EncounteredError) |
343 | { | 340 | { |
@@ -345,6 +342,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
345 | } | 342 | } |
346 | 343 | ||
347 | // Time to create the output object. Try to put as much above here as possible, updating the IR is better. | 344 | // Time to create the output object. Try to put as much above here as possible, updating the IR is better. |
345 | WindowsInstallerData output; | ||
348 | { | 346 | { |
349 | var command = new CreateOutputFromIRCommand(this.Messaging, section, tableDefinitions, this.BackendExtensions, this.WindowsInstallerBackendHelper); | 347 | var command = new CreateOutputFromIRCommand(this.Messaging, section, tableDefinitions, this.BackendExtensions, this.WindowsInstallerBackendHelper); |
350 | command.Execute(); | 348 | command.Execute(); |
@@ -352,14 +350,8 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
352 | output = command.Output; | 350 | output = command.Output; |
353 | } | 351 | } |
354 | 352 | ||
355 | // Update file sequence. | ||
356 | { | ||
357 | var command = new UpdateMediaSequencesCommand(output, fileFacades); | ||
358 | command.Execute(); | ||
359 | } | ||
360 | |||
361 | // Modularize identifiers. | 353 | // Modularize identifiers. |
362 | if (OutputType.Module == output.Type) | 354 | if (output.Type == OutputType.Module) |
363 | { | 355 | { |
364 | var command = new ModularizeCommand(output, modularizationSuffix, section.Tuples.OfType<WixSuppressModularizationTuple>()); | 356 | var command = new ModularizeCommand(output, modularizationSuffix, section.Tuples.OfType<WixSuppressModularizationTuple>()); |
365 | command.Execute(); | 357 | command.Execute(); |
@@ -457,18 +449,12 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
457 | trackedFiles.AddRange(command.TrackedFiles); | 449 | trackedFiles.AddRange(command.TrackedFiles); |
458 | } | 450 | } |
459 | 451 | ||
460 | #if DELETE | 452 | if (output.Type == OutputType.Patch) |
461 | if (OutputType.Patch == output.Type) | 453 | { |
462 | { | 454 | // Copy output data back into the transforms. |
463 | // Copy output data back into the transforms. | 455 | var command = new UpdateTransformsWithFileFacades(this.Messaging, output, this.SubStorages, tableDefinitions, fileFacades); |
464 | #if TODO_PATCHING | 456 | command.Execute(); |
465 | var command = new CopyTransformDataCommand(this.Messaging, output, tableDefinitions, copyOutFileRows: false); | 457 | } |
466 | command.Execute(); | ||
467 | |||
468 | this.CopyToTransformData(this.Output); | ||
469 | #endif | ||
470 | } | ||
471 | #endif | ||
472 | 458 | ||
473 | // stop processing if an error previously occurred | 459 | // stop processing if an error previously occurred |
474 | if (this.Messaging.EncounteredError) | 460 | if (this.Messaging.EncounteredError) |
@@ -483,8 +469,10 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
483 | var trackMsi = this.BackendHelper.TrackFile(this.OutputPath, TrackedFileType.Final); | 469 | var trackMsi = this.BackendHelper.TrackFile(this.OutputPath, TrackedFileType.Final); |
484 | trackedFiles.Add(trackMsi); | 470 | trackedFiles.Add(trackMsi); |
485 | 471 | ||
486 | var temporaryFiles = this.GenerateDatabase(output, tableDefinitions, trackMsi.Path, false, false); | 472 | var command = new GenerateDatabaseCommand(this.Messaging, this.BackendHelper, this.FileSystemManager, output, trackMsi.Path, tableDefinitions, this.IntermediateFolder, this.Codepage, keepAddedColumns: false, this.SuppressAddingValidationRows, useSubdirectory: false); |
487 | trackedFiles.AddRange(temporaryFiles); | 473 | command.Execute(); |
474 | |||
475 | trackedFiles.AddRange(command.GeneratedTemporaryFiles); | ||
488 | } | 476 | } |
489 | 477 | ||
490 | // Stop processing if an error previously occurred. | 478 | // Stop processing if an error previously occurred. |
@@ -498,31 +486,12 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
498 | { | 486 | { |
499 | this.Messaging.Write(VerboseMessages.MergingModules()); | 487 | this.Messaging.Write(VerboseMessages.MergingModules()); |
500 | 488 | ||
501 | // Add back possibly suppressed sequence tables since all sequence tables must be present | ||
502 | // for the merge process to work. We'll drop the suppressed sequence tables again as | ||
503 | // necessary. | ||
504 | foreach (SequenceTable sequence in Enum.GetValues(typeof(SequenceTable))) | ||
505 | { | ||
506 | var sequenceTableName = (sequence == SequenceTable.AdvertiseExecuteSequence) ? "AdvtExecuteSequence" : sequence.ToString(); | ||
507 | var sequenceTable = output.Tables[sequenceTableName]; | ||
508 | |||
509 | if (null == sequenceTable) | ||
510 | { | ||
511 | sequenceTable = output.EnsureTable(tableDefinitions[sequenceTableName]); | ||
512 | } | ||
513 | |||
514 | if (0 == sequenceTable.Rows.Count) | ||
515 | { | ||
516 | suppressedTableNames.Add(sequenceTableName); | ||
517 | } | ||
518 | } | ||
519 | |||
520 | var command = new MergeModulesCommand(this.Messaging); | 489 | var command = new MergeModulesCommand(this.Messaging); |
521 | command.FileFacades = fileFacades; | 490 | command.FileFacades = fileFacades; |
522 | command.IntermediateFolder = this.IntermediateFolder; | 491 | command.IntermediateFolder = this.IntermediateFolder; |
523 | command.Output = output; | 492 | command.Output = output; |
524 | command.OutputPath = this.OutputPath; | 493 | command.OutputPath = this.OutputPath; |
525 | command.SuppressedTableNames = suppressedTableNames; | 494 | command.TableDefinitions = tableDefinitions; |
526 | command.Execute(); | 495 | command.Execute(); |
527 | } | 496 | } |
528 | 497 | ||
@@ -607,38 +576,6 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
607 | return wixout; | 576 | return wixout; |
608 | } | 577 | } |
609 | 578 | ||
610 | #if TODO_PATCHING | ||
611 | /// <summary> | ||
612 | /// Copy file data between transform substorages and the patch output object | ||
613 | /// </summary> | ||
614 | /// <param name="output">The output to bind.</param> | ||
615 | /// <param name="allFileRows">True if copying from transform to patch, false the other way.</param> | ||
616 | private IEnumerable<FileFacade> CopyFromTransformData(Output output) | ||
617 | { | ||
618 | var command = new CopyTransformDataCommand(); | ||
619 | command.CopyOutFileRows = true; | ||
620 | command.Output = output; | ||
621 | command.TableDefinitions = this.TableDefinitions; | ||
622 | command.Execute(); | ||
623 | |||
624 | return command.FileFacades; | ||
625 | } | ||
626 | |||
627 | /// <summary> | ||
628 | /// Copy file data between transform substorages and the patch output object | ||
629 | /// </summary> | ||
630 | /// <param name="output">The output to bind.</param> | ||
631 | /// <param name="allFileRows">True if copying from transform to patch, false the other way.</param> | ||
632 | private void CopyToTransformData(Output output) | ||
633 | { | ||
634 | var command = new CopyTransformDataCommand(); | ||
635 | command.CopyOutFileRows = false; | ||
636 | command.Output = output; | ||
637 | command.TableDefinitions = this.TableDefinitions; | ||
638 | command.Execute(); | ||
639 | } | ||
640 | #endif | ||
641 | |||
642 | /// <summary> | 579 | /// <summary> |
643 | /// Validate that there are no duplicate GUIDs in the output. | 580 | /// Validate that there are no duplicate GUIDs in the output. |
644 | /// </summary> | 581 | /// </summary> |
@@ -650,7 +587,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
650 | { | 587 | { |
651 | if (output.TryGetTable("Component", out var componentTable)) | 588 | if (output.TryGetTable("Component", out var componentTable)) |
652 | { | 589 | { |
653 | Dictionary<string, bool> componentGuidConditions = new Dictionary<string, bool>(componentTable.Rows.Count); | 590 | var componentGuidConditions = new Dictionary<string, bool>(componentTable.Rows.Count); |
654 | 591 | ||
655 | foreach (Data.WindowsInstaller.Rows.ComponentRow row in componentTable.Rows) | 592 | foreach (Data.WindowsInstaller.Rows.ComponentRow row in componentTable.Rows) |
656 | { | 593 | { |
@@ -658,12 +595,12 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
658 | // there's already an error that prevented it from being replaced with a real GUID. | 595 | // there's already an error that prevented it from being replaced with a real GUID. |
659 | if (!String.IsNullOrEmpty(row.Guid) && "*" != row.Guid) | 596 | if (!String.IsNullOrEmpty(row.Guid) && "*" != row.Guid) |
660 | { | 597 | { |
661 | bool thisComponentHasCondition = !String.IsNullOrEmpty(row.Condition); | 598 | var thisComponentHasCondition = !String.IsNullOrEmpty(row.Condition); |
662 | bool allComponentsHaveConditions = thisComponentHasCondition; | 599 | var allComponentsHaveConditions = thisComponentHasCondition; |
663 | 600 | ||
664 | if (componentGuidConditions.ContainsKey(row.Guid)) | 601 | if (componentGuidConditions.ContainsKey(row.Guid)) |
665 | { | 602 | { |
666 | allComponentsHaveConditions = componentGuidConditions[row.Guid] && thisComponentHasCondition; | 603 | allComponentsHaveConditions = thisComponentHasCondition && componentGuidConditions[row.Guid]; |
667 | 604 | ||
668 | if (allComponentsHaveConditions) | 605 | if (allComponentsHaveConditions) |
669 | { | 606 | { |
@@ -728,20 +665,5 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
728 | 665 | ||
729 | return layout; | 666 | return layout; |
730 | } | 667 | } |
731 | |||
732 | /// <summary> | ||
733 | /// Creates the MSI/MSM/PCP database. | ||
734 | /// </summary> | ||
735 | /// <param name="output">Output to create database for.</param> | ||
736 | /// <param name="databaseFile">The database file to create.</param> | ||
737 | /// <param name="keepAddedColumns">Whether to keep columns added in a transform.</param> | ||
738 | /// <param name="useSubdirectory">Whether to use a subdirectory based on the <paramref name="databaseFile"/> file name for intermediate files.</param> | ||
739 | private IEnumerable<ITrackedFile> GenerateDatabase(WindowsInstallerData output, TableDefinitionCollection tableDefinitions, string databaseFile, bool keepAddedColumns, bool useSubdirectory) | ||
740 | { | ||
741 | var command = new GenerateDatabaseCommand(this.Messaging, this.BackendHelper, this.FileSystemExtensions, output, databaseFile, tableDefinitions, this.IntermediateFolder, this.Codepage, keepAddedColumns, this.SuppressAddingValidationRows, useSubdirectory); | ||
742 | command.Execute(); | ||
743 | |||
744 | return command.GeneratedTemporaryFiles; | ||
745 | } | ||
746 | } | 668 | } |
747 | } | 669 | } |
diff --git a/src/WixToolset.Core.WindowsInstaller/Bind/BindTransformCommand.cs b/src/WixToolset.Core.WindowsInstaller/Bind/BindTransformCommand.cs index ffe26249..ac98c82d 100644 --- a/src/WixToolset.Core.WindowsInstaller/Bind/BindTransformCommand.cs +++ b/src/WixToolset.Core.WindowsInstaller/Bind/BindTransformCommand.cs | |||
@@ -3,23 +3,21 @@ | |||
3 | namespace WixToolset.Core.WindowsInstaller.Bind | 3 | namespace WixToolset.Core.WindowsInstaller.Bind |
4 | { | 4 | { |
5 | using System; | 5 | using System; |
6 | using System.Collections.Generic; | ||
7 | using System.Globalization; | 6 | using System.Globalization; |
8 | using System.IO; | 7 | using System.IO; |
9 | using WixToolset.Core.WindowsInstaller.Msi; | 8 | using WixToolset.Core.WindowsInstaller.Msi; |
10 | using WixToolset.Data; | 9 | using WixToolset.Data; |
11 | using WixToolset.Data.Tuples; | 10 | using WixToolset.Data.Tuples; |
12 | using WixToolset.Data.WindowsInstaller; | 11 | using WixToolset.Data.WindowsInstaller; |
13 | using WixToolset.Extensibility; | ||
14 | using WixToolset.Extensibility.Services; | 12 | using WixToolset.Extensibility.Services; |
15 | 13 | ||
16 | internal class BindTransformCommand | 14 | internal class BindTransformCommand |
17 | { | 15 | { |
18 | public BindTransformCommand(IMessaging messaging, IBackendHelper backendHelper, IEnumerable<IFileSystemExtension> extensions, string intermediateFolder, WindowsInstallerData transform, string outputPath, TableDefinitionCollection tableDefinitions) | 16 | public BindTransformCommand(IMessaging messaging, IBackendHelper backendHelper, FileSystemManager fileSystemManager, string intermediateFolder, WindowsInstallerData transform, string outputPath, TableDefinitionCollection tableDefinitions) |
19 | { | 17 | { |
20 | this.Messaging = messaging; | 18 | this.Messaging = messaging; |
21 | this.BackendHelper = backendHelper; | 19 | this.BackendHelper = backendHelper; |
22 | this.Extensions = extensions; | 20 | this.FileSystemManager = fileSystemManager; |
23 | this.IntermediateFolder = intermediateFolder; | 21 | this.IntermediateFolder = intermediateFolder; |
24 | this.Transform = transform; | 22 | this.Transform = transform; |
25 | this.OutputPath = outputPath; | 23 | this.OutputPath = outputPath; |
@@ -30,7 +28,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
30 | 28 | ||
31 | private IBackendHelper BackendHelper { get; } | 29 | private IBackendHelper BackendHelper { get; } |
32 | 30 | ||
33 | private IEnumerable<IFileSystemExtension> Extensions { get; } | 31 | private FileSystemManager FileSystemManager { get; } |
34 | 32 | ||
35 | private TableDefinitionCollection TableDefinitions { get; } | 33 | private TableDefinitionCollection TableDefinitions { get; } |
36 | 34 | ||
@@ -353,7 +351,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
353 | targetRow[i] = emptyFile; | 351 | targetRow[i] = emptyFile; |
354 | modifiedRow = true; | 352 | modifiedRow = true; |
355 | } | 353 | } |
356 | else if (!this.CompareFiles(objectField.PreviousData, (string)objectField.Data)) | 354 | else if (!this.FileSystemManager.CompareFiles(objectField.PreviousData, (string)objectField.Data)) |
357 | { | 355 | { |
358 | targetRow[i] = objectField.PreviousData; | 356 | targetRow[i] = objectField.PreviousData; |
359 | modifiedRow = true; | 357 | modifiedRow = true; |
@@ -438,29 +436,9 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
438 | } | 436 | } |
439 | } | 437 | } |
440 | 438 | ||
441 | private bool CompareFiles(string targetFile, string updatedFile) | ||
442 | { | ||
443 | bool? compared = null; | ||
444 | foreach (var extension in this.Extensions) | ||
445 | { | ||
446 | compared = extension.CompareFiles(targetFile, updatedFile); | ||
447 | if (compared.HasValue) | ||
448 | { | ||
449 | break; | ||
450 | } | ||
451 | } | ||
452 | |||
453 | if (!compared.HasValue) | ||
454 | { | ||
455 | throw new InvalidOperationException(); // TODO: something needs to be said here that none of the binder file managers returned a result. | ||
456 | } | ||
457 | |||
458 | return compared.Value; | ||
459 | } | ||
460 | |||
461 | private void GenerateDatabase(WindowsInstallerData output, string outputPath, bool keepAddedColumns) | 439 | private void GenerateDatabase(WindowsInstallerData output, string outputPath, bool keepAddedColumns) |
462 | { | 440 | { |
463 | var command = new GenerateDatabaseCommand(this.Messaging, this.BackendHelper, this.Extensions, output, outputPath, this.TableDefinitions, this.IntermediateFolder, codepage: -1, keepAddedColumns, suppressAddingValidationRows: true, useSubdirectory: true ); | 441 | var command = new GenerateDatabaseCommand(this.Messaging, this.BackendHelper, this.FileSystemManager, output, outputPath, this.TableDefinitions, this.IntermediateFolder, codepage: -1, keepAddedColumns, suppressAddingValidationRows: true, useSubdirectory: true); |
464 | command.Execute(); | 442 | command.Execute(); |
465 | } | 443 | } |
466 | } | 444 | } |
diff --git a/src/WixToolset.Core.WindowsInstaller/Bind/CreateDeltaPatchesCommand.cs b/src/WixToolset.Core.WindowsInstaller/Bind/CreateDeltaPatchesCommand.cs index f5ac00e6..c54e9c53 100644 --- a/src/WixToolset.Core.WindowsInstaller/Bind/CreateDeltaPatchesCommand.cs +++ b/src/WixToolset.Core.WindowsInstaller/Bind/CreateDeltaPatchesCommand.cs | |||
@@ -33,7 +33,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
33 | var optimizePatchSizeForLargeFiles = this.WixPatchId?.OptimizePatchSizeForLargeFiles ?? false; | 33 | var optimizePatchSizeForLargeFiles = this.WixPatchId?.OptimizePatchSizeForLargeFiles ?? false; |
34 | var apiPatchingSymbolFlags = (PatchSymbolFlagsType)(this.WixPatchId?.ApiPatchingSymbolFlags ?? 0); | 34 | var apiPatchingSymbolFlags = (PatchSymbolFlagsType)(this.WixPatchId?.ApiPatchingSymbolFlags ?? 0); |
35 | 35 | ||
36 | #if TODO_PATCHING | 36 | #if TODO_PATCHING_DELTA |
37 | foreach (FileFacade facade in this.FileFacades) | 37 | foreach (FileFacade facade in this.FileFacades) |
38 | { | 38 | { |
39 | if (RowOperation.Modify == facade.File.Operation && | 39 | if (RowOperation.Modify == facade.File.Operation && |
diff --git a/src/WixToolset.Core.WindowsInstaller/Bind/CreateOutputFromIRCommand.cs b/src/WixToolset.Core.WindowsInstaller/Bind/CreateOutputFromIRCommand.cs index 0cbb81d8..ffc4e84d 100644 --- a/src/WixToolset.Core.WindowsInstaller/Bind/CreateOutputFromIRCommand.cs +++ b/src/WixToolset.Core.WindowsInstaller/Bind/CreateOutputFromIRCommand.cs | |||
@@ -499,7 +499,8 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
499 | row.FileSize = tuple.FileSize; | 499 | row.FileSize = tuple.FileSize; |
500 | row.Version = tuple.Version; | 500 | row.Version = tuple.Version; |
501 | row.Language = tuple.Language; | 501 | row.Language = tuple.Language; |
502 | row.DiskId = tuple.DiskId ?? 1; // TODO: is 0 the correct thing to default here | 502 | row.DiskId = tuple.DiskId ?? 1; // TODO: is 1 the correct thing to default here |
503 | row.Sequence = tuple.Sequence; | ||
503 | row.Source = tuple.Source.Path; | 504 | row.Source = tuple.Source.Path; |
504 | 505 | ||
505 | var attributes = (tuple.Attributes & FileTupleAttributes.Checksum) == FileTupleAttributes.Checksum ? WindowsInstallerConstants.MsidbFileAttributesChecksum : 0; | 506 | var attributes = (tuple.Attributes & FileTupleAttributes.Checksum) == FileTupleAttributes.Checksum ? WindowsInstallerConstants.MsidbFileAttributesChecksum : 0; |
diff --git a/src/WixToolset.Core.WindowsInstaller/Bind/CreatePatchTransformsCommand.cs b/src/WixToolset.Core.WindowsInstaller/Bind/CreatePatchTransformsCommand.cs index 854d973e..f65f885b 100644 --- a/src/WixToolset.Core.WindowsInstaller/Bind/CreatePatchTransformsCommand.cs +++ b/src/WixToolset.Core.WindowsInstaller/Bind/CreatePatchTransformsCommand.cs | |||
@@ -45,7 +45,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
45 | var baselineData = this.GetData(tuple.BaselineFile.Path); | 45 | var baselineData = this.GetData(tuple.BaselineFile.Path); |
46 | var updateData = this.GetData(tuple.UpdateFile.Path); | 46 | var updateData = this.GetData(tuple.UpdateFile.Path); |
47 | 47 | ||
48 | var command = new GenerateTransformCommand(this.Messaging, baselineData, updateData, false); | 48 | var command = new GenerateTransformCommand(this.Messaging, baselineData, updateData, preserveUnchangedRows: true, showPedanticMessages: false); |
49 | transform = command.Execute(); | 49 | transform = command.Execute(); |
50 | } | 50 | } |
51 | else | 51 | else |
diff --git a/src/WixToolset.Core.WindowsInstaller/Bind/FileSystemManager.cs b/src/WixToolset.Core.WindowsInstaller/Bind/FileSystemManager.cs new file mode 100644 index 00000000..75477271 --- /dev/null +++ b/src/WixToolset.Core.WindowsInstaller/Bind/FileSystemManager.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 WixToolset.Core.WindowsInstaller.Bind | ||
4 | { | ||
5 | using System.Collections.Generic; | ||
6 | using System.IO; | ||
7 | using WixToolset.Extensibility; | ||
8 | |||
9 | internal class FileSystemManager | ||
10 | { | ||
11 | public FileSystemManager(IEnumerable<IFileSystemExtension> fileSystemExtensions) | ||
12 | { | ||
13 | this.Extensions = fileSystemExtensions; | ||
14 | } | ||
15 | |||
16 | private IEnumerable<IFileSystemExtension> Extensions { get; } | ||
17 | |||
18 | public bool CompareFiles(string firstPath, string secondPath) | ||
19 | { | ||
20 | foreach (var extension in this.Extensions) | ||
21 | { | ||
22 | var compared = extension.CompareFiles(firstPath, secondPath); | ||
23 | if (compared.HasValue) | ||
24 | { | ||
25 | return compared.Value; | ||
26 | } | ||
27 | } | ||
28 | |||
29 | return BuiltinCompareFiles(firstPath, secondPath); | ||
30 | } | ||
31 | |||
32 | private static bool BuiltinCompareFiles(string firstPath, string secondPath) | ||
33 | { | ||
34 | using (var firstStream = File.OpenRead(firstPath)) | ||
35 | using (var secondStream = File.OpenRead(secondPath)) | ||
36 | { | ||
37 | if (firstStream.Length != secondStream.Length) | ||
38 | { | ||
39 | return false; | ||
40 | } | ||
41 | |||
42 | // Using a larger buffer than the default buffer of 4 * 1024 used by FileStream.ReadByte improves performance. | ||
43 | // The buffer size is based on user feedback. Based on performance results, a better buffer size may be determined. | ||
44 | var firstBuffer = new byte[16 * 1024]; | ||
45 | var secondBuffer = new byte[16 * 1024]; | ||
46 | |||
47 | var firstReadLength = 0; | ||
48 | do | ||
49 | { | ||
50 | firstReadLength = firstStream.Read(firstBuffer, 0, firstBuffer.Length); | ||
51 | var secondReadLength = secondStream.Read(secondBuffer, 0, secondBuffer.Length); | ||
52 | |||
53 | if (firstReadLength != secondReadLength) | ||
54 | { | ||
55 | return false; | ||
56 | } | ||
57 | |||
58 | for (var i = 0; i < firstReadLength; ++i) | ||
59 | { | ||
60 | if (firstBuffer[i] != secondBuffer[i]) | ||
61 | { | ||
62 | return false; | ||
63 | } | ||
64 | } | ||
65 | } while (0 < firstReadLength); | ||
66 | } | ||
67 | |||
68 | return true; | ||
69 | } | ||
70 | } | ||
71 | } | ||
diff --git a/src/WixToolset.Core.WindowsInstaller/Bind/GenerateDatabaseCommand.cs b/src/WixToolset.Core.WindowsInstaller/Bind/GenerateDatabaseCommand.cs index ed3b6f01..eff94e80 100644 --- a/src/WixToolset.Core.WindowsInstaller/Bind/GenerateDatabaseCommand.cs +++ b/src/WixToolset.Core.WindowsInstaller/Bind/GenerateDatabaseCommand.cs | |||
@@ -10,17 +10,16 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
10 | using WixToolset.Core.WindowsInstaller.Msi; | 10 | using WixToolset.Core.WindowsInstaller.Msi; |
11 | using WixToolset.Data; | 11 | using WixToolset.Data; |
12 | using WixToolset.Data.WindowsInstaller; | 12 | using WixToolset.Data.WindowsInstaller; |
13 | using WixToolset.Extensibility; | ||
14 | using WixToolset.Extensibility.Data; | 13 | using WixToolset.Extensibility.Data; |
15 | using WixToolset.Extensibility.Services; | 14 | using WixToolset.Extensibility.Services; |
16 | 15 | ||
17 | internal class GenerateDatabaseCommand | 16 | internal class GenerateDatabaseCommand |
18 | { | 17 | { |
19 | public GenerateDatabaseCommand(IMessaging messaging, IBackendHelper backendHelper, IEnumerable<IFileSystemExtension> fileSystemExtensions, WindowsInstallerData data, string outputPath, TableDefinitionCollection tableDefinitions, string intermediateFolder, int codepage, bool keepAddedColumns, bool suppressAddingValidationRows, bool useSubdirectory) | 18 | public GenerateDatabaseCommand(IMessaging messaging, IBackendHelper backendHelper, FileSystemManager fileSystemManager, WindowsInstallerData data, string outputPath, TableDefinitionCollection tableDefinitions, string intermediateFolder, int codepage, bool keepAddedColumns, bool suppressAddingValidationRows, bool useSubdirectory) |
20 | { | 19 | { |
21 | this.Messaging = messaging; | 20 | this.Messaging = messaging; |
22 | this.BackendHelper = backendHelper; | 21 | this.BackendHelper = backendHelper; |
23 | this.Extensions = fileSystemExtensions; | 22 | this.FileSystemManager = fileSystemManager; |
24 | this.Data = data; | 23 | this.Data = data; |
25 | this.OutputPath = outputPath; | 24 | this.OutputPath = outputPath; |
26 | this.TableDefinitions = tableDefinitions; | 25 | this.TableDefinitions = tableDefinitions; |
@@ -35,7 +34,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
35 | 34 | ||
36 | private IBackendHelper BackendHelper { get; } | 35 | private IBackendHelper BackendHelper { get; } |
37 | 36 | ||
38 | private IEnumerable<IFileSystemExtension> Extensions { get; } | 37 | private FileSystemManager FileSystemManager { get; } |
39 | 38 | ||
40 | /// <summary> | 39 | /// <summary> |
41 | /// Whether to keep columns added in a transform. | 40 | /// Whether to keep columns added in a transform. |
@@ -371,7 +370,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
371 | var transformFile = Path.Combine(this.IntermediateFolder, String.Concat(subStorage.Name, ".mst")); | 370 | var transformFile = Path.Combine(this.IntermediateFolder, String.Concat(subStorage.Name, ".mst")); |
372 | 371 | ||
373 | // Bind the transform. | 372 | // Bind the transform. |
374 | var command = new BindTransformCommand(this.Messaging, this.BackendHelper, this.Extensions, this.IntermediateFolder, subStorage.Data, transformFile, this.TableDefinitions); | 373 | var command = new BindTransformCommand(this.Messaging, this.BackendHelper, this.FileSystemManager, this.IntermediateFolder, subStorage.Data, transformFile, this.TableDefinitions); |
375 | command.Execute(); | 374 | command.Execute(); |
376 | 375 | ||
377 | if (this.Messaging.EncounteredError) | 376 | if (this.Messaging.EncounteredError) |
diff --git a/src/WixToolset.Core.WindowsInstaller/Bind/GenerateTransformCommand.cs b/src/WixToolset.Core.WindowsInstaller/Bind/GenerateTransformCommand.cs index 8a7dd702..201a890c 100644 --- a/src/WixToolset.Core.WindowsInstaller/Bind/GenerateTransformCommand.cs +++ b/src/WixToolset.Core.WindowsInstaller/Bind/GenerateTransformCommand.cs | |||
@@ -10,7 +10,6 @@ namespace WixToolset.Core.WindowsInstaller | |||
10 | using WixToolset.Data.Tuples; | 10 | using WixToolset.Data.Tuples; |
11 | using WixToolset.Data.WindowsInstaller; | 11 | using WixToolset.Data.WindowsInstaller; |
12 | using WixToolset.Data.WindowsInstaller.Rows; | 12 | using WixToolset.Data.WindowsInstaller.Rows; |
13 | using WixToolset.Extensibility; | ||
14 | using WixToolset.Extensibility.Services; | 13 | using WixToolset.Extensibility.Services; |
15 | 14 | ||
16 | /// <summary> | 15 | /// <summary> |
@@ -25,11 +24,12 @@ namespace WixToolset.Core.WindowsInstaller | |||
25 | /// <summary> | 24 | /// <summary> |
26 | /// Instantiates a new Differ class. | 25 | /// Instantiates a new Differ class. |
27 | /// </summary> | 26 | /// </summary> |
28 | public GenerateTransformCommand(IMessaging messaging, WindowsInstallerData targetOutput, WindowsInstallerData updatedOutput, bool showPedanticMessages) | 27 | public GenerateTransformCommand(IMessaging messaging, WindowsInstallerData targetOutput, WindowsInstallerData updatedOutput, bool preserveUnchangedRows, bool showPedanticMessages) |
29 | { | 28 | { |
30 | this.messaging = messaging; | 29 | this.messaging = messaging; |
31 | this.TargetOutput = targetOutput; | 30 | this.TargetOutput = targetOutput; |
32 | this.UpdatedOutput = updatedOutput; | 31 | this.UpdatedOutput = updatedOutput; |
32 | this.PreserveUnchangedRows = preserveUnchangedRows; | ||
33 | this.ShowPedanticMessages = showPedanticMessages; | 33 | this.ShowPedanticMessages = showPedanticMessages; |
34 | } | 34 | } |
35 | 35 | ||
@@ -111,10 +111,10 @@ namespace WixToolset.Core.WindowsInstaller | |||
111 | } | 111 | } |
112 | else if (TableOperation.None == operation) | 112 | else if (TableOperation.None == operation) |
113 | { | 113 | { |
114 | var modified = transform.EnsureTable(updatedTable.Definition); | 114 | var modifiedTable = transform.EnsureTable(updatedTable.Definition); |
115 | foreach (var row in rows) | 115 | foreach (var row in rows) |
116 | { | 116 | { |
117 | modified.Rows.Add(row); | 117 | modifiedTable.Rows.Add(row); |
118 | } | 118 | } |
119 | } | 119 | } |
120 | } | 120 | } |
@@ -242,10 +242,7 @@ namespace WixToolset.Core.WindowsInstaller | |||
242 | { | 242 | { |
243 | var columnDefinition = updatedRow.Fields[i].Column; | 243 | var columnDefinition = updatedRow.Fields[i].Column; |
244 | 244 | ||
245 | if (columnDefinition.Unreal) | 245 | if (!columnDefinition.PrimaryKey) |
246 | { | ||
247 | } | ||
248 | else if (!columnDefinition.PrimaryKey) | ||
249 | { | 246 | { |
250 | var modified = false; | 247 | var modified = false; |
251 | 248 | ||
diff --git a/src/WixToolset.Core.WindowsInstaller/Bind/GetFileFacadesCommand.cs b/src/WixToolset.Core.WindowsInstaller/Bind/GetFileFacadesCommand.cs index 2844f797..55171da4 100644 --- a/src/WixToolset.Core.WindowsInstaller/Bind/GetFileFacadesCommand.cs +++ b/src/WixToolset.Core.WindowsInstaller/Bind/GetFileFacadesCommand.cs | |||
@@ -26,28 +26,26 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
26 | var facades = new List<FileFacade>(); | 26 | var facades = new List<FileFacade>(); |
27 | 27 | ||
28 | var assemblyFile = this.Section.Tuples.OfType<AssemblyTuple>().ToDictionary(t => t.Id.Id); | 28 | var assemblyFile = this.Section.Tuples.OfType<AssemblyTuple>().ToDictionary(t => t.Id.Id); |
29 | //var wixFiles = this.Section.Tuples.OfType<WixFileTuple>().ToDictionary(t => t.Id.Id); | ||
30 | //var deltaPatchFiles = this.Section.Tuples.OfType<WixDeltaPatchFileTuple>().ToDictionary(t => t.Id.Id); | 29 | //var deltaPatchFiles = this.Section.Tuples.OfType<WixDeltaPatchFileTuple>().ToDictionary(t => t.Id.Id); |
31 | 30 | ||
32 | foreach (var file in this.Section.Tuples.OfType<FileTuple>()) | 31 | foreach (var file in this.Section.Tuples.OfType<FileTuple>()) |
33 | { | 32 | { |
34 | //var wixFile = wixFiles[file.Id.Id]; | 33 | assemblyFile.TryGetValue(file.Id.Id, out var assembly); |
35 | 34 | ||
36 | //deltaPatchFiles.TryGetValue(file.Id.Id, out var deltaPatchFile); | 35 | //deltaPatchFiles.TryGetValue(file.Id.Id, out var deltaPatchFile); |
37 | 36 | ||
38 | //facades.Add(new FileFacade(file, wixFile, deltaPatchFile)); | ||
39 | |||
40 | assemblyFile.TryGetValue(file.Id.Id, out var assembly); | ||
41 | |||
42 | facades.Add(new FileFacade(file, assembly)); | 37 | facades.Add(new FileFacade(file, assembly)); |
38 | //facades.Add(new FileFacade(file, wixFile, deltaPatchFile)); | ||
43 | } | 39 | } |
44 | 40 | ||
45 | //this.ResolveDeltaPatchSymbolPaths(deltaPatchFiles, facades); | 41 | #if TODO_PATCHING_DELTA |
42 | this.ResolveDeltaPatchSymbolPaths(deltaPatchFiles, facades); | ||
43 | #endif | ||
46 | 44 | ||
47 | this.FileFacades = facades; | 45 | this.FileFacades = facades; |
48 | } | 46 | } |
49 | 47 | ||
50 | #if FIX_THIS | 48 | #if TODO_PATCHING_DELTA |
51 | /// <summary> | 49 | /// <summary> |
52 | /// Merge data from the WixPatchSymbolPaths rows into the WixDeltaPatchFile rows. | 50 | /// Merge data from the WixPatchSymbolPaths rows into the WixDeltaPatchFile rows. |
53 | /// </summary> | 51 | /// </summary> |
@@ -132,7 +130,6 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
132 | file.SymbolPaths = String.Concat(file.SymbolPaths, ";", row.SymbolPaths); | 130 | file.SymbolPaths = String.Concat(file.SymbolPaths, ";", row.SymbolPaths); |
133 | } | 131 | } |
134 | 132 | ||
135 | #if TODO_PATCHING | ||
136 | Field field = row.Fields[2]; | 133 | Field field = row.Fields[2]; |
137 | if (null != field.PreviousData) | 134 | if (null != field.PreviousData) |
138 | { | 135 | { |
@@ -145,7 +142,6 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
145 | file.PreviousSymbols = String.Concat(file.PreviousSymbols, ";", field.PreviousData); | 142 | file.PreviousSymbols = String.Concat(file.PreviousSymbols, ";", field.PreviousData); |
146 | } | 143 | } |
147 | } | 144 | } |
148 | #endif | ||
149 | } | 145 | } |
150 | #endif | 146 | #endif |
151 | } | 147 | } |
diff --git a/src/WixToolset.Core.WindowsInstaller/Bind/GetFileFacadesFromTransforms.cs b/src/WixToolset.Core.WindowsInstaller/Bind/GetFileFacadesFromTransforms.cs index 9818f01a..99bf7101 100644 --- a/src/WixToolset.Core.WindowsInstaller/Bind/GetFileFacadesFromTransforms.cs +++ b/src/WixToolset.Core.WindowsInstaller/Bind/GetFileFacadesFromTransforms.cs | |||
@@ -4,12 +4,9 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
4 | { | 4 | { |
5 | using System; | 5 | using System; |
6 | using System.Collections.Generic; | 6 | using System.Collections.Generic; |
7 | using System.Diagnostics; | ||
8 | using System.IO; | ||
9 | using System.Linq; | 7 | using System.Linq; |
10 | using WixToolset.Core.Bind; | 8 | using WixToolset.Core.Bind; |
11 | using WixToolset.Data; | 9 | using WixToolset.Data; |
12 | using WixToolset.Data.Tuples; | ||
13 | using WixToolset.Data.WindowsInstaller; | 10 | using WixToolset.Data.WindowsInstaller; |
14 | using WixToolset.Data.WindowsInstaller.Rows; | 11 | using WixToolset.Data.WindowsInstaller.Rows; |
15 | using WixToolset.Extensibility; | 12 | using WixToolset.Extensibility; |
@@ -17,90 +14,39 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
17 | 14 | ||
18 | internal class GetFileFacadesFromTransforms | 15 | internal class GetFileFacadesFromTransforms |
19 | { | 16 | { |
20 | public GetFileFacadesFromTransforms(IMessaging messaging, IEnumerable<SubStorage> subStorages, TableDefinitionCollection tableDefinitions) | 17 | public GetFileFacadesFromTransforms(IMessaging messaging, FileSystemManager fileSystemManager, IEnumerable<SubStorage> subStorages) |
21 | { | 18 | { |
22 | this.Messaging = messaging; | 19 | this.Messaging = messaging; |
20 | this.FileSystemManager = fileSystemManager; | ||
23 | this.SubStorages = subStorages; | 21 | this.SubStorages = subStorages; |
24 | this.TableDefinitions = tableDefinitions; | ||
25 | } | 22 | } |
26 | 23 | ||
27 | public IEnumerable<IFileSystemExtension> Extensions { get; } | ||
28 | |||
29 | private IMessaging Messaging { get; } | 24 | private IMessaging Messaging { get; } |
30 | 25 | ||
31 | public IEnumerable<SubStorage> SubStorages { get; } | 26 | private FileSystemManager FileSystemManager { get; } |
32 | 27 | ||
33 | private TableDefinitionCollection TableDefinitions { get; } | 28 | private IEnumerable<SubStorage> SubStorages { get; } |
34 | 29 | ||
35 | public IEnumerable<FileFacade> FileFacades { get; private set; } | 30 | public IEnumerable<FileFacade> FileFacades { get; private set; } |
36 | 31 | ||
37 | public void Execute() | 32 | public void Execute() |
38 | { | 33 | { |
39 | var allFileRows = new List<FileFacade>(); | 34 | var allFileRows = new List<FileFacade>(); |
40 | var copyToPatch = (allFileRows != null); | ||
41 | #if TODO_PATCHING | ||
42 | var patchMediaRows = new RowDictionary<MediaRow>(); | ||
43 | 35 | ||
44 | var patchMediaFileRows = new Dictionary<int, RowDictionary<WixFileRow>>(); | 36 | var patchMediaRows = new RowDictionary<MediaRow>(); |
45 | 37 | ||
46 | var patchActualFileTable = this.Output.EnsureTable(this.TableDefinitions["File"]); | 38 | var patchMediaFileRows = new Dictionary<int, RowDictionary<FileRow>>(); |
47 | var patchFileTable = this.Output.EnsureTable(this.TableDefinitions["WixFile"]); | ||
48 | 39 | ||
49 | if (copyFromPatch) | 40 | //var patchActualFileTable = this.Output.EnsureTable(this.TableDefinitions["File"]); |
50 | { | ||
51 | // index patch files by diskId+fileId | ||
52 | foreach (WixFileRow patchFileRow in patchFileTable.Rows) | ||
53 | { | ||
54 | int diskId = patchFileRow.DiskId; | ||
55 | if (!patchMediaFileRows.TryGetValue(diskId, out var mediaFileRows)) | ||
56 | { | ||
57 | mediaFileRows = new RowDictionary<WixFileRow>(); | ||
58 | patchMediaFileRows.Add(diskId, mediaFileRows); | ||
59 | } | ||
60 | |||
61 | mediaFileRows.Add(patchFileRow); | ||
62 | } | ||
63 | |||
64 | var patchMediaTable = this.Output.EnsureTable(this.TableDefinitions["Media"]); | ||
65 | patchMediaRows = new RowDictionary<MediaRow>(patchMediaTable); | ||
66 | } | ||
67 | 41 | ||
68 | // Index paired transforms by name without their "#" prefix. | 42 | // Index paired transforms by name without their "#" prefix. |
69 | var pairedTransforms = this.SubStorages.Where(s => s.Name.StartsWith("#")).ToDictionary(s => s.Name.Substring(1), s => s.Data); | 43 | var pairedTransforms = this.SubStorages.Where(s => s.Name.StartsWith("#")).ToDictionary(s => s.Name, s => s.Data); |
70 | 44 | ||
71 | foreach (var substorage in this.SubStorages) | 45 | // Enumerate through main transforms. |
46 | foreach (var substorage in this.SubStorages.Where(s => !s.Name.StartsWith("#"))) | ||
72 | { | 47 | { |
73 | if (substorage.Name.StartsWith("#")) | ||
74 | { | ||
75 | // Skip paired transforms. | ||
76 | continue; | ||
77 | } | ||
78 | |||
79 | var mainTransform = substorage.Data; | 48 | var mainTransform = substorage.Data; |
80 | var mainWixFiles = new RowDictionary<WixFileRow>(mainTransform.Tables["WixFile"]); | ||
81 | var mainMsiFileHashIndex = new RowDictionary<Row>(mainTransform.Tables["MsiFileHash"]); | ||
82 | |||
83 | var mainFileTable = mainTransform.Tables["File"]; | 49 | var mainFileTable = mainTransform.Tables["File"]; |
84 | var pairedTransform = pairedTransforms[substorage.Name]; | ||
85 | |||
86 | // copy Media.LastSequence and index the MsiFileHash table if it exists. | ||
87 | if (copyFromPatch) | ||
88 | { | ||
89 | var pairedMediaTable = pairedTransform.Tables["Media"]; | ||
90 | foreach (MediaRow pairedMediaRow in pairedMediaTable.Rows) | ||
91 | { | ||
92 | var patchMediaRow = patchMediaRows.Get(pairedMediaRow.DiskId); | ||
93 | pairedMediaRow.Fields[1] = patchMediaRow.Fields[1]; | ||
94 | } | ||
95 | |||
96 | if (null != mainMsiFileHashTable) | ||
97 | { | ||
98 | mainMsiFileHashIndex = new RowDictionary<Row>(mainMsiFileHashTable); | ||
99 | } | ||
100 | |||
101 | // Validate file row changes for keypath-related issues | ||
102 | this.ValidateFileRowChanges(mainTransform); | ||
103 | } | ||
104 | 50 | ||
105 | if (null == mainFileTable) | 51 | if (null == mainFileTable) |
106 | { | 52 | { |
@@ -108,74 +54,21 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
108 | } | 54 | } |
109 | 55 | ||
110 | // Index File table of pairedTransform | 56 | // Index File table of pairedTransform |
57 | var pairedTransform = pairedTransforms["#" + substorage.Name]; | ||
111 | var pairedFileRows = new RowDictionary<FileRow>(pairedTransform.Tables["File"]); | 58 | var pairedFileRows = new RowDictionary<FileRow>(pairedTransform.Tables["File"]); |
112 | 59 | ||
113 | foreach (FileRow mainFileRow in mainFileTable.Rows) | 60 | foreach (FileRow mainFileRow in mainFileTable.Rows.Where(f => f.Operation != RowOperation.Delete)) |
114 | { | 61 | { |
115 | if (RowOperation.Delete == mainFileRow.Operation) | 62 | var mainFileId = mainFileRow.File; |
116 | { | ||
117 | continue; | ||
118 | } | ||
119 | else if (RowOperation.None == mainFileRow.Operation) | ||
120 | { | ||
121 | continue; | ||
122 | } | ||
123 | 63 | ||
124 | var mainWixFileRow = mainWixFiles.Get(mainFileRow.File); | 64 | // We need compare the underlying files and include all file changes. |
65 | var objectField = (ObjectField)mainFileRow.Fields[9]; | ||
66 | var pairedFileRow = pairedFileRows.Get(mainFileId); | ||
125 | 67 | ||
126 | if (copyToPatch) // when copying to the patch, we need compare the underlying files and include all file changes. | 68 | // If the file is new, we always need to add it to the patch. |
69 | if (mainFileRow.Operation == RowOperation.Add) | ||
127 | { | 70 | { |
128 | var objectField = (ObjectField)mainWixFileRow.Fields[6]; | 71 | if (null != pairedFileRow) // RowOperation.Add |
129 | var pairedFileRow = pairedFileRows.Get(mainFileRow.File); | ||
130 | |||
131 | // If the file is new, we always need to add it to the patch. | ||
132 | if (mainFileRow.Operation != RowOperation.Add) | ||
133 | { | ||
134 | // If PreviousData doesn't exist, target and upgrade layout point to the same location. No need to compare. | ||
135 | if (null == objectField.PreviousData) | ||
136 | { | ||
137 | if (mainFileRow.Operation == RowOperation.None) | ||
138 | { | ||
139 | continue; | ||
140 | } | ||
141 | } | ||
142 | else | ||
143 | { | ||
144 | // TODO: should this entire condition be placed in the binder file manager? | ||
145 | if ((0 == (PatchAttributeType.Ignore & mainWixFileRow.PatchAttributes)) && | ||
146 | !this.CompareFiles(objectField.PreviousData.ToString(), objectField.Data.ToString())) | ||
147 | { | ||
148 | // If the file is different, we need to mark the mainFileRow and pairedFileRow as modified. | ||
149 | mainFileRow.Operation = RowOperation.Modify; | ||
150 | if (null != pairedFileRow) | ||
151 | { | ||
152 | // Always patch-added, but never non-compressed. | ||
153 | pairedFileRow.Attributes |= WindowsInstallerConstants.MsidbFileAttributesPatchAdded; | ||
154 | pairedFileRow.Attributes &= ~WindowsInstallerConstants.MsidbFileAttributesNoncompressed; | ||
155 | pairedFileRow.Fields[6].Modified = true; | ||
156 | pairedFileRow.Operation = RowOperation.Modify; | ||
157 | } | ||
158 | } | ||
159 | else | ||
160 | { | ||
161 | // The File is same. We need mark all the attributes as unchanged. | ||
162 | mainFileRow.Operation = RowOperation.None; | ||
163 | foreach (var field in mainFileRow.Fields) | ||
164 | { | ||
165 | field.Modified = false; | ||
166 | } | ||
167 | |||
168 | if (null != pairedFileRow) | ||
169 | { | ||
170 | pairedFileRow.Attributes &= ~WindowsInstallerConstants.MsidbFileAttributesPatchAdded; | ||
171 | pairedFileRow.Fields[6].Modified = false; | ||
172 | pairedFileRow.Operation = RowOperation.None; | ||
173 | } | ||
174 | continue; | ||
175 | } | ||
176 | } | ||
177 | } | ||
178 | else if (null != pairedFileRow) // RowOperation.Add | ||
179 | { | 72 | { |
180 | // Always patch-added, but never non-compressed. | 73 | // Always patch-added, but never non-compressed. |
181 | pairedFileRow.Attributes |= WindowsInstallerConstants.MsidbFileAttributesPatchAdded; | 74 | pairedFileRow.Attributes |= WindowsInstallerConstants.MsidbFileAttributesPatchAdded; |
@@ -184,402 +77,93 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
184 | pairedFileRow.Operation = RowOperation.Add; | 77 | pairedFileRow.Operation = RowOperation.Add; |
185 | } | 78 | } |
186 | } | 79 | } |
187 | 80 | else | |
188 | // index patch files by diskId+fileId | ||
189 | int diskId = mainWixFileRow.DiskId; | ||
190 | |||
191 | if (!patchMediaFileRows.TryGetValue(diskId, out var mediaFileRows)) | ||
192 | { | ||
193 | mediaFileRows = new RowDictionary<WixFileRow>(); | ||
194 | patchMediaFileRows.Add(diskId, mediaFileRows); | ||
195 | } | ||
196 | |||
197 | var fileId = mainFileRow.File; | ||
198 | var patchFileRow = mediaFileRows.Get(fileId); | ||
199 | if (copyToPatch) | ||
200 | { | 81 | { |
201 | if (null == patchFileRow) | 82 | // If PreviousData doesn't exist, target and upgrade layout point to the same location. No need to compare. |
202 | { | 83 | if (null == objectField.PreviousData) |
203 | var patchActualFileRow = (FileRow)patchFileTable.CreateRow(mainFileRow.SourceLineNumbers); | ||
204 | patchActualFileRow.CopyFrom(mainFileRow); | ||
205 | |||
206 | patchFileRow = (WixFileRow)patchFileTable.CreateRow(mainFileRow.SourceLineNumbers); | ||
207 | patchFileRow.CopyFrom(mainWixFileRow); | ||
208 | |||
209 | mediaFileRows.Add(patchFileRow); | ||
210 | |||
211 | allFileRows.Add(new FileFacade(patchActualFileRow, patchFileRow, null)); // TODO: should we be passing along delta information? Probably, right? | ||
212 | } | ||
213 | else | ||
214 | { | 84 | { |
215 | // TODO: confirm the rest of data is identical? | 85 | if (mainFileRow.Operation == RowOperation.None) |
216 | |||
217 | // make sure Source is same. Otherwise we are silently ignoring a file. | ||
218 | if (0 != String.Compare(patchFileRow.Source, mainWixFileRow.Source, StringComparison.OrdinalIgnoreCase)) | ||
219 | { | 86 | { |
220 | this.Messaging.Write(ErrorMessages.SameFileIdDifferentSource(mainFileRow.SourceLineNumbers, fileId, patchFileRow.Source, mainWixFileRow.Source)); | 87 | continue; |
221 | } | 88 | } |
222 | |||
223 | // capture the previous file versions (and associated data) from this targeted instance of the baseline into the current filerow. | ||
224 | patchFileRow.AppendPreviousDataFrom(mainWixFileRow); | ||
225 | } | ||
226 | } | ||
227 | //else | ||
228 | //{ | ||
229 | // // copy data from the patch back to the transform | ||
230 | // if (null != patchFileRow) | ||
231 | // { | ||
232 | // var pairedFileRow = pairedFileRows.Get(fileId); | ||
233 | // for (var i = 0; i < patchFileRow.Fields.Length; i++) | ||
234 | // { | ||
235 | // var patchValue = patchFileRow[i] == null ? String.Empty : patchFileRow.FieldAsString(i); | ||
236 | // var mainValue = mainFileRow[i] == null ? String.Empty : mainFileRow.FieldAsString(i); | ||
237 | |||
238 | // if (1 == i) | ||
239 | // { | ||
240 | // // File.Component_ changes should not come from the shared file rows | ||
241 | // // that contain the file information as each individual transform might | ||
242 | // // have different changes (or no changes at all). | ||
243 | // } | ||
244 | // // File.Attributes should not changed for binary deltas | ||
245 | // else if (6 == i) | ||
246 | // { | ||
247 | // if (null != patchFileRow.Patch) | ||
248 | // { | ||
249 | // // File.Attribute should not change for binary deltas | ||
250 | // pairedFileRow.Attributes = mainFileRow.Attributes; | ||
251 | // mainFileRow.Fields[i].Modified = false; | ||
252 | // } | ||
253 | // } | ||
254 | // // File.Sequence is updated in pairedTransform, not mainTransform | ||
255 | // else if (7 == i) | ||
256 | // { | ||
257 | // // file sequence is updated in Patch table instead of File table for delta patches | ||
258 | // if (null != patchFileRow.Patch) | ||
259 | // { | ||
260 | // pairedFileRow.Fields[i].Modified = false; | ||
261 | // } | ||
262 | // else | ||
263 | // { | ||
264 | // pairedFileRow[i] = patchFileRow[i]; | ||
265 | // pairedFileRow.Fields[i].Modified = true; | ||
266 | // } | ||
267 | // mainFileRow.Fields[i].Modified = false; | ||
268 | // } | ||
269 | // else if (patchValue != mainValue) | ||
270 | // { | ||
271 | // mainFileRow[i] = patchFileRow[i]; | ||
272 | // mainFileRow.Fields[i].Modified = true; | ||
273 | // if (mainFileRow.Operation == RowOperation.None) | ||
274 | // { | ||
275 | // mainFileRow.Operation = RowOperation.Modify; | ||
276 | // } | ||
277 | // } | ||
278 | // } | ||
279 | |||
280 | // // copy MsiFileHash row for this File | ||
281 | // if (!mainMsiFileHashIndex.TryGetValue(patchFileRow.File, out var patchHashRow)) | ||
282 | // { | ||
283 | // patchHashRow = patchFileRow.Hash; | ||
284 | // } | ||
285 | |||
286 | // if (null != patchHashRow) | ||
287 | // { | ||
288 | // var mainHashTable = mainTransform.EnsureTable(this.TableDefinitions["MsiFileHash"]); | ||
289 | // var mainHashRow = mainHashTable.CreateRow(mainFileRow.SourceLineNumbers); | ||
290 | // for (var i = 0; i < patchHashRow.Fields.Length; i++) | ||
291 | // { | ||
292 | // mainHashRow[i] = patchHashRow[i]; | ||
293 | // if (i > 1) | ||
294 | // { | ||
295 | // // assume all hash fields have been modified | ||
296 | // mainHashRow.Fields[i].Modified = true; | ||
297 | // } | ||
298 | // } | ||
299 | |||
300 | // // assume the MsiFileHash operation follows the File one | ||
301 | // mainHashRow.Operation = mainFileRow.Operation; | ||
302 | // } | ||
303 | |||
304 | // // copy MsiAssemblyName rows for this File | ||
305 | // List<Row> patchAssemblyNameRows = patchFileRow.AssemblyNames; | ||
306 | // if (null != patchAssemblyNameRows) | ||
307 | // { | ||
308 | // var mainAssemblyNameTable = mainTransform.EnsureTable(this.TableDefinitions["MsiAssemblyName"]); | ||
309 | // foreach (var patchAssemblyNameRow in patchAssemblyNameRows) | ||
310 | // { | ||
311 | // // Copy if there isn't an identical modified/added row already in the transform. | ||
312 | // var foundMatchingModifiedRow = false; | ||
313 | // foreach (var mainAssemblyNameRow in mainAssemblyNameTable.Rows) | ||
314 | // { | ||
315 | // if (RowOperation.None != mainAssemblyNameRow.Operation && mainAssemblyNameRow.GetPrimaryKey('/').Equals(patchAssemblyNameRow.GetPrimaryKey('/'))) | ||
316 | // { | ||
317 | // foundMatchingModifiedRow = true; | ||
318 | // break; | ||
319 | // } | ||
320 | // } | ||
321 | |||
322 | // if (!foundMatchingModifiedRow) | ||
323 | // { | ||
324 | // var mainAssemblyNameRow = mainAssemblyNameTable.CreateRow(mainFileRow.SourceLineNumbers); | ||
325 | // for (var i = 0; i < patchAssemblyNameRow.Fields.Length; i++) | ||
326 | // { | ||
327 | // mainAssemblyNameRow[i] = patchAssemblyNameRow[i]; | ||
328 | // } | ||
329 | |||
330 | // // assume value field has been modified | ||
331 | // mainAssemblyNameRow.Fields[2].Modified = true; | ||
332 | // mainAssemblyNameRow.Operation = mainFileRow.Operation; | ||
333 | // } | ||
334 | // } | ||
335 | // } | ||
336 | |||
337 | // // Add patch header for this file | ||
338 | // if (null != patchFileRow.Patch) | ||
339 | // { | ||
340 | // // Add the PatchFiles action automatically to the AdminExecuteSequence and InstallExecuteSequence tables. | ||
341 | // this.AddPatchFilesActionToSequenceTable(SequenceTable.AdminExecuteSequence, mainTransform, pairedTransform, mainFileRow); | ||
342 | // this.AddPatchFilesActionToSequenceTable(SequenceTable.InstallExecuteSequence, mainTransform, pairedTransform, mainFileRow); | ||
343 | |||
344 | // // Add to Patch table | ||
345 | // var patchTable = pairedTransform.EnsureTable(this.TableDefinitions["Patch"]); | ||
346 | // if (0 == patchTable.Rows.Count) | ||
347 | // { | ||
348 | // patchTable.Operation = TableOperation.Add; | ||
349 | // } | ||
350 | |||
351 | // var patchRow = patchTable.CreateRow(mainFileRow.SourceLineNumbers); | ||
352 | // patchRow[0] = patchFileRow.File; | ||
353 | // patchRow[1] = patchFileRow.Sequence; | ||
354 | |||
355 | // var patchFile = new FileInfo(patchFileRow.Source); | ||
356 | // patchRow[2] = (int)patchFile.Length; | ||
357 | // patchRow[3] = 0 == (PatchAttributeType.AllowIgnoreOnError & patchFileRow.PatchAttributes) ? 0 : 1; | ||
358 | |||
359 | // var streamName = patchTable.Name + "." + patchRow[0] + "." + patchRow[1]; | ||
360 | // if (Msi.MsiInterop.MsiMaxStreamNameLength < streamName.Length) | ||
361 | // { | ||
362 | // streamName = "_" + Guid.NewGuid().ToString("D").ToUpperInvariant().Replace('-', '_'); | ||
363 | |||
364 | // var patchHeadersTable = pairedTransform.EnsureTable(this.TableDefinitions["MsiPatchHeaders"]); | ||
365 | // if (0 == patchHeadersTable.Rows.Count) | ||
366 | // { | ||
367 | // patchHeadersTable.Operation = TableOperation.Add; | ||
368 | // } | ||
369 | |||
370 | // var patchHeadersRow = patchHeadersTable.CreateRow(mainFileRow.SourceLineNumbers); | ||
371 | // patchHeadersRow[0] = streamName; | ||
372 | // patchHeadersRow[1] = patchFileRow.Patch; | ||
373 | // patchRow[5] = streamName; | ||
374 | // patchHeadersRow.Operation = RowOperation.Add; | ||
375 | // } | ||
376 | // else | ||
377 | // { | ||
378 | // patchRow[4] = patchFileRow.Patch; | ||
379 | // } | ||
380 | // patchRow.Operation = RowOperation.Add; | ||
381 | // } | ||
382 | // } | ||
383 | // else | ||
384 | // { | ||
385 | // // TODO: throw because all transform rows should have made it into the patch | ||
386 | // } | ||
387 | //} | ||
388 | } | ||
389 | } | ||
390 | #endif | ||
391 | this.FileFacades = allFileRows; | ||
392 | } | ||
393 | |||
394 | /// <summary> | ||
395 | /// Adds the PatchFiles action to the sequence table if it does not already exist. | ||
396 | /// </summary> | ||
397 | /// <param name="table">The sequence table to check or modify.</param> | ||
398 | /// <param name="mainTransform">The primary authoring transform.</param> | ||
399 | /// <param name="pairedTransform">The secondary patch transform.</param> | ||
400 | /// <param name="mainFileRow">The file row that contains information about the patched file.</param> | ||
401 | private void AddPatchFilesActionToSequenceTable(SequenceTable table, WindowsInstallerData mainTransform, WindowsInstallerData pairedTransform, Row mainFileRow) | ||
402 | { | ||
403 | var tableName = table.ToString(); | ||
404 | |||
405 | // Find/add PatchFiles action (also determine sequence for it). | ||
406 | // Search mainTransform first, then pairedTransform (pairedTransform overrides). | ||
407 | var hasPatchFilesAction = false; | ||
408 | var installFilesSequence = 0; | ||
409 | var duplicateFilesSequence = 0; | ||
410 | |||
411 | TestSequenceTableForPatchFilesAction( | ||
412 | mainTransform.Tables[tableName], | ||
413 | ref hasPatchFilesAction, | ||
414 | ref installFilesSequence, | ||
415 | ref duplicateFilesSequence); | ||
416 | TestSequenceTableForPatchFilesAction( | ||
417 | pairedTransform.Tables[tableName], | ||
418 | ref hasPatchFilesAction, | ||
419 | ref installFilesSequence, | ||
420 | ref duplicateFilesSequence); | ||
421 | if (!hasPatchFilesAction) | ||
422 | { | ||
423 | WindowsInstallerStandard.TryGetStandardAction(tableName, "PatchFiles", out var patchFilesActionTuple); | ||
424 | |||
425 | var sequence = patchFilesActionTuple.Sequence; | ||
426 | |||
427 | // Test for default sequence value's appropriateness | ||
428 | if (installFilesSequence >= sequence || (0 != duplicateFilesSequence && duplicateFilesSequence <= sequence)) | ||
429 | { | ||
430 | if (0 != duplicateFilesSequence) | ||
431 | { | ||
432 | if (duplicateFilesSequence < installFilesSequence) | ||
433 | { | ||
434 | throw new WixException(ErrorMessages.InsertInvalidSequenceActionOrder(mainFileRow.SourceLineNumbers, tableName, "InstallFiles", "DuplicateFiles", patchFilesActionTuple.Action)); | ||
435 | } | 89 | } |
436 | else | 90 | else |
437 | { | 91 | { |
438 | sequence = (duplicateFilesSequence + installFilesSequence) / 2; | 92 | // TODO: should this entire condition be placed in the binder file manager? |
439 | if (installFilesSequence == sequence || duplicateFilesSequence == sequence) | 93 | if (/*(0 == (PatchAttributeType.Ignore & mainWixFileRow.PatchAttributes)) &&*/ |
94 | !this.FileSystemManager.CompareFiles(objectField.PreviousData.ToString(), objectField.Data.ToString())) | ||
440 | { | 95 | { |
441 | throw new WixException(ErrorMessages.InsertSequenceNoSpace(mainFileRow.SourceLineNumbers, tableName, "InstallFiles", "DuplicateFiles", patchFilesActionTuple.Action)); | 96 | // If the file is different, we need to mark the mainFileRow and pairedFileRow as modified. |
97 | mainFileRow.Operation = RowOperation.Modify; | ||
98 | if (null != pairedFileRow) | ||
99 | { | ||
100 | // Always patch-added, but never non-compressed. | ||
101 | pairedFileRow.Attributes |= WindowsInstallerConstants.MsidbFileAttributesPatchAdded; | ||
102 | pairedFileRow.Attributes &= ~WindowsInstallerConstants.MsidbFileAttributesNoncompressed; | ||
103 | pairedFileRow.Fields[6].Modified = true; | ||
104 | pairedFileRow.Operation = RowOperation.Modify; | ||
105 | } | ||
106 | } | ||
107 | else | ||
108 | { | ||
109 | // The File is same. We need mark all the attributes as unchanged. | ||
110 | mainFileRow.Operation = RowOperation.None; | ||
111 | foreach (var field in mainFileRow.Fields) | ||
112 | { | ||
113 | field.Modified = false; | ||
114 | } | ||
115 | |||
116 | if (null != pairedFileRow) | ||
117 | { | ||
118 | pairedFileRow.Attributes &= ~WindowsInstallerConstants.MsidbFileAttributesPatchAdded; | ||
119 | pairedFileRow.Fields[6].Modified = false; | ||
120 | pairedFileRow.Operation = RowOperation.None; | ||
121 | } | ||
122 | continue; | ||
442 | } | 123 | } |
443 | } | 124 | } |
444 | } | 125 | } |
445 | else | ||
446 | { | ||
447 | sequence = installFilesSequence + 1; | ||
448 | } | ||
449 | } | ||
450 | 126 | ||
451 | var sequenceTable = pairedTransform.EnsureTable(this.TableDefinitions[tableName]); | 127 | // index patch files by diskId+fileId |
452 | if (0 == sequenceTable.Rows.Count) | 128 | var diskId = mainFileRow.DiskId; |
453 | { | ||
454 | sequenceTable.Operation = TableOperation.Add; | ||
455 | } | ||
456 | |||
457 | var patchAction = sequenceTable.CreateRow(null); | ||
458 | patchAction[0] = patchFilesActionTuple.Action; | ||
459 | patchAction[1] = patchFilesActionTuple.Condition; | ||
460 | patchAction[2] = sequence; | ||
461 | patchAction.Operation = RowOperation.Add; | ||
462 | } | ||
463 | } | ||
464 | 129 | ||
465 | /// <summary> | 130 | if (!patchMediaFileRows.TryGetValue(diskId, out var mediaFileRows)) |
466 | /// Tests sequence table for PatchFiles and associated actions | ||
467 | /// </summary> | ||
468 | /// <param name="sequenceTable">The table to test.</param> | ||
469 | /// <param name="hasPatchFilesAction">Set to true if PatchFiles action is found. Left unchanged otherwise.</param> | ||
470 | /// <param name="installFilesSequence">Set to sequence value of InstallFiles action if found. Left unchanged otherwise.</param> | ||
471 | /// <param name="duplicateFilesSequence">Set to sequence value of DuplicateFiles action if found. Left unchanged otherwise.</param> | ||
472 | private static void TestSequenceTableForPatchFilesAction(Table sequenceTable, ref bool hasPatchFilesAction, ref int installFilesSequence, ref int duplicateFilesSequence) | ||
473 | { | ||
474 | if (null != sequenceTable) | ||
475 | { | ||
476 | foreach (var row in sequenceTable.Rows) | ||
477 | { | ||
478 | var actionName = row.FieldAsString(0); | ||
479 | switch (actionName) | ||
480 | { | 131 | { |
481 | case "PatchFiles": | 132 | mediaFileRows = new RowDictionary<FileRow>(); |
482 | hasPatchFilesAction = true; | 133 | patchMediaFileRows.Add(diskId, mediaFileRows); |
483 | break; | ||
484 | |||
485 | case "InstallFiles": | ||
486 | installFilesSequence = row.FieldAsInteger(2); | ||
487 | break; | ||
488 | |||
489 | case "DuplicateFiles": | ||
490 | duplicateFilesSequence = row.FieldAsInteger(2); | ||
491 | break; | ||
492 | } | 134 | } |
493 | } | ||
494 | } | ||
495 | } | ||
496 | |||
497 | /// <summary> | ||
498 | /// Signal a warning if a non-keypath file was changed in a patch without also changing the keypath file of the component. | ||
499 | /// </summary> | ||
500 | /// <param name="output">The output to validate.</param> | ||
501 | private void ValidateFileRowChanges(WindowsInstallerData transform) | ||
502 | { | ||
503 | var componentTable = transform.Tables["Component"]; | ||
504 | var fileTable = transform.Tables["File"]; | ||
505 | |||
506 | // There's no sense validating keypaths if the transform has no component or file table | ||
507 | if (componentTable == null || fileTable == null) | ||
508 | { | ||
509 | return; | ||
510 | } | ||
511 | 135 | ||
512 | var componentKeyPath = new Dictionary<string, string>(componentTable.Rows.Count); | 136 | var patchFileRow = mediaFileRows.Get(mainFileId); |
513 | |||
514 | // Index the Component table for non-directory & non-registry key paths. | ||
515 | foreach (var row in componentTable.Rows) | ||
516 | { | ||
517 | var keyPath = row.FieldAsString(5); | ||
518 | if (keyPath != null && 0 != (row.FieldAsInteger(3) & WindowsInstallerConstants.MsidbComponentAttributesRegistryKeyPath)) | ||
519 | { | ||
520 | componentKeyPath.Add(row.FieldAsString(0), keyPath); | ||
521 | } | ||
522 | } | ||
523 | 137 | ||
524 | var componentWithChangedKeyPath = new Dictionary<string, string>(); | 138 | if (null == patchFileRow) |
525 | var componentWithNonKeyPathChanged = new Dictionary<string, string>(); | 139 | { |
526 | // Verify changes in the file table, now that file diffing has occurred | 140 | //patchFileRow = (FileRow)patchFileTable.CreateRow(mainFileRow.SourceLineNumbers); |
527 | foreach (FileRow row in fileTable.Rows) | 141 | patchFileRow = (FileRow)mainFileRow.TableDefinition.CreateRow(mainFileRow.SourceLineNumbers); |
528 | { | 142 | mainFileRow.CopyTo(patchFileRow); |
529 | if (RowOperation.Modify != row.Operation) | ||
530 | { | ||
531 | continue; | ||
532 | } | ||
533 | 143 | ||
534 | var fileId = row.FieldAsString(0); | 144 | mediaFileRows.Add(patchFileRow); |
535 | var componentId = row.FieldAsString(1); | ||
536 | 145 | ||
537 | // If this file is the keypath of a component | 146 | allFileRows.Add(new FileFacade(patchFileRow)); // TODO: should we be passing along delta information? Probably, right? |
538 | if (componentKeyPath.ContainsValue(fileId)) | ||
539 | { | ||
540 | if (!componentWithChangedKeyPath.ContainsKey(componentId)) | ||
541 | { | ||
542 | componentWithChangedKeyPath.Add(componentId, fileId); | ||
543 | } | 147 | } |
544 | } | 148 | else |
545 | else | ||
546 | { | ||
547 | if (!componentWithNonKeyPathChanged.ContainsKey(componentId)) | ||
548 | { | 149 | { |
549 | componentWithNonKeyPathChanged.Add(componentId, fileId); | 150 | // TODO: confirm the rest of data is identical? |
550 | } | ||
551 | } | ||
552 | } | ||
553 | |||
554 | foreach (var componentFile in componentWithNonKeyPathChanged) | ||
555 | { | ||
556 | // Make sure all changes to non keypath files also had a change in the keypath. | ||
557 | if (!componentWithChangedKeyPath.ContainsKey(componentFile.Key) && componentKeyPath.TryGetValue(componentFile.Key, out var keyPath)) | ||
558 | { | ||
559 | this.Messaging.Write(WarningMessages.UpdateOfNonKeyPathFile(componentFile.Value, componentFile.Key, keyPath)); | ||
560 | } | ||
561 | } | ||
562 | } | ||
563 | 151 | ||
564 | private bool CompareFiles(string targetFile, string updatedFile) | 152 | // make sure Source is same. Otherwise we are silently ignoring a file. |
565 | { | 153 | if (0 != String.Compare(patchFileRow.Source, mainFileRow.Source, StringComparison.OrdinalIgnoreCase)) |
566 | bool? compared = null; | 154 | { |
567 | foreach (var extension in this.Extensions) | 155 | this.Messaging.Write(ErrorMessages.SameFileIdDifferentSource(mainFileRow.SourceLineNumbers, mainFileId, patchFileRow.Source, mainFileRow.Source)); |
568 | { | 156 | } |
569 | compared = extension.CompareFiles(targetFile, updatedFile); | ||
570 | 157 | ||
571 | if (compared.HasValue) | 158 | #if TODO_PATCHING_DELTA |
572 | { | 159 | // capture the previous file versions (and associated data) from this targeted instance of the baseline into the current filerow. |
573 | break; | 160 | patchFileRow.AppendPreviousDataFrom(mainFileRow); |
161 | #endif | ||
162 | } | ||
574 | } | 163 | } |
575 | } | 164 | } |
576 | 165 | ||
577 | if (!compared.HasValue) | 166 | this.FileFacades = allFileRows; |
578 | { | ||
579 | throw new InvalidOperationException(); // TODO: something needs to be said here that none of the binder file managers returned a result. | ||
580 | } | ||
581 | |||
582 | return compared.Value; | ||
583 | } | 167 | } |
584 | } | 168 | } |
585 | } | 169 | } |
diff --git a/src/WixToolset.Core.WindowsInstaller/Bind/MergeModulesCommand.cs b/src/WixToolset.Core.WindowsInstaller/Bind/MergeModulesCommand.cs index cd6170d0..bddcccb7 100644 --- a/src/WixToolset.Core.WindowsInstaller/Bind/MergeModulesCommand.cs +++ b/src/WixToolset.Core.WindowsInstaller/Bind/MergeModulesCommand.cs | |||
@@ -12,6 +12,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
12 | using WixToolset.Core.Native; | 12 | using WixToolset.Core.Native; |
13 | using WixToolset.Core.WindowsInstaller.Msi; | 13 | using WixToolset.Core.WindowsInstaller.Msi; |
14 | using WixToolset.Data; | 14 | using WixToolset.Data; |
15 | using WixToolset.Data.Tuples; | ||
15 | using WixToolset.Data.WindowsInstaller; | 16 | using WixToolset.Data.WindowsInstaller; |
16 | using WixToolset.Data.WindowsInstaller.Rows; | 17 | using WixToolset.Data.WindowsInstaller.Rows; |
17 | using WixToolset.Extensibility.Services; | 18 | using WixToolset.Extensibility.Services; |
@@ -34,7 +35,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
34 | 35 | ||
35 | public string OutputPath { private get; set; } | 36 | public string OutputPath { private get; set; } |
36 | 37 | ||
37 | public IEnumerable<string> SuppressedTableNames { private get; set; } | 38 | public TableDefinitionCollection TableDefinitions { private get; set; } |
38 | 39 | ||
39 | public string IntermediateFolder { private get; set; } | 40 | public string IntermediateFolder { private get; set; } |
40 | 41 | ||
@@ -49,6 +50,8 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
49 | return; | 50 | return; |
50 | } | 51 | } |
51 | 52 | ||
53 | var suppressedTableNames = this.AddBackSuppresedSequenceTables(); | ||
54 | |||
52 | IMsmMerge2 merge = null; | 55 | IMsmMerge2 merge = null; |
53 | bool commit = true; | 56 | bool commit = true; |
54 | bool logOpen = false; | 57 | bool logOpen = false; |
@@ -212,9 +215,9 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
212 | return; | 215 | return; |
213 | } | 216 | } |
214 | 217 | ||
215 | using (Database db = new Database(this.OutputPath, OpenDatabase.Direct)) | 218 | using (var db = new Database(this.OutputPath, OpenDatabase.Direct)) |
216 | { | 219 | { |
217 | Table suppressActionTable = this.Output.Tables["WixSuppressAction"]; | 220 | var suppressActionTable = this.Output.Tables["WixSuppressAction"]; |
218 | 221 | ||
219 | // suppress individual actions | 222 | // suppress individual actions |
220 | if (null != suppressActionTable) | 223 | if (null != suppressActionTable) |
@@ -239,40 +242,38 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
239 | } | 242 | } |
240 | 243 | ||
241 | // query for merge module actions in suppressed sequences and drop them | 244 | // query for merge module actions in suppressed sequences and drop them |
242 | foreach (string tableName in this.SuppressedTableNames) | 245 | foreach (var tableName in suppressedTableNames) |
243 | { | 246 | { |
244 | if (!db.TableExists(tableName)) | 247 | if (!db.TableExists(tableName)) |
245 | { | 248 | { |
246 | continue; | 249 | continue; |
247 | } | 250 | } |
248 | 251 | ||
249 | using (View view = db.OpenExecuteView(String.Concat("SELECT `Action` FROM ", tableName))) | 252 | using (var view = db.OpenExecuteView(String.Concat("SELECT `Action` FROM ", tableName))) |
250 | { | 253 | { |
251 | foreach (Record resultRecord in view.Records) | 254 | foreach (var resultRecord in view.Records) |
252 | { | 255 | { |
253 | this.Messaging.Write(WarningMessages.SuppressMergedAction(resultRecord.GetString(1), tableName)); | 256 | this.Messaging.Write(WarningMessages.SuppressMergedAction(resultRecord.GetString(1), tableName)); |
254 | } | 257 | } |
255 | } | 258 | } |
256 | 259 | ||
257 | // drop suppressed sequences | 260 | // drop suppressed sequences |
258 | using (View view = db.OpenExecuteView(String.Concat("DROP TABLE ", tableName))) | 261 | using (var view = db.OpenExecuteView(String.Concat("DROP TABLE ", tableName))) |
259 | { | 262 | { |
260 | } | 263 | } |
261 | 264 | ||
262 | // delete the validation rows | 265 | // delete the validation rows |
263 | using (View view = db.OpenView(String.Concat("DELETE FROM _Validation WHERE `Table` = ?"))) | 266 | using (var view = db.OpenView(String.Concat("DELETE FROM _Validation WHERE `Table` = ?"))) |
267 | using (var record = new Record(1)) | ||
264 | { | 268 | { |
265 | using (Record record = new Record(1)) | 269 | record.SetString(1, tableName); |
266 | { | 270 | view.Execute(record); |
267 | record.SetString(1, tableName); | ||
268 | view.Execute(record); | ||
269 | } | ||
270 | } | 271 | } |
271 | } | 272 | } |
272 | 273 | ||
273 | // now update the Attributes column for the files from the Merge Modules | 274 | // now update the Attributes column for the files from the Merge Modules |
274 | this.Messaging.Write(VerboseMessages.ResequencingMergeModuleFiles()); | 275 | this.Messaging.Write(VerboseMessages.ResequencingMergeModuleFiles()); |
275 | using (View view = db.OpenView("SELECT `Sequence`, `Attributes` FROM `File` WHERE `File`=?")) | 276 | using (var view = db.OpenView("SELECT `Sequence`, `Attributes` FROM `File` WHERE `File`=?")) |
276 | { | 277 | { |
277 | foreach (var file in this.FileFacades) | 278 | foreach (var file in this.FileFacades) |
278 | { | 279 | { |
@@ -281,13 +282,13 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
281 | continue; | 282 | continue; |
282 | } | 283 | } |
283 | 284 | ||
284 | using (Record record = new Record(1)) | 285 | using (var record = new Record(1)) |
285 | { | 286 | { |
286 | record.SetString(1, file.Id); | 287 | record.SetString(1, file.Id); |
287 | view.Execute(record); | 288 | view.Execute(record); |
288 | } | 289 | } |
289 | 290 | ||
290 | using (Record recordUpdate = view.Fetch()) | 291 | using (var recordUpdate = view.Fetch()) |
291 | { | 292 | { |
292 | if (null == recordUpdate) | 293 | if (null == recordUpdate) |
293 | { | 294 | { |
@@ -332,5 +333,31 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
332 | db.Commit(); | 333 | db.Commit(); |
333 | } | 334 | } |
334 | } | 335 | } |
336 | |||
337 | private IEnumerable<string> AddBackSuppresedSequenceTables() | ||
338 | { | ||
339 | // Add back possibly suppressed sequence tables since all sequence tables must be present | ||
340 | // for the merge process to work. We'll drop the suppressed sequence tables again as | ||
341 | // necessary. | ||
342 | var suppressedTableNames = new HashSet<string>(); | ||
343 | |||
344 | foreach (SequenceTable sequence in Enum.GetValues(typeof(SequenceTable))) | ||
345 | { | ||
346 | var sequenceTableName = (sequence == SequenceTable.AdvertiseExecuteSequence) ? "AdvtExecuteSequence" : sequence.ToString(); | ||
347 | var sequenceTable = this.Output.Tables[sequenceTableName]; | ||
348 | |||
349 | if (null == sequenceTable) | ||
350 | { | ||
351 | sequenceTable = this.Output.EnsureTable(this.TableDefinitions[sequenceTableName]); | ||
352 | } | ||
353 | |||
354 | if (0 == sequenceTable.Rows.Count) | ||
355 | { | ||
356 | suppressedTableNames.Add(sequenceTableName); | ||
357 | } | ||
358 | } | ||
359 | |||
360 | return suppressedTableNames; | ||
361 | } | ||
335 | } | 362 | } |
336 | } | 363 | } |
diff --git a/src/WixToolset.Core.WindowsInstaller/Bind/PatchTransform.cs b/src/WixToolset.Core.WindowsInstaller/Bind/PatchTransform.cs index 5ada29de..4d849753 100644 --- a/src/WixToolset.Core.WindowsInstaller/Bind/PatchTransform.cs +++ b/src/WixToolset.Core.WindowsInstaller/Bind/PatchTransform.cs | |||
@@ -2,14 +2,7 @@ | |||
2 | 2 | ||
3 | namespace WixToolset.Core.WindowsInstaller.Bind | 3 | namespace WixToolset.Core.WindowsInstaller.Bind |
4 | { | 4 | { |
5 | using System; | ||
6 | using System.Collections; | ||
7 | using System.Globalization; | ||
8 | using System.Text; | ||
9 | using System.Text.RegularExpressions; | ||
10 | using WixToolset.Data; | ||
11 | using WixToolset.Data.WindowsInstaller; | 5 | using WixToolset.Data.WindowsInstaller; |
12 | using WixToolset.Extensibility; | ||
13 | 6 | ||
14 | internal class PatchTransform | 7 | internal class PatchTransform |
15 | { | 8 | { |
@@ -22,225 +15,5 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
22 | public string Baseline { get; } | 15 | public string Baseline { get; } |
23 | 16 | ||
24 | public WindowsInstallerData Transform { get; } | 17 | public WindowsInstallerData Transform { get; } |
25 | |||
26 | /// <summary> | ||
27 | /// Validates that the differences in the transform are valid for patch transforms. | ||
28 | /// </summary> | ||
29 | public void Validate() | ||
30 | { | ||
31 | #if TODO_PATCHING | ||
32 | // Changing the ProdocutCode in a patch transform is not recommended. | ||
33 | Table propertyTable = this.Transform.Tables["Property"]; | ||
34 | if (null != propertyTable) | ||
35 | { | ||
36 | foreach (Row row in propertyTable.Rows) | ||
37 | { | ||
38 | // Only interested in modified rows; fast check. | ||
39 | if (RowOperation.Modify == row.Operation) | ||
40 | { | ||
41 | if (0 == String.CompareOrdinal("ProductCode", (string)row[0])) | ||
42 | { | ||
43 | this.OnMessage(WixWarnings.MajorUpgradePatchNotRecommended()); | ||
44 | } | ||
45 | } | ||
46 | } | ||
47 | } | ||
48 | |||
49 | // If there is nothing in the component table we can return early because the remaining checks are component based. | ||
50 | Table componentTable = this.Transform.Tables["Component"]; | ||
51 | if (null == componentTable) | ||
52 | { | ||
53 | return; | ||
54 | } | ||
55 | |||
56 | // Index Feature table row operations | ||
57 | Table featureTable = this.Transform.Tables["Feature"]; | ||
58 | Table featureComponentsTable = this.Transform.Tables["FeatureComponents"]; | ||
59 | Hashtable featureOps = null; | ||
60 | if (null != featureTable) | ||
61 | { | ||
62 | int capacity = featureTable.Rows.Count; | ||
63 | featureOps = new Hashtable(capacity); | ||
64 | |||
65 | foreach (Row row in featureTable.Rows) | ||
66 | { | ||
67 | featureOps[(string)row[0]] = row.Operation; | ||
68 | } | ||
69 | } | ||
70 | else | ||
71 | { | ||
72 | featureOps = new Hashtable(); | ||
73 | } | ||
74 | |||
75 | // Index Component table and check for keypath modifications | ||
76 | Hashtable deletedComponent = new Hashtable(); | ||
77 | Hashtable componentKeyPath = new Hashtable(); | ||
78 | foreach (Row row in componentTable.Rows) | ||
79 | { | ||
80 | string id = row.Fields[0].Data.ToString(); | ||
81 | string keypath = (null == row.Fields[5].Data) ? String.Empty : row.Fields[5].Data.ToString(); | ||
82 | |||
83 | componentKeyPath.Add(id, keypath); | ||
84 | if (RowOperation.Delete == row.Operation) | ||
85 | { | ||
86 | deletedComponent.Add(id, row); | ||
87 | } | ||
88 | else if (RowOperation.Modify == row.Operation) | ||
89 | { | ||
90 | if (row.Fields[1].Modified) | ||
91 | { | ||
92 | // Changing the guid of a component is equal to deleting the old one and adding a new one. | ||
93 | deletedComponent.Add(id, row); | ||
94 | } | ||
95 | |||
96 | // If the keypath is modified its an error | ||
97 | if (row.Fields[5].Modified) | ||
98 | { | ||
99 | this.OnMessage(WixErrors.InvalidKeypathChange(row.SourceLineNumbers, id, this.transformPath)); | ||
100 | } | ||
101 | } | ||
102 | } | ||
103 | |||
104 | // Verify changes in the file table | ||
105 | Table fileTable = this.Transform.Tables["File"]; | ||
106 | if (null != fileTable) | ||
107 | { | ||
108 | Hashtable componentWithChangedKeyPath = new Hashtable(); | ||
109 | foreach (Row row in fileTable.Rows) | ||
110 | { | ||
111 | if (RowOperation.None != row.Operation) | ||
112 | { | ||
113 | string fileId = row.Fields[0].Data.ToString(); | ||
114 | string componentId = row.Fields[1].Data.ToString(); | ||
115 | |||
116 | // If this file is the keypath of a component | ||
117 | if (String.Equals((string)componentKeyPath[componentId], fileId, StringComparison.Ordinal)) | ||
118 | { | ||
119 | if (row.Fields[2].Modified) | ||
120 | { | ||
121 | // You cant change the filename of a file that is the keypath of a component. | ||
122 | this.OnMessage(WixErrors.InvalidKeypathChange(row.SourceLineNumbers, componentId, this.transformPath)); | ||
123 | } | ||
124 | |||
125 | if (!componentWithChangedKeyPath.ContainsKey(componentId)) | ||
126 | { | ||
127 | componentWithChangedKeyPath.Add(componentId, fileId); | ||
128 | } | ||
129 | } | ||
130 | |||
131 | if (RowOperation.Delete == row.Operation) | ||
132 | { | ||
133 | // If the file is removed from a component that is not deleted. | ||
134 | if (!deletedComponent.ContainsKey(componentId)) | ||
135 | { | ||
136 | bool foundRemoveFileEntry = false; | ||
137 | string filename = Common.GetName((string)row[2], false, true); | ||
138 | |||
139 | Table removeFileTable = this.Transform.Tables["RemoveFile"]; | ||
140 | if (null != removeFileTable) | ||
141 | { | ||
142 | foreach (Row removeFileRow in removeFileTable.Rows) | ||
143 | { | ||
144 | if (RowOperation.Delete == removeFileRow.Operation) | ||
145 | { | ||
146 | continue; | ||
147 | } | ||
148 | |||
149 | if (componentId == (string)removeFileRow[1]) | ||
150 | { | ||
151 | // Check if there is a RemoveFile entry for this file | ||
152 | if (null != removeFileRow[2]) | ||
153 | { | ||
154 | string removeFileName = Common.GetName((string)removeFileRow[2], false, true); | ||
155 | |||
156 | // Convert the MSI format for a wildcard string to Regex format. | ||
157 | removeFileName = removeFileName.Replace('.', '|').Replace('?', '.').Replace("*", ".*").Replace("|", "\\."); | ||
158 | |||
159 | Regex regex = new Regex(removeFileName, RegexOptions.CultureInvariant | RegexOptions.IgnoreCase); | ||
160 | if (regex.IsMatch(filename)) | ||
161 | { | ||
162 | foundRemoveFileEntry = true; | ||
163 | break; | ||
164 | } | ||
165 | } | ||
166 | } | ||
167 | } | ||
168 | } | ||
169 | |||
170 | if (!foundRemoveFileEntry) | ||
171 | { | ||
172 | this.OnMessage(WixWarnings.InvalidRemoveFile(row.SourceLineNumbers, fileId, componentId)); | ||
173 | } | ||
174 | } | ||
175 | } | ||
176 | } | ||
177 | } | ||
178 | } | ||
179 | |||
180 | if (0 < deletedComponent.Count) | ||
181 | { | ||
182 | // Index FeatureComponents table. | ||
183 | Hashtable featureComponents = new Hashtable(); | ||
184 | |||
185 | if (null != featureComponentsTable) | ||
186 | { | ||
187 | foreach (Row row in featureComponentsTable.Rows) | ||
188 | { | ||
189 | ArrayList features; | ||
190 | string componentId = row.Fields[1].Data.ToString(); | ||
191 | |||
192 | if (featureComponents.Contains(componentId)) | ||
193 | { | ||
194 | features = (ArrayList)featureComponents[componentId]; | ||
195 | } | ||
196 | else | ||
197 | { | ||
198 | features = new ArrayList(); | ||
199 | featureComponents.Add(componentId, features); | ||
200 | } | ||
201 | features.Add(row.Fields[0].Data.ToString()); | ||
202 | } | ||
203 | } | ||
204 | |||
205 | // Check to make sure if a component was deleted, the feature was too. | ||
206 | foreach (DictionaryEntry entry in deletedComponent) | ||
207 | { | ||
208 | if (featureComponents.Contains(entry.Key.ToString())) | ||
209 | { | ||
210 | ArrayList features = (ArrayList)featureComponents[entry.Key.ToString()]; | ||
211 | foreach (string featureId in features) | ||
212 | { | ||
213 | if (!featureOps.ContainsKey(featureId) || RowOperation.Delete != (RowOperation)featureOps[featureId]) | ||
214 | { | ||
215 | // The feature was not deleted. | ||
216 | this.OnMessage(WixErrors.InvalidRemoveComponent(((Row)entry.Value).SourceLineNumbers, entry.Key.ToString(), featureId, this.transformPath)); | ||
217 | } | ||
218 | } | ||
219 | } | ||
220 | } | ||
221 | } | ||
222 | |||
223 | // Warn if new components are added to existing features | ||
224 | if (null != featureComponentsTable) | ||
225 | { | ||
226 | foreach (Row row in featureComponentsTable.Rows) | ||
227 | { | ||
228 | if (RowOperation.Add == row.Operation) | ||
229 | { | ||
230 | // Check if the feature is in the Feature table | ||
231 | string feature_ = (string)row[0]; | ||
232 | string component_ = (string)row[1]; | ||
233 | |||
234 | // Features may not be present if not referenced | ||
235 | if (!featureOps.ContainsKey(feature_) || RowOperation.Add != (RowOperation)featureOps[feature_]) | ||
236 | { | ||
237 | this.OnMessage(WixWarnings.NewComponentAddedToExistingFeature(row.SourceLineNumbers, component_, feature_, this.transformPath)); | ||
238 | } | ||
239 | } | ||
240 | } | ||
241 | } | ||
242 | #endif | ||
243 | throw new NotImplementedException(); | ||
244 | } | ||
245 | } | 18 | } |
246 | } | 19 | } |
diff --git a/src/WixToolset.Core.WindowsInstaller/Bind/UpdateFileFacadesCommand.cs b/src/WixToolset.Core.WindowsInstaller/Bind/UpdateFileFacadesCommand.cs index 4ca5ec48..63a8b3d9 100644 --- a/src/WixToolset.Core.WindowsInstaller/Bind/UpdateFileFacadesCommand.cs +++ b/src/WixToolset.Core.WindowsInstaller/Bind/UpdateFileFacadesCommand.cs | |||
@@ -39,20 +39,16 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
39 | 39 | ||
40 | public void Execute() | 40 | public void Execute() |
41 | { | 41 | { |
42 | var assemblyNameTuples = this.Section.Tuples.OfType<MsiAssemblyNameTuple>().ToDictionary(t => t.Id.Id); | ||
43 | |||
42 | foreach (var file in this.UpdateFileFacades) | 44 | foreach (var file in this.UpdateFileFacades) |
43 | { | 45 | { |
44 | this.UpdateFileFacade(file); | 46 | this.UpdateFileFacade(file, assemblyNameTuples); |
45 | } | 47 | } |
46 | } | 48 | } |
47 | 49 | ||
48 | private void UpdateFileFacade(FileFacade facade) | 50 | private void UpdateFileFacade(FileFacade facade, Dictionary<string, MsiAssemblyNameTuple> assemblyNameTuples) |
49 | { | 51 | { |
50 | var assemblyNameTuples = new Dictionary<string, MsiAssemblyNameTuple>(); | ||
51 | foreach (var assemblyTuple in this.Section.Tuples.OfType<MsiAssemblyNameTuple>()) | ||
52 | { | ||
53 | assemblyNameTuples.Add(assemblyTuple.ComponentRef + "/" + assemblyTuple.Name, assemblyTuple); | ||
54 | } | ||
55 | |||
56 | FileInfo fileInfo = null; | 52 | FileInfo fileInfo = null; |
57 | try | 53 | try |
58 | { | 54 | { |
@@ -335,7 +331,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
335 | var lookup = String.Concat(facade.ComponentRef, "/", name); | 331 | var lookup = String.Concat(facade.ComponentRef, "/", name); |
336 | if (!assemblyNameTuples.TryGetValue(lookup, out var assemblyNameTuple)) | 332 | if (!assemblyNameTuples.TryGetValue(lookup, out var assemblyNameTuple)) |
337 | { | 333 | { |
338 | assemblyNameTuple = this.Section.AddTuple(new MsiAssemblyNameTuple(facade.SourceLineNumber) | 334 | assemblyNameTuple = this.Section.AddTuple(new MsiAssemblyNameTuple(facade.SourceLineNumber, new Identifier(AccessModifier.Private, facade.ComponentRef, name)) |
339 | { | 335 | { |
340 | ComponentRef = facade.ComponentRef, | 336 | ComponentRef = facade.ComponentRef, |
341 | Name = name, | 337 | Name = name, |
@@ -348,6 +344,8 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
348 | } | 344 | } |
349 | 345 | ||
350 | facade.AssemblyNames.Add(assemblyNameTuple); | 346 | facade.AssemblyNames.Add(assemblyNameTuple); |
347 | |||
348 | assemblyNameTuples.Add(assemblyNameTuple.Id.Id, assemblyNameTuple); | ||
351 | } | 349 | } |
352 | 350 | ||
353 | assemblyNameTuple.Value = value; | 351 | assemblyNameTuple.Value = value; |
diff --git a/src/WixToolset.Core.WindowsInstaller/Bind/UpdateMediaSequencesCommand.cs b/src/WixToolset.Core.WindowsInstaller/Bind/UpdateMediaSequencesCommand.cs index 5d18a230..9aab7b98 100644 --- a/src/WixToolset.Core.WindowsInstaller/Bind/UpdateMediaSequencesCommand.cs +++ b/src/WixToolset.Core.WindowsInstaller/Bind/UpdateMediaSequencesCommand.cs | |||
@@ -6,62 +6,59 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
6 | using System.Linq; | 6 | using System.Linq; |
7 | using WixToolset.Core.Bind; | 7 | using WixToolset.Core.Bind; |
8 | using WixToolset.Data; | 8 | using WixToolset.Data; |
9 | using WixToolset.Data.WindowsInstaller; | 9 | using WixToolset.Data.Tuples; |
10 | using WixToolset.Data.WindowsInstaller.Rows; | ||
11 | 10 | ||
12 | internal class UpdateMediaSequencesCommand | 11 | internal class UpdateMediaSequencesCommand |
13 | { | 12 | { |
14 | public UpdateMediaSequencesCommand(WindowsInstallerData output, List<FileFacade> fileFacades) | 13 | public UpdateMediaSequencesCommand(IntermediateSection section, List<FileFacade> fileFacades) |
15 | { | 14 | { |
16 | this.Output = output; | 15 | this.Section = section; |
17 | this.FileFacades = fileFacades; | 16 | this.FileFacades = fileFacades; |
18 | } | 17 | } |
19 | 18 | ||
20 | private WindowsInstallerData Output { get; } | 19 | private IntermediateSection Section { get; } |
21 | 20 | ||
22 | private List<FileFacade> FileFacades { get; } | 21 | private List<FileFacade> FileFacades { get; } |
23 | 22 | ||
24 | public void Execute() | 23 | public void Execute() |
25 | { | 24 | { |
26 | var fileRows = new RowDictionary<FileRow>(this.Output.Tables["File"]); | 25 | var mediaRows = this.Section.Tuples.OfType<MediaTuple>().ToDictionary(t => t.DiskId); |
27 | var mediaRows = new RowDictionary<MediaRow>(this.Output.Tables["Media"]); | ||
28 | 26 | ||
29 | // Calculate sequence numbers and media disk id layout for all file media information objects. | 27 | // Calculate sequence numbers and media disk id layout for all file media information objects. |
30 | if (OutputType.Module == this.Output.Type) | 28 | if (SectionType.Module == this.Section.Type) |
31 | { | 29 | { |
32 | var lastSequence = 0; | 30 | var lastSequence = 0; |
33 | 31 | ||
34 | // Order by Component to group the files by directory. | 32 | // Order by Component to group the files by directory. |
35 | var optimized = this.OptimizedFileFacades(); | 33 | var optimized = this.OptimizedFileFacades(); |
36 | foreach (var fileId in optimized.Select(f => f.Id)) | 34 | foreach (var facade in optimized) |
37 | { | 35 | { |
38 | var fileRow = fileRows.Get(fileId); | 36 | facade.Sequence = ++lastSequence; |
39 | fileRow.Sequence = ++lastSequence; | ||
40 | } | 37 | } |
41 | } | 38 | } |
42 | else | 39 | else |
43 | { | 40 | { |
44 | var lastSequence = 0; | 41 | var lastSequence = 0; |
45 | MediaRow mediaRow = null; | 42 | MediaTuple mediaTuple = null; |
46 | var patchGroups = new Dictionary<int, List<FileFacade>>(); | 43 | var patchGroups = new Dictionary<int, List<FileFacade>>(); |
47 | 44 | ||
48 | // sequence the non-patch-added files | 45 | // sequence the non-patch-added files |
49 | var optimized = this.OptimizedFileFacades(); | 46 | var optimized = this.OptimizedFileFacades(); |
50 | foreach (var facade in optimized) | 47 | foreach (var facade in optimized) |
51 | { | 48 | { |
52 | if (null == mediaRow) | 49 | if (null == mediaTuple) |
53 | { | 50 | { |
54 | mediaRow = mediaRows.Get(facade.DiskId); | 51 | mediaTuple = mediaRows[facade.DiskId]; |
55 | if (OutputType.Patch == this.Output.Type) | 52 | if (SectionType.Patch == this.Section.Type) |
56 | { | 53 | { |
57 | // patch Media cannot start at zero | 54 | // patch Media cannot start at zero |
58 | lastSequence = mediaRow.LastSequence; | 55 | lastSequence = mediaTuple.LastSequence ?? 1; |
59 | } | 56 | } |
60 | } | 57 | } |
61 | else if (mediaRow.DiskId != facade.DiskId) | 58 | else if (mediaTuple.DiskId != facade.DiskId) |
62 | { | 59 | { |
63 | mediaRow.LastSequence = lastSequence; | 60 | mediaTuple.LastSequence = lastSequence; |
64 | mediaRow = mediaRows.Get(facade.DiskId); | 61 | mediaTuple = mediaRows[facade.DiskId]; |
65 | } | 62 | } |
66 | 63 | ||
67 | if (facade.PatchGroup.HasValue) | 64 | if (facade.PatchGroup.HasValue) |
@@ -76,15 +73,14 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
76 | } | 73 | } |
77 | else if (!facade.FromModule) | 74 | else if (!facade.FromModule) |
78 | { | 75 | { |
79 | var fileRow = fileRows.Get(facade.Id); | 76 | facade.Sequence = ++lastSequence; |
80 | fileRow.Sequence = ++lastSequence; | ||
81 | } | 77 | } |
82 | } | 78 | } |
83 | 79 | ||
84 | if (null != mediaRow) | 80 | if (null != mediaTuple) |
85 | { | 81 | { |
86 | mediaRow.LastSequence = lastSequence; | 82 | mediaTuple.LastSequence = lastSequence; |
87 | mediaRow = null; | 83 | mediaTuple = null; |
88 | } | 84 | } |
89 | 85 | ||
90 | // sequence the patch-added files | 86 | // sequence the patch-added files |
@@ -92,24 +88,23 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
92 | { | 88 | { |
93 | foreach (var facade in patchGroup) | 89 | foreach (var facade in patchGroup) |
94 | { | 90 | { |
95 | if (null == mediaRow) | 91 | if (null == mediaTuple) |
96 | { | 92 | { |
97 | mediaRow = mediaRows.Get(facade.DiskId); | 93 | mediaTuple = mediaRows[facade.DiskId]; |
98 | } | 94 | } |
99 | else if (mediaRow.DiskId != facade.DiskId) | 95 | else if (mediaTuple.DiskId != facade.DiskId) |
100 | { | 96 | { |
101 | mediaRow.LastSequence = lastSequence; | 97 | mediaTuple.LastSequence = lastSequence; |
102 | mediaRow = mediaRows.Get(facade.DiskId); | 98 | mediaTuple = mediaRows[facade.DiskId]; |
103 | } | 99 | } |
104 | 100 | ||
105 | var fileRow = fileRows.Get(facade.Id); | 101 | facade.Sequence = ++lastSequence; |
106 | fileRow.Sequence = ++lastSequence; | ||
107 | } | 102 | } |
108 | } | 103 | } |
109 | 104 | ||
110 | if (null != mediaRow) | 105 | if (null != mediaTuple) |
111 | { | 106 | { |
112 | mediaRow.LastSequence = lastSequence; | 107 | mediaTuple.LastSequence = lastSequence; |
113 | } | 108 | } |
114 | } | 109 | } |
115 | } | 110 | } |
diff --git a/src/WixToolset.Core.WindowsInstaller/Bind/UpdateTransformsWithFileFacades.cs b/src/WixToolset.Core.WindowsInstaller/Bind/UpdateTransformsWithFileFacades.cs new file mode 100644 index 00000000..af2e8f85 --- /dev/null +++ b/src/WixToolset.Core.WindowsInstaller/Bind/UpdateTransformsWithFileFacades.cs | |||
@@ -0,0 +1,453 @@ | |||
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 System.Diagnostics; | ||
8 | using System.IO; | ||
9 | using System.Linq; | ||
10 | using WixToolset.Core.Bind; | ||
11 | using WixToolset.Data; | ||
12 | using WixToolset.Data.Tuples; | ||
13 | using WixToolset.Data.WindowsInstaller; | ||
14 | using WixToolset.Data.WindowsInstaller.Rows; | ||
15 | using WixToolset.Extensibility.Services; | ||
16 | |||
17 | internal class UpdateTransformsWithFileFacades | ||
18 | { | ||
19 | public UpdateTransformsWithFileFacades(IMessaging messaging, WindowsInstallerData output, IEnumerable<SubStorage> subStorages, TableDefinitionCollection tableDefinitions, IEnumerable<FileFacade> fileFacades) | ||
20 | { | ||
21 | this.Messaging = messaging; | ||
22 | this.Output = output; | ||
23 | this.SubStorages = subStorages; | ||
24 | this.TableDefinitions = tableDefinitions; | ||
25 | this.FileFacades = fileFacades; | ||
26 | } | ||
27 | |||
28 | private IMessaging Messaging { get; } | ||
29 | |||
30 | private WindowsInstallerData Output { get; } | ||
31 | |||
32 | private IEnumerable<SubStorage> SubStorages { get; } | ||
33 | |||
34 | private TableDefinitionCollection TableDefinitions { get; } | ||
35 | |||
36 | private IEnumerable<FileFacade> FileFacades { get; } | ||
37 | |||
38 | public void Execute() | ||
39 | { | ||
40 | var fileFacadesByDiskId = new Dictionary<int, Dictionary<string, FileFacade>>(); | ||
41 | |||
42 | // Index patch file facades by diskId+fileId. | ||
43 | foreach (var facade in this.FileFacades) | ||
44 | { | ||
45 | if (!fileFacadesByDiskId.TryGetValue(facade.DiskId, out var mediaFacades)) | ||
46 | { | ||
47 | mediaFacades = new Dictionary<string, FileFacade>(); | ||
48 | fileFacadesByDiskId.Add(facade.DiskId, mediaFacades); | ||
49 | } | ||
50 | |||
51 | mediaFacades.Add(facade.Id, facade); | ||
52 | } | ||
53 | |||
54 | var patchMediaRows = new RowDictionary<MediaRow>(this.Output.Tables["Media"]); | ||
55 | |||
56 | // Index paired transforms by name without the "#" prefix. | ||
57 | var pairedTransforms = this.SubStorages.Where(s => s.Name.StartsWith("#")).ToDictionary(s => s.Name, s => s.Data); | ||
58 | |||
59 | // Copy File bind data into substorages | ||
60 | foreach (var substorage in this.SubStorages.Where(s => !s.Name.StartsWith("#"))) | ||
61 | { | ||
62 | var mainTransform = substorage.Data; | ||
63 | |||
64 | var mainMsiFileHashIndex = new RowDictionary<Row>(mainTransform.Tables["MsiFileHash"]); | ||
65 | |||
66 | var pairedTransform = pairedTransforms["#" + substorage.Name]; | ||
67 | |||
68 | // Copy Media.LastSequence. | ||
69 | var pairedMediaTable = pairedTransform.Tables["Media"]; | ||
70 | foreach (MediaRow pairedMediaRow in pairedMediaTable.Rows) | ||
71 | { | ||
72 | var patchMediaRow = patchMediaRows.Get(pairedMediaRow.DiskId); | ||
73 | pairedMediaRow.LastSequence = patchMediaRow.LastSequence; | ||
74 | } | ||
75 | |||
76 | // Validate file row changes for keypath-related issues | ||
77 | this.ValidateFileRowChanges(mainTransform); | ||
78 | |||
79 | // Index File table of pairedTransform | ||
80 | var pairedFileRows = new RowDictionary<FileRow>(pairedTransform.Tables["File"]); | ||
81 | |||
82 | var mainFileTable = mainTransform.Tables["File"]; | ||
83 | if (null != mainFileTable) | ||
84 | { | ||
85 | // Remove the MsiFileHash table because it will be updated later with the final file hash for each file | ||
86 | mainTransform.Tables.Remove("MsiFileHash"); | ||
87 | |||
88 | foreach (FileRow mainFileRow in mainFileTable.Rows) | ||
89 | { | ||
90 | if (RowOperation.Delete == mainFileRow.Operation) | ||
91 | { | ||
92 | continue; | ||
93 | } | ||
94 | else if (RowOperation.None == mainFileRow.Operation) | ||
95 | { | ||
96 | continue; | ||
97 | } | ||
98 | |||
99 | // Index patch files by diskId+fileId | ||
100 | if (!fileFacadesByDiskId.TryGetValue(mainFileRow.DiskId, out var mediaFacades)) | ||
101 | { | ||
102 | mediaFacades = new Dictionary<string, FileFacade>(); | ||
103 | fileFacadesByDiskId.Add(mainFileRow.DiskId, mediaFacades); | ||
104 | } | ||
105 | |||
106 | // copy data from the patch back to the transform | ||
107 | if (mediaFacades.TryGetValue(mainFileRow.File, out var facade)) | ||
108 | { | ||
109 | var patchFileRow = facade.GetFileRow(); | ||
110 | var pairedFileRow = pairedFileRows.Get(mainFileRow.File); | ||
111 | |||
112 | for (var i = 0; i < patchFileRow.Fields.Length; i++) | ||
113 | { | ||
114 | var patchValue = patchFileRow.FieldAsString(i) ?? String.Empty; | ||
115 | var mainValue = mainFileRow.FieldAsString(i) ?? String.Empty; | ||
116 | |||
117 | if (1 == i) | ||
118 | { | ||
119 | // File.Component_ changes should not come from the shared file rows | ||
120 | // that contain the file information as each individual transform might | ||
121 | // have different changes (or no changes at all). | ||
122 | } | ||
123 | else if (6 == i) // File.Attributes should not changed for binary deltas | ||
124 | { | ||
125 | #if TODO_PATCHING_DELTA | ||
126 | if (null != patchFileRow.Patch) | ||
127 | { | ||
128 | // File.Attribute should not change for binary deltas | ||
129 | pairedFileRow.Attributes = mainFileRow.Attributes; | ||
130 | mainFileRow.Fields[i].Modified = false; | ||
131 | } | ||
132 | #endif | ||
133 | } | ||
134 | else if (7 == i) // File.Sequence is updated in pairedTransform, not mainTransform | ||
135 | { | ||
136 | // file sequence is updated in Patch table instead of File table for delta patches | ||
137 | #if TODO_PATCHING_DELTA | ||
138 | if (null != patchFileRow.Patch) | ||
139 | { | ||
140 | pairedFileRow.Fields[i].Modified = false; | ||
141 | } | ||
142 | else | ||
143 | #endif | ||
144 | { | ||
145 | pairedFileRow[i] = patchFileRow[i]; | ||
146 | pairedFileRow.Fields[i].Modified = true; | ||
147 | } | ||
148 | mainFileRow.Fields[i].Modified = false; | ||
149 | } | ||
150 | else if (patchValue != mainValue) | ||
151 | { | ||
152 | mainFileRow[i] = patchFileRow[i]; | ||
153 | mainFileRow.Fields[i].Modified = true; | ||
154 | if (mainFileRow.Operation == RowOperation.None) | ||
155 | { | ||
156 | mainFileRow.Operation = RowOperation.Modify; | ||
157 | } | ||
158 | } | ||
159 | } | ||
160 | |||
161 | // Copy MsiFileHash row for this File. | ||
162 | if (!mainMsiFileHashIndex.TryGetValue(patchFileRow.File, out var patchHashRow)) | ||
163 | { | ||
164 | //patchHashRow = patchFileRow.Hash; | ||
165 | throw new NotImplementedException(); | ||
166 | } | ||
167 | |||
168 | if (null != patchHashRow) | ||
169 | { | ||
170 | var mainHashTable = mainTransform.EnsureTable(this.TableDefinitions["MsiFileHash"]); | ||
171 | var mainHashRow = mainHashTable.CreateRow(mainFileRow.SourceLineNumbers); | ||
172 | for (var i = 0; i < patchHashRow.Fields.Length; i++) | ||
173 | { | ||
174 | mainHashRow[i] = patchHashRow[i]; | ||
175 | if (i > 1) | ||
176 | { | ||
177 | // assume all hash fields have been modified | ||
178 | mainHashRow.Fields[i].Modified = true; | ||
179 | } | ||
180 | } | ||
181 | |||
182 | // assume the MsiFileHash operation follows the File one | ||
183 | mainHashRow.Operation = mainFileRow.Operation; | ||
184 | } | ||
185 | |||
186 | // copy MsiAssemblyName rows for this File | ||
187 | #if TODO_PATCHING | ||
188 | List<Row> patchAssemblyNameRows = patchFileRow.AssemblyNames; | ||
189 | if (null != patchAssemblyNameRows) | ||
190 | { | ||
191 | var mainAssemblyNameTable = mainTransform.EnsureTable(this.TableDefinitions["MsiAssemblyName"]); | ||
192 | foreach (var patchAssemblyNameRow in patchAssemblyNameRows) | ||
193 | { | ||
194 | // Copy if there isn't an identical modified/added row already in the transform. | ||
195 | var foundMatchingModifiedRow = false; | ||
196 | foreach (var mainAssemblyNameRow in mainAssemblyNameTable.Rows) | ||
197 | { | ||
198 | if (RowOperation.None != mainAssemblyNameRow.Operation && mainAssemblyNameRow.GetPrimaryKey('/').Equals(patchAssemblyNameRow.GetPrimaryKey('/'))) | ||
199 | { | ||
200 | foundMatchingModifiedRow = true; | ||
201 | break; | ||
202 | } | ||
203 | } | ||
204 | |||
205 | if (!foundMatchingModifiedRow) | ||
206 | { | ||
207 | var mainAssemblyNameRow = mainAssemblyNameTable.CreateRow(mainFileRow.SourceLineNumbers); | ||
208 | for (var i = 0; i < patchAssemblyNameRow.Fields.Length; i++) | ||
209 | { | ||
210 | mainAssemblyNameRow[i] = patchAssemblyNameRow[i]; | ||
211 | } | ||
212 | |||
213 | // assume value field has been modified | ||
214 | mainAssemblyNameRow.Fields[2].Modified = true; | ||
215 | mainAssemblyNameRow.Operation = mainFileRow.Operation; | ||
216 | } | ||
217 | } | ||
218 | } | ||
219 | #endif | ||
220 | |||
221 | // Add patch header for this file | ||
222 | #if TODO_PATCHING_DELTA | ||
223 | if (null != patchFileRow.Patch) | ||
224 | { | ||
225 | // Add the PatchFiles action automatically to the AdminExecuteSequence and InstallExecuteSequence tables. | ||
226 | this.AddPatchFilesActionToSequenceTable(SequenceTable.AdminExecuteSequence, mainTransform, pairedTransform, mainFileRow); | ||
227 | this.AddPatchFilesActionToSequenceTable(SequenceTable.InstallExecuteSequence, mainTransform, pairedTransform, mainFileRow); | ||
228 | |||
229 | // Add to Patch table | ||
230 | var patchTable = pairedTransform.EnsureTable(this.TableDefinitions["Patch"]); | ||
231 | if (0 == patchTable.Rows.Count) | ||
232 | { | ||
233 | patchTable.Operation = TableOperation.Add; | ||
234 | } | ||
235 | |||
236 | var patchRow = patchTable.CreateRow(mainFileRow.SourceLineNumbers); | ||
237 | patchRow[0] = patchFileRow.File; | ||
238 | patchRow[1] = patchFileRow.Sequence; | ||
239 | |||
240 | var patchFile = new FileInfo(patchFileRow.Source); | ||
241 | patchRow[2] = (int)patchFile.Length; | ||
242 | patchRow[3] = 0 == (PatchAttributeType.AllowIgnoreOnError & patchFileRow.PatchAttributes) ? 0 : 1; | ||
243 | |||
244 | var streamName = patchTable.Name + "." + patchRow[0] + "." + patchRow[1]; | ||
245 | if (Msi.MsiInterop.MsiMaxStreamNameLength < streamName.Length) | ||
246 | { | ||
247 | streamName = "_" + Guid.NewGuid().ToString("D").ToUpperInvariant().Replace('-', '_'); | ||
248 | |||
249 | var patchHeadersTable = pairedTransform.EnsureTable(this.TableDefinitions["MsiPatchHeaders"]); | ||
250 | if (0 == patchHeadersTable.Rows.Count) | ||
251 | { | ||
252 | patchHeadersTable.Operation = TableOperation.Add; | ||
253 | } | ||
254 | |||
255 | var patchHeadersRow = patchHeadersTable.CreateRow(mainFileRow.SourceLineNumbers); | ||
256 | patchHeadersRow[0] = streamName; | ||
257 | patchHeadersRow[1] = patchFileRow.Patch; | ||
258 | patchRow[5] = streamName; | ||
259 | patchHeadersRow.Operation = RowOperation.Add; | ||
260 | } | ||
261 | else | ||
262 | { | ||
263 | patchRow[4] = patchFileRow.Patch; | ||
264 | } | ||
265 | patchRow.Operation = RowOperation.Add; | ||
266 | } | ||
267 | #endif | ||
268 | } | ||
269 | else | ||
270 | { | ||
271 | // TODO: throw because all transform rows should have made it into the patch | ||
272 | } | ||
273 | } | ||
274 | } | ||
275 | |||
276 | this.Output.Tables.Remove("Media"); | ||
277 | this.Output.Tables.Remove("File"); | ||
278 | this.Output.Tables.Remove("MsiFileHash"); | ||
279 | this.Output.Tables.Remove("MsiAssemblyName"); | ||
280 | } | ||
281 | } | ||
282 | |||
283 | /// <summary> | ||
284 | /// Adds the PatchFiles action to the sequence table if it does not already exist. | ||
285 | /// </summary> | ||
286 | /// <param name="table">The sequence table to check or modify.</param> | ||
287 | /// <param name="mainTransform">The primary authoring transform.</param> | ||
288 | /// <param name="pairedTransform">The secondary patch transform.</param> | ||
289 | /// <param name="mainFileRow">The file row that contains information about the patched file.</param> | ||
290 | private void AddPatchFilesActionToSequenceTable(SequenceTable table, WindowsInstallerData mainTransform, WindowsInstallerData pairedTransform, Row mainFileRow) | ||
291 | { | ||
292 | var tableName = table.ToString(); | ||
293 | |||
294 | // Find/add PatchFiles action (also determine sequence for it). | ||
295 | // Search mainTransform first, then pairedTransform (pairedTransform overrides). | ||
296 | var hasPatchFilesAction = false; | ||
297 | var installFilesSequence = 0; | ||
298 | var duplicateFilesSequence = 0; | ||
299 | |||
300 | TestSequenceTableForPatchFilesAction( | ||
301 | mainTransform.Tables[tableName], | ||
302 | ref hasPatchFilesAction, | ||
303 | ref installFilesSequence, | ||
304 | ref duplicateFilesSequence); | ||
305 | TestSequenceTableForPatchFilesAction( | ||
306 | pairedTransform.Tables[tableName], | ||
307 | ref hasPatchFilesAction, | ||
308 | ref installFilesSequence, | ||
309 | ref duplicateFilesSequence); | ||
310 | if (!hasPatchFilesAction) | ||
311 | { | ||
312 | WindowsInstallerStandard.TryGetStandardAction(tableName, "PatchFiles", out var patchFilesActionTuple); | ||
313 | |||
314 | var sequence = patchFilesActionTuple.Sequence; | ||
315 | |||
316 | // Test for default sequence value's appropriateness | ||
317 | if (installFilesSequence >= sequence || (0 != duplicateFilesSequence && duplicateFilesSequence <= sequence)) | ||
318 | { | ||
319 | if (0 != duplicateFilesSequence) | ||
320 | { | ||
321 | if (duplicateFilesSequence < installFilesSequence) | ||
322 | { | ||
323 | throw new WixException(ErrorMessages.InsertInvalidSequenceActionOrder(mainFileRow.SourceLineNumbers, tableName, "InstallFiles", "DuplicateFiles", patchFilesActionTuple.Action)); | ||
324 | } | ||
325 | else | ||
326 | { | ||
327 | sequence = (duplicateFilesSequence + installFilesSequence) / 2; | ||
328 | if (installFilesSequence == sequence || duplicateFilesSequence == sequence) | ||
329 | { | ||
330 | throw new WixException(ErrorMessages.InsertSequenceNoSpace(mainFileRow.SourceLineNumbers, tableName, "InstallFiles", "DuplicateFiles", patchFilesActionTuple.Action)); | ||
331 | } | ||
332 | } | ||
333 | } | ||
334 | else | ||
335 | { | ||
336 | sequence = installFilesSequence + 1; | ||
337 | } | ||
338 | } | ||
339 | |||
340 | var sequenceTable = pairedTransform.EnsureTable(this.TableDefinitions[tableName]); | ||
341 | if (0 == sequenceTable.Rows.Count) | ||
342 | { | ||
343 | sequenceTable.Operation = TableOperation.Add; | ||
344 | } | ||
345 | |||
346 | var patchAction = sequenceTable.CreateRow(null); | ||
347 | patchAction[0] = patchFilesActionTuple.Action; | ||
348 | patchAction[1] = patchFilesActionTuple.Condition; | ||
349 | patchAction[2] = sequence; | ||
350 | patchAction.Operation = RowOperation.Add; | ||
351 | } | ||
352 | } | ||
353 | |||
354 | /// <summary> | ||
355 | /// Tests sequence table for PatchFiles and associated actions | ||
356 | /// </summary> | ||
357 | /// <param name="sequenceTable">The table to test.</param> | ||
358 | /// <param name="hasPatchFilesAction">Set to true if PatchFiles action is found. Left unchanged otherwise.</param> | ||
359 | /// <param name="installFilesSequence">Set to sequence value of InstallFiles action if found. Left unchanged otherwise.</param> | ||
360 | /// <param name="duplicateFilesSequence">Set to sequence value of DuplicateFiles action if found. Left unchanged otherwise.</param> | ||
361 | private static void TestSequenceTableForPatchFilesAction(Table sequenceTable, ref bool hasPatchFilesAction, ref int installFilesSequence, ref int duplicateFilesSequence) | ||
362 | { | ||
363 | if (null != sequenceTable) | ||
364 | { | ||
365 | foreach (var row in sequenceTable.Rows) | ||
366 | { | ||
367 | var actionName = row.FieldAsString(0); | ||
368 | switch (actionName) | ||
369 | { | ||
370 | case "PatchFiles": | ||
371 | hasPatchFilesAction = true; | ||
372 | break; | ||
373 | |||
374 | case "InstallFiles": | ||
375 | installFilesSequence = row.FieldAsInteger(2); | ||
376 | break; | ||
377 | |||
378 | case "DuplicateFiles": | ||
379 | duplicateFilesSequence = row.FieldAsInteger(2); | ||
380 | break; | ||
381 | } | ||
382 | } | ||
383 | } | ||
384 | } | ||
385 | |||
386 | /// <summary> | ||
387 | /// Signal a warning if a non-keypath file was changed in a patch without also changing the keypath file of the component. | ||
388 | /// </summary> | ||
389 | /// <param name="output">The output to validate.</param> | ||
390 | private void ValidateFileRowChanges(WindowsInstallerData transform) | ||
391 | { | ||
392 | var componentTable = transform.Tables["Component"]; | ||
393 | var fileTable = transform.Tables["File"]; | ||
394 | |||
395 | // There's no sense validating keypaths if the transform has no component or file table | ||
396 | if (componentTable == null || fileTable == null) | ||
397 | { | ||
398 | return; | ||
399 | } | ||
400 | |||
401 | var componentKeyPath = new Dictionary<string, string>(componentTable.Rows.Count); | ||
402 | |||
403 | // Index the Component table for non-directory & non-registry key paths. | ||
404 | foreach (var row in componentTable.Rows) | ||
405 | { | ||
406 | var keyPath = row.FieldAsString(5); | ||
407 | if (keyPath != null && 0 != (row.FieldAsInteger(3) & WindowsInstallerConstants.MsidbComponentAttributesRegistryKeyPath)) | ||
408 | { | ||
409 | componentKeyPath.Add(row.FieldAsString(0), keyPath); | ||
410 | } | ||
411 | } | ||
412 | |||
413 | var componentWithChangedKeyPath = new Dictionary<string, string>(); | ||
414 | var componentWithNonKeyPathChanged = new Dictionary<string, string>(); | ||
415 | // Verify changes in the file table, now that file diffing has occurred | ||
416 | foreach (FileRow row in fileTable.Rows) | ||
417 | { | ||
418 | if (RowOperation.Modify != row.Operation) | ||
419 | { | ||
420 | continue; | ||
421 | } | ||
422 | |||
423 | var fileId = row.FieldAsString(0); | ||
424 | var componentId = row.FieldAsString(1); | ||
425 | |||
426 | // If this file is the keypath of a component | ||
427 | if (componentKeyPath.ContainsValue(fileId)) | ||
428 | { | ||
429 | if (!componentWithChangedKeyPath.ContainsKey(componentId)) | ||
430 | { | ||
431 | componentWithChangedKeyPath.Add(componentId, fileId); | ||
432 | } | ||
433 | } | ||
434 | else | ||
435 | { | ||
436 | if (!componentWithNonKeyPathChanged.ContainsKey(componentId)) | ||
437 | { | ||
438 | componentWithNonKeyPathChanged.Add(componentId, fileId); | ||
439 | } | ||
440 | } | ||
441 | } | ||
442 | |||
443 | foreach (var componentFile in componentWithNonKeyPathChanged) | ||
444 | { | ||
445 | // Make sure all changes to non keypath files also had a change in the keypath. | ||
446 | if (!componentWithChangedKeyPath.ContainsKey(componentFile.Key) && componentKeyPath.TryGetValue(componentFile.Key, out var keyPath)) | ||
447 | { | ||
448 | this.Messaging.Write(WarningMessages.UpdateOfNonKeyPathFile(componentFile.Value, componentFile.Key, keyPath)); | ||
449 | } | ||
450 | } | ||
451 | } | ||
452 | } | ||
453 | } | ||
diff --git a/src/WixToolset.Core/Bind/FileFacade.cs b/src/WixToolset.Core/Bind/FileFacade.cs index 7bfdb9bb..f0ce14ca 100644 --- a/src/WixToolset.Core/Bind/FileFacade.cs +++ b/src/WixToolset.Core/Bind/FileFacade.cs | |||
@@ -15,18 +15,27 @@ namespace WixToolset.Core.Bind | |||
15 | { | 15 | { |
16 | this.FileTuple = file; | 16 | this.FileTuple = file; |
17 | this.AssemblyTuple = assembly; | 17 | this.AssemblyTuple = assembly; |
18 | |||
19 | this.Identifier = file.Id; | ||
20 | this.ComponentRef = file.ComponentRef; | ||
18 | } | 21 | } |
19 | 22 | ||
20 | public FileFacade(bool fromModule, FileTuple file) | 23 | public FileFacade(bool fromModule, FileTuple file) |
21 | { | 24 | { |
22 | this.FromModule = fromModule; | 25 | this.FromModule = fromModule; |
23 | this.FileTuple = file; | 26 | this.FileTuple = file; |
27 | |||
28 | this.Identifier = file.Id; | ||
29 | this.ComponentRef = file.ComponentRef; | ||
24 | } | 30 | } |
25 | 31 | ||
26 | internal FileFacade(FileRow row) | 32 | public FileFacade(FileRow row) |
27 | { | 33 | { |
28 | this.FromTransform = true; | 34 | this.FromTransform = true; |
29 | this.FileRow = row; | 35 | this.FileRow = row; |
36 | |||
37 | this.Identifier = new Identifier(AccessModifier.Private, row.File); | ||
38 | this.ComponentRef = row.Component; | ||
30 | } | 39 | } |
31 | 40 | ||
32 | public bool FromModule { get; } | 41 | public bool FromModule { get; } |
@@ -39,11 +48,11 @@ namespace WixToolset.Core.Bind | |||
39 | 48 | ||
40 | private AssemblyTuple AssemblyTuple { get; } | 49 | private AssemblyTuple AssemblyTuple { get; } |
41 | 50 | ||
42 | public string Id => this.FileRow == null ? this.FileTuple.Id.Id : this.FileRow.File; | 51 | public string Id => this.Identifier.Id; |
43 | 52 | ||
44 | public Identifier Identifier => this.FileRow == null ? this.FileTuple.Id : throw new NotImplementedException(); | 53 | public Identifier Identifier { get; } |
45 | 54 | ||
46 | public string ComponentRef => this.FileRow == null ? this.FileTuple.ComponentRef : this.FileRow.Component; | 55 | public string ComponentRef { get; } |
47 | 56 | ||
48 | public int DiskId | 57 | public int DiskId |
49 | { | 58 | { |
@@ -137,7 +146,7 @@ namespace WixToolset.Core.Bind | |||
137 | } | 146 | } |
138 | } | 147 | } |
139 | 148 | ||
140 | public AssemblyType? AssemblyType => this.FileRow == null ? this.AssemblyTuple?.Type : throw new NotImplementedException(); | 149 | public AssemblyType? AssemblyType => this.FileRow == null ? this.AssemblyTuple?.Type : null; |
141 | 150 | ||
142 | public string AssemblyApplicationFileRef => this.FileRow == null ? this.AssemblyTuple?.ApplicationFileRef : throw new NotImplementedException(); | 151 | public string AssemblyApplicationFileRef => this.FileRow == null ? this.AssemblyTuple?.ApplicationFileRef : throw new NotImplementedException(); |
143 | 152 | ||
@@ -153,5 +162,10 @@ namespace WixToolset.Core.Bind | |||
153 | /// Gets or sets the MsiFileHash row for this file. | 162 | /// Gets or sets the MsiFileHash row for this file. |
154 | /// </summary> | 163 | /// </summary> |
155 | public MsiFileHashTuple Hash { get; set; } | 164 | public MsiFileHashTuple Hash { get; set; } |
165 | |||
166 | /// <summary> | ||
167 | /// Allows direct access to the underlying FileRow as requried for patching. | ||
168 | /// </summary> | ||
169 | public FileRow GetFileRow() => this.FileRow ?? throw new NotImplementedException(); | ||
156 | } | 170 | } |
157 | } | 171 | } |
diff --git a/src/WixToolset.Core/CommandLine/BuildCommand.cs b/src/WixToolset.Core/CommandLine/BuildCommand.cs index 80003392..8392131f 100644 --- a/src/WixToolset.Core/CommandLine/BuildCommand.cs +++ b/src/WixToolset.Core/CommandLine/BuildCommand.cs | |||
@@ -334,6 +334,7 @@ namespace WixToolset.Core.CommandLine | |||
334 | context.DelayedFields = resolveResult.DelayedFields; | 334 | context.DelayedFields = resolveResult.DelayedFields; |
335 | context.ExpectedEmbeddedFiles = resolveResult.ExpectedEmbeddedFiles; | 335 | context.ExpectedEmbeddedFiles = resolveResult.ExpectedEmbeddedFiles; |
336 | context.Extensions = this.ExtensionManager.GetServices<IBinderExtension>(); | 336 | context.Extensions = this.ExtensionManager.GetServices<IBinderExtension>(); |
337 | context.FileSystemExtensions = this.ExtensionManager.GetServices<IFileSystemExtension>(); | ||
337 | context.Ices = Array.Empty<string>(); // TODO: set this correctly | 338 | context.Ices = Array.Empty<string>(); // TODO: set this correctly |
338 | context.IntermediateFolder = intermediateFolder; | 339 | context.IntermediateFolder = intermediateFolder; |
339 | context.IntermediateRepresentation = resolveResult.IntermediateRepresentation; | 340 | context.IntermediateRepresentation = resolveResult.IntermediateRepresentation; |
diff --git a/src/test/WixToolsetTest.CoreIntegration/PatchFixture.cs b/src/test/WixToolsetTest.CoreIntegration/PatchFixture.cs index 584f86fe..3616bcab 100644 --- a/src/test/WixToolsetTest.CoreIntegration/PatchFixture.cs +++ b/src/test/WixToolsetTest.CoreIntegration/PatchFixture.cs | |||
@@ -16,7 +16,7 @@ namespace WixToolsetTest.CoreIntegration | |||
16 | { | 16 | { |
17 | private static readonly XNamespace PatchNamespace = "http://www.microsoft.com/msi/patch_applicability.xsd"; | 17 | private static readonly XNamespace PatchNamespace = "http://www.microsoft.com/msi/patch_applicability.xsd"; |
18 | 18 | ||
19 | [Fact(Skip = "Skip until patches have files in them")] | 19 | [Fact] |
20 | public void CanBuildSimplePatch() | 20 | public void CanBuildSimplePatch() |
21 | { | 21 | { |
22 | var folder = TestData.Get(@"TestData\PatchSingle"); | 22 | var folder = TestData.Get(@"TestData\PatchSingle"); |
@@ -45,7 +45,7 @@ namespace WixToolsetTest.CoreIntegration | |||
45 | Assert.True(File.Exists(cab)); | 45 | Assert.True(File.Exists(cab)); |
46 | 46 | ||
47 | var files = Query.GetCabinetFiles(cab); | 47 | var files = Query.GetCabinetFiles(cab); |
48 | Assert.Equal(new[] { "a", "b" }, files.Select(f => f.ArchiveName).ToArray()); // This test may not be quite correct, yet. | 48 | Assert.Equal(new[] { "a.txt", "b.txt" }, files.Select(f => f.Name).ToArray()); |
49 | } | 49 | } |
50 | } | 50 | } |
51 | 51 | ||