aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorRob Mensching <rob@firegiant.com>2020-06-04 10:32:28 -0700
committerRob Mensching <rob@firegiant.com>2020-06-04 11:32:20 -0700
commitf89238b23402e33c2fc09b13a02217f03b722216 (patch)
treeb783409460e7ed00fd3e07ca1934c05ac0c6096b /src
parent110bfc5b5bfee7c4592d9898406d2250f3c96ca3 (diff)
downloadwix-f89238b23402e33c2fc09b13a02217f03b722216.tar.gz
wix-f89238b23402e33c2fc09b13a02217f03b722216.tar.bz2
wix-f89238b23402e33c2fc09b13a02217f03b722216.zip
Drive merge process from tuples not rows and fix merge table suppression
Diffstat (limited to 'src')
-rw-r--r--src/WixToolset.Core.WindowsInstaller/Bind/AddBackSuppresedSequenceTablesCommand.cs52
-rw-r--r--src/WixToolset.Core.WindowsInstaller/Bind/BindDatabaseCommand.cs24
-rw-r--r--src/WixToolset.Core.WindowsInstaller/Bind/MergeModulesCommand.cs141
3 files changed, 119 insertions, 98 deletions
diff --git a/src/WixToolset.Core.WindowsInstaller/Bind/AddBackSuppresedSequenceTablesCommand.cs b/src/WixToolset.Core.WindowsInstaller/Bind/AddBackSuppresedSequenceTablesCommand.cs
new file mode 100644
index 00000000..78bf7a29
--- /dev/null
+++ b/src/WixToolset.Core.WindowsInstaller/Bind/AddBackSuppresedSequenceTablesCommand.cs
@@ -0,0 +1,52 @@
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
3namespace WixToolset.Core.WindowsInstaller.Bind
4{
5 using System;
6 using System.Collections.Generic;
7 using WixToolset.Data.Tuples;
8 using WixToolset.Data.WindowsInstaller;
9
10 /// <summary>
11 /// Add back possibly suppressed sequence tables since all sequence tables must be present
12 /// for the merge process to work. We'll drop the suppressed sequence tables again as
13 /// necessary.
14 /// </summary>
15 internal class AddBackSuppresedSequenceTablesCommand
16 {
17 public AddBackSuppresedSequenceTablesCommand(WindowsInstallerData output, TableDefinitionCollection tableDefinitions)
18 {
19 this.Output = output;
20 this.TableDefinitions = tableDefinitions;
21 }
22
23 private WindowsInstallerData Output { get; }
24
25 private TableDefinitionCollection TableDefinitions { get; }
26
27 public IEnumerable<string> SuppressedTableNames { get; private set; }
28
29 public IEnumerable<string> Execute()
30 {
31 var suppressedTableNames = new HashSet<string>();
32
33 foreach (SequenceTable sequence in Enum.GetValues(typeof(SequenceTable)))
34 {
35 var sequenceTableName = sequence.WindowsInstallerTableName();
36 var sequenceTable = this.Output.Tables[sequenceTableName];
37
38 if (null == sequenceTable)
39 {
40 sequenceTable = this.Output.EnsureTable(this.TableDefinitions[sequenceTableName]);
41 }
42
43 if (0 == sequenceTable.Rows.Count)
44 {
45 suppressedTableNames.Add(sequenceTableName);
46 }
47 }
48
49 return this.SuppressedTableNames = suppressedTableNames;
50 }
51 }
52}
diff --git a/src/WixToolset.Core.WindowsInstaller/Bind/BindDatabaseCommand.cs b/src/WixToolset.Core.WindowsInstaller/Bind/BindDatabaseCommand.cs
index d9d246f5..8887d4eb 100644
--- a/src/WixToolset.Core.WindowsInstaller/Bind/BindDatabaseCommand.cs
+++ b/src/WixToolset.Core.WindowsInstaller/Bind/BindDatabaseCommand.cs
@@ -350,11 +350,16 @@ namespace WixToolset.Core.WindowsInstaller.Bind
350 output = command.Output; 350 output = command.Output;
351 } 351 }
352 352
353 // Modularize identifiers. 353 IEnumerable<string> suppressedTableNames = null;
354 if (output.Type == OutputType.Module) 354 if (output.Type == OutputType.Module)
355 { 355 {
356 var command = new ModularizeCommand(output, modularizationSuffix, section.Tuples.OfType<WixSuppressModularizationTuple>()); 356 // Modularize identifiers.
357 command.Execute(); 357 var modularize = new ModularizeCommand(output, modularizationSuffix, section.Tuples.OfType<WixSuppressModularizationTuple>());
358 modularize.Execute();
359
360 // Ensure all sequence tables in place because, mergemod.dll requires them.
361 var unsuppress = new AddBackSuppresedSequenceTablesCommand(output, tableDefinitions);
362 suppressedTableNames = unsuppress.Execute();
358 } 363 }
359 else if (output.Type == OutputType.Patch) 364 else if (output.Type == OutputType.Patch)
360 { 365 {
@@ -486,12 +491,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
486 { 491 {
487 this.Messaging.Write(VerboseMessages.MergingModules()); 492 this.Messaging.Write(VerboseMessages.MergingModules());
488 493
489 var command = new MergeModulesCommand(this.Messaging); 494 var command = new MergeModulesCommand(this.Messaging, fileFacades, section, suppressedTableNames, this.OutputPath, this.IntermediateFolder);
490 command.FileFacades = fileFacades;
491 command.IntermediateFolder = this.IntermediateFolder;
492 command.Output = output;
493 command.OutputPath = this.OutputPath;
494 command.TableDefinitions = tableDefinitions;
495 command.Execute(); 495 command.Execute();
496 } 496 }
497 497
@@ -591,7 +591,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
591 591
592 foreach (Data.WindowsInstaller.Rows.ComponentRow row in componentTable.Rows) 592 foreach (Data.WindowsInstaller.Rows.ComponentRow row in componentTable.Rows)
593 { 593 {
594 // we don't care about unmanaged components and if there's a * GUID remaining, 594 // We don't care about unmanaged components and if there's a * GUID remaining,
595 // 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.
596 if (!String.IsNullOrEmpty(row.Guid) && "*" != row.Guid) 596 if (!String.IsNullOrEmpty(row.Guid) && "*" != row.Guid)
597 { 597 {
@@ -633,13 +633,13 @@ namespace WixToolset.Core.WindowsInstaller.Bind
633 command.Execute(); 633 command.Execute();
634 } 634 }
635 635
636 private string ResolveMedia(MediaTuple mediaRow, string mediaLayoutDirectory, string layoutDirectory) 636 private string ResolveMedia(MediaTuple media, string mediaLayoutDirectory, string layoutDirectory)
637 { 637 {
638 string layout = null; 638 string layout = null;
639 639
640 foreach (var extension in this.BackendExtensions) 640 foreach (var extension in this.BackendExtensions)
641 { 641 {
642 layout = extension.ResolveMedia(mediaRow, mediaLayoutDirectory, layoutDirectory); 642 layout = extension.ResolveMedia(media, mediaLayoutDirectory, layoutDirectory);
643 if (!String.IsNullOrEmpty(layout)) 643 if (!String.IsNullOrEmpty(layout))
644 { 644 {
645 break; 645 break;
diff --git a/src/WixToolset.Core.WindowsInstaller/Bind/MergeModulesCommand.cs b/src/WixToolset.Core.WindowsInstaller/Bind/MergeModulesCommand.cs
index bddcccb7..1f85a33f 100644
--- a/src/WixToolset.Core.WindowsInstaller/Bind/MergeModulesCommand.cs
+++ b/src/WixToolset.Core.WindowsInstaller/Bind/MergeModulesCommand.cs
@@ -6,6 +6,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
6 using System.Collections.Generic; 6 using System.Collections.Generic;
7 using System.Globalization; 7 using System.Globalization;
8 using System.IO; 8 using System.IO;
9 using System.Linq;
9 using System.Runtime.InteropServices; 10 using System.Runtime.InteropServices;
10 using System.Text; 11 using System.Text;
11 using WixToolset.Core.Bind; 12 using WixToolset.Core.Bind;
@@ -14,65 +15,66 @@ namespace WixToolset.Core.WindowsInstaller.Bind
14 using WixToolset.Data; 15 using WixToolset.Data;
15 using WixToolset.Data.Tuples; 16 using WixToolset.Data.Tuples;
16 using WixToolset.Data.WindowsInstaller; 17 using WixToolset.Data.WindowsInstaller;
17 using WixToolset.Data.WindowsInstaller.Rows;
18 using WixToolset.Extensibility.Services; 18 using WixToolset.Extensibility.Services;
19 19
20 /// <summary> 20 /// <summary>
21 /// Update file information. 21 /// Merge modules into the database at output path.
22 /// </summary> 22 /// </summary>
23 internal class MergeModulesCommand 23 internal class MergeModulesCommand
24 { 24 {
25 public MergeModulesCommand(IMessaging messaging) 25 public MergeModulesCommand(IMessaging messaging, IEnumerable<FileFacade> fileFacades, IntermediateSection section, IEnumerable<string> suppressedTableNames, string outputPath, string intermediateFolder)
26 { 26 {
27 this.Messaging = messaging; 27 this.Messaging = messaging;
28 this.FileFacades = fileFacades;
29 this.Section = section;
30 this.SuppressedTableNames = suppressedTableNames ?? Array.Empty<string>();
31 this.OutputPath = outputPath;
32 this.IntermediateFolder = intermediateFolder;
28 } 33 }
29 34
30 public IEnumerable<FileFacade> FileFacades { private get; set; } 35 private IMessaging Messaging { get; }
31 36
32 public IMessaging Messaging { private get; set; } 37 private IEnumerable<FileFacade> FileFacades { get; }
33 38
34 public WindowsInstallerData Output { private get; set; } 39 private IntermediateSection Section { get; }
35 40
36 public string OutputPath { private get; set; } 41 private IEnumerable<string> SuppressedTableNames { get; }
37 42
38 public TableDefinitionCollection TableDefinitions { private get; set; } 43 private string OutputPath { get; }
39 44
40 public string IntermediateFolder { private get; set; } 45 private string IntermediateFolder { get; }
41 46
42 public void Execute() 47 public void Execute()
43 { 48 {
44 Table wixMergeTable = this.Output.Tables["WixMerge"]; 49 var wixMergeTuples = this.Section.Tuples.OfType<WixMergeTuple>().ToList();
45 Table wixFeatureModulesTable = this.Output.Tables["WixFeatureModules"]; 50 if (!wixMergeTuples.Any())
46
47 // check for merge rows to see if there is any work to do
48 if (null == wixMergeTable || 0 == wixMergeTable.Rows.Count)
49 { 51 {
50 return; 52 return;
51 } 53 }
52 54
53 var suppressedTableNames = this.AddBackSuppresedSequenceTables();
54
55 IMsmMerge2 merge = null; 55 IMsmMerge2 merge = null;
56 bool commit = true; 56 var commit = true;
57 bool logOpen = false; 57 var logOpen = false;
58 bool databaseOpen = false; 58 var databaseOpen = false;
59 string logPath = null; 59 var logPath = Path.Combine(this.IntermediateFolder, "merge.log");
60
60 try 61 try
61 { 62 {
62 var interop = new MsmInterop(); 63 var interop = new MsmInterop();
63 merge = interop.GetMsmMerge(); 64 merge = interop.GetMsmMerge();
64 65
65 logPath = Path.Combine(this.IntermediateFolder, "merge.log");
66 merge.OpenLog(logPath); 66 merge.OpenLog(logPath);
67 logOpen = true; 67 logOpen = true;
68 68
69 merge.OpenDatabase(this.OutputPath); 69 merge.OpenDatabase(this.OutputPath);
70 databaseOpen = true; 70 databaseOpen = true;
71 71
72 var featureModulesByMergeId = this.Section.Tuples.OfType<WixFeatureModulesTuple>().GroupBy(t => t.WixMergeRef).ToDictionary(g => g.Key);
73
72 // process all the merge rows 74 // process all the merge rows
73 foreach (WixMergeRow wixMergeRow in wixMergeTable.Rows) 75 foreach (var wixMergeRow in wixMergeTuples)
74 { 76 {
75 bool moduleOpen = false; 77 var moduleOpen = false;
76 78
77 try 79 try
78 { 80 {
@@ -84,7 +86,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
84 } 86 }
85 catch (FormatException) 87 catch (FormatException)
86 { 88 {
87 this.Messaging.Write(ErrorMessages.InvalidMergeLanguage(wixMergeRow.SourceLineNumbers, wixMergeRow.Id, wixMergeRow.Language)); 89 this.Messaging.Write(ErrorMessages.InvalidMergeLanguage(wixMergeRow.SourceLineNumbers, wixMergeRow.Id.Id, wixMergeRow.Language.ToString()));
88 continue; 90 continue;
89 } 91 }
90 92
@@ -99,20 +101,17 @@ namespace WixToolset.Core.WindowsInstaller.Bind
99 callback = new ConfigurationCallback(wixMergeRow.ConfigurationData); 101 callback = new ConfigurationCallback(wixMergeRow.ConfigurationData);
100 } 102 }
101 103
102 // merge the module into the database that's being built 104 // Merge the module into the database that's being built.
103 this.Messaging.Write(VerboseMessages.MergingMergeModule(wixMergeRow.SourceFile)); 105 this.Messaging.Write(VerboseMessages.MergingMergeModule(wixMergeRow.SourceFile));
104 merge.MergeEx(wixMergeRow.Feature, wixMergeRow.Directory, callback); 106 merge.MergeEx(wixMergeRow.FeatureRef, wixMergeRow.DirectoryRef, callback);
105 107
106 // connect any non-primary features 108 // Connect any non-primary features.
107 if (null != wixFeatureModulesTable) 109 if (featureModulesByMergeId.TryGetValue(wixMergeRow.Id.Id, out var featureModules))
108 { 110 {
109 foreach (Row row in wixFeatureModulesTable.Rows) 111 foreach (var featureModule in featureModules)
110 { 112 {
111 if (wixMergeRow.Id == (string)row[1]) 113 this.Messaging.Write(VerboseMessages.ConnectingMergeModule(wixMergeRow.SourceFile, featureModule.FeatureRef));
112 { 114 merge.Connect(featureModule.FeatureRef);
113 this.Messaging.Write(VerboseMessages.ConnectingMergeModule(wixMergeRow.SourceFile, (string)row[0]));
114 merge.Connect((string)row[0]);
115 }
116 } 115 }
117 } 116 }
118 } 117 }
@@ -122,17 +121,17 @@ namespace WixToolset.Core.WindowsInstaller.Bind
122 } 121 }
123 finally 122 finally
124 { 123 {
125 IMsmErrors mergeErrors = merge.Errors; 124 var mergeErrors = merge.Errors;
126 125
127 // display all the errors encountered during the merge operations for this module 126 // display all the errors encountered during the merge operations for this module
128 for (int i = 1; i <= mergeErrors.Count; i++) 127 for (var i = 1; i <= mergeErrors.Count; i++)
129 { 128 {
130 IMsmError mergeError = mergeErrors[i]; 129 var mergeError = mergeErrors[i];
131 StringBuilder databaseKeys = new StringBuilder(); 130 var databaseKeys = new StringBuilder();
132 StringBuilder moduleKeys = new StringBuilder(); 131 var moduleKeys = new StringBuilder();
133 132
134 // build a string of the database keys 133 // build a string of the database keys
135 for (int j = 1; j <= mergeError.DatabaseKeys.Count; j++) 134 for (var j = 1; j <= mergeError.DatabaseKeys.Count; j++)
136 { 135 {
137 if (1 != j) 136 if (1 != j)
138 { 137 {
@@ -142,7 +141,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
142 } 141 }
143 142
144 // build a string of the module keys 143 // build a string of the module keys
145 for (int j = 1; j <= mergeError.ModuleKeys.Count; j++) 144 for (var j = 1; j <= mergeError.ModuleKeys.Count; j++)
146 { 145 {
147 if (1 != j) 146 if (1 != j)
148 { 147 {
@@ -155,10 +154,10 @@ namespace WixToolset.Core.WindowsInstaller.Bind
155 switch (mergeError.Type) 154 switch (mergeError.Type)
156 { 155 {
157 case MsmErrorType.msmErrorExclusion: 156 case MsmErrorType.msmErrorExclusion:
158 this.Messaging.Write(ErrorMessages.MergeExcludedModule(wixMergeRow.SourceLineNumbers, wixMergeRow.Id, moduleKeys.ToString())); 157 this.Messaging.Write(ErrorMessages.MergeExcludedModule(wixMergeRow.SourceLineNumbers, wixMergeRow.Id.Id, moduleKeys.ToString()));
159 break; 158 break;
160 case MsmErrorType.msmErrorFeatureRequired: 159 case MsmErrorType.msmErrorFeatureRequired:
161 this.Messaging.Write(ErrorMessages.MergeFeatureRequired(wixMergeRow.SourceLineNumbers, mergeError.ModuleTable, moduleKeys.ToString(), wixMergeRow.SourceFile, wixMergeRow.Id)); 160 this.Messaging.Write(ErrorMessages.MergeFeatureRequired(wixMergeRow.SourceLineNumbers, mergeError.ModuleTable, moduleKeys.ToString(), wixMergeRow.SourceFile, wixMergeRow.Id.Id));
162 break; 161 break;
163 case MsmErrorType.msmErrorLanguageFailed: 162 case MsmErrorType.msmErrorLanguageFailed:
164 this.Messaging.Write(ErrorMessages.MergeLanguageFailed(wixMergeRow.SourceLineNumbers, mergeError.Language, wixMergeRow.SourceFile)); 163 this.Messaging.Write(ErrorMessages.MergeLanguageFailed(wixMergeRow.SourceLineNumbers, mergeError.Language, wixMergeRow.SourceFile));
@@ -217,32 +216,28 @@ namespace WixToolset.Core.WindowsInstaller.Bind
217 216
218 using (var db = new Database(this.OutputPath, OpenDatabase.Direct)) 217 using (var db = new Database(this.OutputPath, OpenDatabase.Direct))
219 { 218 {
220 var suppressActionTable = this.Output.Tables["WixSuppressAction"]; 219 // Suppress individual actions.
221 220 foreach (var suppressAction in this.Section.Tuples.OfType<WixSuppressActionTuple>())
222 // suppress individual actions
223 if (null != suppressActionTable)
224 { 221 {
225 foreach (Row row in suppressActionTable.Rows) 222 var tableName = suppressAction.SequenceTable.WindowsInstallerTableName();
223 if (db.TableExists(tableName))
226 { 224 {
227 if (db.TableExists((string)row[0])) 225 var query = $"SELECT * FROM {tableName} WHERE `Action` = '{suppressAction.Action}'";
228 {
229 string query = String.Format(CultureInfo.InvariantCulture, "SELECT * FROM {0} WHERE `Action` = '{1}'", row[0].ToString(), (string)row[1]);
230 226
231 using (View view = db.OpenExecuteView(query)) 227 using (var view = db.OpenExecuteView(query))
232 using (Record record = view.Fetch()) 228 using (var record = view.Fetch())
229 {
230 if (null != record)
233 { 231 {
234 if (null != record) 232 this.Messaging.Write(WarningMessages.SuppressMergedAction(suppressAction.Action, tableName));
235 { 233 view.Modify(ModifyView.Delete, record);
236 this.Messaging.Write(WarningMessages.SuppressMergedAction((string)row[1], row[0].ToString()));
237 view.Modify(ModifyView.Delete, record);
238 }
239 } 234 }
240 } 235 }
241 } 236 }
242 } 237 }
243 238
244 // query for merge module actions in suppressed sequences and drop them 239 // Query for merge module actions in suppressed sequences and drop them.
245 foreach (var tableName in suppressedTableNames) 240 foreach (var tableName in this.SuppressedTableNames)
246 { 241 {
247 if (!db.TableExists(tableName)) 242 if (!db.TableExists(tableName))
248 { 243 {
@@ -333,31 +328,5 @@ namespace WixToolset.Core.WindowsInstaller.Bind
333 db.Commit(); 328 db.Commit();
334 } 329 }
335 } 330 }
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 }
362 } 331 }
363} 332}