aboutsummaryrefslogtreecommitdiff
path: root/src/WixToolset.Core.Burn
diff options
context:
space:
mode:
Diffstat (limited to 'src/WixToolset.Core.Burn')
-rw-r--r--src/WixToolset.Core.Burn/Bind/BaseSearchFacade.cs27
-rw-r--r--src/WixToolset.Core.Burn/Bind/BindBundleCommand.cs41
-rw-r--r--src/WixToolset.Core.Burn/Bind/ExtensionSearchFacade.cs24
-rw-r--r--src/WixToolset.Core.Burn/Bind/LegacySearchFacade.cs (renamed from src/WixToolset.Core.Burn/Bind/SearchFacade.cs)74
-rw-r--r--src/WixToolset.Core.Burn/Bundles/BurnCommon.cs8
-rw-r--r--src/WixToolset.Core.Burn/Bundles/CreateBootstrapperApplicationManifestCommand.cs6
-rw-r--r--src/WixToolset.Core.Burn/Bundles/CreateBundleExtensionManifestCommand.cs149
-rw-r--r--src/WixToolset.Core.Burn/Bundles/CreateBurnManifestCommand.cs4
-rw-r--r--src/WixToolset.Core.Burn/Bundles/OrderSearchesCommand.cs71
-rw-r--r--src/WixToolset.Core.Burn/ISearchFacade.cs15
10 files changed, 344 insertions, 75 deletions
diff --git a/src/WixToolset.Core.Burn/Bind/BaseSearchFacade.cs b/src/WixToolset.Core.Burn/Bind/BaseSearchFacade.cs
new file mode 100644
index 00000000..d00c5778
--- /dev/null
+++ b/src/WixToolset.Core.Burn/Bind/BaseSearchFacade.cs
@@ -0,0 +1,27 @@
1// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2
3namespace WixToolset.Core.Burn
4{
5 using System;
6 using System.Xml;
7 using WixToolset.Data.Tuples;
8
9 internal abstract class BaseSearchFacade : ISearchFacade
10 {
11 protected WixSearchTuple SearchTuple { get; set; }
12
13 public virtual void WriteXml(XmlTextWriter writer)
14 {
15 writer.WriteAttributeString("Id", this.SearchTuple.Id.Id);
16 writer.WriteAttributeString("Variable", this.SearchTuple.Variable);
17 if (!String.IsNullOrEmpty(this.SearchTuple.Condition))
18 {
19 writer.WriteAttributeString("Condition", this.SearchTuple.Condition);
20 }
21 if (!String.IsNullOrEmpty(this.SearchTuple.BundleExtensionRef))
22 {
23 writer.WriteAttributeString("ExtensionId", this.SearchTuple.BundleExtensionRef);
24 }
25 }
26 }
27}
diff --git a/src/WixToolset.Core.Burn/Bind/BindBundleCommand.cs b/src/WixToolset.Core.Burn/Bind/BindBundleCommand.cs
index 9f98483f..2cb5ed64 100644
--- a/src/WixToolset.Core.Burn/Bind/BindBundleCommand.cs
+++ b/src/WixToolset.Core.Burn/Bind/BindBundleCommand.cs
@@ -117,10 +117,10 @@ namespace WixToolset.Core.Burn
117 // If there are any fields to resolve later, create the cache to populate during bind. 117 // If there are any fields to resolve later, create the cache to populate during bind.
118 var variableCache = this.DelayedFields.Any() ? new Dictionary<string, string>(StringComparer.InvariantCultureIgnoreCase) : null; 118 var variableCache = this.DelayedFields.Any() ? new Dictionary<string, string>(StringComparer.InvariantCultureIgnoreCase) : null;
119 119
120 // TODO: Although the WixSearch tables are defined in the Util extension, 120 var orderSearchesCommand = new OrderSearchesCommand(this.Messaging, section);
121 // the Bundle Binder has to know all about them. We hope to revisit all 121 orderSearchesCommand.Execute();
122 // of this in the 4.0 timeframe. 122 var orderedSearches = orderSearchesCommand.OrderedSearchFacades;
123 var orderedSearches = this.OrderSearches(section); 123 var extensionSearchTuplesById = orderSearchesCommand.ExtensionSearchTuplesByExtensionId;
124 124
125 // Extract files that come from binary .wixlibs and WixExtensions (this does not extract files from merge modules). 125 // Extract files that come from binary .wixlibs and WixExtensions (this does not extract files from merge modules).
126 { 126 {
@@ -387,6 +387,17 @@ namespace WixToolset.Core.Burn
387 387
388 var baManifestPayload = command.BootstrapperApplicationManifestPayloadRow; 388 var baManifestPayload = command.BootstrapperApplicationManifestPayloadRow;
389 payloadTuples.Add(baManifestPayload.Id.Id, baManifestPayload); 389 payloadTuples.Add(baManifestPayload.Id.Id, baManifestPayload);
390 ++uxPayloadIndex;
391 }
392
393 // Generate the bundle extension manifest...
394 {
395 var command = new CreateBundleExtensionManifestCommand(section, bundleTuple, extensionSearchTuplesById, uxPayloadIndex, this.IntermediateFolder);
396 command.Execute();
397
398 var bextManifestPayload = command.BundleExtensionManifestPayloadRow;
399 payloadTuples.Add(bextManifestPayload.Id.Id, bextManifestPayload);
400 ++uxPayloadIndex;
390 } 401 }
391 402
392#if TODO 403#if TODO
@@ -464,28 +475,6 @@ namespace WixToolset.Core.Burn
464 trackedFiles.Add(trackIntermediate); 475 trackedFiles.Add(trackIntermediate);
465 } 476 }
466 477
467 private IEnumerable<SearchFacade> OrderSearches(IntermediateSection section)
468 {
469 var searchesById = section.Tuples
470 .Where(t => t.Definition.Type == TupleDefinitionType.WixComponentSearch ||
471 t.Definition.Type == TupleDefinitionType.WixFileSearch ||
472 t.Definition.Type == TupleDefinitionType.WixProductSearch ||
473 t.Definition.Type == TupleDefinitionType.WixRegistrySearch)
474 .ToDictionary(t => t.Id.Id);
475
476 var orderedSearches = new List<SearchFacade>(searchesById.Keys.Count);
477
478 foreach (var searchTuple in section.Tuples.OfType<WixSearchTuple>())
479 {
480 if (searchesById.TryGetValue(searchTuple.Id.Id, out var specificSearchTuple))
481 {
482 orderedSearches.Add(new SearchFacade(searchTuple, specificSearchTuple));
483 }
484 }
485
486 return orderedSearches;
487 }
488
489 /// <summary> 478 /// <summary>
490 /// Populates the variable cache with specific package properties. 479 /// Populates the variable cache with specific package properties.
491 /// </summary> 480 /// </summary>
diff --git a/src/WixToolset.Core.Burn/Bind/ExtensionSearchFacade.cs b/src/WixToolset.Core.Burn/Bind/ExtensionSearchFacade.cs
new file mode 100644
index 00000000..6a830a28
--- /dev/null
+++ b/src/WixToolset.Core.Burn/Bind/ExtensionSearchFacade.cs
@@ -0,0 +1,24 @@
1// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2
3namespace WixToolset.Core.Burn
4{
5 using System.Xml;
6 using WixToolset.Data.Tuples;
7
8 internal class ExtensionSearchFacade : BaseSearchFacade
9 {
10 public ExtensionSearchFacade(WixSearchTuple searchTuple)
11 {
12 this.SearchTuple = searchTuple;
13 }
14
15 public override void WriteXml(XmlTextWriter writer)
16 {
17 writer.WriteStartElement("ExtensionSearch");
18
19 base.WriteXml(writer);
20
21 writer.WriteEndElement();
22 }
23 }
24}
diff --git a/src/WixToolset.Core.Burn/Bind/SearchFacade.cs b/src/WixToolset.Core.Burn/Bind/LegacySearchFacade.cs
index 65f3cb5b..0a80760d 100644
--- a/src/WixToolset.Core.Burn/Bind/SearchFacade.cs
+++ b/src/WixToolset.Core.Burn/Bind/LegacySearchFacade.cs
@@ -7,48 +7,36 @@ namespace WixToolset.Core.Burn
7 using WixToolset.Data; 7 using WixToolset.Data;
8 using WixToolset.Data.Tuples; 8 using WixToolset.Data.Tuples;
9 9
10 internal class SearchFacade 10 internal class LegacySearchFacade : BaseSearchFacade
11 { 11 {
12 public SearchFacade(WixSearchTuple searchTuple, IntermediateTuple searchSpecificTuple) 12 public LegacySearchFacade(WixSearchTuple searchTuple, IntermediateTuple searchSpecificTuple)
13 { 13 {
14 this.SearchTuple = searchTuple; 14 this.SearchTuple = searchTuple;
15 this.SearchSpecificTuple = searchSpecificTuple; 15 this.SearchSpecificTuple = searchSpecificTuple;
16 } 16 }
17 17
18 public WixSearchTuple SearchTuple { get; }
19
20 public IntermediateTuple SearchSpecificTuple { get; } 18 public IntermediateTuple SearchSpecificTuple { get; }
21 19
22 /// <summary> 20 /// <summary>
23 /// Generates Burn manifest and ParameterInfo-style markup a search. 21 /// Generates Burn manifest and ParameterInfo-style markup a search.
24 /// </summary> 22 /// </summary>
25 /// <param name="writer"></param> 23 /// <param name="writer"></param>
26 public void WriteXml(XmlTextWriter writer) 24 public override void WriteXml(XmlTextWriter writer)
27 { 25 {
28 switch (this.SearchSpecificTuple) 26 switch (this.SearchSpecificTuple)
29 { 27 {
30 case WixComponentSearchTuple tuple: 28 case WixComponentSearchTuple tuple:
31 this.WriteComponentSearchXml(writer, tuple); 29 this.WriteComponentSearchXml(writer, tuple);
32 break; 30 break;
33 case WixFileSearchTuple tuple: 31 case WixFileSearchTuple tuple:
34 this.WriteFileSearchXml(writer, tuple); 32 this.WriteFileSearchXml(writer, tuple);
35 break; 33 break;
36 case WixProductSearchTuple tuple: 34 case WixProductSearchTuple tuple:
37 this.WriteProductSearchXml(writer, tuple); 35 this.WriteProductSearchXml(writer, tuple);
38 break; 36 break;
39 case WixRegistrySearchTuple tuple: 37 case WixRegistrySearchTuple tuple:
40 this.WriteRegistrySearchXml(writer, tuple); 38 this.WriteRegistrySearchXml(writer, tuple);
41 break; 39 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 } 40 }
53 } 41 }
54 42
@@ -56,7 +44,7 @@ namespace WixToolset.Core.Burn
56 { 44 {
57 writer.WriteStartElement("MsiComponentSearch"); 45 writer.WriteStartElement("MsiComponentSearch");
58 46
59 this.WriteCommonAttributes(writer); 47 base.WriteXml(writer);
60 48
61 writer.WriteAttributeString("ComponentId", searchTuple.Guid); 49 writer.WriteAttributeString("ComponentId", searchTuple.Guid);
62 50
@@ -85,7 +73,7 @@ namespace WixToolset.Core.Burn
85 { 73 {
86 writer.WriteStartElement((0 == (searchTuple.Attributes & WixFileSearchAttributes.IsDirectory)) ? "FileSearch" : "DirectorySearch"); 74 writer.WriteStartElement((0 == (searchTuple.Attributes & WixFileSearchAttributes.IsDirectory)) ? "FileSearch" : "DirectorySearch");
87 75
88 this.WriteCommonAttributes(writer); 76 base.WriteXml(writer);
89 77
90 writer.WriteAttributeString("Path", searchTuple.Path); 78 writer.WriteAttributeString("Path", searchTuple.Path);
91 if (WixFileSearchAttributes.WantExists == (searchTuple.Attributes & WixFileSearchAttributes.WantExists)) 79 if (WixFileSearchAttributes.WantExists == (searchTuple.Attributes & WixFileSearchAttributes.WantExists))
@@ -108,7 +96,7 @@ namespace WixToolset.Core.Burn
108 { 96 {
109 writer.WriteStartElement("MsiProductSearch"); 97 writer.WriteStartElement("MsiProductSearch");
110 98
111 this.WriteCommonAttributes(writer); 99 base.WriteXml(writer);
112 100
113 if (0 != (tuple.Attributes & WixProductSearchAttributes.UpgradeCode)) 101 if (0 != (tuple.Attributes & WixProductSearchAttributes.UpgradeCode))
114 { 102 {
@@ -143,22 +131,22 @@ namespace WixToolset.Core.Burn
143 { 131 {
144 writer.WriteStartElement("RegistrySearch"); 132 writer.WriteStartElement("RegistrySearch");
145 133
146 this.WriteCommonAttributes(writer); 134 base.WriteXml(writer);
147 135
148 switch (tuple.Root) 136 switch (tuple.Root)
149 { 137 {
150 case RegistryRootType.ClassesRoot: 138 case RegistryRootType.ClassesRoot:
151 writer.WriteAttributeString("Root", "HKCR"); 139 writer.WriteAttributeString("Root", "HKCR");
152 break; 140 break;
153 case RegistryRootType.CurrentUser: 141 case RegistryRootType.CurrentUser:
154 writer.WriteAttributeString("Root", "HKCU"); 142 writer.WriteAttributeString("Root", "HKCU");
155 break; 143 break;
156 case RegistryRootType.LocalMachine: 144 case RegistryRootType.LocalMachine:
157 writer.WriteAttributeString("Root", "HKLM"); 145 writer.WriteAttributeString("Root", "HKLM");
158 break; 146 break;
159 case RegistryRootType.Users: 147 case RegistryRootType.Users:
160 writer.WriteAttributeString("Root", "HKU"); 148 writer.WriteAttributeString("Root", "HKU");
161 break; 149 break;
162 } 150 }
163 151
164 writer.WriteAttributeString("Key", tuple.Key); 152 writer.WriteAttributeString("Key", tuple.Key);
diff --git a/src/WixToolset.Core.Burn/Bundles/BurnCommon.cs b/src/WixToolset.Core.Burn/Bundles/BurnCommon.cs
index 78b95bf4..5cff0b5a 100644
--- a/src/WixToolset.Core.Burn/Bundles/BurnCommon.cs
+++ b/src/WixToolset.Core.Burn/Bundles/BurnCommon.cs
@@ -22,6 +22,12 @@ namespace WixToolset.Core.Burn.Bundles
22 public const string BurnUXContainerPayloadIdFormat = "p{0}"; 22 public const string BurnUXContainerPayloadIdFormat = "p{0}";
23 public const string BurnAttachedContainerEmbeddedIdFormat = "a{0}"; 23 public const string BurnAttachedContainerEmbeddedIdFormat = "a{0}";
24 24
25 public const string BADataFileName = "BootstrapperApplicationData.xml";
26 public const string BADataNamespace = "http://wixtoolset.org/schemas/v4/BootstrapperApplicationData";
27
28 public const string BundleExtensionDataFileName = "BundleExtensionData.xml";
29 public const string BundleExtensionDataNamespace = "http://wixtoolset.org/schemas/v4/BundleExtensionData";
30
25 // See WinNT.h for details about the PE format, including the 31 // See WinNT.h for details about the PE format, including the
26 // structure and offsets for IMAGE_DOS_HEADER, IMAGE_NT_HEADERS32, 32 // structure and offsets for IMAGE_DOS_HEADER, IMAGE_NT_HEADERS32,
27 // IMAGE_FILE_HEADER, etc. 33 // IMAGE_FILE_HEADER, etc.
@@ -167,7 +173,7 @@ namespace WixToolset.Core.Burn.Bundles
167 /// <returns>True if initialized.</returns> 173 /// <returns>True if initialized.</returns>
168 protected bool Initialize(BinaryReader reader) 174 protected bool Initialize(BinaryReader reader)
169 { 175 {
170 if (!GetWixburnSectionInfo(reader)) 176 if (!this.GetWixburnSectionInfo(reader))
171 { 177 {
172 return false; 178 return false;
173 } 179 }
diff --git a/src/WixToolset.Core.Burn/Bundles/CreateBootstrapperApplicationManifestCommand.cs b/src/WixToolset.Core.Burn/Bundles/CreateBootstrapperApplicationManifestCommand.cs
index 5cd1f7e8..be8227f2 100644
--- a/src/WixToolset.Core.Burn/Bundles/CreateBootstrapperApplicationManifestCommand.cs
+++ b/src/WixToolset.Core.Burn/Bundles/CreateBootstrapperApplicationManifestCommand.cs
@@ -57,7 +57,7 @@ namespace WixToolset.Core.Burn.Bundles
57 { 57 {
58 writer.Formatting = Formatting.Indented; 58 writer.Formatting = Formatting.Indented;
59 writer.WriteStartDocument(); 59 writer.WriteStartDocument();
60 writer.WriteStartElement("BootstrapperApplicationData", "http://wixtoolset.org/schemas/v4/BootstrapperApplicationData"); 60 writer.WriteStartElement("BootstrapperApplicationData", BurnCommon.BADataNamespace);
61 61
62 this.WriteBundleInfo(writer); 62 this.WriteBundleInfo(writer);
63 63
@@ -247,11 +247,11 @@ namespace WixToolset.Core.Burn.Bundles
247 247
248 private WixBundlePayloadTuple CreateBootstrapperApplicationManifestPayloadRow(string baManifestPath) 248 private WixBundlePayloadTuple CreateBootstrapperApplicationManifestPayloadRow(string baManifestPath)
249 { 249 {
250 var generatedId = Common.GenerateIdentifier("ux", "BootstrapperApplicationData.xml"); 250 var generatedId = Common.GenerateIdentifier("ux", BurnCommon.BADataFileName);
251 251
252 var tuple = new WixBundlePayloadTuple(this.BundleTuple.SourceLineNumbers, new Identifier(AccessModifier.Private, generatedId)) 252 var tuple = new WixBundlePayloadTuple(this.BundleTuple.SourceLineNumbers, new Identifier(AccessModifier.Private, generatedId))
253 { 253 {
254 Name = "BootstrapperApplicationData.xml", 254 Name = BurnCommon.BADataFileName,
255 SourceFile = new IntermediateFieldPathValue { Path = baManifestPath }, 255 SourceFile = new IntermediateFieldPathValue { Path = baManifestPath },
256 Compressed = true, 256 Compressed = true,
257 UnresolvedSourceFile = baManifestPath, 257 UnresolvedSourceFile = baManifestPath,
diff --git a/src/WixToolset.Core.Burn/Bundles/CreateBundleExtensionManifestCommand.cs b/src/WixToolset.Core.Burn/Bundles/CreateBundleExtensionManifestCommand.cs
new file mode 100644
index 00000000..b608c03d
--- /dev/null
+++ b/src/WixToolset.Core.Burn/Bundles/CreateBundleExtensionManifestCommand.cs
@@ -0,0 +1,149 @@
1// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2
3namespace WixToolset.Core.Burn.Bundles
4{
5 using System;
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
17 internal class CreateBundleExtensionManifestCommand
18 {
19 public CreateBundleExtensionManifestCommand(IntermediateSection section, WixBundleTuple bundleTuple, IDictionary<string, IList<IntermediateTuple>> extensionSearchTuplesByExtensionId, int lastUXPayloadIndex, string intermediateFolder)
20 {
21 this.Section = section;
22 this.BundleTuple = bundleTuple;
23 this.ExtensionSearchTuplesByExtensionId = extensionSearchTuplesByExtensionId;
24 this.LastUXPayloadIndex = lastUXPayloadIndex;
25 this.IntermediateFolder = intermediateFolder;
26 }
27
28 private IntermediateSection Section { get; }
29
30 private WixBundleTuple BundleTuple { get; }
31
32 private IDictionary<string, IList<IntermediateTuple>> ExtensionSearchTuplesByExtensionId { get; }
33
34 private int LastUXPayloadIndex { get; }
35
36 private string IntermediateFolder { get; }
37
38 public WixBundlePayloadTuple BundleExtensionManifestPayloadRow { get; private set; }
39
40 public void Execute()
41 {
42 var bextManifestPath = this.CreateBundleExtensionManifest();
43
44 this.BundleExtensionManifestPayloadRow = this.CreateBundleExtensionManifestPayloadRow(bextManifestPath);
45 }
46
47 private string CreateBundleExtensionManifest()
48 {
49 var path = Path.Combine(this.IntermediateFolder, "wix-bextdata.xml");
50
51 Directory.CreateDirectory(Path.GetDirectoryName(path));
52
53 using (var writer = new XmlTextWriter(path, Encoding.Unicode))
54 {
55 writer.Formatting = Formatting.Indented;
56 writer.WriteStartDocument();
57 writer.WriteStartElement("BundleExtensionData", BurnCommon.BundleExtensionDataNamespace);
58
59 foreach (var kvp in this.ExtensionSearchTuplesByExtensionId)
60 {
61 this.WriteExtension(writer, kvp.Key, kvp.Value);
62 }
63
64 writer.WriteEndElement();
65 writer.WriteEndDocument();
66 }
67
68 return path;
69 }
70
71 private void WriteExtension(XmlTextWriter writer, string extensionId, IEnumerable<IntermediateTuple> tuples)
72 {
73 writer.WriteStartElement("BundleExtension");
74
75 writer.WriteAttributeString("Id", extensionId);
76
77 this.WriteBundleExtensionDataTuples(writer, tuples);
78
79 writer.WriteEndElement();
80 }
81
82 private void WriteBundleExtensionDataTuples(XmlTextWriter writer, IEnumerable<IntermediateTuple> tuples)
83 {
84 var dataTuplesGroupedByDefinitionName = tuples.GroupBy(t => t.Definition);
85
86 foreach (var group in dataTuplesGroupedByDefinitionName)
87 {
88 var definition = group.Key;
89
90 // We simply assert that the table (and field) name is valid, because
91 // this is up to the extension developer to get right. An author will
92 // only affect the attribute value, and that will get properly escaped.
93#if DEBUG
94 Debug.Assert(Common.IsIdentifier(definition.Name));
95 foreach (var fieldDef in definition.FieldDefinitions)
96 {
97 Debug.Assert(Common.IsIdentifier(fieldDef.Name));
98 }
99#endif // DEBUG
100
101 foreach (var tuple in group)
102 {
103 writer.WriteStartElement(definition.Name);
104
105 if (tuple.Id != null)
106 {
107 writer.WriteAttributeString("Id", tuple.Id.Id);
108 }
109
110 foreach (var field in tuple.Fields)
111 {
112 if (!field.IsNull())
113 {
114 writer.WriteAttributeString(field.Definition.Name, field.AsString());
115 }
116 }
117
118 writer.WriteEndElement();
119 }
120 }
121 }
122
123 private WixBundlePayloadTuple CreateBundleExtensionManifestPayloadRow(string bextManifestPath)
124 {
125 var generatedId = Common.GenerateIdentifier("ux", BurnCommon.BundleExtensionDataFileName);
126
127 var tuple = new WixBundlePayloadTuple(this.BundleTuple.SourceLineNumbers, new Identifier(AccessModifier.Private, generatedId))
128 {
129 Name = BurnCommon.BundleExtensionDataFileName,
130 SourceFile = new IntermediateFieldPathValue { Path = bextManifestPath },
131 Compressed = true,
132 UnresolvedSourceFile = bextManifestPath,
133 ContainerRef = BurnConstants.BurnUXContainerName,
134 EmbeddedId = String.Format(CultureInfo.InvariantCulture, BurnCommon.BurnUXContainerEmbeddedIdFormat, this.LastUXPayloadIndex),
135 Packaging = PackagingType.Embedded,
136 };
137
138 var fileInfo = new FileInfo(bextManifestPath);
139
140 tuple.FileSize = (int)fileInfo.Length;
141
142 tuple.Hash = BundleHashAlgorithm.Hash(fileInfo);
143
144 this.Section.Tuples.Add(tuple);
145
146 return tuple;
147 }
148 }
149}
diff --git a/src/WixToolset.Core.Burn/Bundles/CreateBurnManifestCommand.cs b/src/WixToolset.Core.Burn/Bundles/CreateBurnManifestCommand.cs
index 64a01794..58133d38 100644
--- a/src/WixToolset.Core.Burn/Bundles/CreateBurnManifestCommand.cs
+++ b/src/WixToolset.Core.Burn/Bundles/CreateBurnManifestCommand.cs
@@ -18,7 +18,7 @@ namespace WixToolset.Core.Burn.Bundles
18 18
19 internal class CreateBurnManifestCommand 19 internal class CreateBurnManifestCommand
20 { 20 {
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) 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<ISearchFacade> orderedSearches, IEnumerable<WixBundleCatalogTuple> catalogs, string intermediateFolder)
22 { 22 {
23 this.Messaging = messaging; 23 this.Messaging = messaging;
24 this.BackendExtensions = backendExtensions; 24 this.BackendExtensions = backendExtensions;
@@ -54,7 +54,7 @@ namespace WixToolset.Core.Burn.Bundles
54 54
55 private IEnumerable<PackageFacade> OrderedPackages { get; } 55 private IEnumerable<PackageFacade> OrderedPackages { get; }
56 56
57 private IEnumerable<SearchFacade> OrderedSearches { get; } 57 private IEnumerable<ISearchFacade> OrderedSearches { get; }
58 58
59 private Dictionary<string, WixBundlePayloadTuple> Payloads { get; } 59 private Dictionary<string, WixBundlePayloadTuple> Payloads { get; }
60 60
diff --git a/src/WixToolset.Core.Burn/Bundles/OrderSearchesCommand.cs b/src/WixToolset.Core.Burn/Bundles/OrderSearchesCommand.cs
new file mode 100644
index 00000000..55b31ed3
--- /dev/null
+++ b/src/WixToolset.Core.Burn/Bundles/OrderSearchesCommand.cs
@@ -0,0 +1,71 @@
1// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2
3namespace WixToolset.Core.Burn.Bundles
4{
5 using System.Collections.Generic;
6 using System.Linq;
7 using WixToolset.Data;
8 using WixToolset.Data.Burn;
9 using WixToolset.Data.Tuples;
10 using WixToolset.Extensibility.Services;
11
12 internal class OrderSearchesCommand
13 {
14 public OrderSearchesCommand(IMessaging messaging, IntermediateSection section)
15 {
16 this.Messaging = messaging;
17 this.Section = section;
18 }
19
20 private IMessaging Messaging { get; }
21
22 private IntermediateSection Section { get; }
23
24 public IDictionary<string, IList<IntermediateTuple>> ExtensionSearchTuplesByExtensionId { get; private set; }
25
26 public IList<ISearchFacade> OrderedSearchFacades { get; private set; }
27
28 public void Execute()
29 {
30 // TODO: Although the WixSearch tables are defined in the Util extension,
31 // the Bundle Binder has to know all about them. We hope to revisit all
32 // of this in the 4.0 timeframe.
33 var legacySearchesById = this.Section.Tuples
34 .Where(t => t.Definition.Type == TupleDefinitionType.WixComponentSearch ||
35 t.Definition.Type == TupleDefinitionType.WixFileSearch ||
36 t.Definition.Type == TupleDefinitionType.WixProductSearch ||
37 t.Definition.Type == TupleDefinitionType.WixRegistrySearch)
38 .ToDictionary(t => t.Id.Id);
39 var extensionSearchesById = this.Section.Tuples
40 .Where(t => t.Definition.HasTag(BurnConstants.BundleExtensionSearchTupleDefinitionTag))
41 .ToDictionary(t => t.Id.Id);
42 var searchTuples = this.Section.Tuples.OfType<WixSearchTuple>().ToList();
43
44 this.ExtensionSearchTuplesByExtensionId = new Dictionary<string, IList<IntermediateTuple>>();
45 this.OrderedSearchFacades = new List<ISearchFacade>(legacySearchesById.Keys.Count + extensionSearchesById.Keys.Count);
46
47 foreach (var searchTuple in searchTuples)
48 {
49 if (legacySearchesById.TryGetValue(searchTuple.Id.Id, out var specificSearchTuple))
50 {
51 this.OrderedSearchFacades.Add(new LegacySearchFacade(searchTuple, specificSearchTuple));
52 }
53 else if (extensionSearchesById.TryGetValue(searchTuple.Id.Id, out var extensionSearchTuple))
54 {
55 this.OrderedSearchFacades.Add(new ExtensionSearchFacade(searchTuple));
56
57 if (!this.ExtensionSearchTuplesByExtensionId.TryGetValue(searchTuple.BundleExtensionRef, out var extensionSearchTuples))
58 {
59 extensionSearchTuples = new List<IntermediateTuple>();
60 this.ExtensionSearchTuplesByExtensionId[searchTuple.BundleExtensionRef] = extensionSearchTuples;
61 }
62 extensionSearchTuples.Add(extensionSearchTuple);
63 }
64 else
65 {
66 this.Messaging.Write(ErrorMessages.MissingBundleSearch(searchTuple.SourceLineNumbers, searchTuple.Id.Id));
67 }
68 }
69 }
70 }
71}
diff --git a/src/WixToolset.Core.Burn/ISearchFacade.cs b/src/WixToolset.Core.Burn/ISearchFacade.cs
new file mode 100644
index 00000000..b9ad8649
--- /dev/null
+++ b/src/WixToolset.Core.Burn/ISearchFacade.cs
@@ -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
3namespace WixToolset.Core.Burn
4{
5 using System.Xml;
6
7 internal interface ISearchFacade
8 {
9 /// <summary>
10 /// Writes the search to the Burn manifest.
11 /// </summary>
12 /// <param name="writer"></param>
13 void WriteXml(XmlTextWriter writer);
14 }
15}