aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/WixToolset.Core.Burn/Bind/BindBundleCommand.cs7
-rw-r--r--src/WixToolset.Core.Burn/Bind/GenerateManifestDataFromIRCommand.cs4
-rw-r--r--src/WixToolset.Core.Burn/Bundles/CreateBurnManifestCommand.cs5
-rw-r--r--src/WixToolset.Core.Burn/Bundles/GetPackageFacadesCommand.cs111
-rw-r--r--src/WixToolset.Core/Compile/CompilerPayload.cs93
-rw-r--r--src/WixToolset.Core/Compiler_Bundle.cs268
-rw-r--r--src/WixToolset.Core/Linker.cs2
-rw-r--r--src/test/WixToolsetTest.CoreIntegration/PackagePayloadFixture.cs207
-rw-r--r--src/test/WixToolsetTest.CoreIntegration/TestData/PackagePayload/MissingSourceFileAndHash.wxs10
-rw-r--r--src/test/WixToolsetTest.CoreIntegration/TestData/PackagePayload/MissingSourceFileAndName.wxs10
-rw-r--r--src/test/WixToolsetTest.CoreIntegration/TestData/PackagePayload/PackagePayloadInPayloadGroup.wxs15
-rw-r--r--src/test/WixToolsetTest.CoreIntegration/TestData/PackagePayload/SpecifiedHash.wxs10
-rw-r--r--src/test/WixToolsetTest.CoreIntegration/TestData/PackagePayload/SpecifiedHashAndMissingDownloadUrl.wxs10
-rw-r--r--src/test/WixToolsetTest.CoreIntegration/TestData/PackagePayload/SpecifiedSourceFileAndHash.wxs10
-rw-r--r--src/test/WixToolsetTest.CoreIntegration/TestData/PackagePayload/WrongPackagePayloadInPayloadGroup.wxs15
-rw-r--r--src/test/WixToolsetTest.CoreIntegration/TestData/SingleExeBundle/SingleExeRemotePayload.wxs9
16 files changed, 670 insertions, 116 deletions
diff --git a/src/WixToolset.Core.Burn/Bind/BindBundleCommand.cs b/src/WixToolset.Core.Burn/Bind/BindBundleCommand.cs
index 724dd7ff..12a530ae 100644
--- a/src/WixToolset.Core.Burn/Bind/BindBundleCommand.cs
+++ b/src/WixToolset.Core.Burn/Bind/BindBundleCommand.cs
@@ -180,12 +180,17 @@ namespace WixToolset.Core.Burn
180 180
181 IDictionary<string, PackageFacade> facades; 181 IDictionary<string, PackageFacade> facades;
182 { 182 {
183 var command = new GetPackageFacadesCommand(chainPackageSymbols, section); 183 var command = new GetPackageFacadesCommand(this.Messaging, chainPackageSymbols, section);
184 command.Execute(); 184 command.Execute();
185 185
186 facades = command.PackageFacades; 186 facades = command.PackageFacades;
187 } 187 }
188 188
189 if (this.Messaging.EncounteredError)
190 {
191 return;
192 }
193
189 // Process each package facade. Note this is likely to add payloads and other symbols so 194 // Process each package facade. Note this is likely to add payloads and other symbols so
190 // note that any indexes created above may be out of date now. 195 // note that any indexes created above may be out of date now.
191 foreach (var facade in facades.Values) 196 foreach (var facade in facades.Values)
diff --git a/src/WixToolset.Core.Burn/Bind/GenerateManifestDataFromIRCommand.cs b/src/WixToolset.Core.Burn/Bind/GenerateManifestDataFromIRCommand.cs
index 36ced6cf..d4a69513 100644
--- a/src/WixToolset.Core.Burn/Bind/GenerateManifestDataFromIRCommand.cs
+++ b/src/WixToolset.Core.Burn/Bind/GenerateManifestDataFromIRCommand.cs
@@ -66,12 +66,16 @@ namespace WixToolset.Core.Burn.Bind
66 case SymbolDefinitionType.WixBundleContainer: 66 case SymbolDefinitionType.WixBundleContainer:
67 case SymbolDefinitionType.WixBundleCustomDataAttribute: 67 case SymbolDefinitionType.WixBundleCustomDataAttribute:
68 case SymbolDefinitionType.WixBundleExePackage: 68 case SymbolDefinitionType.WixBundleExePackage:
69 case SymbolDefinitionType.WixBundleExePackagePayload:
69 case SymbolDefinitionType.WixBundleExtension: 70 case SymbolDefinitionType.WixBundleExtension:
70 case SymbolDefinitionType.WixBundleMsiFeature: 71 case SymbolDefinitionType.WixBundleMsiFeature:
71 case SymbolDefinitionType.WixBundleMsiPackage: 72 case SymbolDefinitionType.WixBundleMsiPackage:
73 case SymbolDefinitionType.WixBundleMsiPackagePayload:
72 case SymbolDefinitionType.WixBundleMsiProperty: 74 case SymbolDefinitionType.WixBundleMsiProperty:
73 case SymbolDefinitionType.WixBundleMspPackage: 75 case SymbolDefinitionType.WixBundleMspPackage:
76 case SymbolDefinitionType.WixBundleMspPackagePayload:
74 case SymbolDefinitionType.WixBundleMsuPackage: 77 case SymbolDefinitionType.WixBundleMsuPackage:
78 case SymbolDefinitionType.WixBundleMsuPackagePayload:
75 case SymbolDefinitionType.WixBundlePackage: 79 case SymbolDefinitionType.WixBundlePackage:
76 case SymbolDefinitionType.WixBundlePackageCommandLine: 80 case SymbolDefinitionType.WixBundlePackageCommandLine:
77 case SymbolDefinitionType.WixBundlePackageExitCode: 81 case SymbolDefinitionType.WixBundlePackageExitCode:
diff --git a/src/WixToolset.Core.Burn/Bundles/CreateBurnManifestCommand.cs b/src/WixToolset.Core.Burn/Bundles/CreateBurnManifestCommand.cs
index 3bc6bf1b..1559a646 100644
--- a/src/WixToolset.Core.Burn/Bundles/CreateBurnManifestCommand.cs
+++ b/src/WixToolset.Core.Burn/Bundles/CreateBurnManifestCommand.cs
@@ -564,15 +564,16 @@ namespace WixToolset.Core.Burn.Bundles
564 } 564 }
565 565
566 // Write any contained Payloads with the PackagePayload being first 566 // Write any contained Payloads with the PackagePayload being first
567 var packagePayloadId = package.PackageSymbol.PayloadRef;
567 writer.WriteStartElement("PayloadRef"); 568 writer.WriteStartElement("PayloadRef");
568 writer.WriteAttributeString("Id", package.PackageSymbol.PayloadRef); 569 writer.WriteAttributeString("Id", packagePayloadId);
569 writer.WriteEndElement(); 570 writer.WriteEndElement();
570 571
571 var packagePayloads = payloadsByPackage[package.PackageId]; 572 var packagePayloads = payloadsByPackage[package.PackageId];
572 573
573 foreach (var payload in packagePayloads) 574 foreach (var payload in packagePayloads)
574 { 575 {
575 if (payload.Id.Id != package.PackageSymbol.PayloadRef) 576 if (payload.Id.Id != packagePayloadId)
576 { 577 {
577 writer.WriteStartElement("PayloadRef"); 578 writer.WriteStartElement("PayloadRef");
578 writer.WriteAttributeString("Id", payload.Id.Id); 579 writer.WriteAttributeString("Id", payload.Id.Id);
diff --git a/src/WixToolset.Core.Burn/Bundles/GetPackageFacadesCommand.cs b/src/WixToolset.Core.Burn/Bundles/GetPackageFacadesCommand.cs
index 24d1e8d8..dacff364 100644
--- a/src/WixToolset.Core.Burn/Bundles/GetPackageFacadesCommand.cs
+++ b/src/WixToolset.Core.Burn/Bundles/GetPackageFacadesCommand.cs
@@ -6,17 +6,21 @@ namespace WixToolset.Core.Burn.Bundles
6 using System.Linq; 6 using System.Linq;
7 using WixToolset.Data; 7 using WixToolset.Data;
8 using WixToolset.Data.Symbols; 8 using WixToolset.Data.Symbols;
9 using WixToolset.Extensibility.Services;
9 10
10 internal class GetPackageFacadesCommand 11 internal class GetPackageFacadesCommand
11 { 12 {
12 public GetPackageFacadesCommand(IEnumerable<WixBundlePackageSymbol> chainPackageSymbols, IntermediateSection section) 13 public GetPackageFacadesCommand(IMessaging messaging, IEnumerable<WixBundlePackageSymbol> chainPackageSymbols, IntermediateSection section)
13 { 14 {
15 this.Messaging = messaging;
14 this.ChainPackageSymbols = chainPackageSymbols; 16 this.ChainPackageSymbols = chainPackageSymbols;
15 this.Section = section; 17 this.Section = section;
16 } 18 }
17 19
18 private IEnumerable<WixBundlePackageSymbol> ChainPackageSymbols { get; } 20 private IEnumerable<WixBundlePackageSymbol> ChainPackageSymbols { get; }
19 21
22 private IMessaging Messaging { get; }
23
20 private IntermediateSection Section { get; } 24 private IntermediateSection Section { get; }
21 25
22 public IDictionary<string, PackageFacade> PackageFacades { get; private set; } 26 public IDictionary<string, PackageFacade> PackageFacades { get; private set; }
@@ -27,12 +31,101 @@ namespace WixToolset.Core.Burn.Bundles
27 var msiPackages = this.Section.Symbols.OfType<WixBundleMsiPackageSymbol>().ToDictionary(t => t.Id.Id); 31 var msiPackages = this.Section.Symbols.OfType<WixBundleMsiPackageSymbol>().ToDictionary(t => t.Id.Id);
28 var mspPackages = this.Section.Symbols.OfType<WixBundleMspPackageSymbol>().ToDictionary(t => t.Id.Id); 32 var mspPackages = this.Section.Symbols.OfType<WixBundleMspPackageSymbol>().ToDictionary(t => t.Id.Id);
29 var msuPackages = this.Section.Symbols.OfType<WixBundleMsuPackageSymbol>().ToDictionary(t => t.Id.Id); 33 var msuPackages = this.Section.Symbols.OfType<WixBundleMsuPackageSymbol>().ToDictionary(t => t.Id.Id);
34 var exePackagePayloads = this.Section.Symbols.OfType<WixBundleExePackagePayloadSymbol>().ToDictionary(t => t.Id.Id);
35 var msiPackagePayloads = this.Section.Symbols.OfType<WixBundleMsiPackagePayloadSymbol>().ToDictionary(t => t.Id.Id);
36 var mspPackagePayloads = this.Section.Symbols.OfType<WixBundleMspPackagePayloadSymbol>().ToDictionary(t => t.Id.Id);
37 var msuPackagePayloads = this.Section.Symbols.OfType<WixBundleMsuPackagePayloadSymbol>().ToDictionary(t => t.Id.Id);
30 38
31 var facades = new Dictionary<string, PackageFacade>(); 39 var facades = new Dictionary<string, PackageFacade>();
32 40
33 foreach (var package in this.ChainPackageSymbols) 41 foreach (var package in this.ChainPackageSymbols)
34 { 42 {
35 var id = package.Id.Id; 43 var id = package.Id.Id;
44
45 IntermediateSymbol packagePayload = null;
46 foreach (var wixGroup in this.Section.Symbols.OfType<WixGroupSymbol>().Where(g => g.ParentType == ComplexReferenceParentType.Package && g.ParentId == id))
47 {
48 if (wixGroup.ChildType == ComplexReferenceChildType.PackagePayload)
49 {
50 IntermediateSymbol tempPackagePayload = null;
51 if (exePackagePayloads.TryGetValue(wixGroup.ChildId, out var exePackagePayload))
52 {
53 if (package.Type == WixBundlePackageType.Exe)
54 {
55 tempPackagePayload = exePackagePayload;
56 }
57 else
58 {
59 this.Messaging.Write(ErrorMessages.PackagePayloadUnsupported(exePackagePayload.SourceLineNumbers, "Exe"));
60 this.Messaging.Write(ErrorMessages.PackagePayloadUnsupported2(package.SourceLineNumbers));
61 }
62 }
63 else if (msiPackagePayloads.TryGetValue(wixGroup.ChildId, out var msiPackagePayload))
64 {
65 if (package.Type == WixBundlePackageType.Msi)
66 {
67 tempPackagePayload = msiPackagePayload;
68 }
69 else
70 {
71 this.Messaging.Write(ErrorMessages.PackagePayloadUnsupported(msiPackagePayload.SourceLineNumbers, "Msi"));
72 this.Messaging.Write(ErrorMessages.PackagePayloadUnsupported2(package.SourceLineNumbers));
73 }
74 }
75 else if (mspPackagePayloads.TryGetValue(wixGroup.ChildId, out var mspPackagePayload))
76 {
77 if (package.Type == WixBundlePackageType.Msp)
78 {
79 tempPackagePayload = mspPackagePayload;
80 }
81 else
82 {
83 this.Messaging.Write(ErrorMessages.PackagePayloadUnsupported(mspPackagePayload.SourceLineNumbers, "Msp"));
84 this.Messaging.Write(ErrorMessages.PackagePayloadUnsupported2(package.SourceLineNumbers));
85 }
86 }
87 else if (msuPackagePayloads.TryGetValue(wixGroup.ChildId, out var msuPackagePayload))
88 {
89 if (package.Type == WixBundlePackageType.Msu)
90 {
91 tempPackagePayload = msuPackagePayload;
92 }
93 else
94 {
95 this.Messaging.Write(ErrorMessages.PackagePayloadUnsupported(msuPackagePayload.SourceLineNumbers, "Msu"));
96 this.Messaging.Write(ErrorMessages.PackagePayloadUnsupported2(package.SourceLineNumbers));
97 }
98 }
99 else
100 {
101 this.Messaging.Write(ErrorMessages.IdentifierNotFound(package.Type + "PackagePayload", wixGroup.ChildId));
102 }
103
104 if (tempPackagePayload != null)
105 {
106 if (packagePayload == null)
107 {
108 packagePayload = tempPackagePayload;
109 }
110 else
111 {
112 this.Messaging.Write(ErrorMessages.MultiplePackagePayloads(tempPackagePayload.SourceLineNumbers, id, packagePayload.Id.Id, tempPackagePayload.Id.Id));
113 this.Messaging.Write(ErrorMessages.MultiplePackagePayloads2(packagePayload.SourceLineNumbers));
114 this.Messaging.Write(ErrorMessages.MultiplePackagePayloads3(package.SourceLineNumbers));
115 }
116 }
117 }
118 }
119
120 if (packagePayload == null)
121 {
122 this.Messaging.Write(ErrorMessages.MissingPackagePayload(package.SourceLineNumbers, id, package.Type.ToString()));
123 }
124 else
125 {
126 package.PayloadRef = packagePayload.Id.Id;
127 }
128
36 switch (package.Type) 129 switch (package.Type)
37 { 130 {
38 case WixBundlePackageType.Exe: 131 case WixBundlePackageType.Exe:
@@ -40,6 +133,10 @@ namespace WixToolset.Core.Burn.Bundles
40 { 133 {
41 facades.Add(id, new PackageFacade(package, exePackage)); 134 facades.Add(id, new PackageFacade(package, exePackage));
42 } 135 }
136 else
137 {
138 this.Messaging.Write(ErrorMessages.IdentifierNotFound("WixBundleExePackage", id));
139 }
43 break; 140 break;
44 141
45 case WixBundlePackageType.Msi: 142 case WixBundlePackageType.Msi:
@@ -47,6 +144,10 @@ namespace WixToolset.Core.Burn.Bundles
47 { 144 {
48 facades.Add(id, new PackageFacade(package, msiPackage)); 145 facades.Add(id, new PackageFacade(package, msiPackage));
49 } 146 }
147 else
148 {
149 this.Messaging.Write(ErrorMessages.IdentifierNotFound("WixBundleMsiPackage", id));
150 }
50 break; 151 break;
51 152
52 case WixBundlePackageType.Msp: 153 case WixBundlePackageType.Msp:
@@ -54,6 +155,10 @@ namespace WixToolset.Core.Burn.Bundles
54 { 155 {
55 facades.Add(id, new PackageFacade(package, mspPackage)); 156 facades.Add(id, new PackageFacade(package, mspPackage));
56 } 157 }
158 else
159 {
160 this.Messaging.Write(ErrorMessages.IdentifierNotFound("WixBundleMspPackage", id));
161 }
57 break; 162 break;
58 163
59 case WixBundlePackageType.Msu: 164 case WixBundlePackageType.Msu:
@@ -61,6 +166,10 @@ namespace WixToolset.Core.Burn.Bundles
61 { 166 {
62 facades.Add(id, new PackageFacade(package, msuPackage)); 167 facades.Add(id, new PackageFacade(package, msuPackage));
63 } 168 }
169 else
170 {
171 this.Messaging.Write(ErrorMessages.IdentifierNotFound("WixBundleMsuPackage", id));
172 }
64 break; 173 break;
65 } 174 }
66 } 175 }
diff --git a/src/WixToolset.Core/Compile/CompilerPayload.cs b/src/WixToolset.Core/Compile/CompilerPayload.cs
index 4eda56f8..7a5fd1b2 100644
--- a/src/WixToolset.Core/Compile/CompilerPayload.cs
+++ b/src/WixToolset.Core/Compile/CompilerPayload.cs
@@ -23,6 +23,8 @@ namespace WixToolset.Core
23 23
24 public Identifier Id { get; set; } 24 public Identifier Id { get; set; }
25 25
26 public bool IsRemoteAllowed { get; set; }
27
26 public bool IsRequired { get; set; } = true; 28 public bool IsRequired { get; set; } = true;
27 29
28 public string Name { get; set; } 30 public string Name { get; set; }
@@ -48,26 +50,17 @@ namespace WixToolset.Core
48 50
49 private SourceLineNumber SourceLineNumbers { get; } 51 private SourceLineNumber SourceLineNumbers { get; }
50 52
51 private void CalculateAndVerifyFields(CompilerPayload remotePayload = null) 53 private void CalculateAndVerifyFields()
52 { 54 {
55 var isRemote = this.IsRemoteAllowed && !String.IsNullOrEmpty(this.Hash);
56
53 if (String.IsNullOrEmpty(this.SourceFile)) 57 if (String.IsNullOrEmpty(this.SourceFile))
54 { 58 {
55 if (String.IsNullOrEmpty(this.Name)) 59 if (!String.IsNullOrEmpty(this.Name) && !isRemote)
56 {
57 if (this.IsRequired)
58 {
59 this.Core.Write(ErrorMessages.ExpectedAttributesWithOtherAttribute(this.SourceLineNumbers, this.Element.Name.LocalName, "Name", "SourceFile"));
60 }
61 }
62 else if (remotePayload == null)
63 { 60 {
64 this.SourceFile = Path.Combine("SourceDir", this.Name); 61 this.SourceFile = Path.Combine("SourceDir", this.Name);
65 } 62 }
66 } 63 }
67 else if (remotePayload != null)
68 {
69 this.Core.Write(ErrorMessages.UnexpectedElementWithAttribute(this.SourceLineNumbers, this.Element.Name.LocalName, "RemotePayload", "SourceFile"));
70 }
71 else if (this.SourceFile.EndsWith(Path.DirectorySeparatorChar.ToString(), StringComparison.Ordinal)) 64 else if (this.SourceFile.EndsWith(Path.DirectorySeparatorChar.ToString(), StringComparison.Ordinal))
72 { 65 {
73 if (String.IsNullOrEmpty(this.Name)) 66 if (String.IsNullOrEmpty(this.Name))
@@ -80,24 +73,67 @@ namespace WixToolset.Core
80 } 73 }
81 } 74 }
82 75
83 if (remotePayload != null) 76 if (String.IsNullOrEmpty(this.SourceFile) && !isRemote)
84 { 77 {
85 if (this.DownloadUrl == null) 78 if (this.IsRequired)
86 { 79 {
87 this.Core.Write(ErrorMessages.ExpectedAttributeWithElement(this.SourceLineNumbers, this.Element.Name.LocalName, "DownloadUrl", "RemotePayload")); 80 if (!this.IsRemoteAllowed)
81 {
82 this.Core.Write(ErrorMessages.ExpectedAttributes(this.SourceLineNumbers, this.Element.Name.LocalName, "Name", "SourceFile"));
83 }
84 else
85 {
86 this.Core.Write(ErrorMessages.ExpectedAttributes(this.SourceLineNumbers, this.Element.Name.LocalName, "SourceFile", "Hash"));
87 }
88 } 88 }
89 }
90 else if (this.IsRemoteAllowed)
91 {
92 var isLocal = !String.IsNullOrEmpty(this.SourceFile);
89 93
90 if (YesNoDefaultType.No != this.Compressed) 94 if (isLocal)
95 {
96 if (isRemote)
97 {
98 this.Core.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(this.SourceLineNumbers, this.Element.Name.LocalName, "Hash", "SourceFile"));
99 }
100 }
101 else
91 { 102 {
103 if (String.IsNullOrEmpty(this.DownloadUrl))
104 {
105 this.Core.Write(ErrorMessages.ExpectedAttribute(this.SourceLineNumbers, this.Element.Name.LocalName, "DownloadUrl", "Hash"));
106 }
107
108 if (String.IsNullOrEmpty(this.Name))
109 {
110 this.Core.Write(ErrorMessages.ExpectedAttribute(this.SourceLineNumbers, this.Element.Name.LocalName, "Name", "Hash"));
111 }
112
113 if (YesNoDefaultType.Yes == this.Compressed)
114 {
115 this.Core.Write(WarningMessages.RemotePayloadsMustNotAlsoBeCompressed(this.SourceLineNumbers, this.Element.Name.LocalName));
116 }
117
92 this.Compressed = YesNoDefaultType.No; 118 this.Compressed = YesNoDefaultType.No;
93 this.Core.Write(WarningMessages.RemotePayloadsMustNotAlsoBeCompressed(this.SourceLineNumbers, this.Element.Name.LocalName));
94 } 119 }
95 120
96 this.Description = remotePayload.Description; 121 VerifyValidValue("Description", !String.IsNullOrEmpty(this.Description));
97 this.DisplayName = remotePayload.DisplayName; 122 VerifyValidValue("ProductName", !String.IsNullOrEmpty(this.ProductName));
98 this.Hash = remotePayload.Hash; 123 VerifyValidValue("Size", this.Size.HasValue);
99 this.Size = remotePayload.Size; 124 VerifyValidValue("Version", !String.IsNullOrEmpty(this.Version));
100 this.Version = remotePayload.Version; 125
126 void VerifyValidValue(string attributeName, bool isSpecified)
127 {
128 if (isLocal && isSpecified)
129 {
130 this.Core.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(this.SourceLineNumbers, this.Element.Name.LocalName, attributeName, "SourceFile"));
131 }
132 else if (!isLocal && !isSpecified)
133 {
134 this.Core.Write(ErrorMessages.ExpectedAttribute(this.SourceLineNumbers, this.Element.Name.LocalName, attributeName, "Hash"));
135 }
136 }
101 } 137 }
102 } 138 }
103 139
@@ -143,9 +179,9 @@ namespace WixToolset.Core
143 return symbol; 179 return symbol;
144 } 180 }
145 181
146 public void FinishCompilingPackage(CompilerPayload remotePayload) 182 public void FinishCompilingPackage()
147 { 183 {
148 this.CalculateAndVerifyFields(remotePayload); 184 this.CalculateAndVerifyFields();
149 this.GenerateIdFromFilename(); 185 this.GenerateIdFromFilename();
150 186
151 if (this.Id == null) 187 if (this.Id == null)
@@ -155,6 +191,13 @@ namespace WixToolset.Core
155 } 191 }
156 } 192 }
157 193
194 public void FinishCompilingPackagePayload()
195 {
196 this.CalculateAndVerifyFields();
197 this.GenerateIdFromFilename();
198 this.GenerateIdFromPrefix("ppy");
199 }
200
158 public void FinishCompilingPayload() 201 public void FinishCompilingPayload()
159 { 202 {
160 this.CalculateAndVerifyFields(); 203 this.CalculateAndVerifyFields();
diff --git a/src/WixToolset.Core/Compiler_Bundle.cs b/src/WixToolset.Core/Compiler_Bundle.cs
index 64fe2acc..60db75d6 100644
--- a/src/WixToolset.Core/Compiler_Bundle.cs
+++ b/src/WixToolset.Core/Compiler_Bundle.cs
@@ -1451,71 +1451,6 @@ namespace WixToolset.Core
1451 return compilerPayload.Id; 1451 return compilerPayload.Id;
1452 } 1452 }
1453 1453
1454 private CompilerPayload ParseRemotePayloadElement(XElement node)
1455 {
1456 var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node);
1457 var remotePayload = new CompilerPayload(this.Core, sourceLineNumbers, node);
1458
1459 foreach (var attrib in node.Attributes())
1460 {
1461 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace)
1462 {
1463 switch (attrib.Name.LocalName)
1464 {
1465 case "Description":
1466 remotePayload.ParseDescription(attrib);
1467 break;
1468 case "Hash":
1469 remotePayload.ParseHash(attrib);
1470 break;
1471 case "ProductName":
1472 remotePayload.ParseProductName(attrib);
1473 break;
1474 case "Size":
1475 remotePayload.ParseSize(attrib);
1476 break;
1477 case "Version":
1478 remotePayload.ParseVersion(attrib);
1479 break;
1480 default:
1481 this.Core.UnexpectedAttribute(node, attrib);
1482 break;
1483 }
1484 }
1485 else
1486 {
1487 this.Core.ParseExtensionAttribute(node, attrib);
1488 }
1489 }
1490
1491 if (String.IsNullOrEmpty(remotePayload.ProductName))
1492 {
1493 this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "ProductName"));
1494 }
1495
1496 if (String.IsNullOrEmpty(remotePayload.Description))
1497 {
1498 this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Description"));
1499 }
1500
1501 if (String.IsNullOrEmpty(remotePayload.Hash))
1502 {
1503 this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Hash"));
1504 }
1505
1506 if (0 == remotePayload.Size)
1507 {
1508 this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Size"));
1509 }
1510
1511 if (String.IsNullOrEmpty(remotePayload.Version))
1512 {
1513 this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Version"));
1514 }
1515
1516 return remotePayload;
1517 }
1518
1519 /// <summary> 1454 /// <summary>
1520 /// Parse PayloadGroup element. 1455 /// Parse PayloadGroup element.
1521 /// </summary> 1456 /// </summary>
@@ -1561,8 +1496,21 @@ namespace WixToolset.Core
1561 { 1496 {
1562 if (CompilerCore.WixNamespace == child.Name.Namespace) 1497 if (CompilerCore.WixNamespace == child.Name.Namespace)
1563 { 1498 {
1499 WixBundlePackageType? packageType = null;
1564 switch (child.Name.LocalName) 1500 switch (child.Name.LocalName)
1565 { 1501 {
1502 case "ExePackagePayload":
1503 packageType = WixBundlePackageType.Exe;
1504 break;
1505 case "MsiPackagePayload":
1506 packageType = WixBundlePackageType.Msi;
1507 break;
1508 case "MspPackagePayload":
1509 packageType = WixBundlePackageType.Msp;
1510 break;
1511 case "MsuPackagePayload":
1512 packageType = WixBundlePackageType.Msu;
1513 break;
1566 case "Payload": 1514 case "Payload":
1567 previousId = this.ParsePayloadElement(child, ComplexReferenceParentType.PayloadGroup, id, previousType, previousId); 1515 previousId = this.ParsePayloadElement(child, ComplexReferenceParentType.PayloadGroup, id, previousType, previousId);
1568 previousType = ComplexReferenceChildType.Payload; 1516 previousType = ComplexReferenceChildType.Payload;
@@ -1575,6 +1523,19 @@ namespace WixToolset.Core
1575 this.Core.UnexpectedElement(node, child); 1523 this.Core.UnexpectedElement(node, child);
1576 break; 1524 break;
1577 } 1525 }
1526
1527 if (packageType.HasValue)
1528 {
1529 var compilerPayload = this.ParsePackagePayloadElement(null, child, packageType.Value, null);
1530 var payloadSymbol = compilerPayload.CreatePayloadSymbol(ComplexReferenceParentType.PayloadGroup, id?.Id, previousType, previousId?.Id);
1531 if (payloadSymbol != null)
1532 {
1533 previousId = payloadSymbol.Id;
1534 previousType = ComplexReferenceChildType.Payload;
1535
1536 this.CreatePackagePayloadSymbol(payloadSymbol.SourceLineNumbers, packageType.Value, payloadSymbol.Id, ComplexReferenceParentType.PayloadGroup, id);
1537 }
1538 }
1578 } 1539 }
1579 else 1540 else
1580 { 1541 {
@@ -1984,7 +1945,7 @@ namespace WixToolset.Core
1984 Debug.Assert(ComplexReferenceParentType.PackageGroup == parentType); 1945 Debug.Assert(ComplexReferenceParentType.PackageGroup == parentType);
1985 Debug.Assert(ComplexReferenceChildType.Unknown == previousType || ComplexReferenceChildType.PackageGroup == previousType || ComplexReferenceChildType.Package == previousType); 1946 Debug.Assert(ComplexReferenceChildType.Unknown == previousType || ComplexReferenceChildType.PackageGroup == previousType || ComplexReferenceChildType.Package == previousType);
1986 1947
1987 var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node);; 1948 var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node);
1988 var compilerPayload = new CompilerPayload(this.Core, sourceLineNumbers, node) 1949 var compilerPayload = new CompilerPayload(this.Core, sourceLineNumbers, node)
1989 { 1950 {
1990 IsRequired = false, 1951 IsRequired = false,
@@ -2008,8 +1969,9 @@ namespace WixToolset.Core
2008 string msuKB = null; 1969 string msuKB = null;
2009 var enableFeatureSelection = YesNoType.NotSet; 1970 var enableFeatureSelection = YesNoType.NotSet;
2010 var forcePerMachine = YesNoType.NotSet; 1971 var forcePerMachine = YesNoType.NotSet;
2011 CompilerPayload remotePayload = null; 1972 CompilerPayload childPackageCompilerPayload = null;
2012 var slipstream = YesNoType.NotSet; 1973 var slipstream = YesNoType.NotSet;
1974 var hasPayloadInfo = false;
2013 1975
2014 var expectedNetFx4Args = new string[] { "/q", "/norestart", "/chainingpackage" }; 1976 var expectedNetFx4Args = new string[] { "/q", "/norestart", "/chainingpackage" };
2015 1977
@@ -2029,12 +1991,15 @@ namespace WixToolset.Core
2029 break; 1991 break;
2030 case "Name": 1992 case "Name":
2031 compilerPayload.ParseName(attrib); 1993 compilerPayload.ParseName(attrib);
1994 hasPayloadInfo = true;
2032 break; 1995 break;
2033 case "SourceFile": 1996 case "SourceFile":
2034 compilerPayload.ParseSourceFile(attrib); 1997 compilerPayload.ParseSourceFile(attrib);
1998 hasPayloadInfo = true;
2035 break; 1999 break;
2036 case "DownloadUrl": 2000 case "DownloadUrl":
2037 compilerPayload.ParseDownloadUrl(attrib); 2001 compilerPayload.ParseDownloadUrl(attrib);
2002 hasPayloadInfo = true;
2038 break; 2003 break;
2039 case "After": 2004 case "After":
2040 after = this.Core.GetAttributeValue(sourceLineNumbers, attrib); 2005 after = this.Core.GetAttributeValue(sourceLineNumbers, attrib);
@@ -2128,6 +2093,7 @@ namespace WixToolset.Core
2128 break; 2093 break;
2129 case "Compressed": 2094 case "Compressed":
2130 compilerPayload.ParseCompressed(attrib); 2095 compilerPayload.ParseCompressed(attrib);
2096 hasPayloadInfo = true;
2131 break; 2097 break;
2132 case "Slipstream": 2098 case "Slipstream":
2133 slipstream = this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); 2099 slipstream = this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib);
@@ -2150,26 +2116,30 @@ namespace WixToolset.Core
2150 } 2116 }
2151 } 2117 }
2152 2118
2153 // We need to handle RemotePayload up front because it effects value of sourceFile which is used in Id generation. Id is needed by other child elements. 2119 // We need to handle the package payload up front because it affects Id generation. Id is needed by other child elements.
2154 foreach (var child in node.Elements(CompilerCore.WixNamespace + "RemotePayload")) 2120 var packagePayloadElementName = packageType + "PackagePayload";
2121 foreach (var child in node.Elements(CompilerCore.WixNamespace + packagePayloadElementName))
2155 { 2122 {
2156 var childSourceLineNumbers = Preprocessor.GetSourceLineNumbers(child); 2123 var childSourceLineNumbers = Preprocessor.GetSourceLineNumbers(child);
2157 2124
2158 if (CompilerCore.WixNamespace == node.Name.Namespace && node.Name.LocalName != "ExePackage" && node.Name.LocalName != "MsuPackage") 2125 if (childPackageCompilerPayload != null)
2159 { 2126 {
2160 this.Core.Write(ErrorMessages.RemotePayloadUnsupported(childSourceLineNumbers)); 2127 this.Core.Write(ErrorMessages.TooManyChildren(childSourceLineNumbers, node.Name.LocalName, child.Name.LocalName));
2161 continue;
2162 } 2128 }
2163 2129 else if (hasPayloadInfo)
2164 if (null != remotePayload)
2165 { 2130 {
2166 this.Core.Write(ErrorMessages.TooManyChildren(childSourceLineNumbers, node.Name.LocalName, child.Name.LocalName)); 2131 this.Core.Write(ErrorMessages.UnexpectedElementWithAttribute(sourceLineNumbers, node.Name.LocalName, child.Name.LocalName, "SourceFile", "Name", "DownloadUrl", "Compressed"));
2167 } 2132 }
2168 2133
2169 remotePayload = this.ParseRemotePayloadElement(child); 2134 childPackageCompilerPayload = this.ParsePackagePayloadElement(childSourceLineNumbers, child, packageType, compilerPayload.Id);
2135 }
2136
2137 if (compilerPayload.Id == null && childPackageCompilerPayload != null)
2138 {
2139 compilerPayload.Id = childPackageCompilerPayload.Id;
2170 } 2140 }
2171 2141
2172 compilerPayload.FinishCompilingPackage(remotePayload); 2142 compilerPayload.FinishCompilingPackage();
2173 var id = compilerPayload.Id; 2143 var id = compilerPayload.Id;
2174 2144
2175 if (null == logPathVariable) 2145 if (null == logPathVariable)
@@ -2279,7 +2249,11 @@ namespace WixToolset.Core
2279 this.ParseCommandLineElement(child, id.Id); 2249 this.ParseCommandLineElement(child, id.Id);
2280 } 2250 }
2281 break; 2251 break;
2282 case "RemotePayload": 2252 case "ExePackagePayload":
2253 case "MsiPackagePayload":
2254 case "MspPackagePayload":
2255 case "MsuPackagePayload":
2256 allowed = packagePayloadElementName == child.Name.LocalName;
2283 // Handled previously 2257 // Handled previously
2284 break; 2258 break;
2285 default: 2259 default:
@@ -2301,8 +2275,13 @@ namespace WixToolset.Core
2301 2275
2302 if (!this.Core.EncounteredError) 2276 if (!this.Core.EncounteredError)
2303 { 2277 {
2304 // We create the package contents as a payload with this package as the parent 2278 var packageCompilerPayload = childPackageCompilerPayload ?? (hasPayloadInfo ? compilerPayload : null);
2305 compilerPayload.CreatePayloadSymbol(ComplexReferenceParentType.Package, id.Id); 2279 if (packageCompilerPayload != null)
2280 {
2281 var payload = packageCompilerPayload.CreatePayloadSymbol(ComplexReferenceParentType.Package, id.Id);
2282
2283 this.CreatePackagePayloadSymbol(sourceLineNumbers, packageType, payload.Id, ComplexReferenceParentType.Package, id);
2284 }
2306 2285
2307 this.Core.AddSymbol(new WixChainItemSymbol(sourceLineNumbers, id)); 2286 this.Core.AddSymbol(new WixChainItemSymbol(sourceLineNumbers, id));
2308 2287
@@ -2313,7 +2292,6 @@ namespace WixToolset.Core
2313 var chainPackageSymbol = this.Core.AddSymbol(new WixBundlePackageSymbol(sourceLineNumbers, id) 2292 var chainPackageSymbol = this.Core.AddSymbol(new WixBundlePackageSymbol(sourceLineNumbers, id)
2314 { 2293 {
2315 Type = packageType, 2294 Type = packageType,
2316 PayloadRef = id.Id,
2317 Attributes = attributes, 2295 Attributes = attributes,
2318 InstallCondition = installCondition, 2296 InstallCondition = installCondition,
2319 CacheId = cacheId, 2297 CacheId = cacheId,
@@ -2391,6 +2369,134 @@ namespace WixToolset.Core
2391 return id.Id; 2369 return id.Id;
2392 } 2370 }
2393 2371
2372 private void CreatePackagePayloadSymbol(SourceLineNumber sourceLineNumbers, WixBundlePackageType packageType, Identifier payloadId, ComplexReferenceParentType parentType, Identifier parentId)
2373 {
2374 switch (packageType)
2375 {
2376 case WixBundlePackageType.Exe:
2377 this.Core.AddSymbol(new WixBundleExePackagePayloadSymbol(sourceLineNumbers, payloadId));
2378 break;
2379
2380 case WixBundlePackageType.Msi:
2381 this.Core.AddSymbol(new WixBundleMsiPackagePayloadSymbol(sourceLineNumbers, payloadId));
2382 break;
2383
2384 case WixBundlePackageType.Msp:
2385 this.Core.AddSymbol(new WixBundleMspPackagePayloadSymbol(sourceLineNumbers, payloadId));
2386 break;
2387
2388 case WixBundlePackageType.Msu:
2389 this.Core.AddSymbol(new WixBundleMsuPackagePayloadSymbol(sourceLineNumbers, payloadId));
2390 break;
2391 }
2392
2393 this.Core.CreateGroupAndOrderingRows(sourceLineNumbers, parentType, parentId?.Id, ComplexReferenceChildType.PackagePayload, payloadId?.Id, ComplexReferenceChildType.Unknown, null);
2394 }
2395
2396 private CompilerPayload ParsePackagePayloadElement(SourceLineNumber sourceLineNumbers, XElement node, WixBundlePackageType packageType, Identifier defaultId)
2397 {
2398 sourceLineNumbers = sourceLineNumbers ?? Preprocessor.GetSourceLineNumbers(node);
2399 var compilerPayload = new CompilerPayload(this.Core, sourceLineNumbers, node)
2400 {
2401 Id = defaultId,
2402 IsRemoteAllowed = packageType == WixBundlePackageType.Exe || packageType == WixBundlePackageType.Msu,
2403 };
2404
2405 // This list lets us evaluate extension attributes *after* all core attributes
2406 // have been parsed and dealt with, regardless of authoring order.
2407 var extensionAttributes = new List<XAttribute>();
2408
2409 foreach (var attrib in node.Attributes())
2410 {
2411 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace)
2412 {
2413 var allowed = true;
2414 switch (attrib.Name.LocalName)
2415 {
2416 case "Id":
2417 compilerPayload.ParseId(attrib);
2418 break;
2419 case "Compressed":
2420 compilerPayload.ParseCompressed(attrib);
2421 break;
2422 case "Name":
2423 compilerPayload.ParseName(attrib);
2424 break;
2425 case "SourceFile":
2426 compilerPayload.ParseSourceFile(attrib);
2427 break;
2428 case "DownloadUrl":
2429 compilerPayload.ParseDownloadUrl(attrib);
2430 break;
2431 case "Description":
2432 allowed = compilerPayload.IsRemoteAllowed;
2433 if (allowed)
2434 {
2435 compilerPayload.ParseDescription(attrib);
2436 }
2437 break;
2438 case "Hash":
2439 allowed = compilerPayload.IsRemoteAllowed;
2440 if (allowed)
2441 {
2442 compilerPayload.ParseHash(attrib);
2443 }
2444 break;
2445 case "ProductName":
2446 allowed = compilerPayload.IsRemoteAllowed;
2447 if (allowed)
2448 {
2449 compilerPayload.ParseProductName(attrib);
2450 }
2451 break;
2452 case "Size":
2453 allowed = compilerPayload.IsRemoteAllowed;
2454 if (allowed)
2455 {
2456 compilerPayload.ParseSize(attrib);
2457 }
2458 break;
2459 case "Version":
2460 allowed = compilerPayload.IsRemoteAllowed;
2461 if (allowed)
2462 {
2463 compilerPayload.ParseVersion(attrib);
2464 }
2465 break;
2466 default:
2467 allowed = false;
2468 break;
2469 }
2470
2471 if (!allowed)
2472 {
2473 this.Core.UnexpectedAttribute(node, attrib);
2474 }
2475 }
2476 else
2477 {
2478 this.Core.ParseExtensionAttribute(node, attrib);
2479 }
2480 }
2481
2482 compilerPayload.FinishCompilingPackagePayload();
2483
2484 // Now that the PayloadId is known, we can parse the extension attributes.
2485 var context = new Dictionary<string, string>
2486 {
2487 ["Id"] = compilerPayload.Id.Id,
2488 };
2489
2490 foreach (var extensionAttribute in extensionAttributes)
2491 {
2492 this.Core.ParseExtensionAttribute(node, extensionAttribute, context);
2493 }
2494
2495 this.Core.ParseForExtensionElements(node);
2496
2497 return compilerPayload;
2498 }
2499
2394 /// <summary> 2500 /// <summary>
2395 /// Parse CommandLine element. 2501 /// Parse CommandLine element.
2396 /// </summary> 2502 /// </summary>
diff --git a/src/WixToolset.Core/Linker.cs b/src/WixToolset.Core/Linker.cs
index e0af89ba..41e0db7d 100644
--- a/src/WixToolset.Core/Linker.cs
+++ b/src/WixToolset.Core/Linker.cs
@@ -1242,7 +1242,7 @@ namespace WixToolset.Core
1242 var groups = new WixGroupingOrdering(entrySection, this.Messaging); 1242 var groups = new WixGroupingOrdering(entrySection, this.Messaging);
1243 1243
1244 // Create UX payloads and Package payloads 1244 // Create UX payloads and Package payloads
1245 groups.UseTypes(new[] { ComplexReferenceParentType.Container, ComplexReferenceParentType.Layout, ComplexReferenceParentType.PackageGroup, ComplexReferenceParentType.PayloadGroup, ComplexReferenceParentType.Package }, new[] { ComplexReferenceChildType.PackageGroup, ComplexReferenceChildType.Package, ComplexReferenceChildType.PayloadGroup, ComplexReferenceChildType.Payload }); 1245 groups.UseTypes(new[] { ComplexReferenceParentType.Container, ComplexReferenceParentType.Layout, ComplexReferenceParentType.PackageGroup, ComplexReferenceParentType.PayloadGroup, ComplexReferenceParentType.Package }, new[] { ComplexReferenceChildType.PackageGroup, ComplexReferenceChildType.Package, ComplexReferenceChildType.PackagePayload, ComplexReferenceChildType.PayloadGroup, ComplexReferenceChildType.Payload });
1246 groups.FlattenAndRewriteGroups(ComplexReferenceParentType.Package, false); 1246 groups.FlattenAndRewriteGroups(ComplexReferenceParentType.Package, false);
1247 groups.FlattenAndRewriteGroups(ComplexReferenceParentType.Container, false); 1247 groups.FlattenAndRewriteGroups(ComplexReferenceParentType.Container, false);
1248 groups.FlattenAndRewriteGroups(ComplexReferenceParentType.Layout, false); 1248 groups.FlattenAndRewriteGroups(ComplexReferenceParentType.Layout, false);
diff --git a/src/test/WixToolsetTest.CoreIntegration/PackagePayloadFixture.cs b/src/test/WixToolsetTest.CoreIntegration/PackagePayloadFixture.cs
new file mode 100644
index 00000000..77a21f61
--- /dev/null
+++ b/src/test/WixToolsetTest.CoreIntegration/PackagePayloadFixture.cs
@@ -0,0 +1,207 @@
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 WixToolsetTest.CoreIntegration
4{
5 using System.Collections.Generic;
6 using System.IO;
7 using System.Linq;
8 using WixBuildTools.TestSupport;
9 using WixToolset.Core.TestPackage;
10 using Xunit;
11
12 public class PackagePayloadFixture
13 {
14 [Fact]
15 public void CanSpecifyPackagePayloadInPayloadGroup()
16 {
17 var folder = TestData.Get(@"TestData");
18
19 using (var fs = new DisposableFileSystem())
20 {
21 var baseFolder = fs.GetFolder();
22 var intermediateFolder = Path.Combine(baseFolder, "obj");
23 var bundlePath = Path.Combine(baseFolder, @"bin\test.exe");
24 var baFolderPath = Path.Combine(baseFolder, "ba");
25 var extractFolderPath = Path.Combine(baseFolder, "extract");
26
27 var result = WixRunner.Execute(new[]
28 {
29 "build",
30 Path.Combine(folder, "PackagePayload", "PackagePayloadInPayloadGroup.wxs"),
31 Path.Combine(folder, "BundleWithPackageGroupRef", "Bundle.wxs"),
32 "-bindpath", Path.Combine(folder, "SimpleBundle", "data"),
33 "-bindpath", Path.Combine(folder, ".Data"),
34 "-intermediateFolder", intermediateFolder,
35 "-o", bundlePath,
36 });
37
38 result.AssertSuccess();
39
40 Assert.True(File.Exists(bundlePath));
41
42 var extractResult = BundleExtractor.ExtractBAContainer(null, bundlePath, baFolderPath, extractFolderPath);
43 extractResult.AssertSuccess();
44
45 var exePackageElements = extractResult.SelectManifestNodes("/burn:BurnManifest/burn:Chain/burn:ExePackage");
46 var ignoreAttributesByElementName = new Dictionary<string, List<string>>
47 {
48 { "ExePackage", new List<string> { "CacheId", "InstallSize", "Size" } },
49 };
50 Assert.Equal(1, exePackageElements.Count);
51 Assert.Equal("<ExePackage Id='PackagePayloadInPayloadGroup' Cache='yes' CacheId='*' InstallSize='*' Size='*' PerMachine='yes' Permanent='yes' Vital='yes' RollbackBoundaryForward='WixDefaultBoundary' RollbackBoundaryBackward='WixDefaultBoundary' LogPathVariable='WixBundleLog_PackagePayloadInPayloadGroup' RollbackLogPathVariable='WixBundleRollbackLog_PackagePayloadInPayloadGroup' DetectCondition='none' InstallArguments='' UninstallArguments='' RepairArguments='' Repairable='no'><PayloadRef Id='burn.exe' /></ExePackage>", exePackageElements[0].GetTestXml(ignoreAttributesByElementName));
52 }
53 }
54
55 [Fact]
56 public void ErrorWhenMissingSourceFileAndHash()
57 {
58 var folder = TestData.Get(@"TestData", "PackagePayload");
59
60 using (var fs = new DisposableFileSystem())
61 {
62 var baseFolder = fs.GetFolder();
63
64 var result = WixRunner.Execute(false, new[]
65 {
66 "build",
67 Path.Combine(folder, "MissingSourceFileAndHash.wxs"),
68 "-o", Path.Combine(baseFolder, "test.wixlib")
69 });
70
71 Assert.Equal(44, result.ExitCode);
72 WixAssert.CompareLineByLine(new[]
73 {
74 "The MsuPackagePayload element's SourceFile or Hash attribute was not found; one of these is required.",
75 }, result.Messages.Select(m => m.ToString()).ToArray());
76 }
77 }
78
79 [Fact]
80 public void ErrorWhenMissingSourceFileAndName()
81 {
82 var folder = TestData.Get(@"TestData", "PackagePayload");
83
84 using (var fs = new DisposableFileSystem())
85 {
86 var baseFolder = fs.GetFolder();
87
88 var result = WixRunner.Execute(false, new[]
89 {
90 "build",
91 Path.Combine(folder, "MissingSourceFileAndName.wxs"),
92 "-o", Path.Combine(baseFolder, "test.wixlib")
93 });
94
95 Assert.Equal(44, result.ExitCode);
96 WixAssert.CompareLineByLine(new[]
97 {
98 "The MsiPackagePayload element's Name or SourceFile attribute was not found; one of these is required.",
99 }, result.Messages.Select(m => m.ToString()).ToArray());
100 }
101 }
102
103 [Fact]
104 public void ErrorWhenSpecifiedHash()
105 {
106 var folder = TestData.Get(@"TestData", "PackagePayload");
107
108 using (var fs = new DisposableFileSystem())
109 {
110 var baseFolder = fs.GetFolder();
111
112 var result = WixRunner.Execute(new[]
113 {
114 "build",
115 Path.Combine(folder, "SpecifiedHash.wxs"),
116 "-o", Path.Combine(baseFolder, "test.wixlib")
117 });
118
119 Assert.Equal(4, result.ExitCode);
120 WixAssert.CompareLineByLine(new[]
121 {
122 "The MspPackagePayload element contains an unexpected attribute 'Hash'.",
123 }, result.Messages.Select(m => m.ToString()).ToArray());
124 }
125 }
126
127 [Fact]
128 public void ErrorWhenSpecifiedHashAndMissingDownloadUrl()
129 {
130 var folder = TestData.Get(@"TestData", "PackagePayload");
131
132 using (var fs = new DisposableFileSystem())
133 {
134 var baseFolder = fs.GetFolder();
135
136 var result = WixRunner.Execute(new[]
137 {
138 "build",
139 Path.Combine(folder, "SpecifiedHashAndMissingDownloadUrl.wxs"),
140 "-o", Path.Combine(baseFolder, "test.wixlib")
141 });
142
143 Assert.Equal(10, result.ExitCode);
144 WixAssert.CompareLineByLine(new[]
145 {
146 "The MsuPackagePayload/@DownloadUrl attribute was not found; it is required when attribute Hash is specified.",
147 }, result.Messages.Select(m => m.ToString()).ToArray());
148 }
149 }
150
151 [Fact]
152 public void ErrorWhenSpecifiedSourceFileAndHash()
153 {
154 var folder = TestData.Get(@"TestData", "PackagePayload");
155
156 using (var fs = new DisposableFileSystem())
157 {
158 var baseFolder = fs.GetFolder();
159
160 var result = WixRunner.Execute(new[]
161 {
162 "build",
163 Path.Combine(folder, "SpecifiedSourceFileAndHash.wxs"),
164 "-o", Path.Combine(baseFolder, "test.wixlib")
165 });
166
167 Assert.Equal(35, result.ExitCode);
168 WixAssert.CompareLineByLine(new[]
169 {
170 "The ExePackagePayload/@Hash attribute cannot be specified when attribute SourceFile is present.",
171 }, result.Messages.Select(m => m.ToString()).ToArray());
172 }
173 }
174
175 [Fact]
176 public void ErrorWhenWrongPackagePayloadInPayloadGroup()
177 {
178 var folder = TestData.Get(@"TestData");
179
180 using (var fs = new DisposableFileSystem())
181 {
182 var baseFolder = fs.GetFolder();
183 var intermediateFolder = Path.Combine(baseFolder, "obj");
184 var bundlePath = Path.Combine(baseFolder, @"bin\test.exe");
185
186 var result = WixRunner.Execute(new[]
187 {
188 "build",
189 Path.Combine(folder, "PackagePayload", "WrongPackagePayloadInPayloadGroup.wxs"),
190 Path.Combine(folder, "BundleWithPackageGroupRef", "Bundle.wxs"),
191 "-bindpath", Path.Combine(folder, "SimpleBundle", "data"),
192 "-bindpath", Path.Combine(folder, ".Data"),
193 "-intermediateFolder", intermediateFolder,
194 "-o", bundlePath,
195 });
196
197 Assert.Equal(407, result.ExitCode);
198 WixAssert.CompareLineByLine(new[]
199 {
200 "The ExePackagePayload element can only be used for ExePackages.",
201 "The location of the package related to previous error.",
202 "There is no payload defined for package 'WrongPackagePayloadInPayloadGroup'. This is specified on the MsiPackage element or a child MsiPackagePayload element.",
203 }, result.Messages.Select(m => m.ToString()).ToArray());
204 }
205 }
206 }
207}
diff --git a/src/test/WixToolsetTest.CoreIntegration/TestData/PackagePayload/MissingSourceFileAndHash.wxs b/src/test/WixToolsetTest.CoreIntegration/TestData/PackagePayload/MissingSourceFileAndHash.wxs
new file mode 100644
index 00000000..5e1b99ff
--- /dev/null
+++ b/src/test/WixToolsetTest.CoreIntegration/TestData/PackagePayload/MissingSourceFileAndHash.wxs
@@ -0,0 +1,10 @@
1<?xml version="1.0" encoding="utf-8"?>
2<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">
3 <Fragment>
4 <PackageGroup Id="BundlePackages">
5 <MsuPackage Id="MissingSourceFileAndHash" Permanent="yes" DetectCondition="none">
6 <MsuPackagePayload DownloadUrl="example.com" />
7 </MsuPackage>
8 </PackageGroup>
9 </Fragment>
10</Wix>
diff --git a/src/test/WixToolsetTest.CoreIntegration/TestData/PackagePayload/MissingSourceFileAndName.wxs b/src/test/WixToolsetTest.CoreIntegration/TestData/PackagePayload/MissingSourceFileAndName.wxs
new file mode 100644
index 00000000..f220d81a
--- /dev/null
+++ b/src/test/WixToolsetTest.CoreIntegration/TestData/PackagePayload/MissingSourceFileAndName.wxs
@@ -0,0 +1,10 @@
1<?xml version="1.0" encoding="utf-8"?>
2<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">
3 <Fragment>
4 <PackageGroup Id="BundlePackages">
5 <MsiPackage Id="MissingSourceFileAndName">
6 <MsiPackagePayload DownloadUrl="example.com" />
7 </MsiPackage>
8 </PackageGroup>
9 </Fragment>
10</Wix>
diff --git a/src/test/WixToolsetTest.CoreIntegration/TestData/PackagePayload/PackagePayloadInPayloadGroup.wxs b/src/test/WixToolsetTest.CoreIntegration/TestData/PackagePayload/PackagePayloadInPayloadGroup.wxs
new file mode 100644
index 00000000..149870a4
--- /dev/null
+++ b/src/test/WixToolsetTest.CoreIntegration/TestData/PackagePayload/PackagePayloadInPayloadGroup.wxs
@@ -0,0 +1,15 @@
1<?xml version="1.0" encoding="utf-8"?>
2<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">
3 <Fragment>
4 <PackageGroup Id="BundlePackages">
5 <ExePackage Id="PackagePayloadInPayloadGroup" Permanent="yes" DetectCondition="none">
6 <PayloadGroupRef Id="PackagePayloadGroup" />
7 </ExePackage>
8 </PackageGroup>
9 </Fragment>
10 <Fragment>
11 <PayloadGroup Id="PackagePayloadGroup">
12 <ExePackagePayload SourceFile="burn.exe" />
13 </PayloadGroup>
14 </Fragment>
15</Wix>
diff --git a/src/test/WixToolsetTest.CoreIntegration/TestData/PackagePayload/SpecifiedHash.wxs b/src/test/WixToolsetTest.CoreIntegration/TestData/PackagePayload/SpecifiedHash.wxs
new file mode 100644
index 00000000..3c361c49
--- /dev/null
+++ b/src/test/WixToolsetTest.CoreIntegration/TestData/PackagePayload/SpecifiedHash.wxs
@@ -0,0 +1,10 @@
1<?xml version="1.0" encoding="utf-8"?>
2<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">
3 <Fragment>
4 <PackageGroup Id="BundlePackages">
5 <MspPackage Id="SpecifiedHash">
6 <MspPackagePayload SourceFile="example.msp" DownloadUrl="example.com" Hash="abcd" />
7 </MspPackage>
8 </PackageGroup>
9 </Fragment>
10</Wix>
diff --git a/src/test/WixToolsetTest.CoreIntegration/TestData/PackagePayload/SpecifiedHashAndMissingDownloadUrl.wxs b/src/test/WixToolsetTest.CoreIntegration/TestData/PackagePayload/SpecifiedHashAndMissingDownloadUrl.wxs
new file mode 100644
index 00000000..8e62f660
--- /dev/null
+++ b/src/test/WixToolsetTest.CoreIntegration/TestData/PackagePayload/SpecifiedHashAndMissingDownloadUrl.wxs
@@ -0,0 +1,10 @@
1<?xml version="1.0" encoding="utf-8"?>
2<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">
3 <Fragment>
4 <PackageGroup Id="BundlePackages">
5 <MsuPackage Id="SpecifiedHashAndMissingDownloadUrl" Permanent="yes" DetectCondition="none">
6 <MsuPackagePayload Name="example.msu" Hash="abcd" Size="1" Version="1.0.0.0" ProductName="KB1234567" Description="fake msu" />
7 </MsuPackage>
8 </PackageGroup>
9 </Fragment>
10</Wix>
diff --git a/src/test/WixToolsetTest.CoreIntegration/TestData/PackagePayload/SpecifiedSourceFileAndHash.wxs b/src/test/WixToolsetTest.CoreIntegration/TestData/PackagePayload/SpecifiedSourceFileAndHash.wxs
new file mode 100644
index 00000000..f79da874
--- /dev/null
+++ b/src/test/WixToolsetTest.CoreIntegration/TestData/PackagePayload/SpecifiedSourceFileAndHash.wxs
@@ -0,0 +1,10 @@
1<?xml version="1.0" encoding="utf-8"?>
2<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">
3 <Fragment>
4 <PackageGroup Id="BundlePackages">
5 <ExePackage Id="SpecifiedSourceFileAndHash" Permanent="yes" DetectCondition="none">
6 <ExePackagePayload SourceFile="example.exe" Hash="abcd" />
7 </ExePackage>
8 </PackageGroup>
9 </Fragment>
10</Wix>
diff --git a/src/test/WixToolsetTest.CoreIntegration/TestData/PackagePayload/WrongPackagePayloadInPayloadGroup.wxs b/src/test/WixToolsetTest.CoreIntegration/TestData/PackagePayload/WrongPackagePayloadInPayloadGroup.wxs
new file mode 100644
index 00000000..dda306cf
--- /dev/null
+++ b/src/test/WixToolsetTest.CoreIntegration/TestData/PackagePayload/WrongPackagePayloadInPayloadGroup.wxs
@@ -0,0 +1,15 @@
1<?xml version="1.0" encoding="utf-8"?>
2<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">
3 <Fragment>
4 <PackageGroup Id="BundlePackages">
5 <MsiPackage Id="WrongPackagePayloadInPayloadGroup">
6 <PayloadGroupRef Id="WrongPackagePayloadGroup" />
7 </MsiPackage>
8 </PackageGroup>
9 </Fragment>
10 <Fragment>
11 <PayloadGroup Id="WrongPackagePayloadGroup">
12 <ExePackagePayload SourceFile="burn.exe" />
13 </PayloadGroup>
14 </Fragment>
15</Wix>
diff --git a/src/test/WixToolsetTest.CoreIntegration/TestData/SingleExeBundle/SingleExeRemotePayload.wxs b/src/test/WixToolsetTest.CoreIntegration/TestData/SingleExeBundle/SingleExeRemotePayload.wxs
index 79ba52d2..56f08ba9 100644
--- a/src/test/WixToolsetTest.CoreIntegration/TestData/SingleExeBundle/SingleExeRemotePayload.wxs
+++ b/src/test/WixToolsetTest.CoreIntegration/TestData/SingleExeBundle/SingleExeRemotePayload.wxs
@@ -13,11 +13,10 @@
13 Vital="yes" 13 Vital="yes"
14 Permanent="yes" 14 Permanent="yes"
15 Protocol="netfx4" 15 Protocol="netfx4"
16 DownloadUrl="C" 16 LogPathVariable="NetFx462FullLog">
17 LogPathVariable="NetFx462FullLog" 17 <ExePackagePayload
18 Compressed="no" 18 DownloadUrl="C"
19 Name="NDP462-KB3151802-Web.exe"> 19 Name="NDP462-KB3151802-Web.exe"
20 <RemotePayload
21 Description="Microsoft .NET Framework 4.6.2 Setup" 20 Description="Microsoft .NET Framework 4.6.2 Setup"
22 Hash="C42E6ED280290648BBD59F664008852F4CFE4548" 21 Hash="C42E6ED280290648BBD59F664008852F4CFE4548"
23 ProductName="Microsoft .NET Framework 4.6.2" 22 ProductName="Microsoft .NET Framework 4.6.2"