Implement Bundle build
Rob Mensching committed
Oct 7, 2019 at 11:18 UTC
860676fa5b40a1904478151e9b4934c004e7db63
62 files changed
+2240
-2151
appveyor.cmd
+2
-2
@@ -2,13 +2,13 @@
2
@pushd %~dp0
3
@set _P=%~dp0build\Release\publish
4
5
+dotnet test -c Release src\test\WixToolsetTest.CoreIntegration
6
+
7
dotnet pack -c Release src\WixToolset.Core
8
dotnet pack -c Release src\WixToolset.Core.Burn
9
dotnet pack -c Release src\WixToolset.Core.WindowsInstaller
10
11
dotnet pack -c Release src\WixToolset.Core.TestPackage
12
11
-dotnet build -c Release src\test\WixToolsetTest.CoreIntegration
12
-
13
@popd
14
@endlocal
src/WixToolset.Core.Burn/Bind/BindBundleCommand.cs
+242
-618
@@ -8,78 +8,51 @@ namespace WixToolset.Core.Burn
8
using System.Globalization;
9
using System.IO;
10
using System.Linq;
11
- using System.Reflection;
11
using WixToolset.Core.Bind;
12
+ using WixToolset.Core.Burn.Bind;
13
using WixToolset.Core.Burn.Bundles;
14
using WixToolset.Data;
15
- using WixToolset.Data.Bind;
15
+ using WixToolset.Data.Burn;
16
+ using WixToolset.Data.Tuples;
17
using WixToolset.Extensibility;
18
using WixToolset.Extensibility.Data;
19
using WixToolset.Extensibility.Services;
20
20
- // TODO: (4.0) Refactor so that these don't need to be copied.
21
- // Copied verbatim from ext\UtilExtension\wixext\UtilCompiler.cs
22
- [Flags]
23
- internal enum WixFileSearchAttributes
24
- {
25
- Default = 0x001,
26
- MinVersionInclusive = 0x002,
27
- MaxVersionInclusive = 0x004,
28
- MinSizeInclusive = 0x008,
29
- MaxSizeInclusive = 0x010,
30
- MinDateInclusive = 0x020,
31
- MaxDateInclusive = 0x040,
32
- WantVersion = 0x080,
33
- WantExists = 0x100,
34
- IsDirectory = 0x200,
35
- }
36
-
37
- [Flags]
38
- internal enum WixRegistrySearchAttributes
39
- {
40
- Raw = 0x01,
41
- Compatible = 0x02,
42
- ExpandEnvironmentVariables = 0x04,
43
- WantValue = 0x08,
44
- WantExists = 0x10,
45
- Win64 = 0x20,
46
- }
47
-
48
- internal enum WixComponentSearchAttributes
49
- {
50
- KeyPath = 0x1,
51
- State = 0x2,
52
- WantDirectory = 0x4,
53
- }
54
-
55
- [Flags]
56
- internal enum WixProductSearchAttributes
57
- {
58
- Version = 0x1,
59
- Language = 0x2,
60
- State = 0x4,
61
- Assignment = 0x8,
62
- UpgradeCode = 0x10,
63
- }
64
-
21
/// <summary>
22
/// Binds a this.bundle.
23
/// </summary>
24
internal class BindBundleCommand
25
{
70
- public BindBundleCommand(IBindContext context)
26
+ public BindBundleCommand(IBindContext context, IEnumerable<IBurnBackendExtension> backedExtensions)
27
{
72
- //this.TableDefinitions = WindowsInstallerStandard.GetTableDefinitions();
28
+ this.ServiceProvider = context.ServiceProvider;
29
+
30
+ this.Messaging = context.ServiceProvider.GetService<IMessaging>();
31
+
32
+ this.BackendHelper = context.ServiceProvider.GetService<IBackendHelper>();
33
34
+ this.BurnStubPath = context.BurnStubPath;
35
+ this.DefaultCompressionLevel = context.DefaultCompressionLevel;
36
this.DelayedFields = context.DelayedFields;
37
this.ExpectedEmbeddedFiles = context.ExpectedEmbeddedFiles;
38
+ this.IntermediateFolder = context.IntermediateFolder;
39
+ this.Output = context.IntermediateRepresentation;
40
+ this.OutputPath = context.OutputPath;
41
+ this.OutputPdbPath = context.OutputPdbPath;
42
+ //this.VariableResolver = context.VariableResolver;
43
77
- var extensionManager = context.ServiceProvider.GetService<IExtensionManager>();
78
-
79
- this.BackendExtensions = extensionManager.GetServices<IBurnBackendExtension>();
44
+ this.BackendExtensions = backedExtensions;
45
}
46
82
- public CompressionLevel DefaultCompressionLevel { private get; set; }
47
+ private IServiceProvider ServiceProvider { get; }
48
+
49
+ private IMessaging Messaging { get; }
50
+
51
+ private IBackendHelper BackendHelper { get; }
52
+
53
+ private string BurnStubPath { get; }
54
+
55
+ private CompressionLevel? DefaultCompressionLevel { get; }
56
57
public IEnumerable<IDelayedField> DelayedFields { get; }
58
@@ -87,17 +60,15 @@ namespace WixToolset.Core.Burn
60
61
private IEnumerable<IBurnBackendExtension> BackendExtensions { get; }
62
90
- public Intermediate Output { private get; set; }
91
-
92
- public string OutputPath { private get; set; }
63
+ private Intermediate Output { get; }
64
94
- public string PdbFile { private get; set; }
65
+ private string OutputPath { get; }
66
96
- //public TableDefinitionCollection TableDefinitions { private get; set; }
67
+ private string OutputPdbPath { get; }
68
98
- public string IntermediateFolder { private get; set; }
69
+ private string IntermediateFolder { get; }
70
100
- public IVariableResolver VariableResolver { private get; set; }
71
+ private IVariableResolver VariableResolver { get; }
72
73
public IEnumerable<IFileTransfer> FileTransfers { get; private set; }
74
@@ -105,196 +76,177 @@ namespace WixToolset.Core.Burn
76
77
public void Execute()
78
{
108
- throw new NotImplementedException();
109
-#if TODO
110
- this.FileTransfers = Enumerable.Empty<FileTransfer>();
111
- this.ContentFilePaths = Enumerable.Empty<string>();
79
+ var section = this.Output.Sections.Single();
80
+
81
+ var fileTransfers = new List<IFileTransfer>();
82
+ var trackedFiles = new List<ITrackedFile>();
83
84
// First look for data we expect to find... Chain, WixGroups, etc.
85
86
// We shouldn't really get past the linker phase if there are
87
// no group items... that means that there's no UX, no Chain,
88
// *and* no Containers!
118
- Table chainPackageTable = this.GetRequiredTable("WixBundlePackage");
89
+ var chainPackageTuples = this.GetRequiredTuples<WixBundlePackageTuple>();
90
120
- Table wixGroupTable = this.GetRequiredTable("WixGroup");
91
+ var wixGroupTuples = this.GetRequiredTuples<WixGroupTuple>();
92
93
// Ensure there is one and only one row in the WixBundle table.
94
// The compiler and linker behavior should have colluded to get
95
// this behavior.
125
- WixBundleRow bundleRow = (WixBundleRow)this.GetSingleRowTable("WixBundle");
96
+ var bundleTuple = this.GetSingleTuple<WixBundleTuple>();
97
+
98
+ bundleTuple.BundleId = Guid.NewGuid().ToString("B").ToUpperInvariant();
99
127
- bundleRow.PerMachine = true; // default to per-machine but the first-per user package wil flip the bundle per-user.
100
+ bundleTuple.Attributes |= WixBundleAttributes.PerMachine; // default to per-machine but the first-per user package wil flip the bundle per-user.
101
102
// Ensure there is one and only one row in the WixBootstrapperApplication table.
103
// The compiler and linker behavior should have colluded to get
104
// this behavior.
132
- Row baRow = this.GetSingleRowTable("WixBootstrapperApplication");
105
+ var bundleApplicationTuple = this.GetSingleTuple<WixBootstrapperApplicationTuple>();
106
107
// Ensure there is one and only one row in the WixChain table.
108
// The compiler and linker behavior should have colluded to get
109
// this behavior.
137
- WixChainRow chainRow = (WixChainRow)this.GetSingleRowTable("WixChain");
110
+ var chainTuple = this.GetSingleTuple<WixChainTuple>();
111
139
- if (Messaging.Instance.EncounteredError)
112
+ if (this.Messaging.EncounteredError)
113
{
114
return;
115
}
116
117
// If there are any fields to resolve later, create the cache to populate during bind.
145
- IDictionary<string, string> variableCache = null;
146
- if (this.DelayedFields.Any())
147
- {
148
- variableCache = new Dictionary<string, string>(StringComparer.InvariantCultureIgnoreCase);
149
- }
118
+ var variableCache = this.DelayedFields.Any() ? new Dictionary<string, string>(StringComparer.InvariantCultureIgnoreCase) : null;
119
120
// TODO: Although the WixSearch tables are defined in the Util extension,
121
// the Bundle Binder has to know all about them. We hope to revisit all
122
// of this in the 4.0 timeframe.
154
- IEnumerable<WixSearchInfo> orderedSearches = this.OrderSearches();
123
+ var orderedSearches = this.OrderSearches(section);
124
125
+#if THIS_SHOULD_BE_DELETED_SINCE_RESOLVE_DOES_THIS_NOW
126
// Extract files that come from cabinet files (this does not extract files from merge modules).
127
{
128
var extractEmbeddedFilesCommand = new ExtractEmbeddedFilesCommand();
129
extractEmbeddedFilesCommand.FilesWithEmbeddedFiles = ExpectedEmbeddedFiles;
130
extractEmbeddedFilesCommand.Execute();
131
}
132
+#endif
133
134
// Get the explicit payloads.
164
- RowDictionary<WixBundlePayloadRow> payloads = new RowDictionary<WixBundlePayloadRow>(this.Output.Tables["WixBundlePayload"]);
135
+ var payloadTuples = section.Tuples.OfType<WixBundlePayloadTuple>().ToDictionary(t => t.Id.Id);
136
137
// Update explicitly authored payloads with their parent package and container (as appropriate)
138
// to make it easier to gather the payloads later.
168
- foreach (WixGroupRow row in wixGroupTable.RowsAs<WixGroupRow>())
139
+ foreach (var groupTuple in wixGroupTuples)
140
{
170
- if (ComplexReferenceChildType.Payload == row.ChildType)
141
+ if (ComplexReferenceChildType.Payload == groupTuple.ChildType)
142
{
172
- WixBundlePayloadRow payload = payloads.Get(row.ChildId);
143
+ var payloadTuple = payloadTuples[groupTuple.ChildId];
144
174
- if (ComplexReferenceParentType.Package == row.ParentType)
145
+ if (ComplexReferenceParentType.Package == groupTuple.ParentType)
146
{
176
- Debug.Assert(String.IsNullOrEmpty(payload.Package));
177
- payload.Package = row.ParentId;
147
+ Debug.Assert(String.IsNullOrEmpty(payloadTuple.PackageRef));
148
+ payloadTuple.PackageRef = groupTuple.ParentId;
149
}
179
- else if (ComplexReferenceParentType.Container == row.ParentType)
150
+ else if (ComplexReferenceParentType.Container == groupTuple.ParentType)
151
{
181
- Debug.Assert(String.IsNullOrEmpty(payload.Container));
182
- payload.Container = row.ParentId;
152
+ Debug.Assert(String.IsNullOrEmpty(payloadTuple.ContainerRef));
153
+ payloadTuple.ContainerRef = groupTuple.ParentId;
154
}
184
- else if (ComplexReferenceParentType.Layout == row.ParentType)
155
+ else if (ComplexReferenceParentType.Layout == groupTuple.ParentType)
156
{
186
- payload.LayoutOnly = true;
157
+ payloadTuple.LayoutOnly = true;
158
}
159
}
160
}
161
191
- List<FileTransfer> fileTransfers = new List<FileTransfer>();
192
- string layoutDirectory = Path.GetDirectoryName(this.OutputPath);
162
+ var layoutDirectory = Path.GetDirectoryName(this.OutputPath);
163
164
// Process the explicitly authored payloads.
165
ISet<string> processedPayloads;
166
{
197
- ProcessPayloadsCommand command = new ProcessPayloadsCommand();
198
- command.Payloads = payloads.Values;
199
- command.DefaultPackaging = bundleRow.DefaultPackagingType;
200
- command.LayoutDirectory = layoutDirectory;
167
+ var command = new ProcessPayloadsCommand(this.ServiceProvider, this.BackendHelper, payloadTuples.Values, bundleTuple.DefaultPackagingType, layoutDirectory);
168
command.Execute();
169
170
fileTransfers.AddRange(command.FileTransfers);
171
205
- processedPayloads = new HashSet<string>(payloads.Keys);
172
+ processedPayloads = new HashSet<string>(payloadTuples.Keys);
173
}
174
175
IDictionary<string, PackageFacade> facades;
176
{
210
- GetPackageFacadesCommand command = new GetPackageFacadesCommand();
211
- command.PackageTable = chainPackageTable;
212
- command.ExePackageTable = this.Output.Tables["WixBundleExePackage"];
213
- command.MsiPackageTable = this.Output.Tables["WixBundleMsiPackage"];
214
- command.MspPackageTable = this.Output.Tables["WixBundleMspPackage"];
215
- command.MsuPackageTable = this.Output.Tables["WixBundleMsuPackage"];
177
+ var command = new GetPackageFacadesCommand(chainPackageTuples, section);
178
command.Execute();
179
180
facades = command.PackageFacades;
181
}
182
221
- // Process each package facade. Note this is likely to add payloads and other rows to tables so
183
+ // Process each package facade. Note this is likely to add payloads and other tuples so
184
// note that any indexes created above may be out of date now.
223
- foreach (PackageFacade facade in facades.Values)
185
+ foreach (var facade in facades.Values)
186
{
225
- switch (facade.Package.Type)
187
+ switch (facade.PackageTuple.Type)
188
{
227
- case WixBundlePackageType.Exe:
228
- {
229
- ProcessExePackageCommand command = new ProcessExePackageCommand();
230
- command.AuthoredPayloads = payloads;
231
- command.Facade = facade;
232
- command.Execute();
233
-
234
- // ? variableCache.Add(String.Concat("packageManufacturer.", facade.Package.WixChainItemId), facade.ExePackage.Manufacturer);
235
- }
236
- break;
189
+ case WixBundlePackageType.Exe:
190
+ {
191
+ var command = new ProcessExePackageCommand(facade, payloadTuples);
192
+ command.Execute();
193
+ }
194
+ break;
195
238
- case WixBundlePackageType.Msi:
239
- {
240
- var command = new ProcessMsiPackageCommand();
241
- command.AuthoredPayloads = payloads;
242
- command.Facade = facade;
243
- command.BackendExtensions = this.BackendExtensions;
244
- command.MsiFeatureTable = this.Output.EnsureTable(this.TableDefinitions["WixBundleMsiFeature"]);
245
- command.MsiPropertyTable = this.Output.EnsureTable(this.TableDefinitions["WixBundleMsiProperty"]);
246
- command.PayloadTable = this.Output.Tables["WixBundlePayload"];
247
- command.RelatedPackageTable = this.Output.EnsureTable(this.TableDefinitions["WixBundleRelatedPackage"]);
248
- command.Execute();
249
-
250
- if (null != variableCache)
251
- {
252
- variableCache.Add(String.Concat("packageLanguage.", facade.Package.WixChainItemId), facade.MsiPackage.ProductLanguage.ToString());
253
-
254
- if (null != facade.MsiPackage.Manufacturer)
255
- {
256
- variableCache.Add(String.Concat("packageManufacturer.", facade.Package.WixChainItemId), facade.MsiPackage.Manufacturer);
257
- }
258
- }
196
+ case WixBundlePackageType.Msi:
197
+ {
198
+ var command = new ProcessMsiPackageCommand(this.ServiceProvider, this.BackendExtensions, section, facade, payloadTuples);
199
+ command.Execute();
200
260
- }
261
- break;
201
+ if (null != variableCache)
202
+ {
203
+ var msiPackage = (WixBundleMsiPackageTuple)facade.SpecificPackageTuple;
204
+ variableCache.Add(String.Concat("packageLanguage.", facade.PackageId), msiPackage.ProductLanguage.ToString());
205
263
- case WixBundlePackageType.Msp:
206
+ if (null != msiPackage.Manufacturer)
207
{
265
- ProcessMspPackageCommand command = new ProcessMspPackageCommand();
266
- command.AuthoredPayloads = payloads;
267
- command.Facade = facade;
268
- command.WixBundlePatchTargetCodeTable = this.Output.EnsureTable(this.TableDefinitions["WixBundlePatchTargetCode"]);
269
- command.Execute();
208
+ variableCache.Add(String.Concat("packageManufacturer.", facade.PackageId), msiPackage.Manufacturer);
209
}
271
- break;
210
+ }
211
273
- case WixBundlePackageType.Msu:
274
- {
275
- ProcessMsuPackageCommand command = new ProcessMsuPackageCommand();
276
- command.Facade = facade;
277
- command.Execute();
278
- }
279
- break;
212
+ }
213
+ break;
214
+
215
+ case WixBundlePackageType.Msp:
216
+ {
217
+ var command = new ProcessMspPackageCommand(this.Messaging, section, facade, payloadTuples);
218
+ command.Execute();
219
+ }
220
+ break;
221
+
222
+ case WixBundlePackageType.Msu:
223
+ {
224
+ var command = new ProcessMsuPackageCommand(facade, payloadTuples);
225
+ command.Execute();
226
+ }
227
+ break;
228
}
229
230
if (null != variableCache)
231
{
284
- BindBundleCommand.PopulatePackageVariableCache(facade.Package, variableCache);
232
+ BindBundleCommand.PopulatePackageVariableCache(facade.PackageTuple, variableCache);
233
}
234
}
235
236
+ if (this.Messaging.EncounteredError)
237
+ {
238
+ return;
239
+ }
240
+
241
// Reindex the payloads now that all the payloads (minus the manifest payloads that will be created later)
242
// are present.
290
- payloads = new RowDictionary<WixBundlePayloadRow>(this.Output.Tables["WixBundlePayload"]);
243
+ payloadTuples = section.Tuples.OfType<WixBundlePayloadTuple>().ToDictionary(t => t.Id.Id);
244
245
// Process the payloads that were added by processing the packages.
246
{
294
- ProcessPayloadsCommand command = new ProcessPayloadsCommand();
295
- command.Payloads = payloads.Values.Where(r => !processedPayloads.Contains(r.Id)).ToList();
296
- command.DefaultPackaging = bundleRow.DefaultPackagingType;
297
- command.LayoutDirectory = layoutDirectory;
247
+ var toProcess = payloadTuples.Values.Where(r => !processedPayloads.Contains(r.Id.Id)).ToList();
248
+
249
+ var command = new ProcessPayloadsCommand(this.ServiceProvider, this.BackendHelper, toProcess, bundleTuple.DefaultPackagingType, layoutDirectory);
250
command.Execute();
251
252
fileTransfers.AddRange(command.FileTransfers);
@@ -303,45 +255,43 @@ namespace WixToolset.Core.Burn
255
}
256
257
// Set the package metadata from the payloads now that we have the complete payload information.
306
- ILookup<string, WixBundlePayloadRow> payloadsByPackage = payloads.Values.ToLookup(p => p.Package);
307
-
258
{
309
- foreach (PackageFacade facade in facades.Values)
259
+ var payloadsByPackageId = payloadTuples.Values.ToLookup(p => p.PackageRef);
260
+
261
+ foreach (var facade in facades.Values)
262
{
311
- facade.Package.Size = 0;
263
+ facade.PackageTuple.Size = 0;
264
313
- IEnumerable<WixBundlePayloadRow> packagePayloads = payloadsByPackage[facade.Package.WixChainItemId];
265
+ var packagePayloads = payloadsByPackageId[facade.PackageId];
266
315
- foreach (WixBundlePayloadRow payload in packagePayloads)
267
+ foreach (var payload in packagePayloads)
268
{
317
- facade.Package.Size += payload.FileSize;
269
+ facade.PackageTuple.Size += payload.FileSize;
270
}
271
320
- if (!facade.Package.InstallSize.HasValue)
272
+ if (!facade.PackageTuple.InstallSize.HasValue)
273
{
322
- facade.Package.InstallSize = facade.Package.Size;
323
-
274
+ facade.PackageTuple.InstallSize = facade.PackageTuple.Size;
275
}
276
326
- WixBundlePayloadRow packagePayload = payloads[facade.Package.PackagePayload];
277
+ var packagePayload = payloadTuples[facade.PackageTuple.PayloadRef];
278
328
- if (String.IsNullOrEmpty(facade.Package.Description))
279
+ if (String.IsNullOrEmpty(facade.PackageTuple.Description))
280
{
330
- facade.Package.Description = packagePayload.Description;
281
+ facade.PackageTuple.Description = packagePayload.Description;
282
}
283
333
- if (String.IsNullOrEmpty(facade.Package.DisplayName))
284
+ if (String.IsNullOrEmpty(facade.PackageTuple.DisplayName))
285
{
335
- facade.Package.DisplayName = packagePayload.DisplayName;
286
+ facade.PackageTuple.DisplayName = packagePayload.DisplayName;
287
}
288
}
289
}
290
340
-
291
// Give the UX payloads their embedded IDs...
342
- int uxPayloadIndex = 0;
292
+ var uxPayloadIndex = 0;
293
{
344
- foreach (WixBundlePayloadRow payload in payloads.Values.Where(p => Compiler.BurnUXContainerId == p.Container))
294
+ foreach (var payload in payloadTuples.Values.Where(p => BurnConstants.BurnUXContainerName == p.ContainerRef))
295
{
296
// In theory, UX payloads could be embedded in the UX CAB, external to the bundle EXE, or even
297
// downloaded. The current engine requires the UX to be fully present before any downloading starts,
@@ -349,7 +299,7 @@ namespace WixToolset.Core.Burn
299
// into the temporary UX directory correctly, so we don't allow external either.
300
if (PackagingType.Embedded != payload.Packaging)
301
{
352
- Messaging.Instance.OnMessage(WixWarnings.UxPayloadsOnlySupportEmbedding(payload.SourceLineNumbers, payload.FullFileName));
302
+ this.Messaging.Write(WarningMessages.UxPayloadsOnlySupportEmbedding(payload.SourceLineNumbers, payload.SourceFile.Path));
303
payload.Packaging = PackagingType.Embedded;
304
}
305
@@ -360,12 +310,12 @@ namespace WixToolset.Core.Burn
310
if (0 == uxPayloadIndex)
311
{
312
// If we didn't get any UX payloads, it's an error!
363
- throw new WixException(WixErrors.MissingBundleInformation("BootstrapperApplication"));
313
+ throw new WixException(ErrorMessages.MissingBundleInformation("BootstrapperApplication"));
314
}
315
316
// Give the embedded payloads without an embedded id yet an embedded id.
367
- int payloadIndex = 0;
368
- foreach (WixBundlePayloadRow payload in payloads.Values)
317
+ var payloadIndex = 0;
318
+ foreach (var payload in payloadTuples.Values)
319
{
320
Debug.Assert(PackagingType.Unknown != payload.Packaging);
321
@@ -377,38 +327,38 @@ namespace WixToolset.Core.Burn
327
}
328
}
329
330
+ if (this.Messaging.EncounteredError)
331
+ {
332
+ return;
333
+ }
334
+
335
// Determine patches to automatically slipstream.
336
{
382
- AutomaticallySlipstreamPatchesCommand command = new AutomaticallySlipstreamPatchesCommand();
383
- command.PackageFacades = facades.Values;
384
- command.SlipstreamMspTable = this.Output.EnsureTable(this.TableDefinitions["WixBundleSlipstreamMsp"]);
385
- command.WixBundlePatchTargetCodeTable = this.Output.EnsureTable(this.TableDefinitions["WixBundlePatchTargetCode"]);
337
+ var command = new AutomaticallySlipstreamPatchesCommand(section, facades.Values);
338
command.Execute();
339
}
340
341
// If catalog files exist, non-embedded payloads should validate with the catalogs.
390
- IEnumerable<WixBundleCatalogRow> catalogs = this.Output.Tables["WixBundleCatalog"].RowsAs<WixBundleCatalogRow>();
342
+ var catalogs = section.Tuples.OfType<WixBundleCatalogTuple>().ToList();
343
392
- if (catalogs.Any())
344
+ if (catalogs.Count > 0)
345
{
394
- VerifyPayloadsWithCatalogCommand command = new VerifyPayloadsWithCatalogCommand();
395
- command.Catalogs = catalogs;
396
- command.Payloads = payloads.Values;
346
+ var command = new VerifyPayloadsWithCatalogCommand(this.Messaging, catalogs, payloadTuples.Values);
347
command.Execute();
348
}
349
400
- if (Messaging.Instance.EncounteredError)
350
+ if (this.Messaging.EncounteredError)
351
{
352
return;
353
}
354
355
IEnumerable<PackageFacade> orderedFacades;
406
- IEnumerable<WixBundleRollbackBoundaryRow> boundaries;
356
+ IEnumerable<WixBundleRollbackBoundaryTuple> boundaries;
357
{
408
- OrderPackagesAndRollbackBoundariesCommand command = new OrderPackagesAndRollbackBoundariesCommand();
409
- command.Boundaries = new RowDictionary<WixBundleRollbackBoundaryRow>(this.Output.Tables["WixBundleRollbackBoundary"]);
410
- command.PackageFacades = facades;
411
- command.WixGroupTable = wixGroupTable;
358
+ var groupTuples = section.Tuples.OfType<WixGroupTuple>();
359
+ var boundaryTuplesById = section.Tuples.OfType<WixBundleRollbackBoundaryTuple>().ToDictionary(b => b.Id.Id);
360
+
361
+ var command = new OrderPackagesAndRollbackBoundariesCommand(this.Messaging, groupTuples, boundaryTuplesById, facades);
362
command.Execute();
363
364
orderedFacades = command.OrderedPackageFacades;
@@ -418,280 +368,122 @@ namespace WixToolset.Core.Burn
368
// Resolve any delayed fields before generating the manifest.
369
if (this.DelayedFields.Any())
370
{
421
- var resolveDelayedFieldsCommand = new ResolveDelayedFieldsCommand();
422
- resolveDelayedFieldsCommand.OutputType = this.Output.Type;
423
- resolveDelayedFieldsCommand.DelayedFields = this.DelayedFields;
424
- resolveDelayedFieldsCommand.ModularizationGuid = null;
425
- resolveDelayedFieldsCommand.VariableCache = variableCache;
371
+ var resolveDelayedFieldsCommand = new ResolveDelayedFieldsCommand(this.Messaging, this.DelayedFields, variableCache);
372
resolveDelayedFieldsCommand.Execute();
373
}
374
429
- // Set the overridable bundle provider key.
430
- this.SetBundleProviderKey(this.Output, bundleRow);
375
+ Dictionary<string, ProvidesDependencyTuple> dependencyTuplesByKey;
376
+ {
377
+ var command = new ProcessDependencyProvidersCommand(this.Messaging, section, facades);
378
+ command.Execute();
379
432
- // Import or generate dependency providers for packages in the manifest.
433
- this.ProcessDependencyProviders(this.Output, facades);
380
+ bundleTuple.ProviderKey = command.BundleProviderKey; // set the overridable bundle provider key.
381
+ dependencyTuplesByKey = command.DependencyTuplesByKey;
382
+ }
383
384
// Update the bundle per-machine/per-user scope based on the chained packages.
436
- this.ResolveBundleInstallScope(bundleRow, orderedFacades);
385
+ this.ResolveBundleInstallScope(section, bundleTuple, orderedFacades);
386
387
// Generate the core-defined BA manifest tables...
388
{
440
- CreateBootstrapperApplicationManifestCommand command = new CreateBootstrapperApplicationManifestCommand();
441
- command.BundleRow = bundleRow;
442
- command.ChainPackages = orderedFacades;
443
- command.LastUXPayloadIndex = uxPayloadIndex;
444
- command.MsiFeatures = this.Output.Tables["WixBundleMsiFeature"].RowsAs<WixBundleMsiFeatureRow>();
445
- command.Output = this.Output;
446
- command.Payloads = payloads;
447
- command.TableDefinitions = this.TableDefinitions;
448
- command.TempFilesLocation = this.IntermediateFolder;
389
+ var command = new CreateBootstrapperApplicationManifestCommand(section, bundleTuple, orderedFacades, uxPayloadIndex, payloadTuples, this.IntermediateFolder);
390
command.Execute();
391
451
- WixBundlePayloadRow baManifestPayload = command.BootstrapperApplicationManifestPayloadRow;
452
- payloads.Add(baManifestPayload);
392
+ var baManifestPayload = command.BootstrapperApplicationManifestPayloadRow;
393
+ payloadTuples.Add(baManifestPayload.Id.Id, baManifestPayload);
394
}
395
455
- //foreach (BinderExtension extension in this.Extensions)
456
- //{
457
- // extension.PostBind(this.Context);
458
- //}
396
+#if TODO
397
+ foreach (BinderExtension extension in this.Extensions)
398
+ {
399
+ extension.PostBind(this.Context);
400
+ }
401
+#endif
402
403
// Create all the containers except the UX container first so the manifest (that goes in the UX container)
404
// can contain all size and hash information about the non-UX containers.
462
- RowDictionary<WixBundleContainerRow> containers = new RowDictionary<WixBundleContainerRow>(this.Output.Tables["WixBundleContainer"]);
463
-
464
- ILookup<string, WixBundlePayloadRow> payloadsByContainer = payloads.Values.ToLookup(p => p.Container);
465
-
466
- int attachedContainerIndex = 1; // count starts at one because UX container is "0".
467
-
468
- IEnumerable<WixBundlePayloadRow> uxContainerPayloads = Enumerable.Empty<WixBundlePayloadRow>();
469
-
470
- foreach (WixBundleContainerRow container in containers.Values)
405
+ WixBundleContainerTuple uxContainer;
406
+ IEnumerable<WixBundlePayloadTuple> uxPayloads;
407
+ IEnumerable<WixBundleContainerTuple> containers;
408
{
472
- IEnumerable<WixBundlePayloadRow> containerPayloads = payloadsByContainer[container.Id];
473
-
474
- if (!containerPayloads.Any())
475
- {
476
- if (container.Id != Compiler.BurnDefaultAttachedContainerId)
477
- {
478
- // TODO: display warning that we're ignoring container that ended up with no paylods in it.
479
- }
480
- }
481
- else if (Compiler.BurnUXContainerId == container.Id)
482
- {
483
- container.WorkingPath = Path.Combine(this.IntermediateFolder, container.Name);
484
- container.AttachedContainerIndex = 0;
485
-
486
- // Gather the list of UX payloads but ensure the BootstrapperApplication Payload is the first
487
- // in the list since that is the Payload that Burn attempts to load.
488
- List<WixBundlePayloadRow> uxPayloads = new List<WixBundlePayloadRow>();
489
-
490
- string baPayloadId = baRow.FieldAsString(0);
491
-
492
- foreach (WixBundlePayloadRow uxPayload in containerPayloads)
493
- {
494
- if (uxPayload.Id == baPayloadId)
495
- {
496
- uxPayloads.Insert(0, uxPayload);
497
- }
498
- else
499
- {
500
- uxPayloads.Add(uxPayload);
501
- }
502
- }
409
+ var command = new CreateNonUXContainers(this.BackendHelper, section, bundleApplicationTuple, payloadTuples, this.IntermediateFolder, layoutDirectory, this.DefaultCompressionLevel);
410
+ command.Execute();
411
504
- uxContainerPayloads = uxPayloads;
505
- }
506
- else
507
- {
508
- container.WorkingPath = Path.Combine(this.IntermediateFolder, container.Name);
412
+ fileTransfers.AddRange(command.FileTransfers);
413
510
- // Add detached containers to the list of file transfers.
511
- if (ContainerType.Detached == container.Type)
512
- {
513
- FileTransfer transfer;
514
- if (FileTransfer.TryCreate(container.WorkingPath, Path.Combine(layoutDirectory, container.Name), true, "Container", container.SourceLineNumbers, out transfer))
515
- {
516
- transfer.Built = true;
517
- fileTransfers.Add(transfer);
518
- }
519
- }
520
- else // update the attached container index.
521
- {
522
- Debug.Assert(ContainerType.Attached == container.Type);
414
+ uxContainer = command.UXContainer;
415
+ uxPayloads = command.UXContainerPayloads;
416
+ containers = command.Containers;
417
+ }
418
+
419
+ // Create the bundle manifest.
420
+ string manifestPath;
421
+ {
422
+ var executableName = Path.GetFileName(this.OutputPath);
423
524
- container.AttachedContainerIndex = attachedContainerIndex;
525
- ++attachedContainerIndex;
526
- }
424
+ var command = new CreateBurnManifestCommand(this.Messaging, this.BackendExtensions, executableName, section, bundleTuple, containers, chainTuple, orderedFacades, boundaries, uxPayloads, payloadTuples, orderedSearches, catalogs, this.IntermediateFolder);
425
+ command.Execute();
426
528
- this.CreateContainer(container, containerPayloads, null);
529
- }
427
+ manifestPath = command.OutputPath;
428
}
429
532
- // Create the bundle manifest then UX container.
533
- string manifestPath = Path.Combine(this.IntermediateFolder, "bundle-manifest.xml");
430
+ // Create the UX container.
431
{
535
- var command = new CreateBurnManifestCommand();
536
- command.BackendExtensions = this.BackendExtensions;
537
- command.Output = this.Output;
538
-
539
- command.BundleInfo = bundleRow;
540
- command.Chain = chainRow;
541
- command.Containers = containers;
542
- command.Catalogs = catalogs;
543
- command.ExecutableName = Path.GetFileName(this.OutputPath);
544
- command.OrderedPackages = orderedFacades;
545
- command.OutputPath = manifestPath;
546
- command.RollbackBoundaries = boundaries;
547
- command.OrderedSearches = orderedSearches;
548
- command.Payloads = payloads;
549
- command.UXContainerPayloads = uxContainerPayloads;
432
+ var command = new CreateContainerCommand(manifestPath, uxPayloads, uxContainer.WorkingPath, this.DefaultCompressionLevel);
433
command.Execute();
551
- }
552
-
553
- WixBundleContainerRow uxContainer = containers[Compiler.BurnUXContainerId];
554
- this.CreateContainer(uxContainer, uxContainerPayloads, manifestPath);
555
-
556
- // Copy the burn.exe to a writable location then mark it to be moved to its final build location. Note
557
- // that today, the x64 Burn uses the x86 stub.
558
- string stubPlatform = (Platform.X64 == bundleRow.Platform) ? "x86" : bundleRow.Platform.ToString();
559
-
560
- string stubFile = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), stubPlatform, "burn.exe");
561
- string bundleTempPath = Path.Combine(this.IntermediateFolder, Path.GetFileName(this.OutputPath));
562
-
563
- Messaging.Instance.OnMessage(WixVerboses.GeneratingBundle(bundleTempPath, stubFile));
434
565
- string bundleFilename = Path.GetFileName(this.OutputPath);
566
- if ("setup.exe".Equals(bundleFilename, StringComparison.OrdinalIgnoreCase))
567
- {
568
- Messaging.Instance.OnMessage(WixErrors.InsecureBundleFilename(bundleFilename));
435
+ uxContainer.Hash = command.Hash;
436
+ uxContainer.Size = command.Size;
437
}
438
571
- FileTransfer bundleTransfer;
572
- if (FileTransfer.TryCreate(bundleTempPath, this.OutputPath, true, "Bundle", bundleRow.SourceLineNumbers, out bundleTransfer))
439
{
574
- bundleTransfer.Built = true;
575
- fileTransfers.Add(bundleTransfer);
576
- }
440
+ var command = new CreateBundleExeCommand(this.Messaging, this.BackendHelper, this.IntermediateFolder, this.OutputPath, bundleTuple, uxContainer, containers, this.BurnStubPath);
441
+ command.Execute();
442
578
- File.Copy(stubFile, bundleTempPath, true);
579
- File.SetAttributes(bundleTempPath, FileAttributes.Normal);
443
+ fileTransfers.Add(command.Transfer);
444
+ }
445
581
- this.UpdateBurnResources(bundleTempPath, this.OutputPath, bundleRow);
446
+#if TODO
447
+ this.Pdb = new Pdb { Output = output };
448
583
- // Update the .wixburn section to point to at the UX and attached container(s) then attach the containers
584
- // if they should be attached.
585
- using (BurnWriter writer = BurnWriter.Open(bundleTempPath))
449
+ if (!String.IsNullOrEmpty(this.OutputPdbPath))
450
{
587
- FileInfo burnStubFile = new FileInfo(bundleTempPath);
588
- writer.InitializeBundleSectionData(burnStubFile.Length, bundleRow.BundleId);
589
-
590
- // Always attach the UX container first
591
- writer.AppendContainer(uxContainer.WorkingPath, BurnWriter.Container.UX);
451
+ var trackPdb = this.BackendHelper.TrackFile(this.OutputPdbPath, TrackedFileType.Final);
452
+ trackedFiles.Add(trackPdb);
453
593
- // Now append all other attached containers
594
- foreach (WixBundleContainerRow container in containers.Values)
595
- {
596
- if (ContainerType.Attached == container.Type)
597
- {
598
- // The container was only created if it had payloads.
599
- if (!String.IsNullOrEmpty(container.WorkingPath) && Compiler.BurnUXContainerId != container.Id)
600
- {
601
- writer.AppendContainer(container.WorkingPath, BurnWriter.Container.Attached);
602
- }
603
- }
604
- }
605
- }
606
-
607
- if (null != this.PdbFile)
608
- {
609
- Pdb pdb = new Pdb();
610
- pdb.Output = Output;
611
- pdb.Save(this.PdbFile);
454
+ this.Pdb.Save(trackPdb.Path);
455
}
456
+#endif
457
458
+#if TODO // does this need to come back, or do they only need to be in TrackedFiles?
459
+ this.ContentFilePaths = payloadTuples.Values.Where(p => p.ContentFile).Select(p => p.FullFileName).ToList();
460
+#endif
461
this.FileTransfers = fileTransfers;
615
- this.ContentFilePaths = payloads.Values.Where(p => p.ContentFile).Select(p => p.FullFileName).ToList();
616
- }
617
-
618
- private Table GetRequiredTable(string tableName)
619
- {
620
- Table table = this.Output.Tables[tableName];
621
- if (null == table || 0 == table.Rows.Count)
622
- {
623
- throw new WixException(WixErrors.MissingBundleInformation(tableName));
624
- }
625
-
626
- return table;
627
- }
628
-
629
- private Row GetSingleRowTable(string tableName)
630
- {
631
- Table table = this.Output.Tables[tableName];
632
- if (null == table || 1 != table.Rows.Count)
633
- {
634
- throw new WixException(WixErrors.MissingBundleInformation(tableName));
635
- }
462
+ this.TrackedFiles = trackedFiles;
463
637
- return table.Rows[0];
464
+ // TODO: Eventually this gets removed
465
+ var intermediate = new Intermediate(this.Output.Id, new[] { section }, this.Output.Localizations.ToDictionary(l => l.Culture, StringComparer.OrdinalIgnoreCase), this.Output.EmbedFilePaths);
466
+ var trackIntermediate = this.BackendHelper.TrackFile(Path.Combine(this.IntermediateFolder, Path.GetFileName(Path.ChangeExtension(this.OutputPath, "wir"))), TrackedFileType.Intermediate);
467
+ intermediate.Save(trackIntermediate.Path);
468
+ trackedFiles.Add(trackIntermediate);
469
}
470
640
- private List<WixSearchInfo> OrderSearches()
471
+ private IEnumerable<SearchFacade> OrderSearches(IntermediateSection section)
472
{
642
- Dictionary<string, WixSearchInfo> allSearches = new Dictionary<string, WixSearchInfo>();
643
- Table wixFileSearchTable = this.Output.Tables["WixFileSearch"];
644
- if (null != wixFileSearchTable && 0 < wixFileSearchTable.Rows.Count)
645
- {
646
- foreach (Row row in wixFileSearchTable.Rows)
647
- {
648
- WixFileSearchInfo fileSearchInfo = new WixFileSearchInfo(row);
649
- allSearches.Add(fileSearchInfo.Id, fileSearchInfo);
650
- }
651
- }
652
-
653
- Table wixRegistrySearchTable = this.Output.Tables["WixRegistrySearch"];
654
- if (null != wixRegistrySearchTable && 0 < wixRegistrySearchTable.Rows.Count)
655
- {
656
- foreach (Row row in wixRegistrySearchTable.Rows)
657
- {
658
- WixRegistrySearchInfo registrySearchInfo = new WixRegistrySearchInfo(row);
659
- allSearches.Add(registrySearchInfo.Id, registrySearchInfo);
660
- }
661
- }
662
-
663
- Table wixComponentSearchTable = this.Output.Tables["WixComponentSearch"];
664
- if (null != wixComponentSearchTable && 0 < wixComponentSearchTable.Rows.Count)
665
- {
666
- foreach (Row row in wixComponentSearchTable.Rows)
667
- {
668
- WixComponentSearchInfo componentSearchInfo = new WixComponentSearchInfo(row);
669
- allSearches.Add(componentSearchInfo.Id, componentSearchInfo);
670
- }
671
- }
473
+ var searchesById = section.Tuples
474
+ .Where(t => t.Definition.Type == TupleDefinitionType.WixComponentSearch ||
475
+ t.Definition.Type == TupleDefinitionType.WixFileSearch ||
476
+ t.Definition.Type == TupleDefinitionType.WixProductSearch ||
477
+ t.Definition.Type == TupleDefinitionType.WixRegistrySearch)
478
+ .ToDictionary(t => t.Id.Id);
479
673
- Table wixProductSearchTable = this.Output.Tables["WixProductSearch"];
674
- if (null != wixProductSearchTable && 0 < wixProductSearchTable.Rows.Count)
675
- {
676
- foreach (Row row in wixProductSearchTable.Rows)
677
- {
678
- WixProductSearchInfo productSearchInfo = new WixProductSearchInfo(row);
679
- allSearches.Add(productSearchInfo.Id, productSearchInfo);
680
- }
681
- }
480
+ var orderedSearches = new List<SearchFacade>(searchesById.Keys.Count);
481
683
- // Merge in the variable/condition info and get the canonical ordering for
684
- // the searches.
685
- List<WixSearchInfo> orderedSearches = new List<WixSearchInfo>();
686
- Table wixSearchTable = this.Output.Tables["WixSearch"];
687
- if (null != wixSearchTable && 0 < wixSearchTable.Rows.Count)
482
+ foreach (var searchTuple in section.Tuples.OfType<WixSearchTuple>())
483
{
689
- orderedSearches.Capacity = wixSearchTable.Rows.Count;
690
- foreach (Row row in wixSearchTable.Rows)
484
+ if (searchesById.TryGetValue(searchTuple.Id.Id, out var specificSearchTuple))
485
{
692
- WixSearchInfo searchInfo = allSearches[(string)row[0]];
693
- searchInfo.AddWixSearchRowInfo(row);
694
- orderedSearches.Add(searchInfo);
486
+ orderedSearches.Add(new SearchFacade(searchTuple, specificSearchTuple));
487
}
488
}
489
@@ -703,9 +495,9 @@ namespace WixToolset.Core.Burn
495
/// </summary>
496
/// <param name="package">The package with properties to cache.</param>
497
/// <param name="variableCache">The property cache.</param>
706
- private static void PopulatePackageVariableCache(WixBundlePackageRow package, IDictionary<string, string> variableCache)
498
+ private static void PopulatePackageVariableCache(WixBundlePackageTuple package, IDictionary<string, string> variableCache)
499
{
708
- string id = package.WixChainItemId;
500
+ var id = package.Id.Id;
501
502
variableCache.Add(String.Concat("packageDescription.", id), package.Description);
503
//variableCache.Add(String.Concat("packageLanguage.", id), package.Language);
@@ -714,231 +506,63 @@ namespace WixToolset.Core.Burn
506
variableCache.Add(String.Concat("packageVersion.", id), package.Version);
507
}
508
717
- private void CreateContainer(WixBundleContainerRow container, IEnumerable<WixBundlePayloadRow> containerPayloads, string manifestFile)
509
+ private void ResolveBundleInstallScope(IntermediateSection section, WixBundleTuple bundleTuple, IEnumerable<PackageFacade> facades)
510
{
719
- CreateContainerCommand command = new CreateContainerCommand();
720
- command.DefaultCompressionLevel = this.DefaultCompressionLevel;
721
- command.Payloads = containerPayloads;
722
- command.ManifestFile = manifestFile;
723
- command.OutputPath = container.WorkingPath;
724
- command.Execute();
725
-
726
- container.Hash = command.Hash;
727
- container.Size = command.Size;
728
- }
511
+ var dependencyTuplesById = section.Tuples.OfType<ProvidesDependencyTuple>().ToDictionary(t => t.Id.Id);
512
730
- private void ResolveBundleInstallScope(WixBundleRow bundleInfo, IEnumerable<PackageFacade> facades)
731
- {
732
- foreach (PackageFacade facade in facades)
513
+ foreach (var facade in facades)
514
{
734
- if (bundleInfo.PerMachine && YesNoDefaultType.No == facade.Package.PerMachine)
515
+ if (bundleTuple.PerMachine && YesNoDefaultType.No == facade.PackageTuple.PerMachine)
516
{
736
- Messaging.Instance.OnMessage(WixVerboses.SwitchingToPerUserPackage(facade.Package.SourceLineNumbers, facade.Package.WixChainItemId));
517
+ this.Messaging.Write(VerboseMessages.SwitchingToPerUserPackage(facade.PackageTuple.SourceLineNumbers, facade.PackageId));
518
738
- bundleInfo.PerMachine = false;
519
+ bundleTuple.Attributes &= ~WixBundleAttributes.PerMachine;
520
break;
521
}
522
}
523
743
- foreach (PackageFacade facade in facades)
524
+ foreach (var facade in facades)
525
{
526
// Update package scope from bundle scope if default.
746
- if (YesNoDefaultType.Default == facade.Package.PerMachine)
527
+ if (YesNoDefaultType.Default == facade.PackageTuple.PerMachine)
528
{
748
- facade.Package.PerMachine = bundleInfo.PerMachine ? YesNoDefaultType.Yes : YesNoDefaultType.No;
529
+ facade.PackageTuple.PerMachine = bundleTuple.PerMachine ? YesNoDefaultType.Yes : YesNoDefaultType.No;
530
}
531
532
// We will only register packages in the same scope as the bundle. Warn if any packages with providers
533
// are in a different scope and not permanent (permanents typically don't need a ref-count).
753
- if (!bundleInfo.PerMachine && YesNoDefaultType.Yes == facade.Package.PerMachine && !facade.Package.Permanent && 0 < facade.Provides.Count)
534
+ if (!bundleTuple.PerMachine &&
535
+ YesNoDefaultType.Yes == facade.PackageTuple.PerMachine &&
536
+ !facade.PackageTuple.Permanent &&
537
+ dependencyTuplesById.ContainsKey(facade.PackageId))
538
{
755
- Messaging.Instance.OnMessage(WixWarnings.NoPerMachineDependencies(facade.Package.SourceLineNumbers, facade.Package.WixChainItemId));
539
+ this.Messaging.Write(WarningMessages.NoPerMachineDependencies(facade.PackageTuple.SourceLineNumbers, facade.PackageId));
540
}
541
}
542
}
543
760
- private void UpdateBurnResources(string bundleTempPath, string outputPath, WixBundleRow bundleInfo)
544
+ private IEnumerable<T> GetRequiredTuples<T>() where T : IntermediateTuple
545
{
762
- WixToolset.Dtf.Resources.ResourceCollection resources = new WixToolset.Dtf.Resources.ResourceCollection();
763
- WixToolset.Dtf.Resources.VersionResource version = new WixToolset.Dtf.Resources.VersionResource("#1", 1033);
546
+ var tuples = this.Output.Sections.Single().Tuples.OfType<T>().ToList();
547
765
- version.Load(bundleTempPath);
766
- resources.Add(version);
767
-
768
- // Ensure the bundle info provides a full four part version.
769
- Version fourPartVersion = new Version(bundleInfo.Version);
770
- int major = (fourPartVersion.Major < 0) ? 0 : fourPartVersion.Major;
771
- int minor = (fourPartVersion.Minor < 0) ? 0 : fourPartVersion.Minor;
772
- int build = (fourPartVersion.Build < 0) ? 0 : fourPartVersion.Build;
773
- int revision = (fourPartVersion.Revision < 0) ? 0 : fourPartVersion.Revision;
774
-
775
- if (UInt16.MaxValue < major || UInt16.MaxValue < minor || UInt16.MaxValue < build || UInt16.MaxValue < revision)
776
- {
777
- throw new WixException(WixErrors.InvalidModuleOrBundleVersion(bundleInfo.SourceLineNumbers, "Bundle", bundleInfo.Version));
778
- }
779
-
780
- fourPartVersion = new Version(major, minor, build, revision);
781
- version.FileVersion = fourPartVersion;
782
- version.ProductVersion = fourPartVersion;
783
-
784
- WixToolset.Dtf.Resources.VersionStringTable strings = version[1033];
785
- strings["LegalCopyright"] = bundleInfo.Copyright;
786
- strings["OriginalFilename"] = Path.GetFileName(outputPath);
787
- strings["FileVersion"] = bundleInfo.Version; // string versions do not have to be four parts.
788
- strings["ProductVersion"] = bundleInfo.Version; // string versions do not have to be four parts.
789
-
790
- if (!String.IsNullOrEmpty(bundleInfo.Name))
548
+ if (0 == tuples.Count)
549
{
792
- strings["ProductName"] = bundleInfo.Name;
793
- strings["FileDescription"] = bundleInfo.Name;
550
+ throw new WixException(ErrorMessages.MissingBundleInformation(nameof(T)));
551
}
552
796
- if (!String.IsNullOrEmpty(bundleInfo.Publisher))
797
- {
798
- strings["CompanyName"] = bundleInfo.Publisher;
799
- }
800
- else
801
- {
802
- strings["CompanyName"] = String.Empty;
803
- }
804
-
805
- if (!String.IsNullOrEmpty(bundleInfo.IconPath))
806
- {
807
- Dtf.Resources.GroupIconResource iconGroup = new Dtf.Resources.GroupIconResource("#1", 1033);
808
- iconGroup.ReadFromFile(bundleInfo.IconPath);
809
- resources.Add(iconGroup);
810
-
811
- foreach (Dtf.Resources.Resource icon in iconGroup.Icons)
812
- {
813
- resources.Add(icon);
814
- }
815
- }
816
-
817
- if (!String.IsNullOrEmpty(bundleInfo.SplashScreenBitmapPath))
818
- {
819
- Dtf.Resources.BitmapResource bitmap = new Dtf.Resources.BitmapResource("#1", 1033);
820
- bitmap.ReadFromFile(bundleInfo.SplashScreenBitmapPath);
821
- resources.Add(bitmap);
822
- }
823
-
824
- resources.Save(bundleTempPath);
553
+ return tuples;
554
}
555
827
-//#region DependencyExtension
828
- /// <summary>
829
- /// Imports authored dependency providers for each package in the manifest,
830
- /// and generates dependency providers for certain package types that do not
831
- /// have a provider defined.
832
- /// </summary>
833
- /// <param name="bundle">The <see cref="Output"/> object for the bundle.</param>
834
- /// <param name="facades">An indexed collection of chained packages.</param>
835
- private void ProcessDependencyProviders(Output bundle, IDictionary<string, PackageFacade> facades)
556
+ private T GetSingleTuple<T>() where T : IntermediateTuple
557
{
837
- // First import any authored dependencies. These may merge with imported provides from MSI packages.
838
- Table wixDependencyProviderTable = bundle.Tables["WixDependencyProvider"];
839
- if (null != wixDependencyProviderTable && 0 < wixDependencyProviderTable.Rows.Count)
840
- {
841
- // Add package information for each dependency provider authored into the manifest.
842
- foreach (Row wixDependencyProviderRow in wixDependencyProviderTable.Rows)
843
- {
844
- string packageId = (string)wixDependencyProviderRow[1];
845
-
846
- PackageFacade facade = null;
847
- if (facades.TryGetValue(packageId, out facade))
848
- {
849
- ProvidesDependency dependency = new ProvidesDependency(wixDependencyProviderRow);
850
-
851
- if (String.IsNullOrEmpty(dependency.Key))
852
- {
853
- switch (facade.Package.Type)
854
- {
855
- // The WixDependencyExtension allows an empty Key for MSIs and MSPs.
856
- case WixBundlePackageType.Msi:
857
- dependency.Key = facade.MsiPackage.ProductCode;
858
- break;
859
- case WixBundlePackageType.Msp:
860
- dependency.Key = facade.MspPackage.PatchCode;
861
- break;
862
- }
863
- }
864
-
865
- if (String.IsNullOrEmpty(dependency.Version))
866
- {
867
- dependency.Version = facade.Package.Version;
868
- }
869
-
870
- // If the version is still missing, a version could not be harvested from the package and was not authored.
871
- if (String.IsNullOrEmpty(dependency.Version))
872
- {
873
- Messaging.Instance.OnMessage(WixErrors.MissingDependencyVersion(facade.Package.WixChainItemId));
874
- }
875
-
876
- if (String.IsNullOrEmpty(dependency.DisplayName))
877
- {
878
- dependency.DisplayName = facade.Package.DisplayName;
879
- }
558
+ var tuples = this.Output.Sections.Single().Tuples.OfType<T>().ToList();
559
881
- if (!facade.Provides.Merge(dependency))
882
- {
883
- Messaging.Instance.OnMessage(WixErrors.DuplicateProviderDependencyKey(dependency.Key, facade.Package.WixChainItemId));
884
- }
885
- }
886
- }
887
- }
888
-
889
- // Generate providers for MSI packages that still do not have providers.
890
- foreach (PackageFacade facade in facades.Values)
560
+ if (1 != tuples.Count)
561
{
892
- string key = null;
893
-
894
- if (WixBundlePackageType.Msi == facade.Package.Type && 0 == facade.Provides.Count)
895
- {
896
- key = facade.MsiPackage.ProductCode;
897
- }
898
- else if (WixBundlePackageType.Msp == facade.Package.Type && 0 == facade.Provides.Count)
899
- {
900
- key = facade.MspPackage.PatchCode;
901
- }
902
-
903
- if (!String.IsNullOrEmpty(key))
904
- {
905
- ProvidesDependency dependency = new ProvidesDependency(key, facade.Package.Version, facade.Package.DisplayName, 0);
906
-
907
- if (!facade.Provides.Merge(dependency))
908
- {
909
- Messaging.Instance.OnMessage(WixErrors.DuplicateProviderDependencyKey(dependency.Key, facade.Package.WixChainItemId));
910
- }
911
- }
562
+ throw new WixException(ErrorMessages.MissingBundleInformation(nameof(T)));
563
}
913
- }
564
915
- /// <summary>
916
- /// Sets the provider key for the bundle.
917
- /// </summary>
918
- /// <param name="bundle">The <see cref="Output"/> object for the bundle.</param>
919
- /// <param name="bundleInfo">The <see cref="BundleInfo"/> containing the provider key and other information for the bundle.</param>
920
- private void SetBundleProviderKey(Output bundle, WixBundleRow bundleInfo)
921
- {
922
- // From DependencyCommon.cs in the WixDependencyExtension.
923
- const int ProvidesAttributesBundle = 0x10000;
924
-
925
- Table wixDependencyProviderTable = bundle.Tables["WixDependencyProvider"];
926
- if (null != wixDependencyProviderTable && 0 < wixDependencyProviderTable.Rows.Count)
927
- {
928
- // Search the WixDependencyProvider table for the single bundle provider key.
929
- foreach (Row wixDependencyProviderRow in wixDependencyProviderTable.Rows)
930
- {
931
- object attributes = wixDependencyProviderRow[5];
932
- if (null != attributes && 0 != (ProvidesAttributesBundle & (int)attributes))
933
- {
934
- bundleInfo.ProviderKey = (string)wixDependencyProviderRow[2];
935
- break;
936
- }
937
- }
938
- }
939
-
940
- // Defaults to the bundle ID as the provider key.
941
-#endif
565
+ return tuples[0];
566
}
567
}
568
}
src/WixToolset.Core.Burn/Bind/ProcessDependencyProvidersCommand.cs
new
+166
@@ -0,0 +1,166 @@
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.Burn.Bind
4
+{
5
+ using System;
6
+ using System.Collections.Generic;
7
+ using System.Linq;
8
+ using WixToolset.Data;
9
+ using WixToolset.Core.Burn.Bundles;
10
+ using WixToolset.Extensibility.Services;
11
+ using WixToolset.Data.Tuples;
12
+
13
+ internal class ProcessDependencyProvidersCommand
14
+ {
15
+ public ProcessDependencyProvidersCommand(IMessaging messaging, IntermediateSection section, IDictionary<string, PackageFacade> facades)
16
+ {
17
+ this.Messaging = messaging;
18
+ this.Section = section;
19
+
20
+ this.Facades = facades;
21
+ }
22
+
23
+ public string BundleProviderKey { get; private set; }
24
+
25
+ public Dictionary<string, ProvidesDependencyTuple> DependencyTuplesByKey { get; private set; }
26
+
27
+ private IMessaging Messaging { get; }
28
+
29
+ private IntermediateSection Section { get; }
30
+
31
+ private IDictionary<string, PackageFacade> Facades { get; }
32
+
33
+ /// <summary>
34
+ /// Sets the explicitly provided bundle provider key, if provided. And...
35
+ /// Imports authored dependency providers for each package in the manifest,
36
+ /// and generates dependency providers for certain package types that do not
37
+ /// have a provider defined.
38
+ /// </summary>
39
+ public void Execute()
40
+ {
41
+ var wixDependencyProviderTuples = this.Section.Tuples.OfType<WixDependencyProviderTuple>();
42
+
43
+ foreach (var wixDependencyProviderTuple in wixDependencyProviderTuples)
44
+ {
45
+ // Sets the provider key for the bundle, if it is not set already.
46
+ if (String.IsNullOrEmpty(this.BundleProviderKey))
47
+ {
48
+ if (wixDependencyProviderTuple.Bundle)
49
+ {
50
+ this.BundleProviderKey = wixDependencyProviderTuple.ProviderKey;
51
+ }
52
+ }
53
+
54
+ // Import any authored dependencies. These may merge with imported provides from MSI packages.
55
+ var packageId = wixDependencyProviderTuple.Id.Id;
56
+
57
+ if (this.Facades.TryGetValue(packageId, out var facade))
58
+ {
59
+ var dependency = new ProvidesDependencyTuple(wixDependencyProviderTuple.SourceLineNumbers, wixDependencyProviderTuple.Id)
60
+ {
61
+ PackageRef = packageId,
62
+ Key = wixDependencyProviderTuple.ProviderKey,
63
+ Version = wixDependencyProviderTuple.Version,
64
+ DisplayName = wixDependencyProviderTuple.DisplayName,
65
+ Attributes = (int)wixDependencyProviderTuple.Attributes
66
+ };
67
+
68
+ if (String.IsNullOrEmpty(dependency.Key))
69
+ {
70
+ switch (facade.SpecificPackageTuple)
71
+ {
72
+ // The WixDependencyExtension allows an empty Key for MSIs and MSPs.
73
+ case WixBundleMsiPackageTuple msiPackage:
74
+ dependency.Key = msiPackage.ProductCode;
75
+ break;
76
+ case WixBundleMspPackageTuple mspPackage:
77
+ dependency.Key = mspPackage.PatchCode;
78
+ break;
79
+ }
80
+ }
81
+
82
+ if (String.IsNullOrEmpty(dependency.Version))
83
+ {
84
+ dependency.Version = facade.PackageTuple.Version;
85
+ }
86
+
87
+ // If the version is still missing, a version could not be harvested from the package and was not authored.
88
+ if (String.IsNullOrEmpty(dependency.Version))
89
+ {
90
+ this.Messaging.Write(ErrorMessages.MissingDependencyVersion(facade.PackageId));
91
+ }
92
+
93
+ if (String.IsNullOrEmpty(dependency.DisplayName))
94
+ {
95
+ dependency.DisplayName = facade.PackageTuple.DisplayName;
96
+ }
97
+
98
+ this.Section.Tuples.Add(dependency);
99
+ }
100
+ }
101
+
102
+ this.DependencyTuplesByKey = this.GetDependencyTuplesByKey();
103
+
104
+ // Generate providers for MSI and MSP packages that still do not have providers.
105
+ foreach (var facade in this.Facades.Values)
106
+ {
107
+ string key = null;
108
+
109
+ //if (WixBundlePackageType.Msi == facade.PackageTuple.Type)
110
+ if (facade.SpecificPackageTuple is WixBundleMsiPackageTuple msiPackage)
111
+ {
112
+ //var msiPackage = (WixBundleMsiPackageTuple)facade.SpecificPackageTuple;
113
+ key = msiPackage.ProductCode;
114
+ }
115
+ //else if (WixBundlePackageType.Msp == facade.PackageTuple.Type)
116
+ else if (facade.SpecificPackageTuple is WixBundleMspPackageTuple mspPackage)
117
+ {
118
+ //var mspPackage = (WixBundleMspPackageTuple)facade.SpecificPackageTuple;
119
+ key = mspPackage.PatchCode;
120
+ }
121
+
122
+ if (!String.IsNullOrEmpty(key) && !this.DependencyTuplesByKey.ContainsKey(key))
123
+ {
124
+ var dependency = new ProvidesDependencyTuple(facade.PackageTuple.SourceLineNumbers, facade.PackageTuple.Id)
125
+ {
126
+ PackageRef = facade.PackageId,
127
+ Key = key,
128
+ Version = facade.PackageTuple.Version,
129
+ DisplayName = facade.PackageTuple.DisplayName
130
+ };
131
+
132
+ this.Section.Tuples.Add(dependency);
133
+
134
+ this.DependencyTuplesByKey.Add(dependency.Key, dependency);
135
+ }
136
+ }
137
+ }
138
+
139
+ private Dictionary<string, ProvidesDependencyTuple> GetDependencyTuplesByKey()
140
+ {
141
+ var dependencyTuplesByKey = new Dictionary<string, ProvidesDependencyTuple>();
142
+
143
+ var dependencyTuples = this.Section.Tuples.OfType<ProvidesDependencyTuple>();
144
+
145
+ foreach (var dependency in dependencyTuples)
146
+ {
147
+ if (dependencyTuplesByKey.TryGetValue(dependency.Key, out var collision))
148
+ {
149
+ // If not a perfect dependency collision, display an error.
150
+ if (dependency.Key != collision.Key ||
151
+ dependency.Version != collision.Version ||
152
+ dependency.DisplayName != collision.DisplayName)
153
+ {
154
+ this.Messaging.Write(ErrorMessages.DuplicateProviderDependencyKey(dependency.Key, dependency.PackageRef));
155
+ }
156
+ }
157
+ else
158
+ {
159
+ dependencyTuplesByKey.Add(dependency.Key, dependency);
160
+ }
161
+ }
162
+
163
+ return dependencyTuplesByKey;
164
+ }
165
+ }
166
+}
src/WixToolset.Core.Burn/Bind/ProvidesDependency.cs
deleted
-110
@@ -1,110 +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
-
3
-namespace WixToolset.Core.Burn
4
-{
5
- using System;
6
- using System.Xml;
7
- using WixToolset.Data;
8
-
9
- /// <summary>
10
- /// Represents an authored or imported dependency provider.
11
- /// </summary>
12
- internal sealed class ProvidesDependency
13
- {
14
-#if TODO
15
- /// <summary>
16
- /// Creates a new instance of the <see cref="ProviderDependency"/> class from a <see cref="Row"/>.
17
- /// </summary>
18
- /// <param name="row">The <see cref="Row"/> from which data is imported.</param>
19
- internal ProvidesDependency(Row row)
20
- : this((string)row[2], (string)row[3], (string)row[4], (int?)row[5])
21
- {
22
- }
23
-#endif
24
-
25
- /// <summary>
26
- /// Creates a new instance of the <see cref="ProviderDependency"/> class.
27
- /// </summary>
28
- /// <param name="key">The unique key of the dependency.</param>
29
- /// <param name="attributes">Additional attributes for the dependency.</param>
30
- internal ProvidesDependency(string key, string version, string displayName, int? attributes)
31
- {
32
- this.Key = key;
33
- this.Version = version;
34
- this.DisplayName = displayName;
35
- this.Attributes = attributes;
36
- }
37
-
38
- /// <summary>
39
- /// Gets or sets the unique key of the package provider.
40
- /// </summary>
41
- internal string Key { get; set; }
42
-
43
- /// <summary>
44
- /// Gets or sets the version of the package provider.
45
- /// </summary>
46
- internal string Version { get; set; }
47
-
48
- /// <summary>
49
- /// Gets or sets the display name of the package provider.
50
- /// </summary>
51
- internal string DisplayName { get; set; }
52
-
53
- /// <summary>
54
- /// Gets or sets the attributes for the dependency.
55
- /// </summary>
56
- internal int? Attributes { get; set; }
57
-
58
- /// <summary>
59
- /// Gets or sets whether the dependency was imported from the package.
60
- /// </summary>
61
- internal bool Imported { get; set; }
62
-
63
- /// <summary>
64
- /// Gets whether certain properties are the same.
65
- /// </summary>
66
- /// <param name="other">Another <see cref="ProvidesDependency"/> to compare.</param>
67
- /// <remarks>This is not the same as object equality, but only checks a subset of properties
68
- /// to determine if the objects are similar and could be merged into a collection.</remarks>
69
- /// <returns>True if certain properties are the same.</returns>
70
- internal bool Equals(ProvidesDependency other)
71
- {
72
- if (null != other)
73
- {
74
- return this.Key == other.Key &&
75
- this.Version == other.Version &&
76
- this.DisplayName == other.DisplayName;
77
- }
78
-
79
- return false;
80
- }
81
-
82
- /// <summary>
83
- /// Writes the dependency to the bundle XML manifest.
84
- /// </summary>
85
- /// <param name="writer">The <see cref="XmlTextWriter"/> for the bundle XML manifest.</param>
86
- internal void WriteXml(XmlTextWriter writer)
87
- {
88
- writer.WriteStartElement("Provides");
89
- writer.WriteAttributeString("Key", this.Key);
90
-
91
- if (!String.IsNullOrEmpty(this.Version))
92
- {
93
- writer.WriteAttributeString("Version", this.Version);
94
- }
95
-
96
- if (!String.IsNullOrEmpty(this.DisplayName))
97
- {
98
- writer.WriteAttributeString("DisplayName", this.DisplayName);
99
- }
100
-
101
- if (this.Imported)
102
- {
103
- // The package dependency was explicitly authored into the manifest.
104
- writer.WriteAttributeString("Imported", "yes");
105
- }
106
-
107
- writer.WriteEndElement();
108
- }
109
- }
110
-}
src/WixToolset.Core.Burn/Bind/ProvidesDependencyCollection.cs
deleted
-64
@@ -1,64 +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
-
3
-namespace WixToolset.Core.Burn
4
-{
5
- using System;
6
- using System.Collections.ObjectModel;
7
-
8
- /// <summary>
9
- /// A case-insensitive collection of unique <see cref="ProvidesDependency"/> objects.
10
- /// </summary>
11
- internal sealed class ProvidesDependencyCollection : KeyedCollection<string, ProvidesDependency>
12
- {
13
- /// <summary>
14
- /// Creates a case-insensitive collection of unique <see cref="ProvidesDependency"/> objects.
15
- /// </summary>
16
- internal ProvidesDependencyCollection()
17
- : base(StringComparer.InvariantCultureIgnoreCase)
18
- {
19
- }
20
-
21
- /// <summary>
22
- /// Adds the <see cref="ProvidesDependency"/> to the collection if it doesn't already exist.
23
- /// </summary>
24
- /// <param name="dependency">The <see cref="ProvidesDependency"/> to add to the collection.</param>
25
- /// <returns>True if the <see cref="ProvidesDependency"/> was added to the collection; otherwise, false.</returns>
26
- /// <exception cref="ArgumentNullException">The <paramref name="dependency"/> parameter is null.</exception>
27
- internal bool Merge(ProvidesDependency dependency)
28
- {
29
- if (null == dependency)
30
- {
31
- throw new ArgumentNullException("dependency");
32
- }
33
-
34
- // If the dependency key is already in the collection, verify equality for a subset of properties.
35
- if (this.Contains(dependency.Key))
36
- {
37
- ProvidesDependency current = this[dependency.Key];
38
- if (!current.Equals(dependency))
39
- {
40
- return false;
41
- }
42
- }
43
-
44
- base.Add(dependency);
45
- return true;
46
- }
47
-
48
- /// <summary>
49
- /// Gets the <see cref="ProvidesDependency.Key"/> for the <paramref name="dependency"/>.
50
- /// </summary>
51
- /// <param name="dependency">The dependency to index.</param>
52
- /// <exception cref="ArgumentNullException">The <paramref name="dependency"/> parameter is null.</exception>
53
- /// <returns>The <see cref="ProvidesDependency.Key"/> for the <paramref name="dependency"/>.</returns>
54
- protected override string GetKeyForItem(ProvidesDependency dependency)
55
- {
56
- if (null == dependency)
57
- {
58
- throw new ArgumentNullException("dependency");
59
- }
60
-
61
- return dependency.Key;
62
- }
63
- }
64
-}
src/WixToolset.Core.Burn/Bind/SearchFacade.cs
new
+197
@@ -0,0 +1,197 @@
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.Burn
4
+{
5
+ using System;
6
+ using System.Xml;
7
+ using WixToolset.Data;
8
+ using WixToolset.Data.Tuples;
9
+
10
+ internal class SearchFacade
11
+ {
12
+ public SearchFacade(WixSearchTuple searchTuple, IntermediateTuple searchSpecificTuple)
13
+ {
14
+ this.SearchTuple = searchTuple;
15
+ this.SearchSpecificTuple = searchSpecificTuple;
16
+ }
17
+
18
+ public WixSearchTuple SearchTuple { get; }
19
+
20
+ public IntermediateTuple SearchSpecificTuple { get; }
21
+
22
+ /// <summary>
23
+ /// Generates Burn manifest and ParameterInfo-style markup a search.
24
+ /// </summary>
25
+ /// <param name="writer"></param>
26
+ public void WriteXml(XmlTextWriter writer)
27
+ {
28
+ switch (this.SearchSpecificTuple)
29
+ {
30
+ case WixComponentSearchTuple tuple:
31
+ this.WriteComponentSearchXml(writer, tuple);
32
+ break;
33
+ case WixFileSearchTuple tuple:
34
+ this.WriteFileSearchXml(writer, tuple);
35
+ break;
36
+ case WixProductSearchTuple tuple:
37
+ this.WriteProductSearchXml(writer, tuple);
38
+ break;
39
+ case WixRegistrySearchTuple tuple:
40
+ this.WriteRegistrySearchXml(writer, tuple);
41
+ break;
42
+ }
43
+ }
44
+
45
+ private void WriteCommonAttributes(XmlTextWriter writer)
46
+ {
47
+ writer.WriteAttributeString("Id", this.SearchTuple.Id.Id);
48
+ writer.WriteAttributeString("Variable", this.SearchTuple.Variable);
49
+ if (!String.IsNullOrEmpty(this.SearchTuple.Condition))
50
+ {
51
+ writer.WriteAttributeString("Condition", this.SearchTuple.Condition);
52
+ }
53
+ }
54
+
55
+ private void WriteComponentSearchXml(XmlTextWriter writer, WixComponentSearchTuple searchTuple)
56
+ {
57
+ writer.WriteStartElement("MsiComponentSearch");
58
+
59
+ this.WriteCommonAttributes(writer);
60
+
61
+ writer.WriteAttributeString("ComponentId", searchTuple.Guid);
62
+
63
+ if (!String.IsNullOrEmpty(searchTuple.ProductCode))
64
+ {
65
+ writer.WriteAttributeString("ProductCode", searchTuple.ProductCode);
66
+ }
67
+
68
+ if (0 != (searchTuple.Attributes & WixComponentSearchAttributes.KeyPath))
69
+ {
70
+ writer.WriteAttributeString("Type", "keyPath");
71
+ }
72
+ else if (0 != (searchTuple.Attributes & WixComponentSearchAttributes.State))
73
+ {
74
+ writer.WriteAttributeString("Type", "state");
75
+ }
76
+ else if (0 != (searchTuple.Attributes & WixComponentSearchAttributes.WantDirectory))
77
+ {
78
+ writer.WriteAttributeString("Type", "directory");
79
+ }
80
+
81
+ writer.WriteEndElement();
82
+ }
83
+
84
+ private void WriteFileSearchXml(XmlTextWriter writer, WixFileSearchTuple searchTuple)
85
+ {
86
+ writer.WriteStartElement((0 == (searchTuple.Attributes & WixFileSearchAttributes.IsDirectory)) ? "FileSearch" : "DirectorySearch");
87
+
88
+ this.WriteCommonAttributes(writer);
89
+
90
+ writer.WriteAttributeString("Path", searchTuple.Path);
91
+ if (WixFileSearchAttributes.WantExists == (searchTuple.Attributes & WixFileSearchAttributes.WantExists))
92
+ {
93
+ writer.WriteAttributeString("Type", "exists");
94
+ }
95
+ else if (WixFileSearchAttributes.WantVersion == (searchTuple.Attributes & WixFileSearchAttributes.WantVersion))
96
+ {
97
+ // Can never get here for DirectorySearch.
98
+ writer.WriteAttributeString("Type", "version");
99
+ }
100
+ else
101
+ {
102
+ writer.WriteAttributeString("Type", "path");
103
+ }
104
+ writer.WriteEndElement();
105
+ }
106
+
107
+ private void WriteProductSearchXml(XmlTextWriter writer, WixProductSearchTuple tuple)
108
+ {
109
+ writer.WriteStartElement("MsiProductSearch");
110
+
111
+ this.WriteCommonAttributes(writer);
112
+
113
+ if (0 != (tuple.Attributes & WixProductSearchAttributes.UpgradeCode))
114
+ {
115
+ writer.WriteAttributeString("UpgradeCode", tuple.Guid);
116
+ }
117
+ else
118
+ {
119
+ writer.WriteAttributeString("ProductCode", tuple.Guid);
120
+ }
121
+
122
+ if (0 != (tuple.Attributes & WixProductSearchAttributes.Version))
123
+ {
124
+ writer.WriteAttributeString("Type", "version");
125
+ }
126
+ else if (0 != (tuple.Attributes & WixProductSearchAttributes.Language))
127
+ {
128
+ writer.WriteAttributeString("Type", "language");
129
+ }
130
+ else if (0 != (tuple.Attributes & WixProductSearchAttributes.State))
131
+ {
132
+ writer.WriteAttributeString("Type", "state");
133
+ }
134
+ else if (0 != (tuple.Attributes & WixProductSearchAttributes.Assignment))
135
+ {
136
+ writer.WriteAttributeString("Type", "assignment");
137
+ }
138
+
139
+ writer.WriteEndElement();
140
+ }
141
+
142
+ private void WriteRegistrySearchXml(XmlTextWriter writer, WixRegistrySearchTuple tuple)
143
+ {
144
+ writer.WriteStartElement("RegistrySearch");
145
+
146
+ this.WriteCommonAttributes(writer);
147
+
148
+ switch (tuple.Root)
149
+ {
150
+ case RegistryRootType.ClassesRoot:
151
+ writer.WriteAttributeString("Root", "HKCR");
152
+ break;
153
+ case RegistryRootType.CurrentUser:
154
+ writer.WriteAttributeString("Root", "HKCU");
155
+ break;
156
+ case RegistryRootType.LocalMachine:
157
+ writer.WriteAttributeString("Root", "HKLM");
158
+ break;
159
+ case RegistryRootType.Users:
160
+ writer.WriteAttributeString("Root", "HKU");
161
+ break;
162
+ }
163
+
164
+ writer.WriteAttributeString("Key", tuple.Key);
165
+
166
+ if (!String.IsNullOrEmpty(tuple.Value))
167
+ {
168
+ writer.WriteAttributeString("Value", tuple.Value);
169
+ }
170
+
171
+ var existenceOnly = 0 != (tuple.Attributes & WixRegistrySearchAttributes.WantExists);
172
+
173
+ writer.WriteAttributeString("Type", existenceOnly ? "exists" : "value");
174
+
175
+ if (0 != (tuple.Attributes & WixRegistrySearchAttributes.Win64))
176
+ {
177
+ writer.WriteAttributeString("Win64", "yes");
178
+ }
179
+
180
+ if (!existenceOnly)
181
+ {
182
+ if (0 != (tuple.Attributes & WixRegistrySearchAttributes.ExpandEnvironmentVariables))
183
+ {
184
+ writer.WriteAttributeString("ExpandEnvironment", "yes");
185
+ }
186
+
187
+ // We *always* say this is VariableType="string". If we end up
188
+ // needing to be more specific, we will have to expand the "Format"
189
+ // attribute to allow "number" and "version".
190
+
191
+ writer.WriteAttributeString("VariableType", "string");
192
+ }
193
+
194
+ writer.WriteEndElement();
195
+ }
196
+ }
197
+}
src/WixToolset.Core.Burn/Bind/WixComponentSearchInfo.cs
deleted
-65
@@ -1,65 +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
-
3
-namespace WixToolset.Core.Burn
4
-{
5
- using System;
6
- using System.Xml;
7
- using WixToolset.Data;
8
-
9
- /// <summary>
10
- /// Utility class for all WixComponentSearches.
11
- /// </summary>
12
- internal class WixComponentSearchInfo : WixSearchInfo
13
- {
14
-#if TODO
15
- public WixComponentSearchInfo(Row row)
16
- : this((string)row[0], (string)row[1], (string)row[2], (int)row[3])
17
- {
18
- }
19
-#endif
20
-
21
- public WixComponentSearchInfo(string id, string guid, string productCode, int attributes)
22
- : base(id)
23
- {
24
- this.Guid = guid;
25
- this.ProductCode = productCode;
26
- this.Attributes = (WixComponentSearchAttributes)attributes;
27
- }
28
-
29
- public string Guid { get; private set; }
30
- public string ProductCode { get; private set; }
31
- public WixComponentSearchAttributes Attributes { get; private set; }
32
-
33
- /// <summary>
34
- /// Generates Burn manifest and ParameterInfo-style markup for a component search.
35
- /// </summary>
36
- /// <param name="writer"></param>
37
- public override void WriteXml(XmlTextWriter writer)
38
- {
39
- writer.WriteStartElement("MsiComponentSearch");
40
- this.WriteWixSearchAttributes(writer);
41
-
42
- writer.WriteAttributeString("ComponentId", this.Guid);
43
-
44
- if (!String.IsNullOrEmpty(this.ProductCode))
45
- {
46
- writer.WriteAttributeString("ProductCode", this.ProductCode);
47
- }
48
-
49
- if (0 != (this.Attributes & WixComponentSearchAttributes.KeyPath))
50
- {
51
- writer.WriteAttributeString("Type", "keyPath");
52
- }
53
- else if (0 != (this.Attributes & WixComponentSearchAttributes.State))
54
- {
55
- writer.WriteAttributeString("Type", "state");
56
- }
57
- else if (0 != (this.Attributes & WixComponentSearchAttributes.WantDirectory))
58
- {
59
- writer.WriteAttributeString("Type", "directory");
60
- }
61
-
62
- writer.WriteEndElement();
63
- }
64
- }
65
-}
src/WixToolset.Core.Burn/Bind/WixFileSearchInfo.cs
deleted
-56
@@ -1,56 +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
-
3
-namespace WixToolset.Core.Burn
4
-{
5
- using System;
6
- using System.Xml;
7
- using WixToolset.Data;
8
-
9
- /// <summary>
10
- /// Utility class for all WixFileSearches (file and directory searches).
11
- /// </summary>
12
- internal class WixFileSearchInfo : WixSearchInfo
13
- {
14
-#if TODO
15
- public WixFileSearchInfo(Row row)
16
- : this((string)row[0], (string)row[1], (int)row[9])
17
- {
18
- }
19
-#endif
20
-
21
- public WixFileSearchInfo(string id, string path, int attributes)
22
- : base(id)
23
- {
24
- this.Path = path;
25
- this.Attributes = (WixFileSearchAttributes)attributes;
26
- }
27
-
28
- public string Path { get; private set; }
29
- public WixFileSearchAttributes Attributes { get; private set; }
30
-
31
- /// <summary>
32
- /// Generates Burn manifest and ParameterInfo-style markup for a file/directory search.
33
- /// </summary>
34
- /// <param name="writer"></param>
35
- public override void WriteXml(XmlTextWriter writer)
36
- {
37
- writer.WriteStartElement((0 == (this.Attributes & WixFileSearchAttributes.IsDirectory)) ? "FileSearch" : "DirectorySearch");
38
- this.WriteWixSearchAttributes(writer);
39
- writer.WriteAttributeString("Path", this.Path);
40
- if (WixFileSearchAttributes.WantExists == (this.Attributes & WixFileSearchAttributes.WantExists))
41
- {
42
- writer.WriteAttributeString("Type", "exists");
43
- }
44
- else if (WixFileSearchAttributes.WantVersion == (this.Attributes & WixFileSearchAttributes.WantVersion))
45
- {
46
- // Can never get here for DirectorySearch.
47
- writer.WriteAttributeString("Type", "version");
48
- }
49
- else
50
- {
51
- writer.WriteAttributeString("Type", "path");
52
- }
53
- writer.WriteEndElement();
54
- }
55
- }
56
-}
src/WixToolset.Core.Burn/Bind/WixProductSearchInfo.cs
deleted
-69
@@ -1,69 +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
-
3
-namespace WixToolset.Core.Burn
4
-{
5
- using System;
6
- using System.Xml;
7
- using WixToolset.Data;
8
-
9
- /// <summary>
10
- /// Utility class for all WixProductSearches.
11
- /// </summary>
12
- internal class WixProductSearchInfo : WixSearchInfo
13
- {
14
-#if TODO
15
- public WixProductSearchInfo(Row row)
16
- : this((string)row[0], (string)row[1], (int)row[2])
17
- {
18
- }
19
-#endif
20
-
21
- public WixProductSearchInfo(string id, string guid, int attributes)
22
- : base(id)
23
- {
24
- this.Guid = guid;
25
- this.Attributes = (WixProductSearchAttributes)attributes;
26
- }
27
-
28
- public string Guid { get; private set; }
29
- public WixProductSearchAttributes Attributes { get; private set; }
30
-
31
- /// <summary>
32
- /// Generates Burn manifest and ParameterInfo-style markup for a product search.
33
- /// </summary>
34
- /// <param name="writer"></param>
35
- public override void WriteXml(XmlTextWriter writer)
36
- {
37
- writer.WriteStartElement("MsiProductSearch");
38
- this.WriteWixSearchAttributes(writer);
39
-
40
- if (0 != (this.Attributes & WixProductSearchAttributes.UpgradeCode))
41
- {
42
- writer.WriteAttributeString("UpgradeCode", this.Guid);
43
- }
44
- else
45
- {
46
- writer.WriteAttributeString("ProductCode", this.Guid);
47
- }
48
-
49
- if (0 != (this.Attributes & WixProductSearchAttributes.Version))
50
- {
51
- writer.WriteAttributeString("Type", "version");
52
- }
53
- else if (0 != (this.Attributes & WixProductSearchAttributes.Language))
54
- {
55
- writer.WriteAttributeString("Type", "language");
56
- }
57
- else if (0 != (this.Attributes & WixProductSearchAttributes.State))
58
- {
59
- writer.WriteAttributeString("Type", "state");
60
- }
61
- else if (0 != (this.Attributes & WixProductSearchAttributes.Assignment))
62
- {
63
- writer.WriteAttributeString("Type", "assignment");
64
- }
65
-
66
- writer.WriteEndElement();
67
- }
68
- }
69
-}
src/WixToolset.Core.Burn/Bind/WixRegistrySearchInfo.cs
deleted
-93
@@ -1,93 +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
-
3
-namespace WixToolset.Core.Burn
4
-{
5
- using System;
6
- using System.Xml;
7
- using WixToolset.Data.WindowsInstaller;
8
-
9
- /// <summary>
10
- /// Utility class for all WixRegistrySearches.
11
- /// </summary>
12
- internal class WixRegistrySearchInfo : WixSearchInfo
13
- {
14
-#if TODO
15
- public WixRegistrySearchInfo(Row row)
16
- : this((string)row[0], (int)row[1], (string)row[2], (string)row[3], (int)row[4])
17
- {
18
- }
19
-#endif
20
-
21
- public WixRegistrySearchInfo(string id, int root, string key, string value, int attributes)
22
- : base(id)
23
- {
24
- this.Root = root;
25
- this.Key = key;
26
- this.Value = value;
27
- this.Attributes = (WixRegistrySearchAttributes)attributes;
28
- }
29
-
30
- public int Root { get; private set; }
31
- public string Key { get; private set; }
32
- public string Value { get; private set; }
33
- public WixRegistrySearchAttributes Attributes { get; private set; }
34
-
35
- /// <summary>
36
- /// Generates Burn manifest and ParameterInfo-style markup for a registry search.
37
- /// </summary>
38
- /// <param name="writer"></param>
39
- public override void WriteXml(XmlTextWriter writer)
40
- {
41
- writer.WriteStartElement("RegistrySearch");
42
- this.WriteWixSearchAttributes(writer);
43
-
44
- switch (this.Root)
45
- {
46
- case WindowsInstallerConstants.MsidbRegistryRootClassesRoot:
47
- writer.WriteAttributeString("Root", "HKCR");
48
- break;
49
- case WindowsInstallerConstants.MsidbRegistryRootCurrentUser:
50
- writer.WriteAttributeString("Root", "HKCU");
51
- break;
52
- case WindowsInstallerConstants.MsidbRegistryRootLocalMachine:
53
- writer.WriteAttributeString("Root", "HKLM");
54
- break;
55
- case WindowsInstallerConstants.MsidbRegistryRootUsers:
56
- writer.WriteAttributeString("Root", "HKU");
57
- break;
58
- }
59
-
60
- writer.WriteAttributeString("Key", this.Key);
61
-
62
- if (!String.IsNullOrEmpty(this.Value))
63
- {
64
- writer.WriteAttributeString("Value", this.Value);
65
- }
66
-
67
- bool existenceOnly = 0 != (this.Attributes & WixRegistrySearchAttributes.WantExists);
68
-
69
- writer.WriteAttributeString("Type", existenceOnly ? "exists" : "value");
70
-
71
- if (0 != (this.Attributes & WixRegistrySearchAttributes.Win64))
72
- {
73
- writer.WriteAttributeString("Win64", "yes");
74
- }
75
-
76
- if (!existenceOnly)
77
- {
78
- if (0 != (this.Attributes & WixRegistrySearchAttributes.ExpandEnvironmentVariables))
79
- {
80
- writer.WriteAttributeString("ExpandEnvironment", "yes");
81
- }
82
-
83
- // We *always* say this is VariableType="string". If we end up
84
- // needing to be more specific, we will have to expand the "Format"
85
- // attribute to allow "number" and "version".
86
-
87
- writer.WriteAttributeString("VariableType", "string");
88
- }
89
-
90
- writer.WriteEndElement();
91
- }
92
- }
93
-}
src/WixToolset.Core.Burn/Bind/WixSearchInfo.cs
deleted
-55
@@ -1,55 +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
-
3
-namespace WixToolset.Core.Burn
4
-{
5
- using System;
6
- using System.Diagnostics;
7
- using System.Xml;
8
- using WixToolset.Data;
9
-
10
- /// <summary>
11
- /// Utility base class for all WixSearches.
12
- /// </summary>
13
- internal abstract class WixSearchInfo
14
- {
15
- public WixSearchInfo(string id)
16
- {
17
- this.Id = id;
18
- }
19
-
20
-#if TODO
21
- public void AddWixSearchRowInfo(Row row)
22
- {
23
- Debug.Assert((string)row[0] == Id);
24
- Variable = (string)row[1];
25
- Condition = (string)row[2];
26
- }
27
-#endif
28
-
29
- public string Id { get; private set; }
30
- public string Variable { get; private set; }
31
- public string Condition { get; private set; }
32
-
33
- /// <summary>
34
- /// Generates Burn manifest and ParameterInfo-style markup a search.
35
- /// </summary>
36
- /// <param name="writer"></param>
37
- public virtual void WriteXml(XmlTextWriter writer)
38
- {
39
- }
40
-
41
- /// <summary>
42
- /// Writes attributes common to all WixSearch elements.
43
- /// </summary>
44
- /// <param name="writer"></param>
45
- protected void WriteWixSearchAttributes(XmlTextWriter writer)
46
- {
47
- writer.WriteAttributeString("Id", this.Id);
48
- writer.WriteAttributeString("Variable", this.Variable);
49
- if (!String.IsNullOrEmpty(this.Condition))
50
- {
51
- writer.WriteAttributeString("Condition", this.Condition);
52
- }
53
- }
54
- }
55
-}
src/WixToolset.Core.Burn/BundleBackend.cs
+17
-11
@@ -15,20 +15,26 @@ namespace WixToolset.Core.Burn
15
{
16
public IBindResult Bind(IBindContext context)
17
{
18
- BindBundleCommand command = new BindBundleCommand(context);
19
- //command.DefaultCompressionLevel = context.DefaultCompressionLevel;
20
- //command.Extensions = context.Extensions;
21
- //command.IntermediateFolder = context.IntermediateFolder;
22
- //command.Output = context.IntermediateRepresentation;
23
- //command.OutputPath = context.OutputPath;
24
- //command.PdbFile = context.OutputPdbPath;
25
- //command.WixVariableResolver = context.WixVariableResolver;
18
+ var extensionManager = context.ServiceProvider.GetService<IExtensionManager>();
19
+
20
+ var backendExtensions = extensionManager.GetServices<IBurnBackendExtension>();
21
+
22
+ foreach (var extension in backendExtensions)
23
+ {
24
+ extension.PreBackendBind(context);
25
+ }
26
+
27
+ var command = new BindBundleCommand(context, backendExtensions);
28
command.Execute();
29
30
var result = context.ServiceProvider.GetService<IBindResult>();
31
result.FileTransfers = command.FileTransfers;
32
result.TrackedFiles = command.TrackedFiles;
33
34
+ foreach (var extension in backendExtensions)
35
+ {
36
+ extension.PostBackendBind(result);
37
+ }
38
return result;
39
}
40
@@ -53,10 +59,10 @@ namespace WixToolset.Core.Burn
59
60
public Intermediate Unbind(IUnbindContext context)
61
{
56
- string uxExtractPath = Path.Combine(context.ExportBasePath, "UX");
57
- string acExtractPath = Path.Combine(context.ExportBasePath, "AttachedContainer");
62
+ var uxExtractPath = Path.Combine(context.ExportBasePath, "UX");
63
+ var acExtractPath = Path.Combine(context.ExportBasePath, "AttachedContainer");
64
59
- using (BurnReader reader = BurnReader.Open(context.InputFilePath))
65
+ using (var reader = BurnReader.Open(context.InputFilePath))
66
{
67
reader.ExtractUXContainer(uxExtractPath, context.IntermediateFolder);
68
reader.ExtractAttachedContainer(acExtractPath, context.IntermediateFolder);
src/WixToolset.Core.Burn/Bundles/AutomaticallySlipstreamPatchesCommand.cs
+65
-56
@@ -7,107 +7,116 @@ namespace WixToolset.Core.Burn.Bundles
7
using System.Diagnostics;
8
using System.Linq;
9
using WixToolset.Data;
10
+ using WixToolset.Data.Tuples;
11
12
internal class AutomaticallySlipstreamPatchesCommand
13
{
13
-#if TODO
14
- public IEnumerable<PackageFacade> PackageFacades { private get; set; }
14
+ public AutomaticallySlipstreamPatchesCommand(IntermediateSection section, ICollection<PackageFacade> packageFacades)
15
+ {
16
+ this.Section = section;
17
+ this.PackageFacades = packageFacades;
18
+ }
19
16
- public Table WixBundlePatchTargetCodeTable { private get; set; }
20
+ private IntermediateSection Section { get; }
21
18
- public Table SlipstreamMspTable { private get; set; }
22
+ private IEnumerable<PackageFacade> PackageFacades { get; }
23
24
public void Execute()
25
{
22
- List<WixBundleMsiPackageRow> msiPackages = new List<WixBundleMsiPackageRow>();
23
- Dictionary<string, List<WixBundlePatchTargetCodeRow>> targetsProductCode = new Dictionary<string, List<WixBundlePatchTargetCodeRow>>();
24
- Dictionary<string, List<WixBundlePatchTargetCodeRow>> targetsUpgradeCode = new Dictionary<string, List<WixBundlePatchTargetCodeRow>>();
26
+ var msiPackages = new List<WixBundleMsiPackageTuple>();
27
+ var targetsProductCode = new Dictionary<string, List<WixBundlePatchTargetCodeTuple>>();
28
+ var targetsUpgradeCode = new Dictionary<string, List<WixBundlePatchTargetCodeTuple>>();
29
26
- foreach (PackageFacade facade in this.PackageFacades)
30
+ foreach (var facade in this.PackageFacades)
31
{
28
- if (WixBundlePackageType.Msi == facade.Package.Type)
32
+ // Keep track of all MSI packages.
33
+ if (facade.SpecificPackageTuple is WixBundleMsiPackageTuple msiPackage)
34
{
30
- // Keep track of all MSI packages.
31
- msiPackages.Add(facade.MsiPackage);
35
+ msiPackages.Add(msiPackage);
36
}
33
- else if (WixBundlePackageType.Msp == facade.Package.Type && facade.MspPackage.Slipstream)
37
+ else if (facade.SpecificPackageTuple is WixBundleMspPackageTuple mspPackage && mspPackage.Slipstream)
38
{
35
- IEnumerable<WixBundlePatchTargetCodeRow> patchTargetCodeRows = this.WixBundlePatchTargetCodeTable.RowsAs<WixBundlePatchTargetCodeRow>().Where(r => r.MspPackageId == facade.Package.WixChainItemId);
39
+ var patchTargetCodeTuples = this.Section.Tuples
40
+ .OfType<WixBundlePatchTargetCodeTuple>()
41
+ .Where(r => r.PackageRef == facade.PackageId);
42
43
// Index target ProductCodes and UpgradeCodes for slipstreamed MSPs.
38
- foreach (WixBundlePatchTargetCodeRow row in patchTargetCodeRows)
44
+ foreach (var tuple in patchTargetCodeTuples)
45
{
40
- if (row.TargetsProductCode)
46
+ if (tuple.TargetsProductCode)
47
{
42
- List<WixBundlePatchTargetCodeRow> rows;
43
- if (!targetsProductCode.TryGetValue(row.TargetCode, out rows))
48
+ if (!targetsProductCode.TryGetValue(tuple.TargetCode, out var tuples))
49
{
45
- rows = new List<WixBundlePatchTargetCodeRow>();
46
- targetsProductCode.Add(row.TargetCode, rows);
50
+ tuples = new List<WixBundlePatchTargetCodeTuple>();
51
+ targetsProductCode.Add(tuple.TargetCode, tuples);
52
}
53
49
- rows.Add(row);
54
+ tuples.Add(tuple);
55
}
51
- else if (row.TargetsUpgradeCode)
56
+ else if (tuple.TargetsUpgradeCode)
57
{
53
- List<WixBundlePatchTargetCodeRow> rows;
54
- if (!targetsUpgradeCode.TryGetValue(row.TargetCode, out rows))
58
+ if (!targetsUpgradeCode.TryGetValue(tuple.TargetCode, out var tuples))
59
{
56
- rows = new List<WixBundlePatchTargetCodeRow>();
57
- targetsUpgradeCode.Add(row.TargetCode, rows);
60
+ tuples = new List<WixBundlePatchTargetCodeTuple>();
61
+ targetsUpgradeCode.Add(tuple.TargetCode, tuples);
62
}
63
}
64
}
65
}
66
}
67
64
- RowIndexedList<Row> slipstreamMspRows = new RowIndexedList<Row>(SlipstreamMspTable);
68
+ var slipstreamMspIds = new HashSet<string>();
69
70
// Loop through the MSI and slipstream patches targeting it.
67
- foreach (WixBundleMsiPackageRow msi in msiPackages)
71
+ foreach (var msi in msiPackages)
72
{
69
- List<WixBundlePatchTargetCodeRow> rows;
70
- if (targetsProductCode.TryGetValue(msi.ProductCode, out rows))
73
+ if (targetsProductCode.TryGetValue(msi.ProductCode, out var tuples))
74
{
72
- foreach (WixBundlePatchTargetCodeRow row in rows)
75
+ foreach (var tuple in tuples)
76
{
74
- Debug.Assert(row.TargetsProductCode);
75
- Debug.Assert(!row.TargetsUpgradeCode);
76
-
77
- Row slipstreamMspRow = SlipstreamMspTable.CreateRow(row.SourceLineNumbers, false);
78
- slipstreamMspRow[0] = msi.ChainPackageId;
79
- slipstreamMspRow[1] = row.MspPackageId;
77
+ Debug.Assert(tuple.TargetsProductCode);
78
+ Debug.Assert(!tuple.TargetsUpgradeCode);
79
81
- if (slipstreamMspRows.TryAdd(slipstreamMspRow))
82
- {
83
- SlipstreamMspTable.Rows.Add(slipstreamMspRow);
84
- }
80
+ this.TryAddSlipstreamTuple(slipstreamMspIds, msi, tuple);
81
}
86
-
87
- rows = null;
82
}
83
90
- if (!String.IsNullOrEmpty(msi.UpgradeCode) && targetsUpgradeCode.TryGetValue(msi.UpgradeCode, out rows))
84
+ if (!String.IsNullOrEmpty(msi.UpgradeCode) && targetsUpgradeCode.TryGetValue(msi.UpgradeCode, out tuples))
85
{
92
- foreach (WixBundlePatchTargetCodeRow row in rows)
86
+ foreach (var tuple in tuples)
87
{
94
- Debug.Assert(!row.TargetsProductCode);
95
- Debug.Assert(row.TargetsUpgradeCode);
96
-
97
- Row slipstreamMspRow = SlipstreamMspTable.CreateRow(row.SourceLineNumbers, false);
98
- slipstreamMspRow[0] = msi.ChainPackageId;
99
- slipstreamMspRow[1] = row.MspPackageId;
88
+ Debug.Assert(!tuple.TargetsProductCode);
89
+ Debug.Assert(tuple.TargetsUpgradeCode);
90
101
- if (slipstreamMspRows.TryAdd(slipstreamMspRow))
102
- {
103
- SlipstreamMspTable.Rows.Add(slipstreamMspRow);
104
- }
91
+ this.TryAddSlipstreamTuple(slipstreamMspIds, msi, tuple);
92
}
93
107
- rows = null;
94
+ tuples = null;
95
}
96
}
97
}
111
-#endif
98
+
99
+ private bool TryAddSlipstreamTuple(HashSet<string> slipstreamMspIds, WixBundleMsiPackageTuple msiPackage, WixBundlePatchTargetCodeTuple patchTargetCode)
100
+ {
101
+ var id = new Identifier(AccessModifier.Private, msiPackage.Id.Id, patchTargetCode.PackageRef);
102
+
103
+ if (slipstreamMspIds.Add(id.Id))
104
+ {
105
+ var slipstreamTuple = new WixBundleSlipstreamMspTuple(patchTargetCode.SourceLineNumbers)
106
+ {
107
+ TargetPackageRef = msiPackage.Id.Id,
108
+ MspPackageRef = patchTargetCode.PackageRef
109
+ };
110
+
111
+ //var slipstreamMspRow = SlipstreamMspTable.CreateRow(tuple.SourceLineNumbers, false);
112
+ //slipstreamMspRow[0] = msi.ChainPackageId;
113
+ //slipstreamMspRow[1] = tuple.MspPackageId;
114
+
115
+ this.Section.Tuples.Add(slipstreamTuple);
116
+ return true;
117
+ }
118
+
119
+ return false;
120
+ }
121
}
122
}
src/WixToolset.Core.Burn/Bundles/BundleHashAlgorithm.cs
new
+30
@@ -0,0 +1,30 @@
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.Burn.Bundles
4
+{
5
+ using System.IO;
6
+ using System.Security.Cryptography;
7
+ using System.Text;
8
+
9
+ internal static class BundleHashAlgorithm
10
+ {
11
+ public static string Hash(FileInfo fileInfo)
12
+ {
13
+ byte[] hashBytes;
14
+
15
+ using (var managed = new SHA1Managed())
16
+ using (var stream = fileInfo.OpenRead())
17
+ {
18
+ hashBytes = managed.ComputeHash(stream);
19
+ }
20
+
21
+ var sb = new StringBuilder(hashBytes.Length * 2);
22
+ for (var i = 0; i < hashBytes.Length; i++)
23
+ {
24
+ sb.AppendFormat("{0:X2}", hashBytes[i]);
25
+ }
26
+
27
+ return sb.ToString();
28
+ }
29
+ }
30
+}
src/WixToolset.Core.Burn/Bundles/BurnCommon.cs
+3
-3
@@ -128,7 +128,7 @@ namespace WixToolset.Core.Burn.Bundles
128
129
public void Dispose()
130
{
131
- Dispose(true);
131
+ this.Dispose(true);
132
133
GC.SuppressFinalize(this);
134
}
@@ -238,7 +238,7 @@ namespace WixToolset.Core.Burn.Bundles
238
{
239
if (UInt32.MaxValue == this.wixburnDataOffset)
240
{
241
- if (!EnsureNTHeader(reader))
241
+ if (!this.EnsureNTHeader(reader))
242
{
243
return false;
244
}
@@ -286,7 +286,7 @@ namespace WixToolset.Core.Burn.Bundles
286
{
287
if (UInt32.MaxValue == this.firstSectionOffset)
288
{
289
- if (!EnsureDosHeader(reader))
289
+ if (!this.EnsureDosHeader(reader))
290
{
291
return false;
292
}
src/WixToolset.Core.Burn/Bundles/BurnWriter.cs
+6
-4
@@ -67,19 +67,21 @@ namespace WixToolset.Core.Burn.Bundles
67
/// <param name="stubSize">Size of the stub engine "burn.exe".</param>
68
/// <param name="bundleId">Unique identifier for this bundle.</param>
69
/// <returns></returns>
70
- public bool InitializeBundleSectionData(long stubSize, Guid bundleId)
70
+ public bool InitializeBundleSectionData(long stubSize, string bundleId)
71
{
72
if (this.invalidBundle)
73
{
74
return false;
75
}
76
77
+ var bundleGuid = Guid.Parse(bundleId);
78
+
79
this.WriteToBurnSectionOffset(BURN_SECTION_OFFSET_MAGIC, BURN_SECTION_MAGIC);
80
this.WriteToBurnSectionOffset(BURN_SECTION_OFFSET_VERSION, BURN_SECTION_VERSION);
81
80
- this.messaging.Write(VerboseMessages.BundleGuid(bundleId.ToString("B")));
82
+ this.messaging.Write(VerboseMessages.BundleGuid(bundleId));
83
this.binaryWriter.BaseStream.Seek(this.wixburnDataOffset + BURN_SECTION_OFFSET_BUNDLEGUID, SeekOrigin.Begin);
82
- this.binaryWriter.Write(bundleId.ToByteArray());
84
+ this.binaryWriter.Write(bundleGuid.ToByteArray());
85
86
this.StubSize = (uint)stubSize;
87
@@ -146,7 +148,7 @@ namespace WixToolset.Core.Burn.Bundles
148
return false;
149
}
150
149
- return AppendContainer(containerStream, (UInt32)containerSize, burnSectionOffsetSize, burnSectionCount);
151
+ return this.AppendContainer(containerStream, (UInt32)containerSize, burnSectionOffsetSize, burnSectionCount);
152
}
153
154
public void RememberThenResetSignature()
src/WixToolset.Core.Burn/Bundles/CreateBootstrapperApplicationManifestCommand.cs
+172
-140
@@ -7,236 +7,268 @@ namespace WixToolset.Core.Burn.Bundles
7
using System.Diagnostics;
8
using System.Globalization;
9
using System.IO;
10
+ using System.Linq;
11
using System.Text;
12
using System.Xml;
13
using WixToolset.Data;
14
+ using WixToolset.Data.Burn;
15
+ using WixToolset.Data.Tuples;
16
17
internal class CreateBootstrapperApplicationManifestCommand
18
{
16
-#if TODO
17
- public WixBundleRow BundleRow { private get; set; }
18
-
19
- public IEnumerable<PackageFacade> ChainPackages { private get; set; }
19
+ public CreateBootstrapperApplicationManifestCommand(IntermediateSection section, WixBundleTuple bundleTuple, IEnumerable<PackageFacade> chainPackages, int lastUXPayloadIndex, Dictionary<string, WixBundlePayloadTuple> payloadTuples, string intermediateFolder)
20
+ {
21
+ this.Section = section;
22
+ this.BundleTuple = bundleTuple;
23
+ this.ChainPackages = chainPackages;
24
+ this.LastUXPayloadIndex = lastUXPayloadIndex;
25
+ this.Payloads = payloadTuples;
26
+ this.IntermediateFolder = intermediateFolder;
27
+ }
28
21
- public int LastUXPayloadIndex { private get; set; }
29
+ private IntermediateSection Section { get; }
30
23
- public IEnumerable<WixBundleMsiFeatureRow> MsiFeatures { private get; set; }
31
+ private WixBundleTuple BundleTuple { get; }
32
25
- public Output Output { private get; set; }
33
+ private IEnumerable<PackageFacade> ChainPackages { get; }
34
27
- public RowDictionary<WixBundlePayloadRow> Payloads { private get; set; }
35
+ private int LastUXPayloadIndex { get; }
36
29
- public TableDefinitionCollection TableDefinitions { private get; set; }
37
+ private Dictionary<string, WixBundlePayloadTuple> Payloads { get; }
38
31
- public string TempFilesLocation { private get; set; }
39
+ private string IntermediateFolder { get; }
40
33
- public WixBundlePayloadRow BootstrapperApplicationManifestPayloadRow { get; private set; }
41
+ public WixBundlePayloadTuple BootstrapperApplicationManifestPayloadRow { get; private set; }
42
43
public void Execute()
44
{
37
- this.GenerateBAManifestBundleTables();
45
+ var baManifestPath = this.CreateBootstrapperApplicationManifest();
46
39
- this.GenerateBAManifestMsiFeatureTables();
47
+ this.BootstrapperApplicationManifestPayloadRow = this.CreateBootstrapperApplicationManifestPayloadRow(baManifestPath);
48
+ }
49
41
- this.GenerateBAManifestPackageTables();
50
+ private string CreateBootstrapperApplicationManifest()
51
+ {
52
+ var path = Path.Combine(this.IntermediateFolder, "wix-badata.xml");
53
43
- this.GenerateBAManifestPayloadTables();
54
+ Directory.CreateDirectory(Path.GetDirectoryName(path));
55
45
- string baManifestPath = Path.Combine(this.TempFilesLocation, "wix-badata.xml");
56
+ using (var writer = new XmlTextWriter(path, Encoding.Unicode))
57
+ {
58
+ writer.Formatting = Formatting.Indented;
59
+ writer.WriteStartDocument();
60
+ writer.WriteStartElement("BootstrapperApplicationData", "http://wixtoolset.org/schemas/v4/BootstrapperApplicationData");
61
47
- this.CreateBootstrapperApplicationManifest(baManifestPath);
62
+ this.WriteBundleInfo(writer);
63
49
- this.BootstrapperApplicationManifestPayloadRow = this.CreateBootstrapperApplicationManifestPayloadRow(baManifestPath);
64
+ this.WritePackageInfo(writer);
65
+
66
+ this.WriteFeatureInfo(writer);
67
+
68
+ this.WritePayloadInfo(writer);
69
+
70
+ this.WriteCustomBootstrapperApplicationData(writer);
71
+
72
+ writer.WriteEndElement();
73
+ writer.WriteEndDocument();
74
+ }
75
+
76
+ return path;
77
}
78
52
- private void GenerateBAManifestBundleTables()
79
+ private void WriteBundleInfo(XmlTextWriter writer)
80
{
54
- Table wixBundlePropertiesTable = this.Output.EnsureTable(this.TableDefinitions["WixBundleProperties"]);
55
-
56
- Row row = wixBundlePropertiesTable.CreateRow(this.BundleRow.SourceLineNumbers);
57
- row[0] = this.BundleRow.Name;
58
- row[1] = this.BundleRow.LogPathVariable;
59
- row[2] = (YesNoDefaultType.Yes == this.BundleRow.Compressed) ? "yes" : "no";
60
- row[3] = this.BundleRow.BundleId.ToString("B");
61
- row[4] = this.BundleRow.UpgradeCode;
62
- row[5] = this.BundleRow.PerMachine ? "yes" : "no";
81
+ writer.WriteStartElement("WixBundleProperties");
82
+
83
+ writer.WriteAttributeString("DisplayName", this.BundleTuple.Name);
84
+ writer.WriteAttributeString("LogPathVariable", this.BundleTuple.LogPathVariable);
85
+ writer.WriteAttributeString("Compressed", this.BundleTuple.Compressed == true ? "yes" : "no");
86
+ writer.WriteAttributeString("BundleId", this.BundleTuple.BundleId.ToUpperInvariant());
87
+ writer.WriteAttributeString("UpgradeCode", this.BundleTuple.UpgradeCode);
88
+ writer.WriteAttributeString("PerMachine", this.BundleTuple.PerMachine ? "yes" : "no");
89
+
90
+ writer.WriteEndElement();
91
}
92
65
- private void GenerateBAManifestPackageTables()
93
+ private void WritePackageInfo(XmlTextWriter writer)
94
{
67
- Table wixPackagePropertiesTable = this.Output.EnsureTable(this.TableDefinitions["WixPackageProperties"]);
68
-
69
- foreach (PackageFacade package in this.ChainPackages)
95
+ foreach (var package in this.ChainPackages)
96
{
71
- WixBundlePayloadRow packagePayload = this.Payloads[package.Package.PackagePayload];
72
-
73
- Row row = wixPackagePropertiesTable.CreateRow(package.Package.SourceLineNumbers);
74
- row[0] = package.Package.WixChainItemId;
75
- row[1] = (YesNoType.Yes == package.Package.Vital) ? "yes" : "no";
76
- row[2] = package.Package.DisplayName;
77
- row[3] = package.Package.Description;
78
- row[4] = package.Package.Size.ToString(CultureInfo.InvariantCulture); // TODO: DownloadSize (compressed) (what does this mean when it's embedded?)
79
- row[5] = package.Package.Size.ToString(CultureInfo.InvariantCulture); // Package.Size (uncompressed)
80
- row[6] = package.Package.InstallSize.Value.ToString(CultureInfo.InvariantCulture); // InstallSize (required disk space)
81
- row[7] = package.Package.Type.ToString();
82
- row[8] = package.Package.Permanent ? "yes" : "no";
83
- row[9] = package.Package.LogPathVariable;
84
- row[10] = package.Package.RollbackLogPathVariable;
85
- row[11] = (PackagingType.Embedded == packagePayload.Packaging) ? "yes" : "no";
86
-
87
- if (WixBundlePackageType.Msi == package.Package.Type)
97
+ var packagePayload = this.Payloads[package.PackageTuple.PayloadRef];
98
+
99
+ var size = package.PackageTuple.Size.ToString(CultureInfo.InvariantCulture);
100
+
101
+ writer.WriteStartElement("WixBundleProperties");
102
+
103
+ writer.WriteAttributeString("Package", package.PackageId);
104
+ writer.WriteAttributeString("Vital", package.PackageTuple.Vital == true ? "yes" : "no");
105
+ writer.WriteAttributeString("DisplayName", package.PackageTuple.DisplayName);
106
+ writer.WriteAttributeString("Description", package.PackageTuple.Description);
107
+ writer.WriteAttributeString("DownloadSize", size);
108
+ writer.WriteAttributeString("PackageSize", size);
109
+ writer.WriteAttributeString("InstalledSize", package.PackageTuple.InstallSize?.ToString(CultureInfo.InvariantCulture) ?? size);
110
+ writer.WriteAttributeString("PackageType", package.PackageTuple.Type.ToString());
111
+ writer.WriteAttributeString("Permanent", package.PackageTuple.Permanent ? "yes" : "no");
112
+ writer.WriteAttributeString("LogPathVariable", package.PackageTuple.LogPathVariable);
113
+ writer.WriteAttributeString("RollbackLogPathVariable", package.PackageTuple.RollbackLogPathVariable);
114
+ writer.WriteAttributeString("Compressed", packagePayload.Compressed == true ? "yes" : "no");
115
+
116
+ if (package.SpecificPackageTuple is WixBundleMsiPackageTuple msiPackage)
117
{
89
- row[12] = package.MsiPackage.DisplayInternalUI ? "yes" : "no";
118
+ writer.WriteAttributeString("DisplayInternalUI", msiPackage.DisplayInternalUI ? "yes" : "no");
119
91
- if (!String.IsNullOrEmpty(package.MsiPackage.ProductCode))
120
+ if (!String.IsNullOrEmpty(msiPackage.ProductCode))
121
{
93
- row[13] = package.MsiPackage.ProductCode;
122
+ writer.WriteAttributeString("ProductCode", msiPackage.ProductCode);
123
}
124
96
- if (!String.IsNullOrEmpty(package.MsiPackage.UpgradeCode))
125
+ if (!String.IsNullOrEmpty(msiPackage.UpgradeCode))
126
{
98
- row[14] = package.MsiPackage.UpgradeCode;
127
+ writer.WriteAttributeString("UpgradeCode", msiPackage.UpgradeCode);
128
}
129
}
101
- else if (WixBundlePackageType.Msp == package.Package.Type)
130
+ else if (package.SpecificPackageTuple is WixBundleMspPackageTuple mspPackage)
131
{
103
- row[12] = package.MspPackage.DisplayInternalUI ? "yes" : "no";
132
+ writer.WriteAttributeString("DisplayInternalUI", mspPackage.DisplayInternalUI ? "yes" : "no");
133
105
- if (!String.IsNullOrEmpty(package.MspPackage.PatchCode))
134
+ if (!String.IsNullOrEmpty(mspPackage.PatchCode))
135
{
107
- row[13] = package.MspPackage.PatchCode;
136
+ writer.WriteAttributeString("ProductCode", mspPackage.PatchCode);
137
}
138
}
139
111
- if (!String.IsNullOrEmpty(package.Package.Version))
140
+ if (!String.IsNullOrEmpty(package.PackageTuple.Version))
141
{
113
- row[15] = package.Package.Version;
142
+ writer.WriteAttributeString("Version", package.PackageTuple.Version);
143
}
144
116
- if (!String.IsNullOrEmpty(package.Package.InstallCondition))
145
+ if (!String.IsNullOrEmpty(package.PackageTuple.InstallCondition))
146
{
118
- row[16] = package.Package.InstallCondition;
147
+ writer.WriteAttributeString("InstallCondition", package.PackageTuple.InstallCondition);
148
}
149
121
- switch (package.Package.Cache)
150
+ switch (package.PackageTuple.Cache)
151
{
152
case YesNoAlwaysType.No:
124
- row[17] = "no";
153
+ writer.WriteAttributeString("Cache", "no");
154
break;
155
case YesNoAlwaysType.Yes:
127
- row[17] = "yes";
156
+ writer.WriteAttributeString("Cache", "yes");
157
break;
158
case YesNoAlwaysType.Always:
130
- row[17] = "always";
159
+ writer.WriteAttributeString("Cache", "always");
160
break;
161
}
162
+
163
+ writer.WriteEndElement();
164
}
165
}
166
136
- private void GenerateBAManifestMsiFeatureTables()
167
+ private void WriteFeatureInfo(XmlTextWriter writer)
168
{
138
- Table wixPackageFeatureInfoTable = this.Output.EnsureTable(this.TableDefinitions["WixPackageFeatureInfo"]);
169
+ var featureTuples = this.Section.Tuples.OfType<WixBundleMsiFeatureTuple>();
170
140
- foreach (WixBundleMsiFeatureRow feature in this.MsiFeatures)
171
+ foreach (var featureTuple in featureTuples)
172
{
142
- Row row = wixPackageFeatureInfoTable.CreateRow(feature.SourceLineNumbers);
143
- row[0] = feature.ChainPackageId;
144
- row[1] = feature.Name;
145
- row[2] = Convert.ToString(feature.Size, CultureInfo.InvariantCulture);
146
- row[3] = feature.Parent;
147
- row[4] = feature.Title;
148
- row[5] = feature.Description;
149
- row[6] = Convert.ToString(feature.Display, CultureInfo.InvariantCulture);
150
- row[7] = Convert.ToString(feature.Level, CultureInfo.InvariantCulture);
151
- row[8] = feature.Directory;
152
- row[9] = Convert.ToString(feature.Attributes, CultureInfo.InvariantCulture);
153
- }
173
+ writer.WriteStartElement("WixPackageFeatureInfo");
174
+
175
+ writer.WriteAttributeString("Package", featureTuple.PackageRef);
176
+ writer.WriteAttributeString("Feature", featureTuple.Name);
177
+ writer.WriteAttributeString("Size", featureTuple.Size.ToString(CultureInfo.InvariantCulture));
178
+ writer.WriteAttributeString("Parent", featureTuple.Parent);
179
+ writer.WriteAttributeString("Title", featureTuple.Title);
180
+ writer.WriteAttributeString("Description", featureTuple.Description);
181
+ writer.WriteAttributeString("Display", featureTuple.Display.ToString(CultureInfo.InvariantCulture));
182
+ writer.WriteAttributeString("Level", featureTuple.Level.ToString(CultureInfo.InvariantCulture));
183
+ writer.WriteAttributeString("Directory", featureTuple.Directory);
184
+ writer.WriteAttributeString("Attributes", featureTuple.Attributes.ToString(CultureInfo.InvariantCulture));
185
186
+ writer.WriteEndElement();
187
+ }
188
}
189
157
- private void GenerateBAManifestPayloadTables()
190
+ private void WritePayloadInfo(XmlTextWriter writer)
191
{
159
- Table wixPayloadPropertiesTable = this.Output.EnsureTable(this.TableDefinitions["WixPayloadProperties"]);
192
+ var payloadTuples = this.Section.Tuples.OfType<WixBundlePayloadTuple>();
193
161
- foreach (WixBundlePayloadRow payload in this.Payloads.Values)
194
+ foreach (var payloadTuple in payloadTuples)
195
{
163
- WixPayloadPropertiesRow row = (WixPayloadPropertiesRow)wixPayloadPropertiesTable.CreateRow(payload.SourceLineNumbers);
164
- row.Id = payload.Id;
165
- row.Package = payload.Package;
166
- row.Container = payload.Container;
167
- row.Name = payload.Name;
168
- row.Size = payload.FileSize.ToString();
169
- row.DownloadUrl = payload.DownloadUrl;
170
- row.LayoutOnly = payload.LayoutOnly ? "yes" : "no";
196
+ writer.WriteStartElement("WixPackageFeatureInfo");
197
+
198
+ writer.WriteAttributeString("Id", payloadTuple.Id.Id);
199
+ writer.WriteAttributeString("Package", payloadTuple.PackageRef);
200
+ writer.WriteAttributeString("Container", payloadTuple.ContainerRef);
201
+ writer.WriteAttributeString("Name", payloadTuple.Name);
202
+ writer.WriteAttributeString("Size", payloadTuple.FileSize.ToString(CultureInfo.InvariantCulture));
203
+ writer.WriteAttributeString("DownloadUrl", payloadTuple.DownloadUrl);
204
+ writer.WriteAttributeString("LayoutOnly", payloadTuple.LayoutOnly ? "yes" : "no");
205
+
206
+ writer.WriteEndElement();
207
}
208
}
209
174
- private void CreateBootstrapperApplicationManifest(string path)
210
+ private void WriteCustomBootstrapperApplicationData(XmlTextWriter writer)
211
{
176
- using (XmlTextWriter writer = new XmlTextWriter(path, Encoding.Unicode))
212
+ var dataTuplesGroupedByDefinitionName = this.Section.Tuples
213
+ .Where(t => t.Definition.HasTag(BurnConstants.BootstrapperApplicationDataTupleDefinitionTag))
214
+ .GroupBy(t => t.Definition);
215
+
216
+ foreach (var group in dataTuplesGroupedByDefinitionName)
217
{
178
- writer.Formatting = Formatting.Indented;
179
- writer.WriteStartDocument();
180
- writer.WriteStartElement("BootstrapperApplicationData", "http://wixtoolset.org/schemas/v4/2010/BootstrapperApplicationData");
218
+ var definition = group.Key;
219
182
- foreach (Table table in this.Output.Tables)
183
- {
184
- if (table.Definition.BootstrapperApplicationData)
185
- {
186
- // We simply assert that the table (and field) name is valid, because
187
- // this is up to the extension developer to get right. An author will
188
- // only affect the attribute value, and that will get properly escaped.
220
+ // We simply assert that the table (and field) name is valid, because
221
+ // this is up to the extension developer to get right. An author will
222
+ // only affect the attribute value, and that will get properly escaped.
223
#if DEBUG
190
- Debug.Assert(Common.IsIdentifier(table.Name));
191
- foreach (ColumnDefinition column in table.Definition.Columns)
192
- {
193
- Debug.Assert(Common.IsIdentifier(column.Name));
194
- }
224
+ Debug.Assert(Common.IsIdentifier(definition.Name));
225
+ foreach (var fieldDef in definition.FieldDefinitions)
226
+ {
227
+ Debug.Assert(Common.IsIdentifier(fieldDef.Name));
228
+ }
229
#endif // DEBUG
230
197
- foreach (Row row in table.Rows)
198
- {
199
- writer.WriteStartElement(table.Name);
200
-
201
- foreach (Field field in row.Fields)
202
- {
203
- if (null != field.Data)
204
- {
205
- writer.WriteAttributeString(field.Column.Name, field.Data.ToString());
206
- }
207
- }
231
+ foreach (var row in group)
232
+ {
233
+ writer.WriteStartElement(definition.Name);
234
209
- writer.WriteEndElement();
235
+ foreach (var field in row.Fields)
236
+ {
237
+ if (!field.IsNull())
238
+ {
239
+ writer.WriteAttributeString(field.Definition.Name, field.AsString());
240
}
241
}
212
- }
242
214
- writer.WriteEndElement();
215
- writer.WriteEndDocument();
243
+ writer.WriteEndElement();
244
+ }
245
}
246
}
247
219
- private WixBundlePayloadRow CreateBootstrapperApplicationManifestPayloadRow(string baManifestPath)
248
+ private WixBundlePayloadTuple CreateBootstrapperApplicationManifestPayloadRow(string baManifestPath)
249
{
221
- Table payloadTable = this.Output.EnsureTable(this.TableDefinitions["WixBundlePayload"]);
222
- WixBundlePayloadRow row = (WixBundlePayloadRow)payloadTable.CreateRow(this.BundleRow.SourceLineNumbers);
223
- row.Id = Common.GenerateIdentifier("ux", "BootstrapperApplicationData.xml");
224
- row.Name = "BootstrapperApplicationData.xml";
225
- row.SourceFile = baManifestPath;
226
- row.Compressed = YesNoDefaultType.Yes;
227
- row.UnresolvedSourceFile = baManifestPath;
228
- row.Container = Compiler.BurnUXContainerId;
229
- row.EmbeddedId = String.Format(CultureInfo.InvariantCulture, BurnCommon.BurnUXContainerEmbeddedIdFormat, this.LastUXPayloadIndex);
230
- row.Packaging = PackagingType.Embedded;
250
+ var generatedId = Common.GenerateIdentifier("ux", "BootstrapperApplicationData.xml");
251
+
252
+ var tuple = new WixBundlePayloadTuple(this.BundleTuple.SourceLineNumbers, new Identifier(AccessModifier.Private, generatedId))
253
+ {
254
+ Name = "BootstrapperApplicationData.xml",
255
+ SourceFile = new IntermediateFieldPathValue { Path = baManifestPath },
256
+ Compressed = true,
257
+ UnresolvedSourceFile = baManifestPath,
258
+ ContainerRef = BurnConstants.BurnUXContainerName,
259
+ EmbeddedId = String.Format(CultureInfo.InvariantCulture, BurnCommon.BurnUXContainerEmbeddedIdFormat, this.LastUXPayloadIndex),
260
+ Packaging = PackagingType.Embedded,
261
+ };
262
+
263
+ var fileInfo = new FileInfo(baManifestPath);
264
232
- FileInfo fileInfo = new FileInfo(row.SourceFile);
265
+ tuple.FileSize = (int)fileInfo.Length;
266
234
- row.FileSize = (int)fileInfo.Length;
267
+ tuple.Hash = BundleHashAlgorithm.Hash(fileInfo);
268
236
- row.Hash = Common.GetFileHash(fileInfo.FullName);
269
+ this.Section.Tuples.Add(tuple);
270
238
- return row;
271
+ return tuple;
272
}
240
-#endif
273
}
274
}
src/WixToolset.Core.Burn/Bundles/CreateBundleExeCommand.cs
new
+171
@@ -0,0 +1,171 @@
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.Burn.Bundles
4
+{
5
+ using System;
6
+ using System.Collections.Generic;
7
+ using System.IO;
8
+ using System.Reflection;
9
+ using WixToolset.Data;
10
+ using WixToolset.Data.Burn;
11
+ using WixToolset.Data.Tuples;
12
+ using WixToolset.Extensibility.Data;
13
+ using WixToolset.Extensibility.Services;
14
+
15
+ internal class CreateBundleExeCommand
16
+ {
17
+ public CreateBundleExeCommand(IMessaging messaging, IBackendHelper backendHelper, string intermediateFolder, string outputPath, WixBundleTuple bundleTuple, WixBundleContainerTuple uxContainer, IEnumerable<WixBundleContainerTuple> containers, string burnStubPath)
18
+ {
19
+ this.Messaging = messaging;
20
+ this.BackendHelper = backendHelper;
21
+ this.IntermediateFolder = intermediateFolder;
22
+ this.OutputPath = outputPath;
23
+ this.BundleTuple = bundleTuple;
24
+ this.UXContainer = uxContainer;
25
+ this.Containers = containers;
26
+ this.BurnStubPath = burnStubPath;
27
+ }
28
+
29
+ public IFileTransfer Transfer { get; private set; }
30
+
31
+ private IMessaging Messaging { get; }
32
+
33
+ private IBackendHelper BackendHelper { get; }
34
+
35
+ private string IntermediateFolder { get; }
36
+
37
+ private string OutputPath { get; }
38
+
39
+ private WixBundleTuple BundleTuple { get; }
40
+
41
+ private WixBundleContainerTuple UXContainer { get; }
42
+
43
+ private IEnumerable<WixBundleContainerTuple> Containers { get; }
44
+
45
+ private string BurnStubPath { get; }
46
+
47
+ public void Execute()
48
+ {
49
+ var bundleFilename = Path.GetFileName(this.OutputPath);
50
+
51
+ // Copy the burn.exe to a writable location then mark it to be moved to its final build location. Note
52
+ // that today, the x64 Burn uses the x86 stub.
53
+
54
+ var stubFile = this.BurnStubPath;
55
+
56
+ if (String.IsNullOrEmpty(stubFile))
57
+ {
58
+ var stubPlatform = (Platform.X64 == this.BundleTuple.Platform) ? "x86" : this.BundleTuple.Platform.ToString();
59
+
60
+ stubFile = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), stubPlatform, "burn.exe");
61
+ }
62
+
63
+ var bundleTempPath = Path.Combine(this.IntermediateFolder, bundleFilename);
64
+
65
+ this.Messaging.Write(VerboseMessages.GeneratingBundle(bundleTempPath, stubFile));
66
+
67
+ if ("setup.exe".Equals(bundleFilename, StringComparison.OrdinalIgnoreCase))
68
+ {
69
+ this.Messaging.Write(ErrorMessages.InsecureBundleFilename(bundleFilename));
70
+ }
71
+
72
+ this.Transfer = this.BackendHelper.CreateFileTransfer(bundleTempPath, this.OutputPath, true, this.BundleTuple.SourceLineNumbers);
73
+
74
+ File.Copy(stubFile, bundleTempPath, true);
75
+ File.SetAttributes(bundleTempPath, FileAttributes.Normal);
76
+
77
+ this.UpdateBurnResources(bundleTempPath, this.OutputPath, this.BundleTuple);
78
+
79
+ // Update the .wixburn section to point to at the UX and attached container(s) then attach the containers
80
+ // if they should be attached.
81
+ using (var writer = BurnWriter.Open(this.Messaging, bundleTempPath))
82
+ {
83
+ var burnStubFile = new FileInfo(bundleTempPath);
84
+ writer.InitializeBundleSectionData(burnStubFile.Length, this.BundleTuple.BundleId);
85
+
86
+ // Always attach the UX container first
87
+ writer.AppendContainer(this.UXContainer.WorkingPath, BurnWriter.Container.UX);
88
+
89
+ // Now append all other attached containers
90
+ foreach (var container in this.Containers)
91
+ {
92
+ if (ContainerType.Attached == container.Type)
93
+ {
94
+ // The container was only created if it had payloads.
95
+ if (!String.IsNullOrEmpty(container.WorkingPath) && BurnConstants.BurnUXContainerName != container.Id.Id)
96
+ {
97
+ writer.AppendContainer(container.WorkingPath, BurnWriter.Container.Attached);
98
+ }
99
+ }
100
+ }
101
+ }
102
+ }
103
+
104
+ private void UpdateBurnResources(string bundleTempPath, string outputPath, WixBundleTuple bundleInfo)
105
+ {
106
+ var resources = new Dtf.Resources.ResourceCollection();
107
+ var version = new Dtf.Resources.VersionResource("#1", 1033);
108
+
109
+ version.Load(bundleTempPath);
110
+ resources.Add(version);
111
+
112
+ // Ensure the bundle info provides a full four part version.
113
+ var fourPartVersion = new Version(bundleInfo.Version);
114
+ var major = (fourPartVersion.Major < 0) ? 0 : fourPartVersion.Major;
115
+ var minor = (fourPartVersion.Minor < 0) ? 0 : fourPartVersion.Minor;
116
+ var build = (fourPartVersion.Build < 0) ? 0 : fourPartVersion.Build;
117
+ var revision = (fourPartVersion.Revision < 0) ? 0 : fourPartVersion.Revision;
118
+
119
+ if (UInt16.MaxValue < major || UInt16.MaxValue < minor || UInt16.MaxValue < build || UInt16.MaxValue < revision)
120
+ {
121
+ throw new WixException(ErrorMessages.InvalidModuleOrBundleVersion(bundleInfo.SourceLineNumbers, "Bundle", bundleInfo.Version));
122
+ }
123
+
124
+ fourPartVersion = new Version(major, minor, build, revision);
125
+ version.FileVersion = fourPartVersion;
126
+ version.ProductVersion = fourPartVersion;
127
+
128
+ var strings = version[1033];
129
+ strings["LegalCopyright"] = bundleInfo.Copyright;
130
+ strings["OriginalFilename"] = Path.GetFileName(outputPath);
131
+ strings["FileVersion"] = bundleInfo.Version; // string versions do not have to be four parts.
132
+ strings["ProductVersion"] = bundleInfo.Version; // string versions do not have to be four parts.
133
+
134
+ if (!String.IsNullOrEmpty(bundleInfo.Name))
135
+ {
136
+ strings["ProductName"] = bundleInfo.Name;
137
+ strings["FileDescription"] = bundleInfo.Name;
138
+ }
139
+
140
+ if (!String.IsNullOrEmpty(bundleInfo.Manufacturer))
141
+ {
142
+ strings["CompanyName"] = bundleInfo.Manufacturer;
143
+ }
144
+ else
145
+ {
146
+ strings["CompanyName"] = String.Empty;
147
+ }
148
+
149
+ if (!String.IsNullOrEmpty(bundleInfo.IconSourceFile))
150
+ {
151
+ var iconGroup = new Dtf.Resources.GroupIconResource("#1", 1033);
152
+ iconGroup.ReadFromFile(bundleInfo.IconSourceFile);
153
+ resources.Add(iconGroup);
154
+
155
+ foreach (var icon in iconGroup.Icons)
156
+ {
157
+ resources.Add(icon);
158
+ }
159
+ }
160
+
161
+ if (!String.IsNullOrEmpty(bundleInfo.SplashScreenSourceFile))
162
+ {
163
+ var bitmap = new Dtf.Resources.BitmapResource("#1", 1033);
164
+ bitmap.ReadFromFile(bundleInfo.SplashScreenSourceFile);
165
+ resources.Add(bitmap);
166
+ }
167
+
168
+ resources.Save(bundleTempPath);
169
+ }
170
+ }
171
+}
src/WixToolset.Core.Burn/Bundles/CreateBurnManifestCommand.cs
+227
-172
@@ -6,76 +6,103 @@ namespace WixToolset.Core.Burn.Bundles
6
using System.Collections.Generic;
7
using System.Diagnostics;
8
using System.Globalization;
9
+ using System.IO;
10
using System.Linq;
11
using System.Text;
12
using System.Xml;
13
using WixToolset.Data;
14
+ using WixToolset.Data.Burn;
15
+ using WixToolset.Data.Tuples;
16
using WixToolset.Extensibility;
17
+ using WixToolset.Extensibility.Services;
18
19
internal class CreateBurnManifestCommand
20
{
17
-#if TODO
18
- public IEnumerable<IBurnBackendExtension> BackendExtensions { private get; set; }
21
+ public CreateBurnManifestCommand(IMessaging messaging, IEnumerable<IBurnBackendExtension> backendExtensions, string executableName, IntermediateSection section, WixBundleTuple bundleTuple, IEnumerable<WixBundleContainerTuple> containers, WixChainTuple chainTuple, IEnumerable<PackageFacade> orderedPackages, IEnumerable<WixBundleRollbackBoundaryTuple> boundaries, IEnumerable<WixBundlePayloadTuple> uxPayloads, Dictionary<string, WixBundlePayloadTuple> allPayloadsById, IEnumerable<SearchFacade> orderedSearches, IEnumerable<WixBundleCatalogTuple> catalogs, string intermediateFolder)
22
+ {
23
+ this.Messaging = messaging;
24
+ this.BackendExtensions = backendExtensions;
25
+ this.ExecutableName = executableName;
26
+ this.Section = section;
27
+ this.BundleTuple = bundleTuple;
28
+ this.Chain = chainTuple;
29
+ this.Containers = containers;
30
+ this.OrderedPackages = orderedPackages;
31
+ this.RollbackBoundaries = boundaries;
32
+ this.UXContainerPayloads = uxPayloads;
33
+ this.Payloads = allPayloadsById;
34
+ this.OrderedSearches = orderedSearches;
35
+ this.Catalogs = catalogs;
36
+ this.IntermediateFolder = intermediateFolder;
37
+ }
38
+
39
+ public string OutputPath { get; private set; }
40
+
41
+ private IMessaging Messaging { get; }
42
20
- public Output Output { private get; set; }
43
+ private IEnumerable<IBurnBackendExtension> BackendExtensions { get; }
44
22
- public string ExecutableName { private get; set; }
45
+ private string ExecutableName { get; }
46
24
- public WixBundleRow BundleInfo { private get; set; }
47
+ private IntermediateSection Section { get; }
48
26
- public WixChainRow Chain { private get; set; }
49
+ private WixBundleTuple BundleTuple { get; }
50
28
- public string OutputPath { private get; set; }
51
+ private WixChainTuple Chain { get; }
52
30
- public IEnumerable<WixBundleRollbackBoundaryRow> RollbackBoundaries { private get; set; }
53
+ private IEnumerable<WixBundleRollbackBoundaryTuple> RollbackBoundaries { get; }
54
32
- public IEnumerable<PackageFacade> OrderedPackages { private get; set; }
55
+ private IEnumerable<PackageFacade> OrderedPackages { get; }
56
34
- public IEnumerable<WixSearchInfo> OrderedSearches { private get; set; }
57
+ private IEnumerable<SearchFacade> OrderedSearches { get; }
58
36
- public Dictionary<string, WixBundlePayloadRow> Payloads { private get; set; }
59
+ private Dictionary<string, WixBundlePayloadTuple> Payloads { get; }
60
38
- public Dictionary<string, WixBundleContainerRow> Containers { private get; set; }
61
+ private IEnumerable<WixBundleContainerTuple> Containers { get; }
62
40
- public IEnumerable<WixBundlePayloadRow> UXContainerPayloads { private get; set; }
63
+ private IEnumerable<WixBundlePayloadTuple> UXContainerPayloads { get; }
64
42
- public IEnumerable<WixBundleCatalogRow> Catalogs { private get; set; }
65
+ private IEnumerable<WixBundleCatalogTuple> Catalogs { get; }
66
+
67
+ private string IntermediateFolder { get; }
68
69
public void Execute()
70
{
46
- using (XmlTextWriter writer = new XmlTextWriter(this.OutputPath, Encoding.UTF8))
71
+ this.OutputPath = Path.Combine(this.IntermediateFolder, "bundle-manifest.xml");
72
+
73
+ using (var writer = new XmlTextWriter(this.OutputPath, Encoding.UTF8))
74
{
75
writer.WriteStartDocument();
76
77
writer.WriteStartElement("BurnManifest", BurnCommon.BurnNamespace);
78
79
// Write the condition, if there is one
53
- if (null != this.BundleInfo.Condition)
80
+ if (null != this.BundleTuple.Condition)
81
{
55
- writer.WriteElementString("Condition", this.BundleInfo.Condition);
82
+ writer.WriteElementString("Condition", this.BundleTuple.Condition);
83
}
84
85
// Write the log element if default logging wasn't disabled.
59
- if (!String.IsNullOrEmpty(this.BundleInfo.LogPrefix))
86
+ if (!String.IsNullOrEmpty(this.BundleTuple.LogPrefix))
87
{
88
writer.WriteStartElement("Log");
62
- if (!String.IsNullOrEmpty(this.BundleInfo.LogPathVariable))
89
+ if (!String.IsNullOrEmpty(this.BundleTuple.LogPathVariable))
90
{
64
- writer.WriteAttributeString("PathVariable", this.BundleInfo.LogPathVariable);
91
+ writer.WriteAttributeString("PathVariable", this.BundleTuple.LogPathVariable);
92
}
66
- writer.WriteAttributeString("Prefix", this.BundleInfo.LogPrefix);
67
- writer.WriteAttributeString("Extension", this.BundleInfo.LogExtension);
93
+ writer.WriteAttributeString("Prefix", this.BundleTuple.LogPrefix);
94
+ writer.WriteAttributeString("Extension", this.BundleTuple.LogExtension);
95
writer.WriteEndElement();
96
}
97
98
99
// Get update if specified.
73
- WixBundleUpdateRow updateRow = this.Output.Tables["WixBundleUpdate"].RowsAs<WixBundleUpdateRow>().FirstOrDefault();
100
+ var updateTuple = this.Section.Tuples.OfType<WixBundleUpdateTuple>().FirstOrDefault();
101
75
- if (null != updateRow)
102
+ if (null != updateTuple)
103
{
104
writer.WriteStartElement("Update");
78
- writer.WriteAttributeString("Location", updateRow.Location);
105
+ writer.WriteAttributeString("Location", updateTuple.Location);
106
writer.WriteEndElement(); // </Update>
107
}
108
@@ -83,23 +110,27 @@ namespace WixToolset.Core.Burn.Bundles
110
111
// For the related bundles with duplicated identifiers the second instance is ignored (i.e. the Duplicates
112
// enumeration in the index row list is not used).
86
- RowIndexedList<WixRelatedBundleRow> relatedBundles = new RowIndexedList<WixRelatedBundleRow>(this.Output.Tables["WixRelatedBundle"]);
113
+ var relatedBundles = this.Section.Tuples.OfType<WixRelatedBundleTuple>();
114
+ var distinctRelatedBundles = new HashSet<string>();
115
88
- foreach (WixRelatedBundleRow relatedBundle in relatedBundles)
116
+ foreach (var relatedBundle in relatedBundles)
117
{
90
- writer.WriteStartElement("RelatedBundle");
91
- writer.WriteAttributeString("Id", relatedBundle.Id);
92
- writer.WriteAttributeString("Action", Convert.ToString(relatedBundle.Action, CultureInfo.InvariantCulture));
93
- writer.WriteEndElement();
118
+ if (distinctRelatedBundles.Add(relatedBundle.BundleId))
119
+ {
120
+ writer.WriteStartElement("RelatedBundle");
121
+ writer.WriteAttributeString("Id", relatedBundle.BundleId);
122
+ writer.WriteAttributeString("Action", relatedBundle.Action.ToString());
123
+ writer.WriteEndElement();
124
+ }
125
}
126
127
// Write the variables
97
- IEnumerable<WixBundleVariableRow> variables = this.Output.Tables["WixBundleVariable"].RowsAs<WixBundleVariableRow>();
128
+ var variables = this.Section.Tuples.OfType<WixBundleVariableTuple>();
129
99
- foreach (WixBundleVariableRow variable in variables)
130
+ foreach (var variable in variables)
131
{
132
writer.WriteStartElement("Variable");
102
- writer.WriteAttributeString("Id", variable.Id);
133
+ writer.WriteAttributeString("Id", variable.Id.Id);
134
if (null != variable.Type)
135
{
136
writer.WriteAttributeString("Value", variable.Value);
@@ -111,20 +142,20 @@ namespace WixToolset.Core.Burn.Bundles
142
}
143
144
// Write the searches
114
- foreach (WixSearchInfo searchinfo in this.OrderedSearches)
145
+ foreach (var searchinfo in this.OrderedSearches)
146
{
147
searchinfo.WriteXml(writer);
148
}
149
150
// write the UX element
151
writer.WriteStartElement("UX");
121
- if (!String.IsNullOrEmpty(this.BundleInfo.SplashScreenBitmapPath))
152
+ if (!String.IsNullOrEmpty(this.BundleTuple.SplashScreenSourceFile))
153
{
154
writer.WriteAttributeString("SplashScreen", "yes");
155
}
156
157
// write the UX allPayloads...
127
- foreach (WixBundlePayloadRow payload in this.UXContainerPayloads)
158
+ foreach (var payload in this.UXContainerPayloads)
159
{
160
writer.WriteStartElement("Payload");
161
this.WriteBurnManifestPayloadAttributes(writer, payload, true, this.Payloads);
@@ -136,18 +167,18 @@ namespace WixToolset.Core.Burn.Bundles
167
// write the catalog elements
168
if (this.Catalogs.Any())
169
{
139
- foreach (WixBundleCatalogRow catalog in this.Catalogs)
170
+ foreach (var catalog in this.Catalogs)
171
{
172
writer.WriteStartElement("Catalog");
142
- writer.WriteAttributeString("Id", catalog.Id);
143
- writer.WriteAttributeString("Payload", catalog.Payload);
173
+ writer.WriteAttributeString("Id", catalog.Id.Id);
174
+ writer.WriteAttributeString("Payload", catalog.PayloadRef);
175
writer.WriteEndElement();
176
}
177
}
178
148
- foreach (WixBundleContainerRow container in this.Containers.Values)
179
+ foreach (var container in this.Containers)
180
{
150
- if (!String.IsNullOrEmpty(container.WorkingPath) && Compiler.BurnUXContainerId != container.Id)
181
+ if (!String.IsNullOrEmpty(container.WorkingPath) && BurnConstants.BurnUXContainerName != container.Id.Id)
182
{
183
writer.WriteStartElement("Container");
184
this.WriteBurnManifestContainerAttributes(writer, this.ExecutableName, container);
@@ -155,9 +186,9 @@ namespace WixToolset.Core.Burn.Bundles
186
}
187
}
188
158
- foreach (WixBundlePayloadRow payload in this.Payloads.Values)
189
+ foreach (var payload in this.Payloads.Values)
190
{
160
- if (PackagingType.Embedded == payload.Packaging && Compiler.BurnUXContainerId != payload.Container)
191
+ if (PackagingType.Embedded == payload.Packaging && BurnConstants.BurnUXContainerName != payload.ContainerRef)
192
{
193
writer.WriteStartElement("Payload");
194
this.WriteBurnManifestPayloadAttributes(writer, payload, true, this.Payloads);
@@ -171,77 +202,78 @@ namespace WixToolset.Core.Burn.Bundles
202
}
203
}
204
174
- foreach (WixBundleRollbackBoundaryRow rollbackBoundary in this.RollbackBoundaries)
205
+ foreach (var rollbackBoundary in this.RollbackBoundaries)
206
{
207
writer.WriteStartElement("RollbackBoundary");
177
- writer.WriteAttributeString("Id", rollbackBoundary.ChainPackageId);
178
- writer.WriteAttributeString("Vital", YesNoType.Yes == rollbackBoundary.Vital ? "yes" : "no");
179
- writer.WriteAttributeString("Transaction", YesNoType.Yes == rollbackBoundary.Transaction ? "yes" : "no");
208
+ writer.WriteAttributeString("Id", rollbackBoundary.Id.Id);
209
+ writer.WriteAttributeString("Vital", rollbackBoundary.Vital == false ? "no" : "yes");
210
+ writer.WriteAttributeString("Transaction", rollbackBoundary.Transaction == true ? "yes" : "no");
211
writer.WriteEndElement();
212
}
213
214
// Write the registration information...
215
writer.WriteStartElement("Registration");
216
186
- writer.WriteAttributeString("Id", this.BundleInfo.BundleId.ToString("B"));
217
+ writer.WriteAttributeString("Id", this.BundleTuple.BundleId);
218
writer.WriteAttributeString("ExecutableName", this.ExecutableName);
188
- writer.WriteAttributeString("PerMachine", this.BundleInfo.PerMachine ? "yes" : "no");
189
- writer.WriteAttributeString("Tag", this.BundleInfo.Tag);
190
- writer.WriteAttributeString("Version", this.BundleInfo.Version);
191
- writer.WriteAttributeString("ProviderKey", this.BundleInfo.ProviderKey);
219
+ writer.WriteAttributeString("PerMachine", this.BundleTuple.PerMachine ? "yes" : "no");
220
+ writer.WriteAttributeString("Tag", this.BundleTuple.Tag);
221
+ writer.WriteAttributeString("Version", this.BundleTuple.Version);
222
+ writer.WriteAttributeString("ProviderKey", this.BundleTuple.ProviderKey);
223
224
writer.WriteStartElement("Arp");
194
- writer.WriteAttributeString("Register", (0 < this.BundleInfo.DisableModify && this.BundleInfo.DisableRemove) ? "no" : "yes"); // do not register if disabled modify and remove.
195
- writer.WriteAttributeString("DisplayName", this.BundleInfo.Name);
196
- writer.WriteAttributeString("DisplayVersion", this.BundleInfo.Version);
225
+ writer.WriteAttributeString("Register", (this.BundleTuple.DisableModify || this.BundleTuple.SingleChangeUninstallButton) && this.BundleTuple.DisableRemove ? "no" : "yes"); // do not register if disabled modify and remove.
226
+ writer.WriteAttributeString("DisplayName", this.BundleTuple.Name);
227
+ writer.WriteAttributeString("DisplayVersion", this.BundleTuple.Version);
228
198
- if (!String.IsNullOrEmpty(this.BundleInfo.Publisher))
229
+ if (!String.IsNullOrEmpty(this.BundleTuple.Manufacturer))
230
{
200
- writer.WriteAttributeString("Publisher", this.BundleInfo.Publisher);
231
+ writer.WriteAttributeString("Publisher", this.BundleTuple.Manufacturer);
232
}
233
203
- if (!String.IsNullOrEmpty(this.BundleInfo.HelpLink))
234
+ if (!String.IsNullOrEmpty(this.BundleTuple.HelpUrl))
235
{
205
- writer.WriteAttributeString("HelpLink", this.BundleInfo.HelpLink);
236
+ writer.WriteAttributeString("HelpLink", this.BundleTuple.HelpUrl);
237
}
238
208
- if (!String.IsNullOrEmpty(this.BundleInfo.HelpTelephone))
239
+ if (!String.IsNullOrEmpty(this.BundleTuple.HelpTelephone))
240
{
210
- writer.WriteAttributeString("HelpTelephone", this.BundleInfo.HelpTelephone);
241
+ writer.WriteAttributeString("HelpTelephone", this.BundleTuple.HelpTelephone);
242
}
243
213
- if (!String.IsNullOrEmpty(this.BundleInfo.AboutUrl))
244
+ if (!String.IsNullOrEmpty(this.BundleTuple.AboutUrl))
245
{
215
- writer.WriteAttributeString("AboutUrl", this.BundleInfo.AboutUrl);
246
+ writer.WriteAttributeString("AboutUrl", this.BundleTuple.AboutUrl);
247
}
248
218
- if (!String.IsNullOrEmpty(this.BundleInfo.UpdateUrl))
249
+ if (!String.IsNullOrEmpty(this.BundleTuple.UpdateUrl))
250
{
220
- writer.WriteAttributeString("UpdateUrl", this.BundleInfo.UpdateUrl);
251
+ writer.WriteAttributeString("UpdateUrl", this.BundleTuple.UpdateUrl);
252
}
253
223
- if (!String.IsNullOrEmpty(this.BundleInfo.ParentName))
254
+ if (!String.IsNullOrEmpty(this.BundleTuple.ParentName))
255
{
225
- writer.WriteAttributeString("ParentDisplayName", this.BundleInfo.ParentName);
256
+ writer.WriteAttributeString("ParentDisplayName", this.BundleTuple.ParentName);
257
}
258
228
- if (1 == this.BundleInfo.DisableModify)
259
+ if (this.BundleTuple.DisableModify)
260
{
261
writer.WriteAttributeString("DisableModify", "yes");
262
}
232
- else if (2 == this.BundleInfo.DisableModify)
263
+
264
+ if (this.BundleTuple.DisableRemove)
265
{
234
- writer.WriteAttributeString("DisableModify", "button");
266
+ writer.WriteAttributeString("DisableRemove", "yes");
267
}
268
237
- if (this.BundleInfo.DisableRemove)
269
+ if (this.BundleTuple.SingleChangeUninstallButton)
270
{
239
- writer.WriteAttributeString("DisableRemove", "yes");
271
+ writer.WriteAttributeString("DisableModify", "button");
272
}
273
writer.WriteEndElement(); // </Arp>
274
275
// Get update registration if specified.
244
- WixUpdateRegistrationRow updateRegistrationInfo = this.Output.Tables["WixUpdateRegistration"].RowsAs<WixUpdateRegistrationRow>().FirstOrDefault();
276
+ var updateRegistrationInfo = this.Section.Tuples.OfType<WixUpdateRegistrationTuple>().FirstOrDefault();
277
278
if (null != updateRegistrationInfo)
279
{
@@ -263,9 +295,9 @@ namespace WixToolset.Core.Burn.Bundles
295
writer.WriteEndElement(); // </Update>
296
}
297
266
- IEnumerable<Row> bundleTags = this.Output.Tables["WixBundleTag"].RowsAs<Row>();
267
-
268
- foreach (Row row in bundleTags)
298
+#if TODO // Handle SWID Tags
299
+ var bundleTags = this.Output.Tables["WixBundleTag"].RowsAs<Row>();
300
+ foreach (var row in bundleTags)
301
{
302
writer.WriteStartElement("SoftwareTag");
303
writer.WriteAttributeString("Filename", (string)row[0]);
@@ -273,6 +305,7 @@ namespace WixToolset.Core.Burn.Bundles
305
writer.WriteCData((string)row[4]);
306
writer.WriteEndElement();
307
}
308
+#endif
309
310
writer.WriteEndElement(); // </Register>
311
@@ -294,25 +327,28 @@ namespace WixToolset.Core.Burn.Bundles
327
}
328
329
// Index a few tables by package.
297
- ILookup<string, WixBundlePatchTargetCodeRow> targetCodesByPatch = this.Output.Tables["WixBundlePatchTargetCode"].RowsAs<WixBundlePatchTargetCodeRow>().ToLookup(r => r.MspPackageId);
298
- ILookup<string, WixBundleMsiFeatureRow> msiFeaturesByPackage = this.Output.Tables["WixBundleMsiFeature"].RowsAs<WixBundleMsiFeatureRow>().ToLookup(r => r.ChainPackageId);
299
- ILookup<string, WixBundleMsiPropertyRow> msiPropertiesByPackage = this.Output.Tables["WixBundleMsiProperty"].RowsAs<WixBundleMsiPropertyRow>().ToLookup(r => r.ChainPackageId);
300
- ILookup<string, WixBundlePayloadRow> payloadsByPackage = this.Payloads.Values.ToLookup(p => p.Package);
301
- ILookup<string, WixBundleRelatedPackageRow> relatedPackagesByPackage = this.Output.Tables["WixBundleRelatedPackage"].RowsAs<WixBundleRelatedPackageRow>().ToLookup(r => r.ChainPackageId);
302
- ILookup<string, WixBundleSlipstreamMspRow> slipstreamMspsByPackage = this.Output.Tables["WixBundleSlipstreamMsp"].RowsAs<WixBundleSlipstreamMspRow>().ToLookup(r => r.ChainPackageId);
303
- ILookup<string, WixBundlePackageExitCodeRow> exitCodesByPackage = this.Output.Tables["WixBundlePackageExitCode"].RowsAs<WixBundlePackageExitCodeRow>().ToLookup(r => r.ChainPackageId);
304
- ILookup<string, WixBundlePackageCommandLineRow> commandLinesByPackage = this.Output.Tables["WixBundlePackageCommandLine"].RowsAs<WixBundlePackageCommandLineRow>().ToLookup(r => r.ChainPackageId);
330
+ var targetCodesByPatch = this.Section.Tuples.OfType<WixBundlePatchTargetCodeTuple>().ToLookup(r => r.PackageRef);
331
+ var msiFeaturesByPackage = this.Section.Tuples.OfType<WixBundleMsiFeatureTuple>().ToLookup(r => r.PackageRef);
332
+ var msiPropertiesByPackage = this.Section.Tuples.OfType<WixBundleMsiPropertyTuple>().ToLookup(r => r.PackageRef);
333
+ var payloadsByPackage = this.Payloads.Values.ToLookup(p => p.PackageRef);
334
+ var relatedPackagesByPackage = this.Section.Tuples.OfType<WixBundleRelatedPackageTuple>().ToLookup(r => r.PackageRef);
335
+ var slipstreamMspsByPackage = this.Section.Tuples.OfType<WixBundleSlipstreamMspTuple>().ToLookup(r => r.MspPackageRef);
336
+ var exitCodesByPackage = this.Section.Tuples.OfType<WixBundlePackageExitCodeTuple>().ToLookup(r => r.ChainPackageId);
337
+ var commandLinesByPackage = this.Section.Tuples.OfType<WixBundlePackageCommandLineTuple>().ToLookup(r => r.WixBundlePackageRef);
338
+
339
+ var dependenciesByPackage = this.Section.Tuples.OfType<ProvidesDependencyTuple>().ToLookup(p => p.PackageRef);
340
+
341
342
// Build up the list of target codes from all the MSPs in the chain.
307
- List<WixBundlePatchTargetCodeRow> targetCodes = new List<WixBundlePatchTargetCodeRow>();
343
+ var targetCodes = new List<WixBundlePatchTargetCodeTuple>();
344
309
- foreach (PackageFacade package in this.OrderedPackages)
345
+ foreach (var package in this.OrderedPackages)
346
{
311
- writer.WriteStartElement(String.Format(CultureInfo.InvariantCulture, "{0}Package", package.Package.Type));
347
+ writer.WriteStartElement(String.Format(CultureInfo.InvariantCulture, "{0}Package", package.PackageTuple.Type));
348
313
- writer.WriteAttributeString("Id", package.Package.WixChainItemId);
349
+ writer.WriteAttributeString("Id", package.PackageId);
350
315
- switch (package.Package.Cache)
351
+ switch (package.PackageTuple.Cache)
352
{
353
case YesNoAlwaysType.No:
354
writer.WriteAttributeString("Cache", "no");
@@ -325,74 +361,74 @@ namespace WixToolset.Core.Burn.Bundles
361
break;
362
}
363
328
- writer.WriteAttributeString("CacheId", package.Package.CacheId);
329
- writer.WriteAttributeString("InstallSize", Convert.ToString(package.Package.InstallSize));
330
- writer.WriteAttributeString("Size", Convert.ToString(package.Package.Size));
331
- writer.WriteAttributeString("PerMachine", YesNoDefaultType.Yes == package.Package.PerMachine ? "yes" : "no");
332
- writer.WriteAttributeString("Permanent", package.Package.Permanent ? "yes" : "no");
333
- writer.WriteAttributeString("Vital", (YesNoType.Yes == package.Package.Vital) ? "yes" : "no");
364
+ writer.WriteAttributeString("CacheId", package.PackageTuple.CacheId);
365
+ writer.WriteAttributeString("InstallSize", Convert.ToString(package.PackageTuple.InstallSize));
366
+ writer.WriteAttributeString("Size", Convert.ToString(package.PackageTuple.Size));
367
+ writer.WriteAttributeString("PerMachine", YesNoDefaultType.Yes == package.PackageTuple.PerMachine ? "yes" : "no");
368
+ writer.WriteAttributeString("Permanent", package.PackageTuple.Permanent ? "yes" : "no");
369
+ writer.WriteAttributeString("Vital", package.PackageTuple.Vital == false ? "no" : "yes");
370
335
- if (null != package.Package.RollbackBoundary)
371
+ if (null != package.PackageTuple.RollbackBoundaryRef)
372
{
337
- writer.WriteAttributeString("RollbackBoundaryForward", package.Package.RollbackBoundary);
373
+ writer.WriteAttributeString("RollbackBoundaryForward", package.PackageTuple.RollbackBoundaryRef);
374
}
375
340
- if (!String.IsNullOrEmpty(package.Package.RollbackBoundaryBackward))
376
+ if (!String.IsNullOrEmpty(package.PackageTuple.RollbackBoundaryBackwardRef))
377
{
342
- writer.WriteAttributeString("RollbackBoundaryBackward", package.Package.RollbackBoundaryBackward);
378
+ writer.WriteAttributeString("RollbackBoundaryBackward", package.PackageTuple.RollbackBoundaryBackwardRef);
379
}
380
345
- if (!String.IsNullOrEmpty(package.Package.LogPathVariable))
381
+ if (!String.IsNullOrEmpty(package.PackageTuple.LogPathVariable))
382
{
347
- writer.WriteAttributeString("LogPathVariable", package.Package.LogPathVariable);
383
+ writer.WriteAttributeString("LogPathVariable", package.PackageTuple.LogPathVariable);
384
}
385
350
- if (!String.IsNullOrEmpty(package.Package.RollbackLogPathVariable))
386
+ if (!String.IsNullOrEmpty(package.PackageTuple.RollbackLogPathVariable))
387
{
352
- writer.WriteAttributeString("RollbackLogPathVariable", package.Package.RollbackLogPathVariable);
388
+ writer.WriteAttributeString("RollbackLogPathVariable", package.PackageTuple.RollbackLogPathVariable);
389
}
390
355
- if (!String.IsNullOrEmpty(package.Package.InstallCondition))
391
+ if (!String.IsNullOrEmpty(package.PackageTuple.InstallCondition))
392
{
357
- writer.WriteAttributeString("InstallCondition", package.Package.InstallCondition);
393
+ writer.WriteAttributeString("InstallCondition", package.PackageTuple.InstallCondition);
394
}
395
360
- if (WixBundlePackageType.Exe == package.Package.Type)
396
+ if (package.SpecificPackageTuple is WixBundleExePackageTuple exePackage) // EXE
397
{
362
- writer.WriteAttributeString("DetectCondition", package.ExePackage.DetectCondition);
363
- writer.WriteAttributeString("InstallArguments", package.ExePackage.InstallCommand);
364
- writer.WriteAttributeString("UninstallArguments", package.ExePackage.UninstallCommand);
365
- writer.WriteAttributeString("RepairArguments", package.ExePackage.RepairCommand);
366
- writer.WriteAttributeString("Repairable", package.ExePackage.Repairable ? "yes" : "no");
367
- if (!String.IsNullOrEmpty(package.ExePackage.ExeProtocol))
398
+ writer.WriteAttributeString("DetectCondition", exePackage.DetectCondition);
399
+ writer.WriteAttributeString("InstallArguments", exePackage.InstallCommand);
400
+ writer.WriteAttributeString("UninstallArguments", exePackage.UninstallCommand);
401
+ writer.WriteAttributeString("RepairArguments", exePackage.RepairCommand);
402
+ writer.WriteAttributeString("Repairable", exePackage.Repairable ? "yes" : "no");
403
+ if (!String.IsNullOrEmpty(exePackage.ExeProtocol))
404
{
369
- writer.WriteAttributeString("Protocol", package.ExePackage.ExeProtocol);
405
+ writer.WriteAttributeString("Protocol", exePackage.ExeProtocol);
406
}
407
}
372
- else if (WixBundlePackageType.Msi == package.Package.Type)
408
+ else if (package.SpecificPackageTuple is WixBundleMsiPackageTuple msiPackage) // MSI
409
{
374
- writer.WriteAttributeString("ProductCode", package.MsiPackage.ProductCode);
375
- writer.WriteAttributeString("Language", package.MsiPackage.ProductLanguage.ToString(CultureInfo.InvariantCulture));
376
- writer.WriteAttributeString("Version", package.MsiPackage.ProductVersion);
377
- writer.WriteAttributeString("DisplayInternalUI", package.MsiPackage.DisplayInternalUI ? "yes" : "no");
378
- if (!String.IsNullOrEmpty(package.MsiPackage.UpgradeCode))
410
+ writer.WriteAttributeString("ProductCode", msiPackage.ProductCode);
411
+ writer.WriteAttributeString("Language", msiPackage.ProductLanguage.ToString(CultureInfo.InvariantCulture));
412
+ writer.WriteAttributeString("Version", msiPackage.ProductVersion);
413
+ writer.WriteAttributeString("DisplayInternalUI", msiPackage.DisplayInternalUI ? "yes" : "no");
414
+ if (!String.IsNullOrEmpty(msiPackage.UpgradeCode))
415
{
380
- writer.WriteAttributeString("UpgradeCode", package.MsiPackage.UpgradeCode);
416
+ writer.WriteAttributeString("UpgradeCode", msiPackage.UpgradeCode);
417
}
418
}
383
- else if (WixBundlePackageType.Msp == package.Package.Type)
419
+ else if (package.SpecificPackageTuple is WixBundleMspPackageTuple mspPackage) // MSP
420
{
385
- writer.WriteAttributeString("PatchCode", package.MspPackage.PatchCode);
386
- writer.WriteAttributeString("PatchXml", package.MspPackage.PatchXml);
387
- writer.WriteAttributeString("DisplayInternalUI", package.MspPackage.DisplayInternalUI ? "yes" : "no");
421
+ writer.WriteAttributeString("PatchCode", mspPackage.PatchCode);
422
+ writer.WriteAttributeString("PatchXml", mspPackage.PatchXml);
423
+ writer.WriteAttributeString("DisplayInternalUI", mspPackage.DisplayInternalUI ? "yes" : "no");
424
425
// If there is still a chance that all of our patches will target a narrow set of
426
// product codes, add the patch list to the overall list.
427
if (null != targetCodes)
428
{
393
- if (!package.MspPackage.TargetUnspecified)
429
+ if (!mspPackage.TargetUnspecified)
430
{
395
- IEnumerable<WixBundlePatchTargetCodeRow> patchTargetCodes = targetCodesByPatch[package.MspPackage.ChainPackageId];
431
+ var patchTargetCodes = targetCodesByPatch[mspPackage.Id.Id];
432
433
targetCodes.AddRange(patchTargetCodes);
434
}
@@ -402,24 +438,24 @@ namespace WixToolset.Core.Burn.Bundles
438
}
439
}
440
}
405
- else if (WixBundlePackageType.Msu == package.Package.Type)
441
+ else if (package.SpecificPackageTuple is WixBundleMsuPackageTuple msuPackage) // MSU
442
{
407
- writer.WriteAttributeString("DetectCondition", package.MsuPackage.DetectCondition);
408
- writer.WriteAttributeString("KB", package.MsuPackage.MsuKB);
443
+ writer.WriteAttributeString("DetectCondition", msuPackage.DetectCondition);
444
+ writer.WriteAttributeString("KB", msuPackage.MsuKB);
445
}
446
411
- IEnumerable<WixBundleMsiFeatureRow> packageMsiFeatures = msiFeaturesByPackage[package.Package.WixChainItemId];
447
+ var packageMsiFeatures = msiFeaturesByPackage[package.PackageId];
448
413
- foreach (WixBundleMsiFeatureRow feature in packageMsiFeatures)
449
+ foreach (var feature in packageMsiFeatures)
450
{
451
writer.WriteStartElement("MsiFeature");
452
writer.WriteAttributeString("Id", feature.Name);
453
writer.WriteEndElement();
454
}
455
420
- IEnumerable<WixBundleMsiPropertyRow> packageMsiProperties = msiPropertiesByPackage[package.Package.WixChainItemId];
456
+ var packageMsiProperties = msiPropertiesByPackage[package.PackageId];
457
422
- foreach (WixBundleMsiPropertyRow msiProperty in packageMsiProperties)
458
+ foreach (var msiProperty in packageMsiProperties)
459
{
460
writer.WriteStartElement("MsiProperty");
461
writer.WriteAttributeString("Id", msiProperty.Name);
@@ -431,18 +467,18 @@ namespace WixToolset.Core.Burn.Bundles
467
writer.WriteEndElement();
468
}
469
434
- IEnumerable<WixBundleSlipstreamMspRow> packageSlipstreamMsps = slipstreamMspsByPackage[package.Package.WixChainItemId];
470
+ var packageSlipstreamMsps = slipstreamMspsByPackage[package.PackageId];
471
436
- foreach (WixBundleSlipstreamMspRow slipstreamMsp in packageSlipstreamMsps)
472
+ foreach (var slipstreamMsp in packageSlipstreamMsps)
473
{
474
writer.WriteStartElement("SlipstreamMsp");
439
- writer.WriteAttributeString("Id", slipstreamMsp.MspPackageId);
475
+ writer.WriteAttributeString("Id", slipstreamMsp.MspPackageRef);
476
writer.WriteEndElement();
477
}
478
443
- IEnumerable<WixBundlePackageExitCodeRow> packageExitCodes = exitCodesByPackage[package.Package.WixChainItemId];
479
+ var packageExitCodes = exitCodesByPackage[package.PackageId];
480
445
- foreach (WixBundlePackageExitCodeRow exitCode in packageExitCodes)
481
+ foreach (var exitCode in packageExitCodes)
482
{
483
writer.WriteStartElement("ExitCode");
484
@@ -459,9 +495,9 @@ namespace WixToolset.Core.Burn.Bundles
495
writer.WriteEndElement();
496
}
497
462
- IEnumerable<WixBundlePackageCommandLineRow> packageCommandLines = commandLinesByPackage[package.Package.WixChainItemId];
498
+ var packageCommandLines = commandLinesByPackage[package.PackageId];
499
464
- foreach (WixBundlePackageCommandLineRow commandLine in packageCommandLines)
500
+ foreach (var commandLine in packageCommandLines)
501
{
502
writer.WriteStartElement("CommandLine");
503
writer.WriteAttributeString("InstallArgument", commandLine.InstallArgument);
@@ -472,18 +508,38 @@ namespace WixToolset.Core.Burn.Bundles
508
}
509
510
// Output the dependency information.
475
- foreach (ProvidesDependency dependency in package.Provides)
511
+ var dependencies = dependenciesByPackage[package.PackageId];
512
+
513
+ foreach (var dependency in dependencies)
514
{
477
- // TODO: Add to wixpdb as an imported table, or link package wixpdbs to bundle wixpdbs.
478
- dependency.WriteXml(writer);
515
+ writer.WriteStartElement("Provides");
516
+ writer.WriteAttributeString("Key", dependency.Key);
517
+
518
+ if (!String.IsNullOrEmpty(dependency.Version))
519
+ {
520
+ writer.WriteAttributeString("Version", dependency.Version);
521
+ }
522
+
523
+ if (!String.IsNullOrEmpty(dependency.DisplayName))
524
+ {
525
+ writer.WriteAttributeString("DisplayName", dependency.DisplayName);
526
+ }
527
+
528
+ if (dependency.Imported)
529
+ {
530
+ // The package dependency was explicitly authored into the manifest.
531
+ writer.WriteAttributeString("Imported", "yes");
532
+ }
533
+
534
+ writer.WriteEndElement();
535
}
536
481
- IEnumerable<WixBundleRelatedPackageRow> packageRelatedPackages = relatedPackagesByPackage[package.Package.WixChainItemId];
537
+ var packageRelatedPackages = relatedPackagesByPackage[package.PackageId];
538
483
- foreach (WixBundleRelatedPackageRow related in packageRelatedPackages)
539
+ foreach (var related in packageRelatedPackages)
540
{
541
writer.WriteStartElement("RelatedPackage");
486
- writer.WriteAttributeString("Id", related.Id);
542
+ writer.WriteAttributeString("Id", related.RelatedId);
543
if (!String.IsNullOrEmpty(related.MinVersion))
544
{
545
writer.WriteAttributeString("MinVersion", related.MinVersion);
@@ -496,7 +552,7 @@ namespace WixToolset.Core.Burn.Bundles
552
}
553
writer.WriteAttributeString("OnlyDetect", related.OnlyDetect ? "yes" : "no");
554
499
- string[] relatedLanguages = related.Languages.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
555
+ var relatedLanguages = related.Languages.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
556
557
if (0 < relatedLanguages.Length)
558
{
@@ -513,17 +569,17 @@ namespace WixToolset.Core.Burn.Bundles
569
570
// Write any contained Payloads with the PackagePayload being first
571
writer.WriteStartElement("PayloadRef");
516
- writer.WriteAttributeString("Id", package.Package.PackagePayload);
572
+ writer.WriteAttributeString("Id", package.PackageTuple.PayloadRef);
573
writer.WriteEndElement();
574
519
- IEnumerable<WixBundlePayloadRow> packagePayloads = payloadsByPackage[package.Package.WixChainItemId];
575
+ var packagePayloads = payloadsByPackage[package.PackageId];
576
521
- foreach (WixBundlePayloadRow payload in packagePayloads)
577
+ foreach (var payload in packagePayloads)
578
{
523
- if (payload.Id != package.Package.PackagePayload)
579
+ if (payload.Id.Id != package.PackageTuple.PayloadRef)
580
{
581
writer.WriteStartElement("PayloadRef");
526
- writer.WriteAttributeString("Id", payload.Id);
582
+ writer.WriteAttributeString("Id", payload.Id.Id);
583
writer.WriteEndElement();
584
}
585
}
@@ -534,7 +590,7 @@ namespace WixToolset.Core.Burn.Bundles
590
591
if (null != targetCodes)
592
{
537
- foreach (WixBundlePatchTargetCodeRow targetCode in targetCodes)
593
+ foreach (var targetCode in targetCodes)
594
{
595
writer.WriteStartElement("PatchTargetCode");
596
writer.WriteAttributeString("TargetCode", targetCode.TargetCode);
@@ -544,12 +600,12 @@ namespace WixToolset.Core.Burn.Bundles
600
}
601
602
// Write the ApprovedExeForElevation elements.
547
- IEnumerable<WixApprovedExeForElevationRow> approvedExesForElevation = this.Output.Tables["WixApprovedExeForElevation"].RowsAs<WixApprovedExeForElevationRow>();
603
+ var approvedExesForElevation = this.Section.Tuples.OfType<WixApprovedExeForElevationTuple>();
604
549
- foreach (WixApprovedExeForElevationRow approvedExeForElevation in approvedExesForElevation)
605
+ foreach (var approvedExeForElevation in approvedExesForElevation)
606
{
607
writer.WriteStartElement("ApprovedExeForElevation");
552
- writer.WriteAttributeString("Id", approvedExeForElevation.Id);
608
+ writer.WriteAttributeString("Id", approvedExeForElevation.Id.Id);
609
writer.WriteAttributeString("Key", approvedExeForElevation.Key);
610
611
if (!String.IsNullOrEmpty(approvedExeForElevation.ValueName))
@@ -569,15 +625,15 @@ namespace WixToolset.Core.Burn.Bundles
625
}
626
}
627
572
- private void WriteBurnManifestContainerAttributes(XmlTextWriter writer, string executableName, WixBundleContainerRow container)
628
+ private void WriteBurnManifestContainerAttributes(XmlTextWriter writer, string executableName, WixBundleContainerTuple container)
629
{
574
- writer.WriteAttributeString("Id", container.Id);
630
+ writer.WriteAttributeString("Id", container.Id.Id);
631
writer.WriteAttributeString("FileSize", container.Size.ToString(CultureInfo.InvariantCulture));
632
writer.WriteAttributeString("Hash", container.Hash);
633
634
if (ContainerType.Detached == container.Type)
635
{
580
- string resolvedUrl = this.ResolveUrl(container.DownloadUrl, null, null, container.Id, container.Name);
636
+ string resolvedUrl = this.ResolveUrl(container.DownloadUrl, null, null, container.Id.Id, container.Name);
637
if (!String.IsNullOrEmpty(resolvedUrl))
638
{
639
writer.WriteAttributeString("DownloadUrl", resolvedUrl);
@@ -593,7 +649,7 @@ namespace WixToolset.Core.Burn.Bundles
649
{
650
if (!String.IsNullOrEmpty(container.DownloadUrl))
651
{
596
- Messaging.Instance.OnMessage(WixWarnings.DownloadUrlNotSupportedForAttachedContainers(container.SourceLineNumbers, container.Id));
652
+ this.Messaging.Write(WarningMessages.DownloadUrlNotSupportedForAttachedContainers(container.SourceLineNumbers, container.Id.Id));
653
}
654
655
writer.WriteAttributeString("FilePath", executableName); // attached containers use the name of the bundle since they are attached to the executable.
@@ -603,11 +659,11 @@ namespace WixToolset.Core.Burn.Bundles
659
}
660
}
661
606
- private void WriteBurnManifestPayloadAttributes(XmlTextWriter writer, WixBundlePayloadRow payload, bool embeddedOnly, Dictionary<string, WixBundlePayloadRow> allPayloads)
662
+ private void WriteBurnManifestPayloadAttributes(XmlTextWriter writer, WixBundlePayloadTuple payload, bool embeddedOnly, Dictionary<string, WixBundlePayloadTuple> allPayloads)
663
{
664
Debug.Assert(!embeddedOnly || PackagingType.Embedded == payload.Packaging);
665
610
- writer.WriteAttributeString("Id", payload.Id);
666
+ writer.WriteAttributeString("Id", payload.Id.Id);
667
writer.WriteAttributeString("FilePath", payload.Name);
668
writer.WriteAttributeString("FileSize", payload.FileSize.ToString(CultureInfo.InvariantCulture));
669
writer.WriteAttributeString("Hash", payload.Hash);
@@ -632,22 +688,22 @@ namespace WixToolset.Core.Burn.Bundles
688
case PackagingType.Embedded: // this means it's in a container.
689
if (!String.IsNullOrEmpty(payload.DownloadUrl))
690
{
635
- Messaging.Instance.OnMessage(WixWarnings.DownloadUrlNotSupportedForEmbeddedPayloads(payload.SourceLineNumbers, payload.Id));
691
+ this.Messaging.Write(WarningMessages.DownloadUrlNotSupportedForEmbeddedPayloads(payload.SourceLineNumbers, payload.Id.Id));
692
}
693
694
writer.WriteAttributeString("Packaging", "embedded");
695
writer.WriteAttributeString("SourcePath", payload.EmbeddedId);
696
641
- if (Compiler.BurnUXContainerId != payload.Container)
697
+ if (BurnConstants.BurnUXContainerName != payload.ContainerRef)
698
{
643
- writer.WriteAttributeString("Container", payload.Container);
699
+ writer.WriteAttributeString("Container", payload.ContainerRef);
700
}
701
break;
702
703
case PackagingType.External:
648
- string packageId = payload.ParentPackagePayload;
649
- string parentUrl = payload.ParentPackagePayload == null ? null : allPayloads[payload.ParentPackagePayload].DownloadUrl;
650
- string resolvedUrl = this.ResolveUrl(payload.DownloadUrl, parentUrl, packageId, payload.Id, payload.Name);
704
+ var packageId = payload.ParentPackagePayloadRef;
705
+ var parentUrl = payload.ParentPackagePayloadRef == null ? null : allPayloads[payload.ParentPackagePayloadRef].DownloadUrl;
706
+ var resolvedUrl = this.ResolveUrl(payload.DownloadUrl, parentUrl, packageId, payload.Id.Id, payload.Name);
707
if (!String.IsNullOrEmpty(resolvedUrl))
708
{
709
writer.WriteAttributeString("DownloadUrl", resolvedUrl);
@@ -662,9 +718,9 @@ namespace WixToolset.Core.Burn.Bundles
718
break;
719
}
720
665
- if (!String.IsNullOrEmpty(payload.Catalog))
721
+ if (!String.IsNullOrEmpty(payload.CatalogRef))
722
{
667
- writer.WriteAttributeString("Catalog", payload.Catalog);
723
+ writer.WriteAttributeString("Catalog", payload.CatalogRef);
724
}
725
}
726
@@ -682,6 +738,5 @@ namespace WixToolset.Core.Burn.Bundles
738
739
return resolved;
740
}
685
-#endif
741
}
742
}
src/WixToolset.Core.Burn/Bundles/CreateContainerCommand.cs
+34
-25
@@ -4,24 +4,39 @@ namespace WixToolset.Core.Burn.Bundles
4
{
5
using System;
6
using System.Collections.Generic;
7
- using System.Diagnostics;
7
using System.IO;
8
using System.Linq;
9
+ using WixToolset.Core.Native;
10
using WixToolset.Data;
11
+ using WixToolset.Data.Tuples;
12
13
/// <summary>
14
/// Creates cabinet files.
15
/// </summary>
16
internal class CreateContainerCommand
17
{
17
-#if TODO
18
- public CompressionLevel DefaultCompressionLevel { private get; set; }
18
+ public CreateContainerCommand(IEnumerable<WixBundlePayloadTuple> payloads, string outputPath, CompressionLevel? compressionLevel)
19
+ {
20
+ this.Payloads = payloads;
21
+ this.OutputPath = outputPath;
22
+ this.CompressionLevel = compressionLevel;
23
+ }
24
+
25
+ public CreateContainerCommand(string manifestPath, IEnumerable<WixBundlePayloadTuple> payloads, string outputPath, CompressionLevel? compressionLevel)
26
+ {
27
+ this.ManifestFile = manifestPath;
28
+ this.Payloads = payloads;
29
+ this.OutputPath = outputPath;
30
+ this.CompressionLevel = compressionLevel;
31
+ }
32
+
33
+ private CompressionLevel? CompressionLevel { get; }
34
20
- public IEnumerable<WixBundlePayloadRow> Payloads { private get; set; }
35
+ private string ManifestFile { get; }
36
22
- public string ManifestFile { private get; set; }
37
+ private string OutputPath { get; }
38
24
- public string OutputPath { private get; set; }
39
+ private IEnumerable<WixBundlePayloadTuple> Payloads { get; }
40
41
public string Hash { get; private set; }
42
@@ -29,40 +44,34 @@ namespace WixToolset.Core.Burn.Bundles
44
45
public void Execute()
46
{
32
- int payloadCount = this.Payloads.Count(); // The number of embedded payloads
47
+ var payloadCount = this.Payloads.Count(); // The number of embedded payloads
48
49
if (!String.IsNullOrEmpty(this.ManifestFile))
50
{
51
++payloadCount;
52
}
53
39
- using (var cab = new WixCreateCab(Path.GetFileName(this.OutputPath), Path.GetDirectoryName(this.OutputPath), payloadCount, 0, 0, this.DefaultCompressionLevel))
40
- {
41
- // If a manifest was provided always add it as "payload 0" to the container.
42
- if (!String.IsNullOrEmpty(this.ManifestFile))
43
- {
44
- cab.AddFile(this.ManifestFile, "0");
45
- }
54
+ var cabinetPath = Path.GetFullPath(this.OutputPath);
55
47
- foreach (WixBundlePayloadRow payload in this.Payloads)
48
- {
49
- Debug.Assert(PackagingType.Embedded == payload.Packaging);
56
+ var files = new List<CabinetCompressFile>();
57
51
- Messaging.Instance.OnMessage(WixVerboses.LoadingPayload(payload.FullFileName));
58
+ // If a manifest was provided always add it as "payload 0" to the container.
59
+ if (!String.IsNullOrEmpty(this.ManifestFile))
60
+ {
61
+ files.Add(new CabinetCompressFile(this.ManifestFile, "0"));
62
+ }
63
53
- cab.AddFile(payload.FullFileName, payload.EmbeddedId);
54
- }
64
+ files.AddRange(this.Payloads.Select(p => new CabinetCompressFile(p.SourceFile.Path, p.EmbeddedId)));
65
56
- cab.Complete();
57
- }
66
+ var cab = new Cabinet(cabinetPath);
67
+ cab.Compress(files, this.CompressionLevel ?? Data.CompressionLevel.Mszip);
68
69
// Now that the container is created, set the outputs of the command.
60
- FileInfo fileInfo = new FileInfo(this.OutputPath);
70
+ var fileInfo = new FileInfo(cabinetPath);
71
62
- this.Hash = Common.GetFileHash(fileInfo.FullName);
72
+ this.Hash = BundleHashAlgorithm.Hash(fileInfo);
73
74
this.Size = fileInfo.Length;
75
}
66
-#endif
76
}
77
}
src/WixToolset.Core.Burn/Bundles/CreateNonUXContainers.cs
new
+134
@@ -0,0 +1,134 @@
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.Burn.Bundles
4
+{
5
+ using System.Collections.Generic;
6
+ using System.Diagnostics;
7
+ using System.IO;
8
+ using System.Linq;
9
+ using WixToolset.Data;
10
+ using WixToolset.Data.Burn;
11
+ using WixToolset.Data.Tuples;
12
+ using WixToolset.Extensibility.Data;
13
+ using WixToolset.Extensibility.Services;
14
+
15
+ internal class CreateNonUXContainers
16
+ {
17
+ public CreateNonUXContainers(IBackendHelper backendHelper, IntermediateSection section, WixBootstrapperApplicationTuple bootstrapperApplicationTuple, Dictionary<string, WixBundlePayloadTuple> payloadTuples, string intermediateFolder, string layoutFolder, CompressionLevel? defaultCompressionLevel)
18
+ {
19
+ this.BackendHelper = backendHelper;
20
+ this.Section = section;
21
+ this.BootstrapperApplicationTuple = bootstrapperApplicationTuple;
22
+ this.PayloadTuples = payloadTuples;
23
+ this.IntermediateFolder = intermediateFolder;
24
+ this.LayoutFolder = layoutFolder;
25
+ this.DefaultCompressionLevel = defaultCompressionLevel;
26
+ }
27
+
28
+ public IEnumerable<IFileTransfer> FileTransfers { get; private set; }
29
+
30
+ public WixBundleContainerTuple UXContainer { get; set; }
31
+
32
+ public IEnumerable<WixBundlePayloadTuple> UXContainerPayloads { get; private set; }
33
+
34
+ public IEnumerable<WixBundleContainerTuple> Containers { get; private set; }
35
+
36
+ private IBackendHelper BackendHelper { get; }
37
+
38
+ private IntermediateSection Section { get; }
39
+
40
+ private WixBootstrapperApplicationTuple BootstrapperApplicationTuple { get; }
41
+
42
+ private Dictionary<string, WixBundlePayloadTuple> PayloadTuples { get; }
43
+
44
+ private string IntermediateFolder { get; }
45
+
46
+ private string LayoutFolder { get; }
47
+
48
+ private CompressionLevel? DefaultCompressionLevel { get; }
49
+
50
+ public void Execute()
51
+ {
52
+ var fileTransfers = new List<IFileTransfer>();
53
+
54
+ var uxPayloadTuples = new List<WixBundlePayloadTuple>();
55
+
56
+ var attachedContainerIndex = 1; // count starts at one because UX container is "0".
57
+
58
+ var containerTuples = this.Section.Tuples.OfType<WixBundleContainerTuple>().ToList();
59
+
60
+ var payloadsByContainer = this.PayloadTuples.Values.ToLookup(p => p.ContainerRef);
61
+
62
+ foreach (var container in containerTuples)
63
+ {
64
+ var containerId = container.Id.Id;
65
+
66
+ var containerPayloads = payloadsByContainer[containerId];
67
+
68
+ if (!containerPayloads.Any())
69
+ {
70
+ if (containerId != BurnConstants.BurnDefaultAttachedContainerName)
71
+ {
72
+ // TODO: display warning that we're ignoring container that ended up with no paylods in it.
73
+ }
74
+ }
75
+ else if (BurnConstants.BurnUXContainerName == containerId)
76
+ {
77
+ this.UXContainer = container;
78
+
79
+ container.WorkingPath = Path.Combine(this.IntermediateFolder, container.Name);
80
+ container.AttachedContainerIndex = 0;
81
+
82
+ // Gather the list of UX payloads but ensure the BootstrapperApplication Payload is the first
83
+ // in the list since that is the Payload that Burn attempts to load.
84
+ var baPayloadId = this.BootstrapperApplicationTuple.Id.Id;
85
+
86
+ foreach (var uxPayload in containerPayloads)
87
+ {
88
+ if (uxPayload.Id.Id == baPayloadId)
89
+ {
90
+ uxPayloadTuples.Insert(0, uxPayload);
91
+ }
92
+ else
93
+ {
94
+ uxPayloadTuples.Add(uxPayload);
95
+ }
96
+ }
97
+ }
98
+ else
99
+ {
100
+ container.WorkingPath = Path.Combine(this.IntermediateFolder, container.Name);
101
+
102
+ // Add detached containers to the list of file transfers.
103
+ if (ContainerType.Detached == container.Type)
104
+ {
105
+ var transfer = this.BackendHelper.CreateFileTransfer(container.WorkingPath, Path.Combine(this.LayoutFolder, container.Name), true, container.SourceLineNumbers);
106
+ fileTransfers.Add(transfer);
107
+ }
108
+ else // update the attached container index.
109
+ {
110
+ Debug.Assert(ContainerType.Attached == container.Type);
111
+
112
+ container.AttachedContainerIndex = attachedContainerIndex;
113
+ ++attachedContainerIndex;
114
+ }
115
+
116
+ this.CreateContainer(container, containerPayloads, null);
117
+ }
118
+ }
119
+
120
+ this.Containers = containerTuples;
121
+ this.UXContainerPayloads = uxPayloadTuples;
122
+ this.FileTransfers = fileTransfers;
123
+ }
124
+
125
+ private void CreateContainer(WixBundleContainerTuple container, IEnumerable<WixBundlePayloadTuple> containerPayloads, string manifestFile)
126
+ {
127
+ var command = new CreateContainerCommand(containerPayloads, container.WorkingPath, this.DefaultCompressionLevel);
128
+ command.Execute();
129
+
130
+ container.Hash = command.Hash;
131
+ container.Size = command.Size;
132
+ }
133
+ }
134
+}
src/WixToolset.Core.Burn/Bundles/GetPackageFacadesCommand.cs
+43
-35
@@ -3,61 +3,69 @@
3
namespace WixToolset.Core.Burn.Bundles
4
{
5
using System.Collections.Generic;
6
+ using System.Linq;
7
using WixToolset.Data;
8
+ using WixToolset.Data.Tuples;
9
10
internal class GetPackageFacadesCommand
11
{
10
-#if TODO
11
- public Table PackageTable { private get; set; }
12
-
13
- public Table ExePackageTable { private get; set; }
14
-
15
- public Table MsiPackageTable { private get; set; }
12
+ public GetPackageFacadesCommand(IEnumerable<WixBundlePackageTuple> chainPackageTuples, IntermediateSection section)
13
+ {
14
+ this.ChainPackageTuples = chainPackageTuples;
15
+ this.Section = section;
16
+ }
17
17
- public Table MspPackageTable { private get; set; }
18
+ private IEnumerable<WixBundlePackageTuple> ChainPackageTuples { get; }
19
19
- public Table MsuPackageTable { private get; set; }
20
+ private IntermediateSection Section { get; }
21
22
public IDictionary<string, PackageFacade> PackageFacades { get; private set; }
23
24
public void Execute()
25
{
25
- RowDictionary<WixBundleExePackageRow> exePackages = new RowDictionary<WixBundleExePackageRow>(this.ExePackageTable);
26
- RowDictionary<WixBundleMsiPackageRow> msiPackages = new RowDictionary<WixBundleMsiPackageRow>(this.MsiPackageTable);
27
- RowDictionary<WixBundleMspPackageRow> mspPackages = new RowDictionary<WixBundleMspPackageRow>(this.MspPackageTable);
28
- RowDictionary<WixBundleMsuPackageRow> msuPackages = new RowDictionary<WixBundleMsuPackageRow>(this.MsuPackageTable);
26
+ var exePackages = this.Section.Tuples.OfType<WixBundleExePackageTuple>().ToDictionary(t => t.Id.Id);
27
+ var msiPackages = this.Section.Tuples.OfType<WixBundleMsiPackageTuple>().ToDictionary(t => t.Id.Id);
28
+ var mspPackages = this.Section.Tuples.OfType<WixBundleMspPackageTuple>().ToDictionary(t => t.Id.Id);
29
+ var msuPackages = this.Section.Tuples.OfType<WixBundleMsuPackageTuple>().ToDictionary(t => t.Id.Id);
30
30
- Dictionary<string, PackageFacade> facades = new Dictionary<string, PackageFacade>(this.PackageTable.Rows.Count);
31
+ var facades = new Dictionary<string, PackageFacade>();
32
32
- foreach (WixBundlePackageRow package in this.PackageTable.Rows)
33
+ foreach (var package in this.ChainPackageTuples)
34
{
34
- string id = package.WixChainItemId;
35
- PackageFacade facade = null;
36
-
35
+ var id = package.Id.Id;
36
switch (package.Type)
37
{
39
- case WixBundlePackageType.Exe:
40
- facade = new PackageFacade(package, exePackages.Get(id));
41
- break;
42
-
43
- case WixBundlePackageType.Msi:
44
- facade = new PackageFacade(package, msiPackages.Get(id));
45
- break;
46
-
47
- case WixBundlePackageType.Msp:
48
- facade = new PackageFacade(package, mspPackages.Get(id));
49
- break;
50
-
51
- case WixBundlePackageType.Msu:
52
- facade = new PackageFacade(package, msuPackages.Get(id));
53
- break;
38
+ case WixBundlePackageType.Exe:
39
+ if (exePackages.TryGetValue(id, out var exePackage))
40
+ {
41
+ facades.Add(id, new PackageFacade(package, exePackage));
42
+ }
43
+ break;
44
+
45
+ case WixBundlePackageType.Msi:
46
+ if (msiPackages.TryGetValue(id, out var msiPackage))
47
+ {
48
+ facades.Add(id, new PackageFacade(package, msiPackage));
49
+ }
50
+ break;
51
+
52
+ case WixBundlePackageType.Msp:
53
+ if (mspPackages.TryGetValue(id, out var mspPackage))
54
+ {
55
+ facades.Add(id, new PackageFacade(package, mspPackage));
56
+ }
57
+ break;
58
+
59
+ case WixBundlePackageType.Msu:
60
+ if (msuPackages.TryGetValue(id, out var msuPackage))
61
+ {
62
+ facades.Add(id, new PackageFacade(package, msuPackage));
63
+ }
64
+ break;
65
}
55
-
56
- facades.Add(id, facade);
66
}
67
68
this.PackageFacades = facades;
69
}
61
-#endif
70
}
71
}
src/WixToolset.Core.Burn/Bundles/OrderPackagesAndRollbackBoundariesCommand.cs
+38
-28
@@ -5,24 +5,35 @@ namespace WixToolset.Core.Burn.Bundles
5
using System;
6
using System.Collections.Generic;
7
using WixToolset.Data;
8
+ using WixToolset.Data.Tuples;
9
+ using WixToolset.Extensibility.Services;
10
11
internal class OrderPackagesAndRollbackBoundariesCommand
12
{
11
-#if TODO
12
- public Table WixGroupTable { private get; set; }
13
+ public OrderPackagesAndRollbackBoundariesCommand(IMessaging messaging, IEnumerable<WixGroupTuple> groupTuples, Dictionary<string, WixBundleRollbackBoundaryTuple> boundaryTuples, IDictionary<string, PackageFacade> packageFacades)
14
+ {
15
+ this.Messaging = messaging;
16
+ this.GroupTuples = groupTuples;
17
+ this.Boundaries = boundaryTuples;
18
+ this.PackageFacades = packageFacades;
19
+ }
20
+
21
+ private IMessaging Messaging { get; }
22
+
23
+ public IEnumerable<WixGroupTuple> GroupTuples { get; }
24
14
- public RowDictionary<WixBundleRollbackBoundaryRow> Boundaries { private get; set; }
25
+ public Dictionary<string, WixBundleRollbackBoundaryTuple> Boundaries { get; }
26
16
- public IDictionary<string, PackageFacade> PackageFacades { private get; set; }
27
+ public IDictionary<string, PackageFacade> PackageFacades { get; }
28
29
public IEnumerable<PackageFacade> OrderedPackageFacades { get; private set; }
30
20
- public IEnumerable<WixBundleRollbackBoundaryRow> UsedRollbackBoundaries { get; private set; }
31
+ public IEnumerable<WixBundleRollbackBoundaryTuple> UsedRollbackBoundaries { get; private set; }
32
33
public void Execute()
34
{
24
- List<PackageFacade> orderedFacades = new List<PackageFacade>();
25
- List<WixBundleRollbackBoundaryRow> usedBoundaries = new List<WixBundleRollbackBoundaryRow>();
35
+ var orderedFacades = new List<PackageFacade>();
36
+ var usedBoundaries = new List<WixBundleRollbackBoundaryTuple>();
37
38
// Process the chain of packages to add them in the correct order
39
// and assign the forward rollback boundaries as appropriate. Remember
@@ -33,44 +44,44 @@ namespace WixToolset.Core.Burn.Bundles
44
// We handle uninstall (aka: backwards) rollback boundaries after
45
// we get these install/repair (aka: forward) rollback boundaries
46
// defined.
36
- WixBundleRollbackBoundaryRow previousRollbackBoundary = null;
37
- WixBundleRollbackBoundaryRow lastRollbackBoundary = null;
38
- bool boundaryHadX86Package = false;
47
+ WixBundleRollbackBoundaryTuple previousRollbackBoundary = null;
48
+ WixBundleRollbackBoundaryTuple lastRollbackBoundary = null;
49
+ var boundaryHadX86Package = false;
50
40
- foreach (WixGroupRow row in this.WixGroupTable.Rows)
51
+ foreach (var groupTuple in this.GroupTuples)
52
{
42
- if (ComplexReferenceChildType.Package == row.ChildType && ComplexReferenceParentType.PackageGroup == row.ParentType && "WixChain" == row.ParentId)
53
+ if (ComplexReferenceChildType.Package == groupTuple.ChildType && ComplexReferenceParentType.PackageGroup == groupTuple.ParentType && "WixChain" == groupTuple.ParentId)
54
{
44
- PackageFacade facade = null;
45
- if (PackageFacades.TryGetValue(row.ChildId, out facade))
55
+ if (this.PackageFacades.TryGetValue(groupTuple.ChildId, out var facade))
56
{
57
if (null != previousRollbackBoundary)
58
{
59
usedBoundaries.Add(previousRollbackBoundary);
50
- facade.Package.RollbackBoundary = previousRollbackBoundary.ChainPackageId;
60
+ facade.PackageTuple.RollbackBoundaryRef = previousRollbackBoundary.Id.Id;
61
previousRollbackBoundary = null;
62
53
- boundaryHadX86Package = (facade.Package.x64 == YesNoType.Yes);
63
+ boundaryHadX86Package = facade.PackageTuple.Win64;
64
}
65
66
// Error if MSI transaction has x86 package preceding x64 packages
57
- if ((lastRollbackBoundary != null) && (lastRollbackBoundary.Transaction == YesNoType.Yes)
67
+ if ((lastRollbackBoundary != null)
68
+ && lastRollbackBoundary.Transaction == true
69
&& boundaryHadX86Package
59
- && (facade.Package.x64 == YesNoType.Yes))
70
+ && facade.PackageTuple.Win64)
71
{
61
- Messaging.Instance.OnMessage(WixErrors.MsiTransactionX86BeforeX64(lastRollbackBoundary.SourceLineNumbers));
72
+ this.Messaging.Write(ErrorMessages.MsiTransactionX86BeforeX64(lastRollbackBoundary.SourceLineNumbers));
73
}
63
- boundaryHadX86Package = boundaryHadX86Package || (facade.Package.x64 == YesNoType.No);
74
+ boundaryHadX86Package |= facade.PackageTuple.Win64;
75
76
orderedFacades.Add(facade);
77
}
78
else // must be a rollback boundary.
79
{
80
// Discard the next rollback boundary if we have a previously defined boundary.
70
- WixBundleRollbackBoundaryRow nextRollbackBoundary = Boundaries.Get(row.ChildId);
81
+ var nextRollbackBoundary = this.Boundaries[groupTuple.ChildId];
82
if (null != previousRollbackBoundary)
83
{
73
- Messaging.Instance.OnMessage(WixWarnings.DiscardedRollbackBoundary(nextRollbackBoundary.SourceLineNumbers, nextRollbackBoundary.ChainPackageId));
84
+ this.Messaging.Write(WarningMessages.DiscardedRollbackBoundary(nextRollbackBoundary.SourceLineNumbers, nextRollbackBoundary.Id.Id));
85
}
86
else
87
{
@@ -83,7 +94,7 @@ namespace WixToolset.Core.Burn.Bundles
94
95
if (null != previousRollbackBoundary)
96
{
86
- Messaging.Instance.OnMessage(WixWarnings.DiscardedRollbackBoundary(previousRollbackBoundary.SourceLineNumbers, previousRollbackBoundary.ChainPackageId));
97
+ this.Messaging.Write(WarningMessages.DiscardedRollbackBoundary(previousRollbackBoundary.SourceLineNumbers, previousRollbackBoundary.Id.Id));
98
}
99
100
// With the forward rollback boundaries assigned, we can now go
@@ -120,14 +131,14 @@ namespace WixToolset.Core.Burn.Bundles
131
132
foreach (PackageFacade package in orderedFacades)
133
{
123
- if (null != package.Package.RollbackBoundary)
134
+ if (null != package.PackageTuple.RollbackBoundaryRef)
135
{
136
if (null != previousFacade)
137
{
127
- previousFacade.Package.RollbackBoundaryBackward = previousRollbackBoundaryId;
138
+ previousFacade.PackageTuple.RollbackBoundaryBackwardRef = previousRollbackBoundaryId;
139
}
140
130
- previousRollbackBoundaryId = package.Package.RollbackBoundary;
141
+ previousRollbackBoundaryId = package.PackageTuple.RollbackBoundaryRef;
142
}
143
144
previousFacade = package;
@@ -135,12 +146,11 @@ namespace WixToolset.Core.Burn.Bundles
146
147
if (!String.IsNullOrEmpty(previousRollbackBoundaryId) && null != previousFacade)
148
{
138
- previousFacade.Package.RollbackBoundaryBackward = previousRollbackBoundaryId;
149
+ previousFacade.PackageTuple.RollbackBoundaryBackwardRef = previousRollbackBoundaryId;
150
}
151
152
this.OrderedPackageFacades = orderedFacades;
153
this.UsedRollbackBoundaries = usedBoundaries;
154
}
144
-#endif
155
}
156
}
src/WixToolset.Core.Burn/Bundles/PackageFacade.cs
+11
-44
@@ -2,57 +2,24 @@
2
3
namespace WixToolset.Core.Burn.Bundles
4
{
5
+ using System.Diagnostics;
6
+ using WixToolset.Data;
7
+ using WixToolset.Data.Tuples;
8
+
9
internal class PackageFacade
10
{
7
-#if TODO
8
- private PackageFacade(WixBundlePackageRow package)
9
- {
10
- this.Package = package;
11
- this.Provides = new ProvidesDependencyCollection();
12
- }
13
-
14
- public PackageFacade(WixBundlePackageRow package, WixBundleExePackageRow exePackage)
15
- : this(package)
11
+ public PackageFacade(WixBundlePackageTuple packageTuple, IntermediateTuple specificPackageTuple)
12
{
17
- this.ExePackage = exePackage;
18
- }
13
+ Debug.Assert(packageTuple.Id.Id == specificPackageTuple.Id.Id);
14
20
- public PackageFacade(WixBundlePackageRow package, WixBundleMsiPackageRow msiPackage)
21
- : this(package)
22
- {
23
- this.MsiPackage = msiPackage;
15
+ this.PackageTuple = packageTuple;
16
+ this.SpecificPackageTuple = specificPackageTuple;
17
}
18
26
- public PackageFacade(WixBundlePackageRow package, WixBundleMspPackageRow mspPackage)
27
- : this(package)
28
- {
29
- this.MspPackage = mspPackage;
30
- }
31
-
32
- public PackageFacade(WixBundlePackageRow package, WixBundleMsuPackageRow msuPackage)
33
- : this(package)
34
- {
35
- this.MsuPackage = msuPackage;
36
- }
37
-
38
- public WixBundlePackageRow Package { get; private set; }
39
-
40
- public WixBundleExePackageRow ExePackage { get; private set; }
41
-
42
- public WixBundleMsiPackageRow MsiPackage { get; private set; }
43
-
44
- public WixBundleMspPackageRow MspPackage { get; private set; }
19
+ public string PackageId => this.PackageTuple.Id.Id;
20
46
- public WixBundleMsuPackageRow MsuPackage { get; private set; }
21
+ public WixBundlePackageTuple PackageTuple { get; }
22
48
- /// <summary>
49
- /// The provides dependencies authored and imported for this package.
50
- /// </summary>
51
- /// <remarks>
52
- /// TODO: Eventually this collection should turn into Rows so they are tracked in the PDB but
53
- /// the relationship with the extension makes it much trickier to pull off.
54
- /// </remarks>
55
- public ProvidesDependencyCollection Provides { get; private set; }
56
-#endif
23
+ public IntermediateTuple SpecificPackageTuple { get; }
24
}
25
}
src/WixToolset.Core.Burn/Bundles/ProcessExePackageCommand.cs
+14
-9
@@ -3,32 +3,37 @@
3
namespace WixToolset.Core.Burn.Bundles
4
{
5
using System;
6
- using WixToolset.Data;
6
+ using System.Collections.Generic;
7
+ using WixToolset.Data.Tuples;
8
9
/// <summary>
10
/// Initializes package state from the Exe contents.
11
/// </summary>
12
internal class ProcessExePackageCommand
13
{
13
-#if TODO
14
- public RowDictionary<WixBundlePayloadRow> AuthoredPayloads { private get; set; }
14
+ public ProcessExePackageCommand(PackageFacade facade, Dictionary<string, WixBundlePayloadTuple> payloadTuples)
15
+ {
16
+ this.AuthoredPayloads = payloadTuples;
17
+ this.Facade = facade;
18
+ }
19
+
20
+ public Dictionary<string, WixBundlePayloadTuple> AuthoredPayloads { get; }
21
16
- public PackageFacade Facade { private get; set; }
22
+ public PackageFacade Facade { get; }
23
24
/// <summary>
25
/// Processes the Exe packages to add properties and payloads from the Exe packages.
26
/// </summary>
27
public void Execute()
28
{
23
- WixBundlePayloadRow packagePayload = this.AuthoredPayloads.Get(this.Facade.Package.PackagePayload);
29
+ var packagePayload = this.AuthoredPayloads[this.Facade.PackageTuple.PayloadRef];
30
25
- if (String.IsNullOrEmpty(this.Facade.Package.CacheId))
31
+ if (String.IsNullOrEmpty(this.Facade.PackageTuple.CacheId))
32
{
27
- this.Facade.Package.CacheId = packagePayload.Hash;
33
+ this.Facade.PackageTuple.CacheId = packagePayload.Hash;
34
}
35
30
- this.Facade.Package.Version = packagePayload.Version;
36
+ this.Facade.PackageTuple.Version = packagePayload.Version;
37
}
32
-#endif
38
}
39
}
src/WixToolset.Core.Burn/Bundles/ProcessMsiPackageCommand.cs
+238
-187
@@ -3,7 +3,6 @@
3
namespace WixToolset.Core.Burn.Bundles
4
{
5
using System;
6
- using System.Collections;
6
using System.Collections.Generic;
7
using System.Diagnostics;
8
using System.Globalization;
@@ -11,47 +10,62 @@ namespace WixToolset.Core.Burn.Bundles
10
using System.Linq;
11
using WixToolset.Data;
12
using WixToolset.Extensibility;
14
- using WixToolset.Core.Native;
13
using Dtf = WixToolset.Dtf.WindowsInstaller;
16
- using WixToolset.Data.Bind;
14
+ using WixToolset.Extensibility.Services;
15
+ using WixToolset.Data.Tuples;
16
+ using WixToolset.Data.WindowsInstaller;
17
+ using WixToolset.Extensibility.Data;
18
19
/// <summary>
20
/// Initializes package state from the MSI contents.
21
/// </summary>
22
internal class ProcessMsiPackageCommand
23
{
23
-#if TODO
24
private const string PropertySqlFormat = "SELECT `Value` FROM `Property` WHERE `Property` = '{0}'";
25
26
- public RowDictionary<WixBundlePayloadRow> AuthoredPayloads { private get; set; }
26
+ public ProcessMsiPackageCommand(IServiceProvider serviceProvider, IEnumerable<IBurnBackendExtension> backendExtensions, IntermediateSection section, PackageFacade facade, Dictionary<string, WixBundlePayloadTuple> payloadTuples)
27
+ {
28
+ this.Messaging = serviceProvider.GetService<IMessaging>();
29
+ this.BackendHelper = serviceProvider.GetService<IBackendHelper>();
30
+ this.PathResolver = serviceProvider.GetService<IPathResolver>();
31
+
32
+ this.BackendExtensions = backendExtensions;
33
+
34
+ this.AuthoredPayloads = payloadTuples;
35
+ this.Section = section;
36
+ this.Facade = facade;
37
+ }
38
+
39
+ private IMessaging Messaging { get; }
40
28
- public PackageFacade Facade { private get; set; }
41
+ private IBackendHelper BackendHelper { get; }
42
30
- public IEnumerable<IBurnBackendExtension> BackendExtensions { private get; set; }
43
+ private IPathResolver PathResolver { get; }
44
32
- public Table MsiFeatureTable { private get; set; }
45
+ private IEnumerable<IBurnBackendExtension> BackendExtensions { get; }
46
34
- public Table MsiPropertyTable { private get; set; }
47
+ private Dictionary<string, WixBundlePayloadTuple> AuthoredPayloads { get; }
48
36
- public Table PayloadTable { private get; set; }
49
+ private PackageFacade Facade { get; }
50
38
- public Table RelatedPackageTable { private get; set; }
51
+ private IntermediateSection Section { get; }
52
53
/// <summary>
54
/// Processes the MSI packages to add properties and payloads from the MSI packages.
55
/// </summary>
56
public void Execute()
57
{
45
- WixBundlePayloadRow packagePayload = this.AuthoredPayloads.Get(this.Facade.Package.PackagePayload);
58
+ var packagePayload = this.AuthoredPayloads[this.Facade.PackageTuple.PayloadRef];
59
47
- string sourcePath = packagePayload.FullFileName;
48
- bool longNamesInImage = false;
49
- bool compressed = false;
50
- bool x64 = false;
60
+ var msiPackage = (WixBundleMsiPackageTuple)this.Facade.SpecificPackageTuple;
61
+
62
+ var sourcePath = packagePayload.SourceFile.Path;
63
+ var longNamesInImage = false;
64
+ var compressed = false;
65
try
66
{
67
// Read data out of the msi database...
54
- using (Dtf.SummaryInfo sumInfo = new Dtf.SummaryInfo(sourcePath, false))
68
+ using (var sumInfo = new Dtf.SummaryInfo(sourcePath, false))
69
{
70
// 1 is the Word Count summary information stream bit that means
71
// the MSI uses short file names when set. We care about long file
@@ -62,83 +76,84 @@ namespace WixToolset.Core.Burn.Bundles
76
// files are compressed in the MSI by default when the bit is set.
77
compressed = 2 == (sumInfo.WordCount & 2);
78
65
- x64 = (sumInfo.Template.Contains("x64") || sumInfo.Template.Contains("Intel64"));
66
-
79
// 8 is the Word Count summary information stream bit that means
80
// "Elevated privileges are not required to install this package."
81
// in MSI 4.5 and below, if this bit is 0, elevation is required.
70
- this.Facade.Package.PerMachine = (0 == (sumInfo.WordCount & 8)) ? YesNoDefaultType.Yes : YesNoDefaultType.No;
71
- this.Facade.Package.x64 = x64 ? YesNoType.Yes : YesNoType.No;
82
+ var perMachine = (0 == (sumInfo.WordCount & 8));
83
+ var x64 = (sumInfo.Template.Contains("x64") || sumInfo.Template.Contains("Intel64"));
84
+
85
+ this.Facade.PackageTuple.PerMachine = perMachine ? YesNoDefaultType.Yes : YesNoDefaultType.No;
86
+ this.Facade.PackageTuple.Win64 = x64;
87
}
88
74
- using (Dtf.Database db = new Dtf.Database(sourcePath))
89
+ using (var db = new Dtf.Database(sourcePath))
90
{
76
- this.Facade.MsiPackage.ProductCode = ProcessMsiPackageCommand.GetProperty(db, "ProductCode");
77
- this.Facade.MsiPackage.UpgradeCode = ProcessMsiPackageCommand.GetProperty(db, "UpgradeCode");
78
- this.Facade.MsiPackage.Manufacturer = ProcessMsiPackageCommand.GetProperty(db, "Manufacturer");
79
- this.Facade.MsiPackage.ProductLanguage = Convert.ToInt32(ProcessMsiPackageCommand.GetProperty(db, "ProductLanguage"), CultureInfo.InvariantCulture);
80
- this.Facade.MsiPackage.ProductVersion = ProcessMsiPackageCommand.GetProperty(db, "ProductVersion");
91
+ msiPackage.ProductCode = ProcessMsiPackageCommand.GetProperty(db, "ProductCode");
92
+ msiPackage.UpgradeCode = ProcessMsiPackageCommand.GetProperty(db, "UpgradeCode");
93
+ msiPackage.Manufacturer = ProcessMsiPackageCommand.GetProperty(db, "Manufacturer");
94
+ msiPackage.ProductLanguage = Convert.ToInt32(ProcessMsiPackageCommand.GetProperty(db, "ProductLanguage"), CultureInfo.InvariantCulture);
95
+ msiPackage.ProductVersion = ProcessMsiPackageCommand.GetProperty(db, "ProductVersion");
96
82
- if (!Common.IsValidModuleOrBundleVersion(this.Facade.MsiPackage.ProductVersion))
97
+ if (!Common.IsValidModuleOrBundleVersion(msiPackage.ProductVersion))
98
{
99
// not a proper .NET version (e.g., five fields); can we get a valid four-part version number?
100
string version = null;
86
- string[] versionParts = this.Facade.MsiPackage.ProductVersion.Split('.');
87
- int count = versionParts.Length;
101
+ string[] versionParts = msiPackage.ProductVersion.Split('.');
102
+ var count = versionParts.Length;
103
if (0 < count)
104
{
105
version = versionParts[0];
91
- for (int i = 1; i < 4 && i < count; ++i)
106
+ for (var i = 1; i < 4 && i < count; ++i)
107
{
108
version = String.Concat(version, ".", versionParts[i]);
109
}
110
}
96
-
111
+
112
if (!String.IsNullOrEmpty(version) && Common.IsValidModuleOrBundleVersion(version))
113
{
99
- Messaging.Instance.OnMessage(WixWarnings.VersionTruncated(this.Facade.Package.SourceLineNumbers, this.Facade.MsiPackage.ProductVersion, sourcePath, version));
100
- this.Facade.MsiPackage.ProductVersion = version;
114
+ this.Messaging.Write(WarningMessages.VersionTruncated(this.Facade.PackageTuple.SourceLineNumbers, msiPackage.ProductVersion, sourcePath, version));
115
+ msiPackage.ProductVersion = version;
116
}
117
else
118
{
104
- Messaging.Instance.OnMessage(WixErrors.InvalidProductVersion(this.Facade.Package.SourceLineNumbers, this.Facade.MsiPackage.ProductVersion, sourcePath));
119
+ this.Messaging.Write(ErrorMessages.InvalidProductVersion(this.Facade.PackageTuple.SourceLineNumbers, msiPackage.ProductVersion, sourcePath));
120
}
121
}
122
108
- if (String.IsNullOrEmpty(this.Facade.Package.CacheId))
123
+ if (String.IsNullOrEmpty(this.Facade.PackageTuple.CacheId))
124
{
110
- this.Facade.Package.CacheId = String.Format("{0}v{1}", this.Facade.MsiPackage.ProductCode, this.Facade.MsiPackage.ProductVersion);
125
+ this.Facade.PackageTuple.CacheId = String.Format("{0}v{1}", msiPackage.ProductCode, msiPackage.ProductVersion);
126
}
127
113
- if (String.IsNullOrEmpty(this.Facade.Package.DisplayName))
128
+ if (String.IsNullOrEmpty(this.Facade.PackageTuple.DisplayName))
129
{
115
- this.Facade.Package.DisplayName = ProcessMsiPackageCommand.GetProperty(db, "ProductName");
130
+ this.Facade.PackageTuple.DisplayName = ProcessMsiPackageCommand.GetProperty(db, "ProductName");
131
}
132
118
- if (String.IsNullOrEmpty(this.Facade.Package.Description))
133
+ if (String.IsNullOrEmpty(this.Facade.PackageTuple.Description))
134
{
120
- this.Facade.Package.Description = ProcessMsiPackageCommand.GetProperty(db, "ARPCOMMENTS");
135
+ this.Facade.PackageTuple.Description = ProcessMsiPackageCommand.GetProperty(db, "ARPCOMMENTS");
136
}
137
123
- ISet<string> payloadNames = this.GetPayloadTargetNames();
138
+ var payloadNames = this.GetPayloadTargetNames(packagePayload.Id.Id);
139
125
- ISet<string> msiPropertyNames = this.GetMsiPropertyNames();
140
+ var msiPropertyNames = this.GetMsiPropertyNames(packagePayload.Id.Id);
141
127
- this.SetPerMachineAppropriately(db, sourcePath);
142
+ this.SetPerMachineAppropriately(db, msiPackage, sourcePath);
143
144
// Ensure the MSI package is appropriately marked visible or not.
130
- this.SetPackageVisibility(db, msiPropertyNames);
145
+ this.SetPackageVisibility(db, msiPackage, msiPropertyNames);
146
147
// Unless the MSI or setup code overrides the default, set MSIFASTINSTALL for best performance.
148
if (!msiPropertyNames.Contains("MSIFASTINSTALL") && !ProcessMsiPackageCommand.HasProperty(db, "MSIFASTINSTALL"))
149
{
135
- this.AddMsiProperty("MSIFASTINSTALL", "7");
150
+ this.AddMsiProperty(msiPackage, "MSIFASTINSTALL", "7");
151
}
152
153
this.CreateRelatedPackages(db);
154
155
// If feature selection is enabled, represent the Feature table in the manifest.
141
- if (this.Facade.MsiPackage.EnableFeatureSelection)
156
+ if ((msiPackage.Attributes & WixBundleMsiPackageAttributes.EnableFeatureSelection) == WixBundleMsiPackageAttributes.EnableFeatureSelection)
157
{
158
this.CreateMsiFeatures(db);
159
}
@@ -148,90 +163,92 @@ namespace WixToolset.Core.Burn.Bundles
163
164
// Add all external files as package payloads and calculate the total install size as the rollup of
165
// File table's sizes.
151
- this.Facade.Package.InstallSize = this.ImportExternalFileAsPayloadsAndReturnInstallSize(db, packagePayload, longNamesInImage, compressed, payloadNames);
166
+ this.Facade.PackageTuple.InstallSize = this.ImportExternalFileAsPayloadsAndReturnInstallSize(db, packagePayload, longNamesInImage, compressed, payloadNames);
167
168
// Add all dependency providers from the MSI.
154
- this.ImportDependencyProviders(db);
169
+ this.ImportDependencyProviders(msiPackage, db);
170
}
171
}
172
catch (Dtf.InstallerException e)
173
{
159
- Messaging.Instance.OnMessage(WixErrors.UnableToReadPackageInformation(this.Facade.Package.SourceLineNumbers, sourcePath, e.Message));
174
+ this.Messaging.Write(ErrorMessages.UnableToReadPackageInformation(this.Facade.PackageTuple.SourceLineNumbers, sourcePath, e.Message));
175
}
176
}
177
163
- private ISet<string> GetPayloadTargetNames()
178
+ private ISet<string> GetPayloadTargetNames(string packageId)
179
{
165
- IEnumerable<string> payloadNames = this.PayloadTable.RowsAs<WixBundlePayloadRow>()
166
- .Where(r => r.Package == this.Facade.Package.WixChainItemId)
167
- .Select(r => r.Name);
180
+ var payloadNames = this.Section.Tuples.OfType<WixBundlePayloadTuple>()
181
+ .Where(p => p.PackageRef == packageId)
182
+ .Select(p => p.Name);
183
184
return new HashSet<string>(payloadNames, StringComparer.OrdinalIgnoreCase);
185
}
186
172
- private ISet<string> GetMsiPropertyNames()
187
+ private ISet<string> GetMsiPropertyNames(string packageId)
188
{
174
- IEnumerable<string> properties = this.MsiPropertyTable.RowsAs<WixBundleMsiPropertyRow>()
175
- .Where(r => r.ChainPackageId == this.Facade.Package.WixChainItemId)
176
- .Select(r => r.Name);
189
+ var properties = this.Section.Tuples.OfType<WixBundleMsiPropertyTuple>()
190
+ .Where(p => p.Id.Id == packageId)
191
+ .Select(p => p.Name);
192
193
return new HashSet<string>(properties, StringComparer.Ordinal);
194
}
195
181
- private void SetPerMachineAppropriately(Dtf.Database db, string sourcePath)
196
+ private void SetPerMachineAppropriately(Dtf.Database db, WixBundleMsiPackageTuple msiPackage, string sourcePath)
197
{
183
- if (this.Facade.MsiPackage.ForcePerMachine)
198
+ if (msiPackage.ForcePerMachine)
199
{
185
- if (YesNoDefaultType.No == this.Facade.Package.PerMachine)
200
+ if (YesNoDefaultType.No == this.Facade.PackageTuple.PerMachine)
201
{
187
- Messaging.Instance.OnMessage(WixWarnings.PerUserButForcingPerMachine(this.Facade.Package.SourceLineNumbers, sourcePath));
188
- this.Facade.Package.PerMachine = YesNoDefaultType.Yes; // ensure that we think the package is per-machine.
202
+ this.Messaging.Write(WarningMessages.PerUserButForcingPerMachine(this.Facade.PackageTuple.SourceLineNumbers, sourcePath));
203
+ this.Facade.PackageTuple.PerMachine = YesNoDefaultType.Yes; // ensure that we think the package is per-machine.
204
}
205
206
// Force ALLUSERS=1 via the MSI command-line.
192
- this.AddMsiProperty("ALLUSERS", "1");
207
+ this.AddMsiProperty(msiPackage, "ALLUSERS", "1");
208
}
209
else
210
{
196
- string allusers = ProcessMsiPackageCommand.GetProperty(db, "ALLUSERS");
211
+ var allusers = ProcessMsiPackageCommand.GetProperty(db, "ALLUSERS");
212
213
if (String.IsNullOrEmpty(allusers))
214
{
215
// Not forced per-machine and no ALLUSERS property, flip back to per-user.
201
- if (YesNoDefaultType.Yes == this.Facade.Package.PerMachine)
216
+ if (YesNoDefaultType.Yes == this.Facade.PackageTuple.PerMachine)
217
{
203
- Messaging.Instance.OnMessage(WixWarnings.ImplicitlyPerUser(this.Facade.Package.SourceLineNumbers, sourcePath));
204
- this.Facade.Package.PerMachine = YesNoDefaultType.No;
218
+ this.Messaging.Write(WarningMessages.ImplicitlyPerUser(this.Facade.PackageTuple.SourceLineNumbers, sourcePath));
219
+ this.Facade.PackageTuple.PerMachine = YesNoDefaultType.No;
220
}
221
}
222
else if (allusers.Equals("1", StringComparison.Ordinal))
223
{
209
- if (YesNoDefaultType.No == this.Facade.Package.PerMachine)
224
+ if (YesNoDefaultType.No == this.Facade.PackageTuple.PerMachine)
225
{
211
- Messaging.Instance.OnMessage(WixErrors.PerUserButAllUsersEquals1(this.Facade.Package.SourceLineNumbers, sourcePath));
226
+ this.Messaging.Write(ErrorMessages.PerUserButAllUsersEquals1(this.Facade.PackageTuple.SourceLineNumbers, sourcePath));
227
}
228
}
229
else if (allusers.Equals("2", StringComparison.Ordinal))
230
{
216
- Messaging.Instance.OnMessage(WixWarnings.DiscouragedAllUsersValue(this.Facade.Package.SourceLineNumbers, sourcePath, (YesNoDefaultType.Yes == this.Facade.Package.PerMachine) ? "machine" : "user"));
231
+ this.Messaging.Write(WarningMessages.DiscouragedAllUsersValue(this.Facade.PackageTuple.SourceLineNumbers, sourcePath, (YesNoDefaultType.Yes == this.Facade.PackageTuple.PerMachine) ? "machine" : "user"));
232
}
233
else
234
{
220
- Messaging.Instance.OnMessage(WixErrors.UnsupportedAllUsersValue(this.Facade.Package.SourceLineNumbers, sourcePath, allusers));
235
+ this.Messaging.Write(ErrorMessages.UnsupportedAllUsersValue(this.Facade.PackageTuple.SourceLineNumbers, sourcePath, allusers));
236
}
237
}
238
}
239
225
- private void SetPackageVisibility(Dtf.Database db, ISet<string> msiPropertyNames)
240
+ private void SetPackageVisibility(Dtf.Database db, WixBundleMsiPackageTuple msiPackage, ISet<string> msiPropertyNames)
241
{
227
- bool alreadyVisible = !ProcessMsiPackageCommand.HasProperty(db, "ARPSYSTEMCOMPONENT");
242
+ var alreadyVisible = !ProcessMsiPackageCommand.HasProperty(db, "ARPSYSTEMCOMPONENT");
243
+ var visible = (this.Facade.PackageTuple.Attributes & WixBundlePackageAttributes.Visible) == WixBundlePackageAttributes.Visible;
244
229
- if (alreadyVisible != this.Facade.Package.Visible) // if not already set to the correct visibility.
245
+ // If not already set to the correct visibility.
246
+ if (alreadyVisible != visible)
247
{
248
// If the authoring specifically added "ARPSYSTEMCOMPONENT", don't do it again.
249
if (!msiPropertyNames.Contains("ARPSYSTEMCOMPONENT"))
250
{
234
- this.AddMsiProperty("ARPSYSTEMCOMPONENT", this.Facade.Package.Visible ? String.Empty : "1");
251
+ this.AddMsiProperty(msiPackage, "ARPSYSTEMCOMPONENT", visible ? String.Empty : "1");
252
}
253
}
254
}
@@ -241,30 +258,35 @@ namespace WixToolset.Core.Burn.Bundles
258
// Represent the Upgrade table as related packages.
259
if (db.Tables.Contains("Upgrade"))
260
{
244
- using (Dtf.View view = db.OpenView("SELECT `UpgradeCode`, `VersionMin`, `VersionMax`, `Language`, `Attributes` FROM `Upgrade`"))
261
+ using (var view = db.OpenView("SELECT `UpgradeCode`, `VersionMin`, `VersionMax`, `Language`, `Attributes` FROM `Upgrade`"))
262
{
263
view.Execute();
264
while (true)
265
{
249
- using (Dtf.Record record = view.Fetch())
266
+ using (var record = view.Fetch())
267
{
268
if (null == record)
269
{
270
break;
271
}
272
256
- WixBundleRelatedPackageRow related = (WixBundleRelatedPackageRow)this.RelatedPackageTable.CreateRow(this.Facade.Package.SourceLineNumbers);
257
- related.ChainPackageId = this.Facade.Package.WixChainItemId;
258
- related.Id = record.GetString(1);
259
- related.MinVersion = record.GetString(2);
260
- related.MaxVersion = record.GetString(3);
261
- related.Languages = record.GetString(4);
262
-
263
- int attributes = record.GetInteger(5);
264
- related.OnlyDetect = (attributes & MsiInterop.MsidbUpgradeAttributesOnlyDetect) == MsiInterop.MsidbUpgradeAttributesOnlyDetect;
265
- related.MinInclusive = (attributes & MsiInterop.MsidbUpgradeAttributesVersionMinInclusive) == MsiInterop.MsidbUpgradeAttributesVersionMinInclusive;
266
- related.MaxInclusive = (attributes & MsiInterop.MsidbUpgradeAttributesVersionMaxInclusive) == MsiInterop.MsidbUpgradeAttributesVersionMaxInclusive;
267
- related.LangInclusive = (attributes & MsiInterop.MsidbUpgradeAttributesLanguagesExclusive) == 0;
273
+ var recordAttributes = record.GetInteger(5);
274
+
275
+ var attributes = WixBundleRelatedPackageAttributes.None;
276
+ attributes |= (recordAttributes & WindowsInstallerConstants.MsidbUpgradeAttributesOnlyDetect) == WindowsInstallerConstants.MsidbUpgradeAttributesOnlyDetect ? WixBundleRelatedPackageAttributes.OnlyDetect : 0;
277
+ attributes |= (recordAttributes & WindowsInstallerConstants.MsidbUpgradeAttributesVersionMinInclusive) == WindowsInstallerConstants.MsidbUpgradeAttributesVersionMinInclusive ? WixBundleRelatedPackageAttributes.MinInclusive : 0;
278
+ attributes |= (recordAttributes & WindowsInstallerConstants.MsidbUpgradeAttributesVersionMaxInclusive) == WindowsInstallerConstants.MsidbUpgradeAttributesVersionMaxInclusive ? WixBundleRelatedPackageAttributes.MaxInclusive : 0;
279
+ attributes |= (recordAttributes & WindowsInstallerConstants.MsidbUpgradeAttributesLanguagesExclusive) == WindowsInstallerConstants.MsidbUpgradeAttributesLanguagesExclusive ? WixBundleRelatedPackageAttributes.LangInclusive : 0;
280
+
281
+ var related = new WixBundleRelatedPackageTuple(this.Facade.PackageTuple.SourceLineNumbers)
282
+ {
283
+ PackageRef = this.Facade.PackageId,
284
+ RelatedId = record.GetString(1),
285
+ MinVersion = record.GetString(2),
286
+ MaxVersion = record.GetString(3),
287
+ Languages = record.GetString(4),
288
+ Attributes = attributes,
289
+ };
290
}
291
}
292
}
@@ -275,26 +297,26 @@ namespace WixToolset.Core.Burn.Bundles
297
{
298
if (db.Tables.Contains("Feature"))
299
{
278
- using (Dtf.View featureView = db.OpenView("SELECT `Component_` FROM `FeatureComponents` WHERE `Feature_` = ?"))
279
- using (Dtf.View componentView = db.OpenView("SELECT `FileSize` FROM `File` WHERE `Component_` = ?"))
300
+ using (var featureView = db.OpenView("SELECT `Component_` FROM `FeatureComponents` WHERE `Feature_` = ?"))
301
+ using (var componentView = db.OpenView("SELECT `FileSize` FROM `File` WHERE `Component_` = ?"))
302
{
281
- using (Dtf.Record featureRecord = new Dtf.Record(1))
282
- using (Dtf.Record componentRecord = new Dtf.Record(1))
303
+ using (var featureRecord = new Dtf.Record(1))
304
+ using (var componentRecord = new Dtf.Record(1))
305
{
284
- using (Dtf.View allFeaturesView = db.OpenView("SELECT * FROM `Feature`"))
306
+ using (var allFeaturesView = db.OpenView("SELECT * FROM `Feature`"))
307
{
308
allFeaturesView.Execute();
309
310
while (true)
311
{
290
- using (Dtf.Record allFeaturesResultRecord = allFeaturesView.Fetch())
312
+ using (var allFeaturesResultRecord = allFeaturesView.Fetch())
313
{
314
if (null == allFeaturesResultRecord)
315
{
316
break;
317
}
318
297
- string featureName = allFeaturesResultRecord.GetString(1);
319
+ var featureName = allFeaturesResultRecord.GetString(1);
320
321
// Calculate the Feature size.
322
featureRecord.SetString(1, featureName);
@@ -304,43 +326,46 @@ namespace WixToolset.Core.Burn.Bundles
326
long size = 0;
327
while (true)
328
{
307
- using (Dtf.Record componentResultRecord = featureView.Fetch())
329
+ using (var componentResultRecord = featureView.Fetch())
330
{
331
if (null == componentResultRecord)
332
{
333
break;
334
}
313
- string component = componentResultRecord.GetString(1);
335
+
336
+ var component = componentResultRecord.GetString(1);
337
componentRecord.SetString(1, component);
338
componentView.Execute(componentRecord);
339
340
while (true)
341
{
319
- using (Dtf.Record fileResultRecord = componentView.Fetch())
342
+ using (var fileResultRecord = componentView.Fetch())
343
{
344
if (null == fileResultRecord)
345
{
346
break;
347
}
348
326
- string fileSize = fileResultRecord.GetString(1);
349
+ var fileSize = fileResultRecord.GetString(1);
350
size += Convert.ToInt32(fileSize, CultureInfo.InvariantCulture.NumberFormat);
351
}
352
}
353
}
354
}
355
333
- WixBundleMsiFeatureRow feature = (WixBundleMsiFeatureRow)this.MsiFeatureTable.CreateRow(this.Facade.Package.SourceLineNumbers);
334
- feature.ChainPackageId = this.Facade.Package.WixChainItemId;
335
- feature.Name = featureName;
336
- feature.Parent = allFeaturesResultRecord.GetString(2);
337
- feature.Title = allFeaturesResultRecord.GetString(3);
338
- feature.Description = allFeaturesResultRecord.GetString(4);
339
- feature.Display = allFeaturesResultRecord.GetInteger(5);
340
- feature.Level = allFeaturesResultRecord.GetInteger(6);
341
- feature.Directory = allFeaturesResultRecord.GetString(7);
342
- feature.Attributes = allFeaturesResultRecord.GetInteger(8);
343
- feature.Size = size;
356
+ var feature = new WixBundleMsiFeatureTuple(this.Facade.PackageTuple.SourceLineNumbers, new Identifier(AccessModifier.Private, this.Facade.PackageId, featureName))
357
+ {
358
+ PackageRef = this.Facade.PackageId,
359
+ Name = featureName,
360
+ Parent = allFeaturesResultRecord.GetString(2),
361
+ Title = allFeaturesResultRecord.GetString(3),
362
+ Description = allFeaturesResultRecord.GetString(4),
363
+ Display = allFeaturesResultRecord.GetInteger(5),
364
+ Level = allFeaturesResultRecord.GetInteger(6),
365
+ Directory = allFeaturesResultRecord.GetString(7),
366
+ Attributes = allFeaturesResultRecord.GetInteger(8),
367
+ Size = size
368
+ };
369
}
370
}
371
}
@@ -349,113 +374,119 @@ namespace WixToolset.Core.Burn.Bundles
374
}
375
}
376
352
- private void ImportExternalCabinetAsPayloads(Dtf.Database db, WixBundlePayloadRow packagePayload, ISet<string> payloadNames)
377
+ private void ImportExternalCabinetAsPayloads(Dtf.Database db, WixBundlePayloadTuple packagePayload, ISet<string> payloadNames)
378
{
379
if (db.Tables.Contains("Media"))
380
{
356
- foreach (string cabinet in db.ExecuteStringQuery("SELECT `Cabinet` FROM `Media`"))
381
+ foreach (var cabinet in db.ExecuteStringQuery("SELECT `Cabinet` FROM `Media`"))
382
{
383
if (!String.IsNullOrEmpty(cabinet) && !cabinet.StartsWith("#", StringComparison.Ordinal))
384
{
385
// If we didn't find the Payload as an existing child of the package, we need to
386
// add it. We expect the file to exist on-disk in the same relative location as
387
// the MSI expects to find it...
363
- string cabinetName = Path.Combine(Path.GetDirectoryName(packagePayload.Name), cabinet);
388
+ var cabinetName = Path.Combine(Path.GetDirectoryName(packagePayload.Name), cabinet);
389
390
if (!payloadNames.Contains(cabinetName))
391
{
367
- string generatedId = Common.GenerateIdentifier("cab", packagePayload.Id, cabinet);
368
- string payloadSourceFile = this.ResolveRelatedFile(packagePayload.UnresolvedSourceFile, cabinet, "Cabinet", this.Facade.Package.SourceLineNumbers, BindStage.Normal);
369
-
370
- WixBundlePayloadRow payload = (WixBundlePayloadRow)this.PayloadTable.CreateRow(this.Facade.Package.SourceLineNumbers);
371
- payload.Id = generatedId;
372
- payload.Name = cabinetName;
373
- payload.SourceFile = payloadSourceFile;
374
- payload.Compressed = packagePayload.Compressed;
375
- payload.UnresolvedSourceFile = cabinetName;
376
- payload.Package = packagePayload.Package;
377
- payload.Container = packagePayload.Container;
378
- payload.ContentFile = true;
379
- payload.EnableSignatureValidation = packagePayload.EnableSignatureValidation;
380
- payload.Packaging = packagePayload.Packaging;
381
- payload.ParentPackagePayload = packagePayload.Id;
392
+ var generatedId = Common.GenerateIdentifier("cab", packagePayload.Id.Id, cabinet);
393
+ var payloadSourceFile = this.ResolveRelatedFile(packagePayload.SourceFile.Path, packagePayload.UnresolvedSourceFile, cabinet, "Cabinet", this.Facade.PackageTuple.SourceLineNumbers, BindStage.Normal);
394
+
395
+ var tuple = new WixBundlePayloadTuple(this.Facade.PackageTuple.SourceLineNumbers, new Identifier(AccessModifier.Private, generatedId))
396
+ {
397
+ Name = cabinetName,
398
+ SourceFile = new IntermediateFieldPathValue { Path = payloadSourceFile },
399
+ Compressed = packagePayload.Compressed,
400
+ UnresolvedSourceFile = cabinetName,
401
+ PackageRef = packagePayload.PackageRef,
402
+ ContainerRef = packagePayload.ContainerRef,
403
+ ContentFile = true,
404
+ EnableSignatureValidation = packagePayload.EnableSignatureValidation,
405
+ Packaging = packagePayload.Packaging,
406
+ ParentPackagePayloadRef = packagePayload.Id.Id,
407
+ };
408
+
409
+ this.Section.Tuples.Add(tuple);
410
}
411
}
412
}
413
}
414
}
415
388
- private long ImportExternalFileAsPayloadsAndReturnInstallSize(Dtf.Database db, WixBundlePayloadRow packagePayload, bool longNamesInImage, bool compressed, ISet<string> payloadNames)
416
+ private long ImportExternalFileAsPayloadsAndReturnInstallSize(Dtf.Database db, WixBundlePayloadTuple packagePayload, bool longNamesInImage, bool compressed, ISet<string> payloadNames)
417
{
418
long size = 0;
419
420
if (db.Tables.Contains("Component") && db.Tables.Contains("Directory") && db.Tables.Contains("File"))
421
{
394
- Hashtable directories = new Hashtable();
422
+ var directories = new Dictionary<string, IResolvedDirectory>();
423
424
// Load up the directory hash table so we will be able to resolve source paths
425
// for files in the MSI database.
398
- using (Dtf.View view = db.OpenView("SELECT `Directory`, `Directory_Parent`, `DefaultDir` FROM `Directory`"))
426
+ using (var view = db.OpenView("SELECT `Directory`, `Directory_Parent`, `DefaultDir` FROM `Directory`"))
427
{
428
view.Execute();
429
while (true)
430
{
403
- using (Dtf.Record record = view.Fetch())
431
+ using (var record = view.Fetch())
432
{
433
if (null == record)
434
{
435
break;
436
}
437
410
- string sourceName = Common.GetName(record.GetString(3), true, longNamesInImage);
411
- directories.Add(record.GetString(1), new ResolvedDirectory(record.GetString(2), sourceName));
438
+ var sourceName = Common.GetName(record.GetString(3), true, longNamesInImage);
439
+
440
+ var resolvedDirectory = this.BackendHelper.CreateResolvedDirectory(record.GetString(2), sourceName);
441
+
442
+ directories.Add(record.GetString(1), resolvedDirectory);
443
}
444
}
445
}
446
447
// Resolve the source paths to external files and add each file size to the total
448
// install size of the package.
418
- using (Dtf.View view = db.OpenView("SELECT `Directory_`, `File`, `FileName`, `File`.`Attributes`, `FileSize` FROM `Component`, `File` WHERE `Component`.`Component`=`File`.`Component_`"))
449
+ using (var view = db.OpenView("SELECT `Directory_`, `File`, `FileName`, `File`.`Attributes`, `FileSize` FROM `Component`, `File` WHERE `Component`.`Component`=`File`.`Component_`"))
450
{
451
view.Execute();
452
while (true)
453
{
423
- using (Dtf.Record record = view.Fetch())
454
+ using (var record = view.Fetch())
455
{
456
if (null == record)
457
{
458
break;
459
}
460
430
- // Skip adding the loose files as payloads if it was suppressed.
431
- if (!this.Facade.MsiPackage.SuppressLooseFilePayloadGeneration)
461
+ // If the file is explicitly uncompressed or the MSI is uncompressed and the file is not
462
+ // explicitly marked compressed then this is an external file.
463
+ var compressionBit = record.GetInteger(4);
464
+ if (WindowsInstallerConstants.MsidbFileAttributesNoncompressed == (compressionBit & WindowsInstallerConstants.MsidbFileAttributesNoncompressed) ||
465
+ (!compressed && 0 == (compressionBit & WindowsInstallerConstants.MsidbFileAttributesCompressed)))
466
{
433
- // If the file is explicitly uncompressed or the MSI is uncompressed and the file is not
434
- // explicitly marked compressed then this is an external file.
435
- if (MsiInterop.MsidbFileAttributesNoncompressed == (record.GetInteger(4) & MsiInterop.MsidbFileAttributesNoncompressed) ||
436
- (!compressed && 0 == (record.GetInteger(4) & MsiInterop.MsidbFileAttributesCompressed)))
467
+ string fileSourcePath = this.PathResolver.GetFileSourcePath(directories, record.GetString(1), record.GetString(3), compressed, longNamesInImage);
468
+ var name = Path.Combine(Path.GetDirectoryName(packagePayload.Name), fileSourcePath);
469
+
470
+ if (!payloadNames.Contains(name))
471
{
438
- string fileSourcePath = Binder.GetFileSourcePath(directories, record.GetString(1), record.GetString(3), compressed, longNamesInImage);
439
- string name = Path.Combine(Path.GetDirectoryName(packagePayload.Name), fileSourcePath);
472
+ var generatedId = Common.GenerateIdentifier("f", packagePayload.Id.Id, record.GetString(2));
473
+ var payloadSourceFile = this.ResolveRelatedFile(packagePayload.SourceFile.Path, packagePayload.UnresolvedSourceFile, fileSourcePath, "File", this.Facade.PackageTuple.SourceLineNumbers, BindStage.Normal);
474
441
- if (!payloadNames.Contains(name))
475
+ var tuple = new WixBundlePayloadTuple(this.Facade.PackageTuple.SourceLineNumbers, new Identifier(AccessModifier.Private, generatedId))
476
{
443
- string generatedId = Common.GenerateIdentifier("f", packagePayload.Id, record.GetString(2));
444
- string payloadSourceFile = this.ResolveRelatedFile(packagePayload.UnresolvedSourceFile, fileSourcePath, "File", this.Facade.Package.SourceLineNumbers, BindStage.Normal);
445
-
446
- WixBundlePayloadRow payload = (WixBundlePayloadRow)this.PayloadTable.CreateRow(this.Facade.Package.SourceLineNumbers);
447
- payload.Id = generatedId;
448
- payload.Name = name;
449
- payload.SourceFile = payloadSourceFile;
450
- payload.Compressed = packagePayload.Compressed;
451
- payload.UnresolvedSourceFile = name;
452
- payload.Package = packagePayload.Package;
453
- payload.Container = packagePayload.Container;
454
- payload.ContentFile = true;
455
- payload.EnableSignatureValidation = packagePayload.EnableSignatureValidation;
456
- payload.Packaging = packagePayload.Packaging;
457
- payload.ParentPackagePayload = packagePayload.Id;
458
- }
477
+ Name = name,
478
+ SourceFile = new IntermediateFieldPathValue { Path = payloadSourceFile },
479
+ Compressed = packagePayload.Compressed,
480
+ UnresolvedSourceFile = name,
481
+ PackageRef = packagePayload.PackageRef,
482
+ ContainerRef = packagePayload.ContainerRef,
483
+ ContentFile = true,
484
+ EnableSignatureValidation = packagePayload.EnableSignatureValidation,
485
+ Packaging = packagePayload.Packaging,
486
+ ParentPackagePayloadRef = packagePayload.Id.Id,
487
+ };
488
+
489
+ this.Section.Tuples.Add(tuple);
490
}
491
}
492
@@ -468,26 +499,30 @@ namespace WixToolset.Core.Burn.Bundles
499
return size;
500
}
501
471
- private void AddMsiProperty(string name, string value)
502
+ private void AddMsiProperty(WixBundleMsiPackageTuple msiPackage, string name, string value)
503
{
473
- WixBundleMsiPropertyRow row = (WixBundleMsiPropertyRow)this.MsiPropertyTable.CreateRow(this.Facade.MsiPackage.SourceLineNumbers);
474
- row.ChainPackageId = this.Facade.Package.WixChainItemId;
475
- row.Name = name;
476
- row.Value = value;
504
+ var tuple = new WixBundleMsiPropertyTuple(msiPackage.SourceLineNumbers, new Identifier(AccessModifier.Private, msiPackage.Id.Id, name))
505
+ {
506
+ PackageRef = msiPackage.Id.Id,
507
+ Name = name,
508
+ Value = value
509
+ };
510
+
511
+ this.Section.Tuples.Add(tuple);
512
}
513
479
- private void ImportDependencyProviders(Dtf.Database db)
514
+ private void ImportDependencyProviders(WixBundleMsiPackageTuple msiPackage, Dtf.Database db)
515
{
516
if (db.Tables.Contains("WixDependencyProvider"))
517
{
483
- string query = "SELECT `ProviderKey`, `Version`, `DisplayName`, `Attributes` FROM `WixDependencyProvider`";
518
+ var query = "SELECT `ProviderKey`, `Version`, `DisplayName`, `Attributes` FROM `WixDependencyProvider`";
519
485
- using (Dtf.View view = db.OpenView(query))
520
+ using (var view = db.OpenView(query))
521
{
522
view.Execute();
523
while (true)
524
{
490
- using (Dtf.Record record = view.Fetch())
525
+ using (var record = view.Fetch())
526
{
527
if (null == record)
528
{
@@ -495,34 +530,51 @@ namespace WixToolset.Core.Burn.Bundles
530
}
531
532
// Import the provider key and attributes.
498
- string providerKey = record.GetString(1);
499
- string version = record.GetString(2) ?? this.Facade.MsiPackage.ProductVersion;
500
- string displayName = record.GetString(3) ?? this.Facade.Package.DisplayName;
501
- int attributes = record.GetInteger(4);
502
-
503
- ProvidesDependency dependency = new ProvidesDependency(providerKey, version, displayName, attributes);
504
- dependency.Imported = true;
505
-
506
- this.Facade.Provides.Add(dependency);
533
+ var tuple = new ProvidesDependencyTuple(msiPackage.SourceLineNumbers)
534
+ {
535
+ PackageRef = msiPackage.Id.Id,
536
+ Key = record.GetString(1),
537
+ Version = record.GetString(2) ?? msiPackage.ProductVersion,
538
+ DisplayName = record.GetString(3) ?? this.Facade.PackageTuple.DisplayName,
539
+ Attributes = record.GetInteger(4),
540
+ Imported = true
541
+ };
542
+
543
+ this.Section.Tuples.Add(tuple);
544
}
545
}
546
}
547
}
548
}
549
513
- private string ResolveRelatedFile(string sourceFile, string relatedSource, string type, SourceLineNumber sourceLineNumbers, BindStage stage)
550
+ private string ResolveRelatedFile(string resolvedSource, string unresolvedSource, string relatedSource, string type, SourceLineNumber sourceLineNumbers, BindStage stage)
551
{
552
+ var checkedPaths = new List<string>();
553
+
554
foreach (var extension in this.BackendExtensions)
555
{
517
- var relatedFile = extension.ResolveRelatedFile(sourceFile, relatedSource, type, sourceLineNumbers, stage);
556
+ var resolved = extension.ResolveRelatedFile(unresolvedSource, relatedSource, type, sourceLineNumbers, stage);
557
519
- if (!String.IsNullOrEmpty(relatedFile))
558
+ if (resolved?.CheckedPaths != null)
559
{
521
- return relatedFile;
560
+ checkedPaths.AddRange(resolved.CheckedPaths);
561
+ }
562
+
563
+ if (!String.IsNullOrEmpty(resolved?.Path))
564
+ {
565
+ return resolved?.Path;
566
}
567
}
568
525
- return null;
569
+ var resolvedPath = Path.Combine(Path.GetDirectoryName(resolvedSource), relatedSource);
570
+
571
+ if (!File.Exists(resolvedPath))
572
+ {
573
+ checkedPaths.Add(resolvedPath);
574
+ this.Messaging.Write(ErrorMessages.FileNotFound(sourceLineNumbers, resolvedPath, type, checkedPaths));
575
+ }
576
+
577
+ return resolvedPath;
578
}
579
580
/// <summary>
@@ -571,6 +623,5 @@ namespace WixToolset.Core.Burn.Bundles
623
624
return String.Format(CultureInfo.InvariantCulture, ProcessMsiPackageCommand.PropertySqlFormat, property);
625
}
574
-#endif
626
}
627
}
src/WixToolset.Core.Burn/Bundles/ProcessMspPackageCommand.cs
+55
-47
@@ -10,6 +10,8 @@ namespace WixToolset.Core.Burn.Bundles
10
using System.Text;
11
using System.Xml;
12
using WixToolset.Data;
13
+ using WixToolset.Data.Tuples;
14
+ using WixToolset.Extensibility.Services;
15
using Dtf = WixToolset.Dtf.WindowsInstaller;
16
17
/// <summary>
@@ -17,80 +19,92 @@ namespace WixToolset.Core.Burn.Bundles
19
/// </summary>
20
internal class ProcessMspPackageCommand
21
{
20
-#if TODO
22
private const string PatchMetadataFormat = "SELECT `Value` FROM `MsiPatchMetadata` WHERE `Property` = '{0}'";
23
private static readonly Encoding XmlOutputEncoding = new UTF8Encoding(false);
24
24
- public RowDictionary<WixBundlePayloadRow> AuthoredPayloads { private get; set; }
25
+ public ProcessMspPackageCommand(IMessaging messaging, IntermediateSection section, PackageFacade facade, Dictionary<string, WixBundlePayloadTuple> payloadTuples)
26
+ {
27
+ this.Messaging = messaging;
28
+
29
+ this.AuthoredPayloads = payloadTuples;
30
+ this.Section = section;
31
+ this.Facade = facade;
32
+ }
33
+
34
+ public IMessaging Messaging { get; }
35
+
36
+ public Dictionary<string, WixBundlePayloadTuple> AuthoredPayloads { private get; set; }
37
38
public PackageFacade Facade { private get; set; }
39
28
- public Table WixBundlePatchTargetCodeTable { private get; set; }
40
+ public IntermediateSection Section { get; }
41
42
/// <summary>
43
/// Processes the Msp packages to add properties and payloads from the Msp packages.
44
/// </summary>
45
public void Execute()
46
{
35
- WixBundlePayloadRow packagePayload = this.AuthoredPayloads.Get(this.Facade.Package.PackagePayload);
47
+ var packagePayload = this.AuthoredPayloads[this.Facade.PackageTuple.PayloadRef];
48
+
49
+ var mspPackage = (WixBundleMspPackageTuple)this.Facade.SpecificPackageTuple;
50
37
- string sourcePath = packagePayload.FullFileName;
51
+ var sourcePath = packagePayload.SourceFile.Path;
52
53
try
54
{
55
// Read data out of the msp database...
42
- using (Dtf.SummaryInfo sumInfo = new Dtf.SummaryInfo(sourcePath, false))
56
+ using (var sumInfo = new Dtf.SummaryInfo(sourcePath, false))
57
{
44
- this.Facade.MspPackage.PatchCode = sumInfo.RevisionNumber.Substring(0, 38);
58
+ mspPackage.PatchCode = sumInfo.RevisionNumber.Substring(0, 38);
59
}
60
47
- using (Dtf.Database db = new Dtf.Database(sourcePath))
61
+ using (var db = new Dtf.Database(sourcePath))
62
{
49
- if (String.IsNullOrEmpty(this.Facade.Package.DisplayName))
63
+ if (String.IsNullOrEmpty(this.Facade.PackageTuple.DisplayName))
64
{
51
- this.Facade.Package.DisplayName = ProcessMspPackageCommand.GetPatchMetadataProperty(db, "DisplayName");
65
+ this.Facade.PackageTuple.DisplayName = ProcessMspPackageCommand.GetPatchMetadataProperty(db, "DisplayName");
66
}
67
54
- if (String.IsNullOrEmpty(this.Facade.Package.Description))
68
+ if (String.IsNullOrEmpty(this.Facade.PackageTuple.Description))
69
{
56
- this.Facade.Package.Description = ProcessMspPackageCommand.GetPatchMetadataProperty(db, "Description");
70
+ this.Facade.PackageTuple.Description = ProcessMspPackageCommand.GetPatchMetadataProperty(db, "Description");
71
}
72
59
- this.Facade.MspPackage.Manufacturer = ProcessMspPackageCommand.GetPatchMetadataProperty(db, "ManufacturerName");
73
+ mspPackage.Manufacturer = ProcessMspPackageCommand.GetPatchMetadataProperty(db, "ManufacturerName");
74
}
75
62
- this.ProcessPatchXml(packagePayload, sourcePath);
76
+ this.ProcessPatchXml(packagePayload, mspPackage, sourcePath);
77
}
78
catch (Dtf.InstallerException e)
79
{
66
- Messaging.Instance.OnMessage(WixErrors.UnableToReadPackageInformation(packagePayload.SourceLineNumbers, sourcePath, e.Message));
80
+ this.Messaging.Write(ErrorMessages.UnableToReadPackageInformation(packagePayload.SourceLineNumbers, sourcePath, e.Message));
81
return;
82
}
83
70
- if (String.IsNullOrEmpty(this.Facade.Package.CacheId))
84
+ if (String.IsNullOrEmpty(this.Facade.PackageTuple.CacheId))
85
{
72
- this.Facade.Package.CacheId = this.Facade.MspPackage.PatchCode;
86
+ this.Facade.PackageTuple.CacheId = mspPackage.PatchCode;
87
}
88
}
89
76
- private void ProcessPatchXml(WixBundlePayloadRow packagePayload, string sourcePath)
90
+ private void ProcessPatchXml(WixBundlePayloadTuple packagePayload, WixBundleMspPackageTuple mspPackage, string sourcePath)
91
{
78
- HashSet<string> uniqueTargetCodes = new HashSet<string>();
92
+ var uniqueTargetCodes = new HashSet<string>();
93
80
- string patchXml = Dtf.Installer.ExtractPatchXmlData(sourcePath);
94
+ var patchXml = Dtf.Installer.ExtractPatchXmlData(sourcePath);
95
82
- XmlDocument doc = new XmlDocument();
96
+ var doc = new XmlDocument();
97
doc.LoadXml(patchXml);
98
85
- XmlNamespaceManager nsmgr = new XmlNamespaceManager(doc.NameTable);
99
+ var nsmgr = new XmlNamespaceManager(doc.NameTable);
100
nsmgr.AddNamespace("p", "http://www.microsoft.com/msi/patch_applicability.xsd");
101
102
// Determine target ProductCodes and/or UpgradeCodes.
103
foreach (XmlNode node in doc.SelectNodes("/p:MsiPatch/p:TargetProduct", nsmgr))
104
{
105
// If this patch targets a product code, this is the best case.
92
- XmlNode targetCodeElement = node.SelectSingleNode("p:TargetProductCode", nsmgr);
93
- WixBundlePatchTargetCodeAttributes attributes = WixBundlePatchTargetCodeAttributes.None;
106
+ var targetCodeElement = node.SelectSingleNode("p:TargetProductCode", nsmgr);
107
+ var attributes = WixBundlePatchTargetCodeAttributes.None;
108
109
if (ProcessMspPackageCommand.TargetsCode(targetCodeElement))
110
{
@@ -105,45 +119,49 @@ namespace WixToolset.Core.Burn.Bundles
119
}
120
else // this patch targets an unknown number of products
121
{
108
- this.Facade.MspPackage.Attributes |= WixBundleMspPackageAttributes.TargetUnspecified;
122
+ mspPackage.Attributes |= WixBundleMspPackageAttributes.TargetUnspecified;
123
}
124
}
125
112
- string targetCode = targetCodeElement.InnerText;
126
+ var targetCode = targetCodeElement.InnerText;
127
128
if (uniqueTargetCodes.Add(targetCode))
129
{
116
- WixBundlePatchTargetCodeRow row = (WixBundlePatchTargetCodeRow)this.WixBundlePatchTargetCodeTable.CreateRow(packagePayload.SourceLineNumbers);
117
- row.MspPackageId = packagePayload.Id;
118
- row.TargetCode = targetCode;
119
- row.Attributes = attributes;
130
+ var tuple = new WixBundlePatchTargetCodeTuple(packagePayload.SourceLineNumbers)
131
+ {
132
+ PackageRef = packagePayload.Id.Id,
133
+ TargetCode = targetCode,
134
+ Attributes = attributes
135
+ };
136
+
137
+ this.Section.Tuples.Add(tuple);
138
}
139
}
140
141
// Suppress patch sequence data for improved performance.
124
- XmlNode root = doc.DocumentElement;
142
+ var root = doc.DocumentElement;
143
foreach (XmlNode node in root.SelectNodes("p:SequenceData", nsmgr))
144
{
145
root.RemoveChild(node);
146
}
147
148
// Save the XML as compact as possible.
131
- using (StringWriter writer = new StringWriter())
149
+ using (var writer = new StringWriter())
150
{
133
- XmlWriterSettings settings = new XmlWriterSettings()
151
+ var settings = new XmlWriterSettings()
152
{
153
Encoding = ProcessMspPackageCommand.XmlOutputEncoding,
154
Indent = false,
137
- NewLineChars = string.Empty,
155
+ NewLineChars = String.Empty,
156
NewLineHandling = NewLineHandling.Replace,
157
};
158
141
- using (XmlWriter xmlWriter = XmlWriter.Create(writer, settings))
159
+ using (var xmlWriter = XmlWriter.Create(writer, settings))
160
{
161
doc.WriteTo(xmlWriter);
162
}
163
146
- this.Facade.MspPackage.PatchXml = writer.ToString();
164
+ mspPackage.PatchXml = writer.ToString();
165
}
166
}
167
@@ -175,16 +193,6 @@ namespace WixToolset.Core.Burn.Bundles
193
return String.Format(CultureInfo.InvariantCulture, ProcessMspPackageCommand.PatchMetadataFormat, property);
194
}
195
178
- private static bool TargetsCode(XmlNode node)
179
- {
180
- if (null != node)
181
- {
182
- XmlAttribute attr = node.Attributes["Validate"];
183
- return null != attr && "true".Equals(attr.Value);
184
- }
185
-
186
- return false;
187
- }
188
-#endif
196
+ private static bool TargetsCode(XmlNode node) => "true" == node?.Attributes["Validate"]?.Value;
197
}
198
}
src/WixToolset.Core.Burn/Bundles/ProcessMsuPackageCommand.cs
+13
-7
@@ -3,29 +3,35 @@
3
namespace WixToolset.Core.Burn.Bundles
4
{
5
using System;
6
+ using System.Collections.Generic;
7
using WixToolset.Data;
8
+ using WixToolset.Data.Tuples;
9
10
/// <summary>
11
/// Processes the Msu packages to add properties and payloads from the Msu packages.
12
/// </summary>
13
internal class ProcessMsuPackageCommand
14
{
13
-#if TODO
14
- public RowDictionary<WixBundlePayload> AuthoredPayloads { private get; set; }
15
+ public ProcessMsuPackageCommand(PackageFacade facade, Dictionary<string, WixBundlePayloadTuple> payloadTuples)
16
+ {
17
+ this.AuthoredPayloads = payloadTuples;
18
+ this.Facade = facade;
19
+ }
20
+
21
+ public Dictionary<string, WixBundlePayloadTuple> AuthoredPayloads { private get; set; }
22
23
public PackageFacade Facade { private get; set; }
24
25
public void Execute()
26
{
20
- WixBundlePayloadRow packagePayload = this.AuthoredPayloads.Get(this.Facade.Package.PackagePayload);
27
+ var packagePayload = this.AuthoredPayloads[this.Facade.PackageTuple.PayloadRef];
28
22
- if (String.IsNullOrEmpty(this.Facade.Package.CacheId))
29
+ if (String.IsNullOrEmpty(this.Facade.PackageTuple.CacheId))
30
{
24
- this.Facade.Package.CacheId = packagePayload.Hash;
31
+ this.Facade.PackageTuple.CacheId = packagePayload.Hash;
32
}
33
27
- this.Facade.Package.PerMachine = YesNoDefaultType.Yes; // MSUs are always per-machine.
34
+ this.Facade.PackageTuple.PerMachine = YesNoDefaultType.Yes; // MSUs are always per-machine.
35
}
29
-#endif
36
}
37
}
src/WixToolset.Core.Burn/Bundles/ProcessPayloadsCommand.cs
+52
-37
@@ -9,58 +9,73 @@ namespace WixToolset.Core.Burn.Bundles
9
using System.Security.Cryptography;
10
using System.Security.Cryptography.X509Certificates;
11
using System.Text;
12
+ using WixToolset.Data;
13
+ using WixToolset.Data.Burn;
14
+ using WixToolset.Data.Tuples;
15
+ using WixToolset.Extensibility.Data;
16
+ using WixToolset.Extensibility.Services;
17
18
internal class ProcessPayloadsCommand
19
{
15
-#if TODO
20
private static readonly Version EmptyVersion = new Version(0, 0, 0, 0);
21
18
- public IEnumerable<WixBundlePayloadRow> Payloads { private get; set; }
22
+ public ProcessPayloadsCommand(IServiceProvider serviceProvider, IBackendHelper backendHelper, IEnumerable<WixBundlePayloadTuple> payloads, PackagingType defaultPackaging, string layoutDirectory)
23
+ {
24
+ this.Messaging = serviceProvider.GetService<IMessaging>();
25
+
26
+ this.BackendHelper = backendHelper;
27
+ this.Payloads = payloads;
28
+ this.DefaultPackaging = defaultPackaging;
29
+ this.LayoutDirectory = layoutDirectory;
30
+ }
31
+
32
+ public IEnumerable<IFileTransfer> FileTransfers { get; private set; }
33
20
- public PackagingType DefaultPackaging { private get; set; }
34
+ private IMessaging Messaging { get; }
35
22
- public string LayoutDirectory { private get; set; }
36
+ private IBackendHelper BackendHelper { get; }
37
24
- public IEnumerable<FileTransfer> FileTransfers { get; private set; }
38
+ private IEnumerable<WixBundlePayloadTuple> Payloads { get; }
39
+
40
+ private PackagingType DefaultPackaging { get; }
41
+
42
+ private string LayoutDirectory { get; }
43
44
public void Execute()
45
{
28
- List<FileTransfer> fileTransfers = new List<FileTransfer>();
46
+ var fileTransfers = new List<IFileTransfer>();
47
30
- foreach (WixBundlePayloadRow payload in this.Payloads)
48
+ foreach (var payload in this.Payloads)
49
{
32
- string normalizedPath = payload.Name.Replace('\\', '/');
50
+ var normalizedPath = payload.Name.Replace('\\', '/');
51
if (normalizedPath.StartsWith("../", StringComparison.Ordinal) || normalizedPath.Contains("/../"))
52
{
35
- Messaging.Instance.OnMessage(WixErrors.PayloadMustBeRelativeToCache(payload.SourceLineNumbers, "Payload", "Name", payload.Name));
53
+ this.Messaging.Write(ErrorMessages.PayloadMustBeRelativeToCache(payload.SourceLineNumbers, "Payload", "Name", payload.Name));
54
}
55
56
// Embedded files (aka: files from binary .wixlibs) are not content files (because they are hidden
57
// in the .wixlib).
40
- ObjectField field = (ObjectField)payload.Fields[2];
41
- payload.ContentFile = !field.EmbeddedFileIndex.HasValue;
58
+ var sourceFile = payload.SourceFile;
59
+ payload.ContentFile = !sourceFile.EmbeddedFileIndex.HasValue;
60
61
this.UpdatePayloadPackagingType(payload);
62
45
- if (String.IsNullOrEmpty(payload.SourceFile))
63
+ if (String.IsNullOrEmpty(sourceFile?.Path))
64
{
65
// Remote payloads obviously cannot be embedded.
66
Debug.Assert(PackagingType.Embedded != payload.Packaging);
67
}
68
else // not a remote payload so we have a lot more to update.
69
{
52
- this.UpdatePayloadFileInformation(payload);
70
+ this.UpdatePayloadFileInformation(payload, sourceFile);
71
54
- this.UpdatePayloadVersionInformation(payload);
72
+ this.UpdatePayloadVersionInformation(payload, sourceFile);
73
74
// External payloads need to be transfered.
75
if (PackagingType.External == payload.Packaging)
76
{
59
- FileTransfer transfer;
60
- if (FileTransfer.TryCreate(payload.FullFileName, Path.Combine(this.LayoutDirectory, payload.Name), false, "Payload", payload.SourceLineNumbers, out transfer))
61
- {
62
- fileTransfers.Add(transfer);
63
- }
77
+ var transfer = this.BackendHelper.CreateFileTransfer(sourceFile.Path, Path.Combine(this.LayoutDirectory, payload.Name), false, payload.SourceLineNumbers);
78
+ fileTransfers.Add(transfer);
79
}
80
}
81
}
@@ -68,41 +83,41 @@ namespace WixToolset.Core.Burn.Bundles
83
this.FileTransfers = fileTransfers;
84
}
85
71
- private void UpdatePayloadPackagingType(WixBundlePayloadRow payload)
86
+ private void UpdatePayloadPackagingType(WixBundlePayloadTuple payload)
87
{
88
if (PackagingType.Unknown == payload.Packaging)
89
{
75
- if (YesNoDefaultType.Yes == payload.Compressed)
90
+ if (!payload.Compressed.HasValue)
91
{
77
- payload.Packaging = PackagingType.Embedded;
92
+ payload.Packaging = this.DefaultPackaging;
93
}
79
- else if (YesNoDefaultType.No == payload.Compressed)
94
+ else if (payload.Compressed.Value)
95
{
81
- payload.Packaging = PackagingType.External;
96
+ payload.Packaging = PackagingType.Embedded;
97
}
98
else
99
{
85
- payload.Packaging = this.DefaultPackaging;
100
+ payload.Packaging = PackagingType.External;
101
}
102
}
103
104
// Embedded payloads that are not assigned a container already are placed in the default attached
105
// container.
91
- if (PackagingType.Embedded == payload.Packaging && String.IsNullOrEmpty(payload.Container))
106
+ if (PackagingType.Embedded == payload.Packaging && String.IsNullOrEmpty(payload.ContainerRef))
107
{
93
- payload.Container = Compiler.BurnDefaultAttachedContainerId;
108
+ payload.ContainerRef = BurnConstants.BurnDefaultAttachedContainerName;
109
}
110
}
111
97
- private void UpdatePayloadFileInformation(WixBundlePayloadRow payload)
112
+ private void UpdatePayloadFileInformation(WixBundlePayloadTuple payload, IntermediateFieldPathValue sourceFile)
113
{
99
- FileInfo fileInfo = new FileInfo(payload.SourceFile);
114
+ var fileInfo = new FileInfo(sourceFile.Path);
115
116
if (null != fileInfo)
117
{
118
payload.FileSize = (int)fileInfo.Length;
119
105
- payload.Hash = Common.GetFileHash(fileInfo.FullName);
120
+ payload.Hash = BundleHashAlgorithm.Hash(fileInfo);
121
122
// Try to get the certificate if the payload is a signed file and we're not suppressing signature validation.
123
if (payload.EnableSignatureValidation)
@@ -122,9 +137,10 @@ namespace WixToolset.Core.Burn.Bundles
137
byte[] publicKeyIdentifierHash = new byte[128];
138
uint publicKeyIdentifierHashSize = (uint)publicKeyIdentifierHash.Length;
139
125
- WixToolset.Core.Native.NativeMethods.HashPublicKeyInfo(certificate.Handle, publicKeyIdentifierHash, ref publicKeyIdentifierHashSize);
126
- StringBuilder sb = new StringBuilder(((int)publicKeyIdentifierHashSize + 1) * 2);
127
- for (int i = 0; i < publicKeyIdentifierHashSize; ++i)
140
+ Native.NativeMethods.HashPublicKeyInfo(certificate.Handle, publicKeyIdentifierHash, ref publicKeyIdentifierHashSize);
141
+
142
+ var sb = new StringBuilder(((int)publicKeyIdentifierHashSize + 1) * 2);
143
+ for (var i = 0; i < publicKeyIdentifierHashSize; ++i)
144
{
145
sb.AppendFormat("{0:X2}", publicKeyIdentifierHash[i]);
146
}
@@ -136,14 +152,14 @@ namespace WixToolset.Core.Burn.Bundles
152
}
153
}
154
139
- private void UpdatePayloadVersionInformation(WixBundlePayloadRow payload)
155
+ private void UpdatePayloadVersionInformation(WixBundlePayloadTuple payload, IntermediateFieldPathValue sourceFile)
156
{
141
- FileVersionInfo versionInfo = FileVersionInfo.GetVersionInfo(payload.SourceFile);
157
+ var versionInfo = FileVersionInfo.GetVersionInfo(sourceFile.Path);
158
159
if (null != versionInfo)
160
{
161
// Use the fixed version info block for the file since the resource text may not be a dotted quad.
146
- Version version = new Version(versionInfo.ProductMajorPart, versionInfo.ProductMinorPart, versionInfo.ProductBuildPart, versionInfo.ProductPrivatePart);
162
+ var version = new Version(versionInfo.ProductMajorPart, versionInfo.ProductMinorPart, versionInfo.ProductBuildPart, versionInfo.ProductPrivatePart);
163
164
if (ProcessPayloadsCommand.EmptyVersion != version)
165
{
@@ -154,6 +170,5 @@ namespace WixToolset.Core.Burn.Bundles
170
payload.DisplayName = versionInfo.ProductName;
171
}
172
}
157
-#endif
173
}
174
}
src/WixToolset.Core.Burn/Bundles/VerifyPayloadsWithCatalogCommand.cs
+29
-20
@@ -9,31 +9,42 @@ namespace WixToolset.Core.Burn.Bundles
9
using System.Runtime.InteropServices;
10
using System.Text;
11
using WixToolset.Data;
12
+ using WixToolset.Data.Tuples;
13
+ using WixToolset.Extensibility.Services;
14
15
internal class VerifyPayloadsWithCatalogCommand
16
{
15
-#if TODO
16
- public IEnumerable<WixBundleCatalogRow> Catalogs { private get; set; }
17
+ public VerifyPayloadsWithCatalogCommand(IMessaging messaging, IEnumerable<WixBundleCatalogTuple> catalogs, IEnumerable<WixBundlePayloadTuple> payloads)
18
+ {
19
+ this.Messaging = messaging;
20
+ this.Catalogs = catalogs;
21
+ this.Payloads = payloads;
22
+ }
23
+
24
+ private IMessaging Messaging { get; }
25
+
26
+ private IEnumerable<WixBundleCatalogTuple> Catalogs { get; }
27
18
- public IEnumerable<WixBundlePayloadRow> Payloads { private get; set; }
28
+ private IEnumerable<WixBundlePayloadTuple> Payloads { get; }
29
30
public void Execute()
31
{
22
- List<CatalogIdWithPath> catalogIdsWithPaths = this.Catalogs
32
+ var catalogIdsWithPaths = this.Catalogs
33
.Join(this.Payloads,
24
- catalog => catalog.Payload,
25
- payload => payload.Id,
26
- (catalog, payload) => new CatalogIdWithPath() { Id = catalog.Id, FullPath = Path.GetFullPath(payload.SourceFile) })
34
+ catalog => catalog.PayloadRef,
35
+ payload => payload.Id.Id,
36
+ (catalog, payload) => new CatalogIdWithPath() { Id = catalog.Id.Id, FullPath = Path.GetFullPath(payload.SourceFile.Path) })
37
.ToList();
38
29
- foreach (WixBundlePayloadRow payloadInfo in this.Payloads)
39
+ foreach (var payloadInfo in this.Payloads)
40
{
41
// Payloads that are not embedded should be verfied.
42
if (String.IsNullOrEmpty(payloadInfo.EmbeddedId))
43
{
34
- bool validated = false;
44
+ var sourceFile = payloadInfo.SourceFile.Path;
45
+ var validated = false;
46
36
- foreach (CatalogIdWithPath catalog in catalogIdsWithPaths)
47
+ foreach (var catalog in catalogIdsWithPaths)
48
{
49
if (!validated)
50
{
@@ -41,11 +52,10 @@ namespace WixToolset.Core.Burn.Bundles
52
uint cryptHashSize = 20;
53
byte[] cryptHashBytes = new byte[cryptHashSize];
54
int error;
44
- IntPtr fileHandle = IntPtr.Zero;
45
- using (FileStream payloadStream = File.OpenRead(payloadInfo.FullFileName))
55
+ using (var payloadStream = File.OpenRead(sourceFile))
56
{
57
// Get the file handle
48
- fileHandle = payloadStream.SafeFileHandle.DangerousGetHandle();
58
+ var fileHandle = payloadStream.SafeFileHandle.DangerousGetHandle();
59
60
// 20 bytes is usually the hash size. Future hashes may be bigger
61
if (!VerifyInterop.CryptCATAdminCalcHashFromFileHandle(fileHandle, ref cryptHashSize, cryptHashBytes, 0))
@@ -64,7 +74,7 @@ namespace WixToolset.Core.Burn.Bundles
74
75
if (0 != error)
76
{
67
- Messaging.Instance.OnMessage(WixErrors.CatalogFileHashFailed(payloadInfo.FullFileName, error));
77
+ this.Messaging.Write(ErrorMessages.CatalogFileHashFailed(sourceFile, error));
78
}
79
}
80
}
@@ -79,15 +89,15 @@ namespace WixToolset.Core.Burn.Bundles
89
catalogData.pbCalculatedFileHash = Marshal.AllocCoTaskMem((int)cryptHashSize);
90
Marshal.Copy(cryptHashBytes, 0, catalogData.pbCalculatedFileHash, (int)cryptHashSize);
91
82
- StringBuilder hashString = new StringBuilder();
83
- foreach (byte hashByte in cryptHashBytes)
92
+ var hashString = new StringBuilder();
93
+ foreach (var hashByte in cryptHashBytes)
94
{
95
hashString.Append(hashByte.ToString("X2"));
96
}
97
catalogData.pcwszMemberTag = hashString.ToString();
98
99
// The file names need to be lower case for older OSes
90
- catalogData.pcwszMemberFilePath = payloadInfo.FullFileName.ToLowerInvariant();
100
+ catalogData.pcwszMemberFilePath = sourceFile.ToLowerInvariant();
101
catalogData.pcwszCatalogFilePath = catalog.FullPath.ToLowerInvariant();
102
103
// Create WINTRUST_DATA structure
@@ -108,7 +118,7 @@ namespace WixToolset.Core.Burn.Bundles
118
long verifyResult = VerifyInterop.WinVerifyTrust(noWindow, ref verifyGuid, ref trustData);
119
if (0 == verifyResult)
120
{
111
- payloadInfo.Catalog = catalog.Id;
121
+ payloadInfo.CatalogRef = catalog.Id;
122
validated = true;
123
break;
124
}
@@ -132,7 +142,7 @@ namespace WixToolset.Core.Burn.Bundles
142
// Error message if the file was not validated by one of the catalogs
143
if (!validated)
144
{
135
- Messaging.Instance.OnMessage(WixErrors.CatalogVerificationFailed(payloadInfo.FullFileName));
145
+ this.Messaging.Write(ErrorMessages.CatalogVerificationFailed(sourceFile));
146
}
147
}
148
}
@@ -144,6 +154,5 @@ namespace WixToolset.Core.Burn.Bundles
154
155
public string FullPath { get; set; }
156
}
147
-#endif
157
}
158
}
src/WixToolset.Core.Burn/BurnBackendFactory.cs
+1
-2
@@ -1,11 +1,10 @@
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.
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.Burn
4
{
5
using System;
6
using System.IO;
7
using WixToolset.Extensibility;
8
- using WixToolset.Extensibility.Data;
8
9
internal class BurnBackendFactory : IBackendFactory
10
{
src/WixToolset.Core.Burn/VerifyInterop.cs
-2
@@ -3,8 +3,6 @@
3
namespace WixToolset
4
{
5
using System;
6
- using System.Collections;
7
- using System.Runtime.CompilerServices;
6
using System.Runtime.InteropServices;
7
8
internal class VerifyInterop
src/WixToolset.Core.Burn/WixToolset.Core.Burn.csproj
+1
@@ -15,6 +15,7 @@
15
</ItemGroup>
16
17
<ItemGroup>
18
+ <PackageReference Include="System.Security.Permissions" Version="4.6.0" />
19
<PackageReference Include="WixToolset.Core.Native" Version="4.0.*" />
20
<PackageReference Include="WixToolset.Dtf.Resources" Version="4.0.*" NoWarn="NU1701" />
21
<PackageReference Include="WixToolset.Dtf.WindowsInstaller" Version="4.0.*" NoWarn="NU1701" />
src/WixToolset.Core.WindowsInstaller/Bind/BindDatabaseCommand.cs
+6
-2
@@ -30,6 +30,8 @@ namespace WixToolset.Core.WindowsInstaller.Bind
30
31
this.BackendHelper = context.ServiceProvider.GetService<IBackendHelper>();
32
33
+ this.PathResolver = this.ServiceProvider.GetService<IPathResolver>();
34
+
35
this.TableDefinitions = WindowsInstallerStandardInternal.GetTableDefinitions();
36
37
this.CabbingThreadCount = context.CabbingThreadCount;
@@ -54,6 +56,8 @@ namespace WixToolset.Core.WindowsInstaller.Bind
56
57
private IBackendHelper BackendHelper { get; }
58
59
+ private IPathResolver PathResolver { get; }
60
+
61
private int Codepage { get; }
62
63
private int CabbingThreadCount { get; }
@@ -241,7 +245,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
245
246
// Set generated component guids.
247
{
244
- var command = new CalculateComponentGuids(this.Messaging, this.BackendHelper, section);
248
+ var command = new CalculateComponentGuids(this.Messaging, this.BackendHelper, this.PathResolver, section);
249
command.Execute();
250
}
251
@@ -501,7 +505,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
505
// Process uncompressed files.
506
if (!this.Messaging.EncounteredError && !this.SuppressLayout && uncompressedFiles.Any())
507
{
504
- var command = new ProcessUncompressedFilesCommand(section, this.BackendHelper);
508
+ var command = new ProcessUncompressedFilesCommand(section, this.BackendHelper, this.PathResolver);
509
command.Compressed = compressed;
510
command.FileFacades = uncompressedFiles;
511
command.LayoutDirectory = layoutDirectory;
src/WixToolset.Core.WindowsInstaller/Bind/CalculateComponentGuids.cs
+10
-6
@@ -6,9 +6,9 @@ namespace WixToolset.Core.WindowsInstaller.Bind
6
using System.Collections.Generic;
7
using System.IO;
8
using System.Linq;
9
- using WixToolset.Core.Native;
9
using WixToolset.Data;
10
using WixToolset.Data.Tuples;
11
+ using WixToolset.Extensibility.Data;
12
using WixToolset.Extensibility.Services;
13
14
/// <summary>
@@ -16,10 +16,11 @@ namespace WixToolset.Core.WindowsInstaller.Bind
16
/// </summary>
17
internal class CalculateComponentGuids
18
{
19
- internal CalculateComponentGuids(IMessaging messaging, IBackendHelper helper, IntermediateSection section)
19
+ internal CalculateComponentGuids(IMessaging messaging, IBackendHelper helper, IPathResolver pathResolver, IntermediateSection section)
20
{
21
this.Messaging = messaging;
22
this.BackendHelper = helper;
23
+ this.PathResolver = pathResolver;
24
this.Section = section;
25
}
26
@@ -27,12 +28,14 @@ namespace WixToolset.Core.WindowsInstaller.Bind
28
29
private IBackendHelper BackendHelper { get; }
30
31
+ private IPathResolver PathResolver { get; }
32
+
33
private IntermediateSection Section { get; }
34
35
public void Execute()
36
{
37
Dictionary<string, RegistryTuple> registryKeyRows = null;
35
- Dictionary<string, ResolvedDirectory> targetPathsByDirectoryId = null;
38
+ Dictionary<string, IResolvedDirectory> targetPathsByDirectoryId = null;
39
Dictionary<string, string> componentIdGenSeeds = null;
40
Dictionary<string, List<FileTuple>> filesByComponentId = null;
41
@@ -73,7 +76,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
76
{
77
var directories = this.Section.Tuples.OfType<DirectoryTuple>().ToList();
78
76
- targetPathsByDirectoryId = new Dictionary<string, ResolvedDirectory>(directories.Count);
79
+ targetPathsByDirectoryId = new Dictionary<string, IResolvedDirectory>(directories.Count);
80
81
// Get the target paths for all directories.
82
foreach (var directory in directories)
@@ -86,7 +89,8 @@ namespace WixToolset.Core.WindowsInstaller.Bind
89
continue;
90
}
91
89
- targetPathsByDirectoryId.Add(directory.Id.Id, new ResolvedDirectory(directory.ParentDirectoryRef, directory.Name));
92
+ var resolvedDirectory = this.BackendHelper.CreateResolvedDirectory(directory.ParentDirectoryRef, directory.Name);
93
+ targetPathsByDirectoryId.Add(directory.Id.Id, resolvedDirectory);
94
}
95
}
96
@@ -131,7 +135,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
135
if (fileRow.Id.Id == componentTuple.KeyPath)
136
{
137
// calculate the key file's canonical target path
134
- string directoryPath = PathResolver.GetDirectoryPath(targetPathsByDirectoryId, componentIdGenSeeds, componentTuple.DirectoryRef, true);
138
+ string directoryPath = this.PathResolver.GetDirectoryPath(targetPathsByDirectoryId, componentIdGenSeeds, componentTuple.DirectoryRef, true);
139
string fileName = Common.GetName(fileRow.Name, false, true).ToLowerInvariant();
140
path = Path.Combine(directoryPath, fileName);
141
src/WixToolset.Core.WindowsInstaller/Bind/CreateCabinetsCommand.cs
-1
@@ -8,7 +8,6 @@ namespace WixToolset.Core.WindowsInstaller.Bind
8
using System.IO;
9
using System.Linq;
10
using System.Runtime.InteropServices;
11
- using System.Threading;
11
using WixToolset.Core.Bind;
12
using WixToolset.Data;
13
using WixToolset.Data.Tuples;
src/WixToolset.Core.WindowsInstaller/Bind/CreateOutputFromIRCommand.cs
+16
@@ -105,6 +105,10 @@ namespace WixToolset.Core.WindowsInstaller.Bind
105
this.AddMsiEmbeddedUITuple((MsiEmbeddedUITuple)tuple, output);
106
break;
107
108
+ case TupleDefinitionType.MsiFileHash:
109
+ this.AddMsiFileHashTuple((MsiFileHashTuple)tuple, output);
110
+ break;
111
+
112
case TupleDefinitionType.MsiServiceConfig:
113
this.AddMsiServiceConfigTuple((MsiServiceConfigTuple)tuple, output);
114
break;
@@ -500,6 +504,18 @@ namespace WixToolset.Core.WindowsInstaller.Bind
504
row[4] = tuple.Source;
505
}
506
507
+ private void AddMsiFileHashTuple(MsiFileHashTuple tuple, Output output)
508
+ {
509
+ var table = output.EnsureTable(this.TableDefinitions["MsiFileHash"]);
510
+ var row = table.CreateRow(tuple.SourceLineNumbers);
511
+ row[0] = tuple.Id.Id;
512
+ row[1] = tuple.Options;
513
+ row[2] = tuple.HashPart1;
514
+ row[3] = tuple.HashPart2;
515
+ row[4] = tuple.HashPart3;
516
+ row[5] = tuple.HashPart4;
517
+ }
518
+
519
private void AddMsiServiceConfigTuple(MsiServiceConfigTuple tuple, Output output)
520
{
521
var events = tuple.OnInstall ? WindowsInstallerConstants.MsidbServiceConfigEventInstall : 0;
src/WixToolset.Core.WindowsInstaller/Bind/ProcessUncompressedFilesCommand.cs
+9
-4
@@ -18,16 +18,19 @@ namespace WixToolset.Core.WindowsInstaller.Bind
18
/// </summary>
19
internal class ProcessUncompressedFilesCommand
20
{
21
- public ProcessUncompressedFilesCommand(IntermediateSection section, IBackendHelper backendHelper)
21
+ public ProcessUncompressedFilesCommand(IntermediateSection section, IBackendHelper backendHelper, IPathResolver pathResolver)
22
{
23
this.Section = section;
24
this.BackendHelper = backendHelper;
25
+ this.PathResolver = pathResolver;
26
}
27
28
private IntermediateSection Section { get; }
29
30
public IBackendHelper BackendHelper { get; }
31
32
+ public IPathResolver PathResolver { get; }
33
+
34
public string DatabasePath { private get; set; }
35
36
public IEnumerable<FileFacade> FileFacades { private get; set; }
@@ -50,7 +53,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
53
54
var trackedFiles = new List<ITrackedFile>();
55
53
- var directories = new Dictionary<string, ResolvedDirectory>();
56
+ var directories = new Dictionary<string, IResolvedDirectory>();
57
58
var mediaRows = this.Section.Tuples.OfType<MediaTuple>().ToDictionary(t => t.DiskId);
59
@@ -69,7 +72,9 @@ namespace WixToolset.Core.WindowsInstaller.Bind
72
73
string sourceName = Common.GetName(directoryRecord.GetString(3), true, this.LongNamesInImage);
74
72
- directories.Add(directoryRecord.GetString(1), new ResolvedDirectory(directoryRecord.GetString(2), sourceName));
75
+ var resolvedDirectory = this.BackendHelper.CreateResolvedDirectory(directoryRecord.GetString(2), sourceName);
76
+
77
+ directories.Add(directoryRecord.GetString(1), resolvedDirectory);
78
}
79
}
80
}
@@ -99,7 +104,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
104
throw new WixException(ErrorMessages.FileIdentifierNotFound(facade.File.SourceLineNumbers, facade.File.Id.Id));
105
}
106
102
- relativeFileLayoutPath = PathResolver.GetFileSourcePath(directories, fileRecord[1], fileRecord[2], this.Compressed, this.LongNamesInImage);
107
+ relativeFileLayoutPath = this.PathResolver.GetFileSourcePath(directories, fileRecord[1], fileRecord[2], this.Compressed, this.LongNamesInImage);
108
}
109
110
// finally put together the base media layout path and the relative file layout path
src/WixToolset.Core.WindowsInstaller/Bind/ResolvedDirectory.cs
deleted
-31
@@ -1,31 +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
-
3
-namespace WixToolset.Core.WindowsInstaller.Bind
4
-{
5
- /// <summary>
6
- /// Structure used for resolved directory information.
7
- /// </summary>
8
- internal struct ResolvedDirectory
9
- {
10
- /// <summary>
11
- /// Constructor for ResolvedDirectory.
12
- /// </summary>
13
- /// <param name="directoryParent">Parent directory.</param>
14
- /// <param name="name">The directory name.</param>
15
- public ResolvedDirectory(string directoryParent, string name)
16
- {
17
- this.DirectoryParent = directoryParent;
18
- this.Name = name;
19
- this.Path = null;
20
- }
21
-
22
- /// <summary>The directory parent.</summary>
23
- public string DirectoryParent { get; set; }
24
-
25
- /// <summary>The name of this directory.</summary>
26
- public string Name { get; set; }
27
-
28
- /// <summary>The path of this directory.</summary>
29
- public string Path { get; set; }
30
- }
31
-}
src/WixToolset.Core.WindowsInstaller/Bind/UpdateFileFacadesCommand.cs
-1
@@ -162,7 +162,6 @@ namespace WixToolset.Core.WindowsInstaller.Bind
162
this.Section.Tuples.Add(facade.Hash);
163
}
164
165
- facade.Hash.FileRef = facade.File.Id.Id;
165
facade.Hash.Options = 0;
166
facade.Hash.HashPart1 = hash[0];
167
facade.Hash.HashPart2 = hash[1];
src/WixToolset.Core/Bind/ExtractEmbeddedFiles.cs
+4
-4
@@ -30,10 +30,10 @@ namespace WixToolset.Core.Bind
30
{
31
// If the uri to the file that contains the embedded file does not already have embedded files
32
// being extracted, create the dictionary to track that.
33
- if (!filesWithEmbeddedFiles.TryGetValue(uri, out var extracts))
33
+ if (!this.filesWithEmbeddedFiles.TryGetValue(uri, out var extracts))
34
{
35
extracts = new SortedList<int, string>();
36
- filesWithEmbeddedFiles.Add(uri, extracts);
36
+ this.filesWithEmbeddedFiles.Add(uri, extracts);
37
}
38
39
// If the embedded file is not already tracked in the dictionary of extracts, add it.
@@ -52,7 +52,7 @@ namespace WixToolset.Core.Bind
52
53
public IEnumerable<ExpectedExtractFile> GetExpectedEmbeddedFiles()
54
{
55
- foreach (var uriWithExtracts in filesWithEmbeddedFiles)
55
+ foreach (var uriWithExtracts in this.filesWithEmbeddedFiles)
56
{
57
foreach (var extracts in uriWithExtracts.Value)
58
{
@@ -68,7 +68,7 @@ namespace WixToolset.Core.Bind
68
69
public IEnumerable<ExpectedExtractFile> GetExtractFilesForUri(Uri uri)
70
{
71
- if (!filesWithEmbeddedFiles.TryGetValue(uri, out var extracts))
71
+ if (!this.filesWithEmbeddedFiles.TryGetValue(uri, out var extracts))
72
{
73
extracts = new SortedList<int, string>();
74
}
src/WixToolset.Core/Bind/FileResolver.cs
+7
-1
@@ -70,11 +70,17 @@ namespace WixToolset.Core.Bind
70
/// <param name="type">Optional type of source file being resolved.</param>
71
/// <param name="sourceLineNumbers">Optional source line of source file being resolved.</param>
72
/// <param name="bindStage">The binding stage used to determine what collection of bind paths will be used</param>
73
+ /// <param name="alreadyCheckedPaths">Optional collection of paths already checked.</param>
74
/// <returns>Should return a valid path for the stream to be imported.</returns>
74
- public string ResolveFile(string source, IntermediateTupleDefinition tupleDefinition, SourceLineNumber sourceLineNumbers, BindStage bindStage)
75
+ public string ResolveFile(string source, IntermediateTupleDefinition tupleDefinition, SourceLineNumber sourceLineNumbers, BindStage bindStage, IEnumerable<string> alreadyCheckedPaths = null)
76
{
77
var checkedPaths = new List<string>();
78
79
+ if (alreadyCheckedPaths != null)
80
+ {
81
+ checkedPaths.AddRange(alreadyCheckedPaths);
82
+ }
83
+
84
foreach (var extension in this.ResolverExtensions)
85
{
86
var resolved = extension.ResolveFile(source, tupleDefinition, sourceLineNumbers, bindStage);
src/WixToolset.Core/Bind/ResolveDelayedFieldsCommand.cs
+1
-1
@@ -113,7 +113,7 @@ namespace WixToolset.Core.Bind
113
}
114
}
115
116
- public static string ResolveDelayedVariables(SourceLineNumber sourceLineNumbers, string value, IDictionary<string, string> resolutionData)
116
+ private static string ResolveDelayedVariables(SourceLineNumber sourceLineNumbers, string value, IDictionary<string, string> resolutionData)
117
{
118
var matches = Common.WixVariableRegex.Matches(value);
119
src/WixToolset.Core/BindContext.cs
+3
-1
@@ -1,4 +1,4 @@
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.
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
4
{
@@ -19,6 +19,8 @@ namespace WixToolset.Core
19
20
public IEnumerable<BindPath> BindPaths { get; set; }
21
22
+ public string BurnStubPath { get; set; }
23
+
24
public int CabbingThreadCount { get; set; }
25
26
public string CabCachePath { get; set; }
src/WixToolset.Core/CommandLine/BuildCommand.cs
+9
-2
@@ -122,7 +122,7 @@ namespace WixToolset.Core.CommandLine
122
}
123
else
124
{
125
- this.BindPhase(wixipl, wxls, filterCultures, this.commandLine.CabCachePath, this.commandLine.BindPaths);
125
+ this.BindPhase(wixipl, wxls, filterCultures, this.commandLine.CabCachePath, this.commandLine.BindPaths, this.commandLine.BurnStubPath);
126
}
127
}
128
}
@@ -257,7 +257,7 @@ namespace WixToolset.Core.CommandLine
257
return linker.Link(context);
258
}
259
260
- private void BindPhase(Intermediate output, IEnumerable<Localization> localizations, IEnumerable<string> filterCultures, string cabCachePath, IEnumerable<IBindPath> bindPaths)
260
+ private void BindPhase(Intermediate output, IEnumerable<Localization> localizations, IEnumerable<string> filterCultures, string cabCachePath, IEnumerable<IBindPath> bindPaths, string burnStubPath)
261
{
262
var intermediateFolder = this.IntermediateFolder;
263
if (String.IsNullOrEmpty(intermediateFolder))
@@ -290,6 +290,7 @@ namespace WixToolset.Core.CommandLine
290
{
291
var context = this.ServiceProvider.GetService<IBindContext>();
292
//context.CabbingThreadCount = this.CabbingThreadCount;
293
+ context.BurnStubPath = burnStubPath;
294
context.CabCachePath = cabCachePath;
295
context.Codepage = resolveResult.Codepage;
296
//context.DefaultCompressionLevel = this.DefaultCompressionLevel;
@@ -399,6 +400,8 @@ namespace WixToolset.Core.CommandLine
400
401
public List<IBindPath> BindPaths { get; } = new List<IBindPath>();
402
403
+ public string BurnStubPath { get; private set; }
404
+
405
public string CabCachePath { get; private set; }
406
407
public List<string> Cultures { get; } = new List<string>();
@@ -480,6 +483,10 @@ namespace WixToolset.Core.CommandLine
483
}
484
break;
485
}
486
+ case "burnstub":
487
+ this.BurnStubPath = parser.GetNextArgumentOrError(arg);
488
+ return true;
489
+
490
case "cc":
491
this.CabCachePath = parser.GetNextArgumentOrError(arg);
492
return true;
src/WixToolset.Core/Compiler.cs
+1
-1
@@ -818,7 +818,7 @@ namespace WixToolset.Core
818
{
819
this.Core.AddTuple(new IconTuple(sourceLineNumbers, id)
820
{
821
- Data = sourceFile
821
+ Data = new IntermediateFieldPathValue { Path = sourceFile }
822
});
823
}
824
src/WixToolset.Core/Compiler_Bundle.cs
+61
-78
@@ -9,6 +9,7 @@ namespace WixToolset.Core
9
using System.IO;
10
using System.Xml.Linq;
11
using WixToolset.Data;
12
+ using WixToolset.Data.Burn;
13
using WixToolset.Data.Tuples;
14
using WixToolset.Extensibility;
15
@@ -17,15 +18,9 @@ namespace WixToolset.Core
18
/// </summary>
19
internal partial class Compiler : ICompiler
20
{
20
- public static readonly Identifier BurnUXContainerId = new Identifier(AccessModifier.Private, "WixUXContainer");
21
- public static readonly Identifier BurnDefaultAttachedContainerId = new Identifier(AccessModifier.Private, "WixAttachedContainer");
22
- public static readonly Identifier BundleLayoutOnlyPayloads = new Identifier(AccessModifier.Private, "BundleLayoutOnlyPayloads");
23
-
24
- // The following constants must stay in sync with src\burn\engine\core.h
25
- private const string BURN_BUNDLE_NAME = "WixBundleName";
26
- private const string BURN_BUNDLE_ORIGINAL_SOURCE = "WixBundleOriginalSource";
27
- private const string BURN_BUNDLE_ORIGINAL_SOURCE_FOLDER = "WixBundleOriginalSourceFolder";
28
- private const string BURN_BUNDLE_LAST_USED_SOURCE = "WixBundleLastUsedSource";
21
+ private static readonly Identifier BurnUXContainerId = new Identifier(AccessModifier.Private, BurnConstants.BurnUXContainerName);
22
+ private static readonly Identifier BurnDefaultAttachedContainerId = new Identifier(AccessModifier.Private, BurnConstants.BurnDefaultAttachedContainerName);
23
+ private static readonly Identifier BundleLayoutOnlyPayloads = new Identifier(AccessModifier.Private, BurnConstants.BundleLayoutOnlyPayloadsName);
24
25
/// <summary>
26
/// Parses an ApprovedExeForElevation element.
@@ -78,11 +73,11 @@ namespace WixToolset.Core
73
this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Key"));
74
}
75
81
- var attributes = BundleApprovedExeForElevationAttributes.None;
76
+ var attributes = WixApprovedExeForElevationAttributes.None;
77
78
if (win64 == YesNoType.Yes)
79
{
85
- attributes |= BundleApprovedExeForElevationAttributes.Win64;
80
+ attributes |= WixApprovedExeForElevationAttributes.Win64;
81
}
82
83
this.Core.ParseForExtensionElements(node);
@@ -92,7 +87,7 @@ namespace WixToolset.Core
87
var tuple = new WixApprovedExeForElevationTuple(sourceLineNumbers, id)
88
{
89
Key = key,
95
- Value = valueName,
90
+ ValueName = valueName,
91
Attributes = attributes
92
};
93
@@ -110,8 +105,7 @@ namespace WixToolset.Core
105
string copyright = null;
106
string aboutUrl = null;
107
var compressed = YesNoDefaultType.Default;
113
- var disableModify = -1;
114
- var disableRemove = YesNoType.NotSet;
108
+ WixBundleAttributes attributes = 0;
109
string helpTelephone = null;
110
string helpUrl = null;
111
string manufacturer = null;
@@ -152,13 +146,12 @@ namespace WixToolset.Core
146
switch (value)
147
{
148
case "button":
155
- disableModify = 2;
149
+ attributes |= WixBundleAttributes.SingleChangeUninstallButton;
150
break;
151
case "yes":
158
- disableModify = 1;
152
+ attributes |= WixBundleAttributes.DisableModify;
153
break;
154
case "no":
161
- disableModify = 0;
155
break;
156
default:
157
this.Core.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, value, "button", "yes", "no"));
@@ -166,10 +159,10 @@ namespace WixToolset.Core
159
}
160
break;
161
case "DisableRemove":
169
- disableRemove = this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib);
170
- break;
171
- case "DisableRepair":
172
- this.Core.Write(WarningMessages.DeprecatedAttribute(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName));
162
+ if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib))
163
+ {
164
+ attributes |= WixBundleAttributes.DisableRemove;
165
+ }
166
break;
167
case "HelpTelephone":
168
helpTelephone = this.Core.GetAttributeValue(sourceLineNumbers, attrib);
@@ -239,13 +232,13 @@ namespace WixToolset.Core
232
233
if (String.IsNullOrEmpty(name))
234
{
242
- logVariablePrefixAndExtension = String.Concat("WixBundleLog:Setup.log");
235
+ logVariablePrefixAndExtension = String.Concat("WixBundleLog:Setup:.log");
236
}
237
else
238
{
239
// Ensure only allowable path characters are in "name" (and change spaces to underscores).
240
fileSystemSafeBundleName = CompilerCore.MakeValidLongFileName(name.Replace(' ', '_'), "_");
248
- logVariablePrefixAndExtension = String.Concat("WixBundleLog:", fileSystemSafeBundleName, ".log");
241
+ logVariablePrefixAndExtension = String.Concat("WixBundleLog:", fileSystemSafeBundleName, ":.log");
242
}
243
244
this.activeName = String.IsNullOrEmpty(name) ? Common.GenerateGuid() : name;
@@ -351,6 +344,37 @@ namespace WixToolset.Core
344
345
if (!this.Core.EncounteredError)
346
{
347
+ var tuple = new WixBundleTuple(sourceLineNumbers)
348
+ {
349
+ UpgradeCode = upgradeCode,
350
+ Version = version,
351
+ Copyright = copyright,
352
+ Name = name,
353
+ Manufacturer = manufacturer,
354
+ Attributes = attributes,
355
+ AboutUrl = aboutUrl,
356
+ HelpUrl = helpUrl,
357
+ HelpTelephone = helpTelephone,
358
+ UpdateUrl = updateUrl,
359
+ Compressed = YesNoDefaultType.Yes == compressed ? true : YesNoDefaultType.No == compressed ? (bool?)false : null,
360
+ IconSourceFile = iconSourceFile,
361
+ SplashScreenSourceFile = splashScreenSourceFile,
362
+ Condition = condition,
363
+ Tag = tag,
364
+ Platform = this.CurrentPlatform,
365
+ ParentName = parentName,
366
+ };
367
+
368
+ if (!String.IsNullOrEmpty(logVariablePrefixAndExtension))
369
+ {
370
+ var split = logVariablePrefixAndExtension.Split(':');
371
+ tuple.LogPathVariable = split[0];
372
+ tuple.LogPrefix = split[1];
373
+ tuple.LogExtension = split[2];
374
+ }
375
+
376
+ this.Core.AddTuple(tuple);;
377
+
378
if (null != upgradeCode)
379
{
380
this.Core.AddTuple(new WixRelatedBundleTuple(sourceLineNumbers)
@@ -360,64 +384,32 @@ namespace WixToolset.Core
384
});
385
}
386
363
- this.Core.AddTuple(new WixBundleContainerTuple(sourceLineNumbers, new Identifier(AccessModifier.Private, Compiler.BurnDefaultAttachedContainerId))
387
+ this.Core.AddTuple(new WixBundleContainerTuple(sourceLineNumbers, Compiler.BurnDefaultAttachedContainerId)
388
{
389
Name = "bundle-attached.cab",
390
Type = ContainerType.Attached
391
});
392
369
- var bundleTuple = this.Core.CreateTuple(sourceLineNumbers, TupleDefinitionType.WixBundle);
370
- bundleTuple.Set(0, version);
371
- bundleTuple.Set(1, copyright);
372
- bundleTuple.Set(2, name);
373
- bundleTuple.Set(3, aboutUrl);
374
- if (-1 != disableModify)
375
- {
376
- bundleTuple.Set(4, disableModify);
377
- }
378
- if (YesNoType.NotSet != disableRemove)
379
- {
380
- bundleTuple.Set(5, (YesNoType.Yes == disableRemove) ? 1 : 0);
381
- }
382
- // row.Set(6] - (deprecated) "disable repair"
383
- bundleTuple.Set(7, helpTelephone);
384
- bundleTuple.Set(8, helpUrl);
385
- bundleTuple.Set(9, manufacturer);
386
- bundleTuple.Set(10, updateUrl);
387
- if (YesNoDefaultType.Default != compressed)
388
- {
389
- bundleTuple.Set(11, (YesNoDefaultType.Yes == compressed) ? 1 : 0);
390
- }
391
-
392
- bundleTuple.Set(12, logVariablePrefixAndExtension);
393
- bundleTuple.Set(13, iconSourceFile);
394
- bundleTuple.Set(14, splashScreenSourceFile);
395
- bundleTuple.Set(15, condition);
396
- bundleTuple.Set(16, tag);
397
- bundleTuple.Set(17, this.CurrentPlatform.ToString());
398
- bundleTuple.Set(18, parentName);
399
- bundleTuple.Set(19, upgradeCode);
400
-
393
// Ensure that the bundle stores the well-known persisted values.
402
- this.Core.AddTuple(new WixBundleVariableTuple(sourceLineNumbers, new Identifier(AccessModifier.Private, Compiler.BURN_BUNDLE_NAME))
394
+ this.Core.AddTuple(new WixBundleVariableTuple(sourceLineNumbers, new Identifier(AccessModifier.Private, BurnConstants.BURN_BUNDLE_NAME))
395
{
396
Hidden = false,
397
Persisted = true
398
});
399
408
- this.Core.AddTuple(new WixBundleVariableTuple(sourceLineNumbers, new Identifier(AccessModifier.Private, Compiler.BURN_BUNDLE_ORIGINAL_SOURCE))
400
+ this.Core.AddTuple(new WixBundleVariableTuple(sourceLineNumbers, new Identifier(AccessModifier.Private, BurnConstants.BURN_BUNDLE_ORIGINAL_SOURCE))
401
{
402
Hidden = false,
403
Persisted = true
404
});
405
414
- this.Core.AddTuple(new WixBundleVariableTuple(sourceLineNumbers, new Identifier(AccessModifier.Private, Compiler.BURN_BUNDLE_ORIGINAL_SOURCE_FOLDER))
406
+ this.Core.AddTuple(new WixBundleVariableTuple(sourceLineNumbers, new Identifier(AccessModifier.Private, BurnConstants.BURN_BUNDLE_ORIGINAL_SOURCE_FOLDER))
407
{
408
Hidden = false,
409
Persisted = true
410
});
411
420
- this.Core.AddTuple(new WixBundleVariableTuple(sourceLineNumbers, new Identifier(AccessModifier.Private, Compiler.BURN_BUNDLE_LAST_USED_SOURCE))
412
+ this.Core.AddTuple(new WixBundleVariableTuple(sourceLineNumbers, new Identifier(AccessModifier.Private, BurnConstants.BURN_BUNDLE_LAST_USED_SOURCE))
413
{
414
Hidden = false,
415
Persisted = true
@@ -473,7 +465,7 @@ namespace WixToolset.Core
465
466
this.Core.ParseForExtensionElements(node);
467
476
- return YesNoType.Yes == disableLog ? null : String.Concat(variable, ":", logPrefix, logExtension);
468
+ return YesNoType.Yes == disableLog ? null : String.Join(":", variable, logPrefix, logExtension);
469
}
470
471
/// <summary>
@@ -1126,9 +1118,9 @@ namespace WixToolset.Core
1118
tuple = new WixBundlePayloadTuple(sourceLineNumbers, id)
1119
{
1120
Name = String.IsNullOrEmpty(name) ? Path.GetFileName(sourceFile) : name,
1129
- SourceFile = sourceFile,
1121
+ SourceFile = new IntermediateFieldPathValue { Path = sourceFile },
1122
DownloadUrl = downloadUrl,
1131
- Compressed = compressed,
1123
+ Compressed = (compressed == YesNoDefaultType.Yes) ? true : (compressed == YesNoDefaultType.No) ? (bool?)false : null,
1124
UnresolvedSourceFile = sourceFile, // duplicate of sourceFile but in a string column so it won't get resolved to a full path during binding.
1125
DisplayName = displayName,
1126
Description = description,
@@ -1665,14 +1657,12 @@ namespace WixToolset.Core
1657
var vital = YesNoType.Yes;
1658
string installCommand = null;
1659
string repairCommand = null;
1668
- var repairable = YesNoType.NotSet;
1660
string uninstallCommand = null;
1661
var perMachine = YesNoDefaultType.NotSet;
1662
string detectCondition = null;
1663
string protocol = null;
1664
var installSize = CompilerConstants.IntegerNotSet;
1665
string msuKB = null;
1675
- var suppressLooseFilePayloadGeneration = YesNoType.NotSet;
1666
var enableSignatureVerification = YesNoType.No;
1667
var compressed = YesNoDefaultType.Default;
1668
var displayInternalUI = YesNoType.NotSet;
@@ -1779,7 +1769,6 @@ namespace WixToolset.Core
1769
break;
1770
case "RepairCommand":
1771
repairCommand = this.Core.GetAttributeValue(sourceLineNumbers, attrib, EmptyRule.CanBeEmpty);
1782
- repairable = YesNoType.Yes;
1772
allowed = (packageType == WixBundlePackageType.Exe);
1773
break;
1774
case "UninstallCommand":
@@ -1808,11 +1797,6 @@ namespace WixToolset.Core
1797
case "Compressed":
1798
compressed = this.Core.GetAttributeYesNoDefaultValue(sourceLineNumbers, attrib);
1799
break;
1811
- case "SuppressLooseFilePayloadGeneration":
1812
- this.Core.Write(WarningMessages.DeprecatedAttribute(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName));
1813
- suppressLooseFilePayloadGeneration = this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib);
1814
- allowed = (packageType == WixBundlePackageType.Msi);
1815
- break;
1800
case "EnableSignatureVerification":
1801
enableSignatureVerification = this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib);
1802
break;
@@ -2076,7 +2060,7 @@ namespace WixToolset.Core
2060
case WixBundlePackageType.Exe:
2061
this.Core.AddTuple(new WixBundleExePackageTuple(sourceLineNumbers, id)
2062
{
2079
- Attributes = (YesNoType.Yes == repairable) ? WixBundleExePackageAttributes.Repairable : 0,
2063
+ Attributes = WixBundleExePackageAttributes.None,
2064
DetectCondition = detectCondition,
2065
InstallCommand = installCommand,
2066
RepairCommand = repairCommand,
@@ -2090,7 +2074,6 @@ namespace WixToolset.Core
2074
msiAttributes |= (YesNoType.Yes == displayInternalUI) ? WixBundleMsiPackageAttributes.DisplayInternalUI : 0;
2075
msiAttributes |= (YesNoType.Yes == enableFeatureSelection) ? WixBundleMsiPackageAttributes.EnableFeatureSelection : 0;
2076
msiAttributes |= (YesNoType.Yes == forcePerMachine) ? WixBundleMsiPackageAttributes.ForcePerMachine : 0;
2093
- msiAttributes |= (YesNoType.Yes == suppressLooseFilePayloadGeneration) ? WixBundleMsiPackageAttributes.SuppressLooseFilePayloadGeneration : 0;
2077
2078
this.Core.AddTuple(new WixBundleMsiPackageTuple(sourceLineNumbers, id)
2079
{
@@ -2458,9 +2441,9 @@ namespace WixToolset.Core
2441
2442
if (!this.Core.EncounteredError)
2443
{
2461
- var tuple = new WixBundleMsiPropertyTuple(sourceLineNumbers)
2444
+ var tuple = new WixBundleMsiPropertyTuple(sourceLineNumbers, new Identifier(AccessModifier.Private, packageId, name))
2445
{
2463
- WixBundlePackageRef = packageId,
2446
+ PackageRef = packageId,
2447
Name = name,
2448
Value = value
2449
};
@@ -2514,10 +2497,10 @@ namespace WixToolset.Core
2497
2498
if (!this.Core.EncounteredError)
2499
{
2517
- this.Core.AddTuple(new WixBundleSlipstreamMspTuple(sourceLineNumbers)
2500
+ this.Core.AddTuple(new WixBundleSlipstreamMspTuple(sourceLineNumbers, new Identifier(AccessModifier.Private, packageId, id))
2501
{
2519
- WixBundlePackageRef = packageId,
2520
- MspWixBundlePackageRef = id
2502
+ TargetPackageRef = packageId,
2503
+ MspPackageRef = id
2504
});
2505
}
2506
}
src/WixToolset.Core/ExtensibilityServices/BackendHelper.cs
+10
-1
@@ -1,4 +1,4 @@
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.
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.ExtensibilityServices
4
{
@@ -40,6 +40,15 @@ namespace WixToolset.Core.ExtensibilityServices
40
return Uuid.NewUuid(namespaceGuid, value).ToString("B").ToUpperInvariant();
41
}
42
43
+ public IResolvedDirectory CreateResolvedDirectory(string directoryParent, string name)
44
+ {
45
+ return new ResolvedDirectory
46
+ {
47
+ DirectoryParent = directoryParent,
48
+ Name = name
49
+ };
50
+ }
51
+
52
public ITrackedFile TrackFile(string path, TrackedFileType type, SourceLineNumber sourceLineNumbers = null)
53
{
54
return new TrackedFile(path, type, sourceLineNumbers);
src/WixToolset.Core/ExtensibilityServices/PathResolver.cs
renamed
+9
-24
@@ -1,24 +1,18 @@
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
3
+namespace WixToolset.Core.ExtensibilityServices
4
{
5
using System;
6
using System.Collections.Generic;
7
using System.IO;
8
using WixToolset.Data;
9
using WixToolset.Data.WindowsInstaller;
10
+ using WixToolset.Extensibility.Data;
11
+ using WixToolset.Extensibility.Services;
12
11
- internal static class PathResolver
13
+ internal class PathResolver : IPathResolver
14
{
13
- /// <summary>
14
- /// Get the source path of a directory.
15
- /// </summary>
16
- /// <param name="directories">All cached directories.</param>
17
- /// <param name="componentIdGenSeeds">Hash table of Component GUID generation seeds indexed by directory id.</param>
18
- /// <param name="directory">Directory identifier.</param>
19
- /// <param name="canonicalize">Canonicalize the path for standard directories.</param>
20
- /// <returns>Source path of a directory.</returns>
21
- public static string GetDirectoryPath(Dictionary<string, ResolvedDirectory> directories, Dictionary<string, string> componentIdGenSeeds, string directory, bool canonicalize)
15
+ public string GetDirectoryPath(Dictionary<string, IResolvedDirectory> directories, Dictionary<string, string> componentIdGenSeeds, string directory, bool canonicalize)
16
{
17
if (!directories.TryGetValue(directory, out var resolvedDirectory))
18
{
@@ -51,7 +45,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
45
}
46
else
47
{
54
- string parentPath = GetDirectoryPath(directories, componentIdGenSeeds, resolvedDirectory.DirectoryParent, canonicalize);
48
+ var parentPath = this.GetDirectoryPath(directories, componentIdGenSeeds, resolvedDirectory.DirectoryParent, canonicalize);
49
50
if (null != resolvedDirectory.Name)
51
{
@@ -68,18 +62,9 @@ namespace WixToolset.Core.WindowsInstaller.Bind
62
return resolvedDirectory.Path;
63
}
64
71
- /// <summary>
72
- /// Gets the source path of a file.
73
- /// </summary>
74
- /// <param name="directories">All cached directories in <see cref="ResolvedDirectory"/>.</param>
75
- /// <param name="directoryId">Parent directory identifier.</param>
76
- /// <param name="fileName">File name (in long|source format).</param>
77
- /// <param name="compressed">Specifies the package is compressed.</param>
78
- /// <param name="useLongName">Specifies the package uses long file names.</param>
79
- /// <returns>Source path of file relative to package directory.</returns>
80
- public static string GetFileSourcePath(Dictionary<string, ResolvedDirectory> directories, string directoryId, string fileName, bool compressed, bool useLongName)
65
+ public string GetFileSourcePath(Dictionary<string, IResolvedDirectory> directories, string directoryId, string fileName, bool compressed, bool useLongName)
66
{
82
- string fileSourcePath = Common.GetName(fileName, true, useLongName);
67
+ var fileSourcePath = Common.GetName(fileName, true, useLongName);
68
69
if (compressed)
70
{
@@ -90,7 +75,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
75
{
76
// Get the relative path of where we want the file to be layed out as specified
77
// in the Directory table.
93
- string directoryPath = PathResolver.GetDirectoryPath(directories, null, directoryId, false);
78
+ var directoryPath = this.GetDirectoryPath(directories, null, directoryId, false);
79
fileSourcePath = Path.Combine(directoryPath, fileSourcePath);
80
}
81
src/WixToolset.Core/ExtensibilityServices/ResolvedDirectory.cs
new
+15
@@ -0,0 +1,15 @@
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.ExtensibilityServices
4
+{
5
+ using WixToolset.Extensibility.Data;
6
+
7
+ internal class ResolvedDirectory : IResolvedDirectory
8
+ {
9
+ public string DirectoryParent { get; set; }
10
+
11
+ public string Name { get; set; }
12
+
13
+ public string Path { get; set; }
14
+ }
15
+}
src/WixToolset.Core/ExtensibilityServices/WindowsInstallerBackendHelper.cs
+17
-15
@@ -1,8 +1,7 @@
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.
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.ExtensibilityServices
4
{
5
- using System;
5
using System.Linq;
6
using WixToolset.Data;
7
using WixToolset.Data.WindowsInstaller;
@@ -10,14 +9,9 @@ namespace WixToolset.Core.ExtensibilityServices
9
10
internal class WindowsInstallerBackendHelper : IWindowsInstallerBackendHelper
11
{
13
- public WindowsInstallerBackendHelper(IServiceProvider serviceProvider)
14
- {
15
- this.ServiceProvider = serviceProvider;
16
- }
12
+ public bool TryAddTupleToOutputMatchingTableDefinitions(IntermediateTuple tuple, Output output, TableDefinition[] tableDefinitions) => this.TryAddTupleToOutputMatchingTableDefinitions(tuple, output, tableDefinitions, false);
13
18
- private IServiceProvider ServiceProvider { get; }
19
-
20
- public bool TryAddTupleToOutputMatchingTableDefinitions(IntermediateTuple tuple, Output output, TableDefinition[] tableDefinitions)
14
+ public bool TryAddTupleToOutputMatchingTableDefinitions(IntermediateTuple tuple, Output output, TableDefinition[] tableDefinitions, bool columnZeroIsId)
15
{
16
var tableDefinition = tableDefinitions.FirstOrDefault(t => t.Name == tuple.Definition.Name);
17
@@ -28,6 +22,14 @@ namespace WixToolset.Core.ExtensibilityServices
22
23
var table = output.EnsureTable(tableDefinition);
24
var row = table.CreateRow(tuple.SourceLineNumbers);
25
+ var rowOffset = 0;
26
+
27
+ if (columnZeroIsId)
28
+ {
29
+ row[0] = tuple.Id.Id;
30
+ rowOffset = 1;
31
+ }
32
+
33
for (var i = 0; i < tuple.Fields.Length; ++i)
34
{
35
if (i < tableDefinition.Columns.Length)
@@ -36,13 +38,13 @@ namespace WixToolset.Core.ExtensibilityServices
38
39
switch (column.Type)
40
{
39
- case ColumnType.Number:
40
- row[i] = tuple.AsNumber(i);
41
- break;
41
+ case ColumnType.Number:
42
+ row[i + rowOffset] = column.Nullable ? tuple.AsNullableNumber(i) : tuple.AsNumber(i);
43
+ break;
44
43
- default:
44
- row[i] = tuple.AsString(i);
45
- break;
45
+ default:
46
+ row[i + rowOffset] = tuple.AsString(i);
47
+ break;
48
}
49
}
50
}
src/WixToolset.Core/Link/WixGroupingOrdering.cs
+15
-16
@@ -12,19 +12,19 @@ namespace WixToolset.Core.Link
12
using WixToolset.Data;
13
using WixToolset.Data.Tuples;
14
using WixToolset.Extensibility.Services;
15
+ using WixToolset.Data.Burn;
16
17
/// <summary>
18
/// Grouping and Ordering class of the WiX toolset.
19
/// </summary>
20
internal class WixGroupingOrdering
21
{
21
- private readonly IMessaging messageHandler;
22
+ private readonly IMessaging Messaging;
23
private List<string> groupTypes;
24
private List<string> itemTypes;
25
private ItemCollection items;
26
private readonly List<int> rowsUsed;
27
private bool loaded;
27
- private bool encounteredError;
28
29
/// <summary>
30
/// Creates a WixGroupingOrdering object.
@@ -36,11 +36,10 @@ namespace WixToolset.Core.Link
36
public WixGroupingOrdering(IntermediateSection entrySections, IMessaging messageHandler)
37
{
38
this.EntrySection = entrySections;
39
- this.messageHandler = messageHandler;
39
+ this.Messaging = messageHandler;
40
41
this.rowsUsed = new List<int>();
42
this.loaded = false;
43
- this.encounteredError = false;
43
}
44
45
private IntermediateSection EntrySection { get; }
@@ -71,7 +70,7 @@ namespace WixToolset.Core.Link
70
Debug.Assert(this.groupTypes.Contains(parentTypeString));
71
72
this.CreateOrderedList(parentTypeString, parentId, out var orderedItems);
74
- if (this.encounteredError)
73
+ if (this.Messaging.EncounteredError)
74
{
75
return;
76
}
@@ -95,7 +94,7 @@ namespace WixToolset.Core.Link
94
Debug.Assert(this.groupTypes.Contains(parentTypeString));
95
96
this.LoadFlattenOrderGroups();
98
- if (this.encounteredError)
97
+ if (this.Messaging.EncounteredError)
98
{
99
return;
100
}
@@ -127,14 +126,14 @@ namespace WixToolset.Core.Link
126
orderedItems = null;
127
128
this.LoadFlattenOrderGroups();
130
- if (this.encounteredError)
129
+ if (this.Messaging.EncounteredError)
130
{
131
return;
132
}
133
134
if (!this.items.TryGetValue(parentType, parentId, out var parentItem))
135
{
137
- this.messageHandler.Write(ErrorMessages.IdentifierNotFound(parentType, parentId));
136
+ this.Messaging.Write(ErrorMessages.IdentifierNotFound(parentType, parentId));
137
return;
138
}
139
@@ -216,7 +215,7 @@ namespace WixToolset.Core.Link
215
// dependencies. Group references, however, we can check directly.
216
this.FindCircularGroupReferences();
217
219
- if (!this.encounteredError)
218
+ if (!this.Messaging.EncounteredError)
219
{
220
this.FlattenGroups();
221
this.FlattenOrdering();
@@ -304,7 +303,7 @@ namespace WixToolset.Core.Link
303
if (this.FindCircularGroupReference(item, item, itemsSeen, out circularReference))
304
{
305
itemsInKnownLoops.Add(itemsSeen);
307
- this.messageHandler.Write(ErrorMessages.ReferenceLoopDetected(item.Row.SourceLineNumbers, circularReference));
306
+ this.Messaging.Write(ErrorMessages.ReferenceLoopDetected(item.Row.SourceLineNumbers, circularReference));
307
}
308
}
309
}
@@ -376,12 +375,12 @@ namespace WixToolset.Core.Link
375
376
if (!this.items.TryGetValue(rowItemType, rowItemName, out var item))
377
{
379
- this.messageHandler.Write(ErrorMessages.IdentifierNotFound(rowItemType, rowItemName));
378
+ this.Messaging.Write(ErrorMessages.IdentifierNotFound(rowItemType, rowItemName));
379
}
380
381
if (!this.items.TryGetValue(rowDependsOnType, rowDependsOnName, out var dependsOn))
382
{
384
- this.messageHandler.Write(ErrorMessages.IdentifierNotFound(rowDependsOnType, rowDependsOnName));
383
+ this.Messaging.Write(ErrorMessages.IdentifierNotFound(rowDependsOnType, rowDependsOnName));
384
}
385
386
if (null == item || null == dependsOn)
@@ -389,7 +388,7 @@ namespace WixToolset.Core.Link
388
continue;
389
}
390
392
- item.AddAfter(dependsOn, this.messageHandler);
391
+ item.AddAfter(dependsOn, this.Messaging);
392
}
393
}
394
@@ -404,12 +403,12 @@ namespace WixToolset.Core.Link
403
// ordering.
404
foreach (Item item in this.items)
405
{
407
- item.PropagateAfterToChildItems(this.messageHandler);
406
+ item.PropagateAfterToChildItems(this.Messaging);
407
}
408
409
foreach (Item item in this.items)
410
{
412
- item.FlattenAfters(this.messageHandler);
411
+ item.FlattenAfters(this.Messaging);
412
}
413
}
414
@@ -668,7 +667,7 @@ namespace WixToolset.Core.Link
667
{
668
if (String.Equals(nameof(ComplexReferenceChildType.Package), this.Type, StringComparison.Ordinal) ||
669
(String.Equals(nameof(ComplexReferenceParentType.Container), this.Type, StringComparison.Ordinal) &&
671
- !String.Equals(Compiler.BurnUXContainerId.Id, this.Id, StringComparison.Ordinal)))
670
+ !String.Equals(BurnConstants.BurnUXContainerName, this.Id, StringComparison.Ordinal)))
671
{
672
return false;
673
}
src/WixToolset.Core/WixToolsetServiceProvider.cs
+3
-1
@@ -24,7 +24,8 @@ namespace WixToolset.Core
24
this.AddService((provider, singletons) => AddSingleton<IParseHelper>(singletons, new ParseHelper(provider)));
25
this.AddService((provider, singletons) => AddSingleton<IPreprocessHelper>(singletons, new PreprocessHelper(provider)));
26
this.AddService((provider, singletons) => AddSingleton<IBackendHelper>(singletons, new BackendHelper(provider)));
27
- this.AddService((provider, singletons) => AddSingleton<IWindowsInstallerBackendHelper>(singletons, new WindowsInstallerBackendHelper(provider)));
27
+ this.AddService((provider, singletons) => AddSingleton<IPathResolver>(singletons, new PathResolver()));
28
+ this.AddService((provider, singletons) => AddSingleton<IWindowsInstallerBackendHelper>(singletons, new WindowsInstallerBackendHelper()));
29
30
// Transients.
31
this.AddService<ICommandLineArguments>((provider, singletons) => new CommandLineArguments(provider));
@@ -47,6 +48,7 @@ namespace WixToolset.Core
48
this.AddService<IDecompileResult>((provider, singletons) => new DecompileResult());
49
this.AddService<IIncludedFile>((provider, singletons) => new IncludedFile());
50
this.AddService<IPreprocessResult>((provider, singletons) => new PreprocessResult());
51
+ this.AddService<IResolvedDirectory>((provider, singletons) => new ResolvedDirectory());
52
this.AddService<IResolveFileResult>((provider, singletons) => new ResolveFileResult());
53
this.AddService<IResolveResult>((provider, singletons) => new ResolveResult());
54
this.AddService<IResolvedCabinet>((provider, singletons) => new ResolvedCabinet());
src/test/WixToolsetTest.CoreIntegration/BundleFixture.cs
new
+52
@@ -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
+
3
+namespace WixToolsetTest.CoreIntegration
4
+{
5
+ using System.IO;
6
+ using System.Linq;
7
+ using WixBuildTools.TestSupport;
8
+ using WixToolset.Core.TestPackage;
9
+ using WixToolset.Data;
10
+ using WixToolset.Data.Tuples;
11
+ using Xunit;
12
+
13
+ public class BundleFixture
14
+ {
15
+ [Fact]
16
+ public void CanBuildSimpleBundle()
17
+ {
18
+ var burnStubPath = TestData.Get(@"TestData\.Data\burn.exe");
19
+ var folder = TestData.Get(@"TestData\SimpleBundle");
20
+
21
+ using (var fs = new DisposableFileSystem())
22
+ {
23
+ var baseFolder = fs.GetFolder();
24
+ var intermediateFolder = Path.Combine(baseFolder, "obj");
25
+
26
+ var result = WixRunner.Execute(new[]
27
+ {
28
+ "build",
29
+ Path.Combine(folder, "Bundle.wxs"),
30
+ "-loc", Path.Combine(folder, "Bundle.en-us.wxl"),
31
+ "-bindpath", Path.Combine(folder, "data"),
32
+ "-intermediateFolder", intermediateFolder,
33
+ "-burnStub", burnStubPath,
34
+ "-o", Path.Combine(baseFolder, @"bin\test.exe")
35
+ });
36
+
37
+ result.AssertSuccess();
38
+
39
+ Assert.True(File.Exists(Path.Combine(baseFolder, @"bin\test.exe")));
40
+#if TODO
41
+ Assert.True(File.Exists(Path.Combine(baseFolder, @"bin\test.wixpdb")));
42
+#endif
43
+
44
+ var intermediate = Intermediate.Load(Path.Combine(intermediateFolder, @"test.wir"));
45
+ var section = intermediate.Sections.Single();
46
+
47
+ var msiTuple = section.Tuples.OfType<WixBundlePackageTuple>().Single();
48
+ Assert.Equal("test.msi", msiTuple.Id.Id );
49
+ }
50
+ }
51
+ }
52
+}
src/test/WixToolsetTest.CoreIntegration/TestData/.Data/burn.exe
Binary files /dev/null and b/src/test/WixToolsetTest.CoreIntegration/TestData/.Data/burn.exe differ
src/test/WixToolsetTest.CoreIntegration/TestData/SimpleBundle/Bundle.en-us.wxl
new
+10
@@ -0,0 +1,10 @@
1
+<?xml version="1.0" encoding="utf-8"?>
2
+
3
+<!--
4
+This file contains the declaration of all the localizable strings.
5
+-->
6
+<WixLocalization xmlns="http://wixtoolset.org/schemas/v4/wxl" Culture="en-US">
7
+
8
+ <String Id="BundleName">~TestBundle</String>
9
+
10
+</WixLocalization>
src/test/WixToolsetTest.CoreIntegration/TestData/SimpleBundle/Bundle.wxs
new
+11
@@ -0,0 +1,11 @@
1
+<?xml version="1.0" encoding="utf-8"?>
2
+<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">
3
+ <Bundle Name="!(loc.BundleName)" Version="1.0.0.0" Manufacturer="Example Corporation" UpgradeCode="047730a5-30fe-4a62-a520-da9381b8226a">
4
+ <BootstrapperApplication SourceFile="fakeba.dll" />
5
+ <Chain>
6
+ <MsiPackage SourceFile="test.msi">
7
+ <MsiProperty Name="TEST" Value="1" />
8
+ </MsiPackage>
9
+ </Chain>
10
+ </Bundle>
11
+</Wix>
src/test/WixToolsetTest.CoreIntegration/TestData/SimpleBundle/data/MsiPackage/Shared.dll
new
+1
@@ -0,0 +1 @@
1
+This is Shared.dll.
\ No newline at end of file
src/test/WixToolsetTest.CoreIntegration/TestData/SimpleBundle/data/MsiPackage/test.txt
new
+1
@@ -0,0 +1 @@
1
+This is test.txt
\ No newline at end of file
src/test/WixToolsetTest.CoreIntegration/TestData/SimpleBundle/data/fakeba.dll
new
+1
@@ -0,0 +1 @@
1
+This is a fakeba.dll
\ No newline at end of file
src/test/WixToolsetTest.CoreIntegration/TestData/SimpleBundle/data/test.msi
Binary files /dev/null and b/src/test/WixToolsetTest.CoreIntegration/TestData/SimpleBundle/data/test.msi differ
src/test/WixToolsetTest.CoreIntegration/WixToolsetTest.CoreIntegration.csproj
+7
@@ -13,6 +13,7 @@
13
</PropertyGroup>
14
15
<ItemGroup>
16
+ <Content Include="TestData\.Data\burn.exe" CopyToOutputDirectory="PreserveNewest" />
17
<Content Include="TestData\AppSearch\ComponentSearch.wxs" CopyToOutputDirectory="PreserveNewest" />
18
<Content Include="TestData\AppSearch\DirectorySearch.wxs" CopyToOutputDirectory="PreserveNewest" />
19
<Content Include="TestData\AppSearch\FileSearch.wxs" CopyToOutputDirectory="PreserveNewest" />
@@ -31,6 +32,9 @@
32
<Content Include="TestData\ReserveCost\ReserveCost.wxs" CopyToOutputDirectory="PreserveNewest" />
33
<Content Include="TestData\ServiceInstall\OwnProcess.wxs" CopyToOutputDirectory="PreserveNewest" />
34
<Content Include="TestData\Shortcut\ShortcutProperty.wxs" CopyToOutputDirectory="PreserveNewest" />
35
+ <Content Include="TestData\SimpleBundle\data\fakeba.dll" CopyToOutputDirectory="PreserveNewest" />
36
+ <Content Include="TestData\SimpleBundle\data\MsiPackage\Shared.dll" CopyToOutputDirectory="PreserveNewest" />
37
+ <Content Include="TestData\SimpleBundle\data\MsiPackage\test.txt" CopyToOutputDirectory="PreserveNewest" />
38
<Content Include="TestData\SimpleModule\data\test.txt" CopyToOutputDirectory="PreserveNewest" />
39
<Content Include="TestData\SimpleModule\Module.en-us.wxl" CopyToOutputDirectory="PreserveNewest" />
40
<Content Include="TestData\SimpleModule\Module.wxs" CopyToOutputDirectory="PreserveNewest" />
@@ -66,6 +70,9 @@
70
<Content Include="TestData\SetProperty\Package.en-us.wxl" CopyToOutputDirectory="PreserveNewest" />
71
<Content Include="TestData\SetProperty\Package.wxs" CopyToOutputDirectory="PreserveNewest" />
72
<Content Include="TestData\SetProperty\PackageComponents.wxs" CopyToOutputDirectory="PreserveNewest" />
73
+ <Content Include="TestData\SimpleBundle\data\test.msi" CopyToOutputDirectory="PreserveNewest" />
74
+ <Content Include="TestData\SimpleBundle\Bundle.en-us.wxl" CopyToOutputDirectory="PreserveNewest" />
75
+ <Content Include="TestData\SimpleBundle\Bundle.wxs" CopyToOutputDirectory="PreserveNewest" />
76
<Content Include="TestData\SingleFile\data\test.txt" CopyToOutputDirectory="PreserveNewest" />
77
<Content Include="TestData\SingleFile\Package.en-us.wxl" CopyToOutputDirectory="PreserveNewest" />
78
<Content Include="TestData\SingleFile\Package.wxs" CopyToOutputDirectory="PreserveNewest" />