Process Unreal custom tables in CreateBootstrapperApplicationManifestCommand
Sean Hall committed
May 16, 2020 at 16:38 UTC
4d96895a19c79ced1543d44e181527824c82c8e8
4 files changed
+113
src/WixToolset.Core.Burn/Bundles/CreateBootstrapperApplicationManifestCommand.cs
+47
@@ -16,6 +16,8 @@ namespace WixToolset.Core.Burn.Bundles
16
17
internal class CreateBootstrapperApplicationManifestCommand
18
{
19
+ private static readonly char[] ColonCharacter = new[] { ':' };
20
+
21
public CreateBootstrapperApplicationManifestCommand(IntermediateSection section, WixBundleTuple bundleTuple, IEnumerable<PackageFacade> chainPackages, int lastUXPayloadIndex, Dictionary<string, WixBundlePayloadTuple> payloadTuples, string intermediateFolder)
22
{
23
this.Section = section;
@@ -277,6 +279,51 @@ namespace WixToolset.Core.Burn.Bundles
279
writer.WriteEndElement();
280
}
281
}
282
+
283
+ var dataTablesById = this.Section.Tuples.OfType<WixCustomTableTuple>()
284
+ .Where(t => t.Unreal && t.Id != null)
285
+ .ToDictionary(t => t.Id.Id);
286
+ var dataRowsByTable = this.Section.Tuples.OfType<WixCustomRowTuple>()
287
+ .GroupBy(t => t.Table);
288
+ foreach (var tableDataRows in dataRowsByTable)
289
+ {
290
+ var tableName = tableDataRows.Key;
291
+ if (!dataTablesById.TryGetValue(tableName, out var tableTuple))
292
+ {
293
+ // This should have been a linker error.
294
+ continue;
295
+ }
296
+
297
+ var columnNames = tableTuple.ColumnNames.Split('\t');
298
+
299
+ // We simply assert that the table (and field) name is valid, because
300
+ // this is up to the extension developer to get right. An author will
301
+ // only affect the attribute value, and that will get properly escaped.
302
+#if DEBUG
303
+ Debug.Assert(Common.IsIdentifier(tableName));
304
+ foreach (var columnName in columnNames)
305
+ {
306
+ Debug.Assert(Common.IsIdentifier(columnName));
307
+ }
308
+#endif // DEBUG
309
+
310
+ foreach (var rowTuple in tableDataRows)
311
+ {
312
+ writer.WriteStartElement(tableName);
313
+
314
+ //var rowFields = rowTuple.FieldDataSeparated;
315
+ foreach (var field in rowTuple.FieldDataSeparated)
316
+ {
317
+ var splitField = field.Split(ColonCharacter, 2);
318
+ if (splitField.Length == 2)
319
+ {
320
+ writer.WriteAttributeString(splitField[0], splitField[1]);
321
+ }
322
+ }
323
+
324
+ writer.WriteEndElement();
325
+ }
326
+ }
327
}
328
329
private WixBundlePayloadTuple CreateBootstrapperApplicationManifestPayloadRow(string baManifestPath)
src/test/WixToolsetTest.CoreIntegration/BundleManifestFixture.cs
+39
@@ -12,6 +12,45 @@ namespace WixToolsetTest.CoreIntegration
12
13
public class BundleManifestFixture
14
{
15
+ [Fact]
16
+ public void PopulatesBAManifestWithUnrealCustomTable()
17
+ {
18
+ var folder = TestData.Get(@"TestData");
19
+
20
+ using (var fs = new DisposableFileSystem())
21
+ {
22
+ var baseFolder = fs.GetFolder();
23
+ var intermediateFolder = Path.Combine(baseFolder, "obj");
24
+ var bundlePath = Path.Combine(baseFolder, @"bin\test.exe");
25
+ var baFolderPath = Path.Combine(baseFolder, "ba");
26
+ var extractFolderPath = Path.Combine(baseFolder, "extract");
27
+
28
+ var result = WixRunner.Execute(new[]
29
+ {
30
+ "build",
31
+ Path.Combine(folder, "BundleCustomTable", "BundleCustomTable.wxs"),
32
+ Path.Combine(folder, "BundleWithPackageGroupRef", "MinimalPackageGroup.wxs"),
33
+ Path.Combine(folder, "BundleWithPackageGroupRef", "Bundle.wxs"),
34
+ "-bindpath", Path.Combine(folder, "SimpleBundle", "data"),
35
+ "-intermediateFolder", intermediateFolder,
36
+ "-o", bundlePath
37
+ });
38
+
39
+ result.AssertSuccess();
40
+
41
+ Assert.True(File.Exists(bundlePath));
42
+
43
+ var extractResult = BundleExtractor.ExtractBAContainer(null, bundlePath, baFolderPath, extractFolderPath);
44
+ extractResult.AssertSuccess();
45
+
46
+ var customElements = extractResult.SelectBADataNodes("/ba:BootstrapperApplicationData/ba:BundleCustomTable");
47
+ Assert.Equal(3, customElements.Count);
48
+ Assert.Equal("<BundleCustomTable Id='one' Column2='two' />", customElements[0].GetTestXml());
49
+ Assert.Equal("<BundleCustomTable Column2='<' Id='>' />", customElements[1].GetTestXml());
50
+ Assert.Equal("<BundleCustomTable Id='1' Column2='2' />", customElements[2].GetTestXml());
51
+ }
52
+ }
53
+
54
[Fact]
55
public void PopulatesManifestWithBundleExtension()
56
{
src/test/WixToolsetTest.CoreIntegration/TestData/BundleCustomTable/BundleCustomTable.wxs
new
+26
@@ -0,0 +1,26 @@
1
+<?xml version="1.0" encoding="utf-8"?>
2
+<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">
3
+ <Fragment>
4
+ <PackageGroup Id="BundlePackages">
5
+ <PackageGroupRef Id="MinimalPackageGroup" />
6
+ </PackageGroup>
7
+
8
+ <CustomTable Id="BundleCustomTable" Unreal="yes">
9
+ <Column Id="Id" Type="string" PrimaryKey="yes" />
10
+ <Column Id="Column2" Type="string" PrimaryKey="yes" />
11
+
12
+ <Row>
13
+ <Data Column="Id">one</Data>
14
+ <Data Column="Column2">two</Data>
15
+ </Row>
16
+ <Row>
17
+ <Data Column="Column2"><</Data>
18
+ <Data Column="Id">></Data>
19
+ </Row>
20
+ <Row>
21
+ <Data Column="Id">1</Data>
22
+ <Data Column="Column2">2</Data>
23
+ </Row>
24
+ </CustomTable>
25
+ </Fragment>
26
+</Wix>
src/test/WixToolsetTest.CoreIntegration/WixToolsetTest.CoreIntegration.csproj
+1
@@ -22,6 +22,7 @@
22
<Content Include="TestData\AppSearch\NestedDirSearchUnderRegSearch.msi" CopyToOutputDirectory="PreserveNewest" />
23
<Content Include="TestData\AppSearch\RegistrySearch.wxs" CopyToOutputDirectory="PreserveNewest" />
24
<Content Include="TestData\BadEnsureTable\BadEnsureTable.wxs" CopyToOutputDirectory="PreserveNewest" />
25
+ <Content Include="TestData\BundleCustomTable\BundleCustomTable.wxs" CopyToOutputDirectory="PreserveNewest" />
26
<Content Include="TestData\BundleExtension\BundleExtension.wxs" CopyToOutputDirectory="PreserveNewest" />
27
<Content Include="TestData\BundleExtension\BundleExtensionSearches.wxs" CopyToOutputDirectory="PreserveNewest" />
28
<Content Include="TestData\BundleExtension\BundleWithSearches.wxs" CopyToOutputDirectory="PreserveNewest" />