aboutsummaryrefslogtreecommitdiff
path: root/src/WixToolset.Core/Bind/Databases/MergeModulesCommand.cs
diff options
context:
space:
mode:
Diffstat (limited to 'src/WixToolset.Core/Bind/Databases/MergeModulesCommand.cs')
-rw-r--r--src/WixToolset.Core/Bind/Databases/MergeModulesCommand.cs350
1 files changed, 0 insertions, 350 deletions
diff --git a/src/WixToolset.Core/Bind/Databases/MergeModulesCommand.cs b/src/WixToolset.Core/Bind/Databases/MergeModulesCommand.cs
deleted file mode 100644
index 035ef059..00000000
--- a/src/WixToolset.Core/Bind/Databases/MergeModulesCommand.cs
+++ /dev/null
@@ -1,350 +0,0 @@
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.Bind.Databases
4{
5 using System;
6 using System.Collections.Generic;
7 using System.Collections.Specialized;
8 using System.ComponentModel;
9 using System.Diagnostics;
10 using System.Globalization;
11 using System.IO;
12 using System.Linq;
13 using System.Runtime.InteropServices;
14 using System.Text;
15 using System.Xml;
16 using System.Xml.XPath;
17 using WixToolset.Clr.Interop;
18 using WixToolset.Data;
19 using WixToolset.Data.Rows;
20 using WixToolset.MergeMod;
21 using WixToolset.Msi;
22 using WixToolset.Core.Native;
23
24 /// <summary>
25 /// Update file information.
26 /// </summary>
27 internal class MergeModulesCommand : ICommand
28 {
29 public IEnumerable<FileFacade> FileFacades { private get; set; }
30
31 public Output Output { private get; set; }
32
33 public string OutputPath { private get; set; }
34
35 public IEnumerable<string> SuppressedTableNames { private get; set; }
36
37 public string TempFilesLocation { private get; set; }
38
39 public void Execute()
40 {
41 Debug.Assert(OutputType.Product == this.Output.Type);
42
43 Table wixMergeTable = this.Output.Tables["WixMerge"];
44 Table wixFeatureModulesTable = this.Output.Tables["WixFeatureModules"];
45
46 // check for merge rows to see if there is any work to do
47 if (null == wixMergeTable || 0 == wixMergeTable.Rows.Count)
48 {
49 return;
50 }
51
52 IMsmMerge2 merge = null;
53 bool commit = true;
54 bool logOpen = false;
55 bool databaseOpen = false;
56 string logPath = null;
57 try
58 {
59 merge = MsmInterop.GetMsmMerge();
60
61 logPath = Path.Combine(this.TempFilesLocation, "merge.log");
62 merge.OpenLog(logPath);
63 logOpen = true;
64
65 merge.OpenDatabase(this.OutputPath);
66 databaseOpen = true;
67
68 // process all the merge rows
69 foreach (WixMergeRow wixMergeRow in wixMergeTable.Rows)
70 {
71 bool moduleOpen = false;
72
73 try
74 {
75 short mergeLanguage;
76
77 try
78 {
79 mergeLanguage = Convert.ToInt16(wixMergeRow.Language, CultureInfo.InvariantCulture);
80 }
81 catch (System.FormatException)
82 {
83 Messaging.Instance.OnMessage(WixErrors.InvalidMergeLanguage(wixMergeRow.SourceLineNumbers, wixMergeRow.Id, wixMergeRow.Language));
84 continue;
85 }
86
87 Messaging.Instance.OnMessage(WixVerboses.OpeningMergeModule(wixMergeRow.SourceFile, mergeLanguage));
88 merge.OpenModule(wixMergeRow.SourceFile, mergeLanguage);
89 moduleOpen = true;
90
91 // If there is merge configuration data, create a callback object to contain it all.
92 ConfigurationCallback callback = null;
93 if (!String.IsNullOrEmpty(wixMergeRow.ConfigurationData))
94 {
95 callback = new ConfigurationCallback(wixMergeRow.ConfigurationData);
96 }
97
98 // merge the module into the database that's being built
99 Messaging.Instance.OnMessage(WixVerboses.MergingMergeModule(wixMergeRow.SourceFile));
100 merge.MergeEx(wixMergeRow.Feature, wixMergeRow.Directory, callback);
101
102 // connect any non-primary features
103 if (null != wixFeatureModulesTable)
104 {
105 foreach (Row row in wixFeatureModulesTable.Rows)
106 {
107 if (wixMergeRow.Id == (string)row[1])
108 {
109 Messaging.Instance.OnMessage(WixVerboses.ConnectingMergeModule(wixMergeRow.SourceFile, (string)row[0]));
110 merge.Connect((string)row[0]);
111 }
112 }
113 }
114 }
115 catch (COMException)
116 {
117 commit = false;
118 }
119 finally
120 {
121 IMsmErrors mergeErrors = merge.Errors;
122
123 // display all the errors encountered during the merge operations for this module
124 for (int i = 1; i <= mergeErrors.Count; i++)
125 {
126 IMsmError mergeError = mergeErrors[i];
127 StringBuilder databaseKeys = new StringBuilder();
128 StringBuilder moduleKeys = new StringBuilder();
129
130 // build a string of the database keys
131 for (int j = 1; j <= mergeError.DatabaseKeys.Count; j++)
132 {
133 if (1 != j)
134 {
135 databaseKeys.Append(';');
136 }
137 databaseKeys.Append(mergeError.DatabaseKeys[j]);
138 }
139
140 // build a string of the module keys
141 for (int j = 1; j <= mergeError.ModuleKeys.Count; j++)
142 {
143 if (1 != j)
144 {
145 moduleKeys.Append(';');
146 }
147 moduleKeys.Append(mergeError.ModuleKeys[j]);
148 }
149
150 // display the merge error based on the msm error type
151 switch (mergeError.Type)
152 {
153 case MsmErrorType.msmErrorExclusion:
154 Messaging.Instance.OnMessage(WixErrors.MergeExcludedModule(wixMergeRow.SourceLineNumbers, wixMergeRow.Id, moduleKeys.ToString()));
155 break;
156 case MsmErrorType.msmErrorFeatureRequired:
157 Messaging.Instance.OnMessage(WixErrors.MergeFeatureRequired(wixMergeRow.SourceLineNumbers, mergeError.ModuleTable, moduleKeys.ToString(), wixMergeRow.SourceFile, wixMergeRow.Id));
158 break;
159 case MsmErrorType.msmErrorLanguageFailed:
160 Messaging.Instance.OnMessage(WixErrors.MergeLanguageFailed(wixMergeRow.SourceLineNumbers, mergeError.Language, wixMergeRow.SourceFile));
161 break;
162 case MsmErrorType.msmErrorLanguageUnsupported:
163 Messaging.Instance.OnMessage(WixErrors.MergeLanguageUnsupported(wixMergeRow.SourceLineNumbers, mergeError.Language, wixMergeRow.SourceFile));
164 break;
165 case MsmErrorType.msmErrorResequenceMerge:
166 Messaging.Instance.OnMessage(WixWarnings.MergeRescheduledAction(wixMergeRow.SourceLineNumbers, mergeError.DatabaseTable, databaseKeys.ToString(), wixMergeRow.SourceFile));
167 break;
168 case MsmErrorType.msmErrorTableMerge:
169 if ("_Validation" != mergeError.DatabaseTable) // ignore merge errors in the _Validation table
170 {
171 Messaging.Instance.OnMessage(WixWarnings.MergeTableFailed(wixMergeRow.SourceLineNumbers, mergeError.DatabaseTable, databaseKeys.ToString(), wixMergeRow.SourceFile));
172 }
173 break;
174 case MsmErrorType.msmErrorPlatformMismatch:
175 Messaging.Instance.OnMessage(WixErrors.MergePlatformMismatch(wixMergeRow.SourceLineNumbers, wixMergeRow.SourceFile));
176 break;
177 default:
178 Messaging.Instance.OnMessage(WixErrors.UnexpectedException(String.Format(CultureInfo.CurrentUICulture, WixStrings.EXP_UnexpectedMergerErrorWithType, Enum.GetName(typeof(MsmErrorType), mergeError.Type), logPath), "InvalidOperationException", Environment.StackTrace));
179 break;
180 }
181 }
182
183 if (0 >= mergeErrors.Count && !commit)
184 {
185 Messaging.Instance.OnMessage(WixErrors.UnexpectedException(String.Format(CultureInfo.CurrentUICulture, WixStrings.EXP_UnexpectedMergerErrorInSourceFile, wixMergeRow.SourceFile, logPath), "InvalidOperationException", Environment.StackTrace));
186 }
187
188 if (moduleOpen)
189 {
190 merge.CloseModule();
191 }
192 }
193 }
194 }
195 finally
196 {
197 if (databaseOpen)
198 {
199 merge.CloseDatabase(commit);
200 }
201
202 if (logOpen)
203 {
204 merge.CloseLog();
205 }
206 }
207
208 // stop processing if an error previously occurred
209 if (Messaging.Instance.EncounteredError)
210 {
211 return;
212 }
213
214 using (Database db = new Database(this.OutputPath, OpenDatabase.Direct))
215 {
216 Table suppressActionTable = this.Output.Tables["WixSuppressAction"];
217
218 // suppress individual actions
219 if (null != suppressActionTable)
220 {
221 foreach (Row row in suppressActionTable.Rows)
222 {
223 if (db.TableExists((string)row[0]))
224 {
225 string query = String.Format(CultureInfo.InvariantCulture, "SELECT * FROM {0} WHERE `Action` = '{1}'", row[0].ToString(), (string)row[1]);
226
227 using (View view = db.OpenExecuteView(query))
228 {
229 using (Record record = view.Fetch())
230 {
231 if (null != record)
232 {
233 Messaging.Instance.OnMessage(WixWarnings.SuppressMergedAction((string)row[1], row[0].ToString()));
234 view.Modify(ModifyView.Delete, record);
235 }
236 }
237 }
238 }
239 }
240 }
241
242 // query for merge module actions in suppressed sequences and drop them
243 foreach (string tableName in this.SuppressedTableNames)
244 {
245 if (!db.TableExists(tableName))
246 {
247 continue;
248 }
249
250 using (View view = db.OpenExecuteView(String.Concat("SELECT `Action` FROM ", tableName)))
251 {
252 while (true)
253 {
254 using (Record resultRecord = view.Fetch())
255 {
256 if (null == resultRecord)
257 {
258 break;
259 }
260
261 Messaging.Instance.OnMessage(WixWarnings.SuppressMergedAction(resultRecord.GetString(1), tableName));
262 }
263 }
264 }
265
266 // drop suppressed sequences
267 using (View view = db.OpenExecuteView(String.Concat("DROP TABLE ", tableName)))
268 {
269 }
270
271 // delete the validation rows
272 using (View view = db.OpenView(String.Concat("DELETE FROM _Validation WHERE `Table` = ?")))
273 {
274 using (Record record = new Record(1))
275 {
276 record.SetString(1, tableName);
277 view.Execute(record);
278 }
279 }
280 }
281
282 // now update the Attributes column for the files from the Merge Modules
283 Messaging.Instance.OnMessage(WixVerboses.ResequencingMergeModuleFiles());
284 using (View view = db.OpenView("SELECT `Sequence`, `Attributes` FROM `File` WHERE `File`=?"))
285 {
286 foreach (FileFacade file in this.FileFacades)
287 {
288 if (!file.FromModule)
289 {
290 continue;
291 }
292
293 using (Record record = new Record(1))
294 {
295 record.SetString(1, file.File.File);
296 view.Execute(record);
297 }
298
299 using (Record recordUpdate = view.Fetch())
300 {
301 if (null == recordUpdate)
302 {
303 throw new InvalidOperationException("Failed to fetch a File row from the database that was merged in from a module.");
304 }
305
306 recordUpdate.SetInteger(1, file.File.Sequence);
307
308 // update the file attributes to match the compression specified
309 // on the Merge element or on the Package element
310 int attributes = 0;
311
312 // get the current value if its not null
313 if (!recordUpdate.IsNull(2))
314 {
315 attributes = recordUpdate.GetInteger(2);
316 }
317
318 if (YesNoType.Yes == file.File.Compressed)
319 {
320 // these are mutually exclusive
321 attributes |= MsiInterop.MsidbFileAttributesCompressed;
322 attributes &= ~MsiInterop.MsidbFileAttributesNoncompressed;
323 }
324 else if (YesNoType.No == file.File.Compressed)
325 {
326 // these are mutually exclusive
327 attributes |= MsiInterop.MsidbFileAttributesNoncompressed;
328 attributes &= ~MsiInterop.MsidbFileAttributesCompressed;
329 }
330 else // not specified
331 {
332 Debug.Assert(YesNoType.NotSet == file.File.Compressed);
333
334 // clear any compression bits
335 attributes &= ~MsiInterop.MsidbFileAttributesCompressed;
336 attributes &= ~MsiInterop.MsidbFileAttributesNoncompressed;
337 }
338
339 recordUpdate.SetInteger(2, attributes);
340
341 view.Modify(ModifyView.Update, recordUpdate);
342 }
343 }
344 }
345
346 db.Commit();
347 }
348 }
349 }
350}