From faa9777b7720a935b28c33c3fa1088cd7bcc2f86 Mon Sep 17 00:00:00 2001 From: Sean Hall Date: Wed, 13 Apr 2022 12:16:37 -0500 Subject: Add support for remote BundlePackagePayload. --- .../Services/IParseHelper.cs | 3 +- .../Bundles/ProcessBundlePackageCommand.cs | 2 +- .../Bundles/ProcessMsiPackageCommand.cs | 2 +- .../Bundles/ProcessMspPackageCommand.cs | 2 +- src/wix/WixToolset.Core/CompilerCore.cs | 5 +- src/wix/WixToolset.Core/Compiler_Bundle.cs | 284 ++++++++++++++++++++- .../ExtensibilityServices/ParseHelper.cs | 4 +- .../BundlePackageFixture.cs | 87 +++++++ .../TestData/BundlePackage/RemoteBundlePackage.wxs | 28 ++ 9 files changed, 407 insertions(+), 10 deletions(-) create mode 100644 src/wix/test/WixToolsetTest.CoreIntegration/TestData/BundlePackage/RemoteBundlePackage.wxs (limited to 'src') diff --git a/src/api/wix/WixToolset.Extensibility/Services/IParseHelper.cs b/src/api/wix/WixToolset.Extensibility/Services/IParseHelper.cs index 3a71d120..546a43a7 100644 --- a/src/api/wix/WixToolset.Extensibility/Services/IParseHelper.cs +++ b/src/api/wix/WixToolset.Extensibility/Services/IParseHelper.cs @@ -422,7 +422,8 @@ namespace WixToolset.Extensibility.Services /// Parent intermediate. /// Parent section. /// Element to parse children. - void ParseForExtensionElements(IEnumerable extensions, Intermediate intermediate, IntermediateSection section, XElement element); + /// Extra information about the context in which this element is being parsed. + void ParseForExtensionElements(IEnumerable extensions, Intermediate intermediate, IntermediateSection section, XElement element, IDictionary context = null); /// /// Schedules an action symbol. diff --git a/src/wix/WixToolset.Core.Burn/Bundles/ProcessBundlePackageCommand.cs b/src/wix/WixToolset.Core.Burn/Bundles/ProcessBundlePackageCommand.cs index c5a1aee0..c8e6bcf2 100644 --- a/src/wix/WixToolset.Core.Burn/Bundles/ProcessBundlePackageCommand.cs +++ b/src/wix/WixToolset.Core.Burn/Bundles/ProcessBundlePackageCommand.cs @@ -57,7 +57,7 @@ namespace WixToolset.Core.Burn.Bundles public void Execute() { var harvestedBundlePackage = this.Section.Symbols.OfType() - .Where(h => h.Id == this.PackagePayload.Id) + .Where(h => h.Id.Id == this.PackagePayload.Id.Id) .SingleOrDefault(); if (harvestedBundlePackage == null) diff --git a/src/wix/WixToolset.Core.Burn/Bundles/ProcessMsiPackageCommand.cs b/src/wix/WixToolset.Core.Burn/Bundles/ProcessMsiPackageCommand.cs index 0bec201d..d640e85d 100644 --- a/src/wix/WixToolset.Core.Burn/Bundles/ProcessMsiPackageCommand.cs +++ b/src/wix/WixToolset.Core.Burn/Bundles/ProcessMsiPackageCommand.cs @@ -65,7 +65,7 @@ namespace WixToolset.Core.Burn.Bundles public void Execute() { var harvestedMsiPackage = this.Section.Symbols.OfType() - .Where(h => h.Id == this.PackagePayload.Id) + .Where(h => h.Id.Id == this.PackagePayload.Id.Id) .SingleOrDefault(); if (harvestedMsiPackage == null) diff --git a/src/wix/WixToolset.Core.Burn/Bundles/ProcessMspPackageCommand.cs b/src/wix/WixToolset.Core.Burn/Bundles/ProcessMspPackageCommand.cs index 466ef5b9..5b43e614 100644 --- a/src/wix/WixToolset.Core.Burn/Bundles/ProcessMspPackageCommand.cs +++ b/src/wix/WixToolset.Core.Burn/Bundles/ProcessMspPackageCommand.cs @@ -53,7 +53,7 @@ namespace WixToolset.Core.Burn.Bundles public void Execute() { var harvestedMspPackage = this.Section.Symbols.OfType() - .Where(h => h.Id == this.PackagePayload.Id) + .Where(h => h.Id.Id == this.PackagePayload.Id.Id) .SingleOrDefault(); if (harvestedMspPackage == null) diff --git a/src/wix/WixToolset.Core/CompilerCore.cs b/src/wix/WixToolset.Core/CompilerCore.cs index e23b1e70..0fd302e5 100644 --- a/src/wix/WixToolset.Core/CompilerCore.cs +++ b/src/wix/WixToolset.Core/CompilerCore.cs @@ -849,9 +849,10 @@ namespace WixToolset.Core /// Process all children of the element looking for extensions and erroring on the unexpected. /// /// Element to parse children. - public void ParseForExtensionElements(XElement element) + /// Extra information about the context in which this element is being parsed. + public void ParseForExtensionElements(XElement element, IDictionary context = null) { - this.parseHelper.ParseForExtensionElements(this.extensions.Values, this.intermediate, this.ActiveSection, element); + this.parseHelper.ParseForExtensionElements(this.extensions.Values, this.intermediate, this.ActiveSection, element, context); } /// diff --git a/src/wix/WixToolset.Core/Compiler_Bundle.cs b/src/wix/WixToolset.Core/Compiler_Bundle.cs index ab405684..4cbfe58a 100644 --- a/src/wix/WixToolset.Core/Compiler_Bundle.cs +++ b/src/wix/WixToolset.Core/Compiler_Bundle.cs @@ -2552,7 +2552,7 @@ namespace WixToolset.Core var compilerPayload = new CompilerPayload(this.Core, sourceLineNumbers, node) { Id = defaultId, - IsRemoteAllowed = packageType == WixBundlePackageType.Exe || packageType == WixBundlePackageType.Msu, + IsRemoteAllowed = packageType == WixBundlePackageType.Bundle || packageType == WixBundlePackageType.Exe || packageType == WixBundlePackageType.Msu, }; // This list lets us evaluate extension attributes *after* all core attributes @@ -2659,11 +2659,291 @@ namespace WixToolset.Core this.Core.ParseExtensionAttribute(node, extensionAttribute, context); } - this.Core.ParseForExtensionElements(node); + foreach (var child in node.Elements()) + { + if (CompilerCore.WixNamespace == child.Name.Namespace) + { + bool allowed; + switch (child.Name.LocalName) + { + case "RemoteBundle": + allowed = packageType == WixBundlePackageType.Bundle; + + if (allowed) + { + this.ParseRemoteBundleElement(child, compilerPayload.Id.Id); + } + + break; + default: + allowed = false; + break; + } + + if (!allowed) + { + this.Core.UnexpectedElement(node, child); + } + } + else + { + this.Core.ParseExtensionElement(node, child, context); + } + } return compilerPayload; } + private void ParseRemoteBundleElement(XElement node, string packagePayloadId) + { + var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); + string bundleId = null; + string displayName = null; + string engineVersion = null; + long? installSize = null; + string manifestNamespace = null; + var perMachine = YesNoType.NotSet; + var protocolVersion = -1; + string providerKey = null; + string upgradeCode = null; + string version = null; + var win64 = YesNoType.NotSet; + + foreach (var attrib in node.Attributes()) + { + if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) + { + switch (attrib.Name.LocalName) + { + case "BundleId": + bundleId = this.Core.GetAttributeGuidValue(sourceLineNumbers, attrib); + break; + case "DisplayName": + displayName = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + break; + case "EngineVersion": + engineVersion = this.Core.GetAttributeVersionValue(sourceLineNumbers, attrib); + break; + case "InstallSize": + installSize = this.Core.GetAttributeLongValue(sourceLineNumbers, attrib, 0, Int64.MaxValue); + break; + case "ManifestNamespace": + manifestNamespace = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + break; + case "PerMachine": + perMachine = this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); + break; + case "ProtocolVersion": + protocolVersion = this.Core.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, Int32.MaxValue); + break; + case "ProviderKey": + providerKey = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + break; + case "UpgradeCode": + upgradeCode = this.Core.GetAttributeGuidValue(sourceLineNumbers, attrib); + break; + case "Version": + version = this.Core.GetAttributeVersionValue(sourceLineNumbers, attrib); + break; + case "Win64": + win64 = this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); + break; + default: + this.Core.UnexpectedAttribute(node, attrib); + break; + } + } + else + { + this.Core.ParseExtensionAttribute(node, attrib); + } + } + + if (String.IsNullOrEmpty(bundleId)) + { + this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "BundleId")); + } + + if (String.IsNullOrEmpty(manifestNamespace)) + { + this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "ManifestNamespace")); + } + + if (perMachine == YesNoType.NotSet) + { + this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "PerMachine")); + } + + if (protocolVersion == -1) + { + this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "ProtocolVersion")); + } + + if (String.IsNullOrEmpty(providerKey)) + { + this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "ProviderKey")); + } + + if (String.IsNullOrEmpty(upgradeCode)) + { + this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "UpgradeCode")); + } + + if (String.IsNullOrEmpty(version)) + { + this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Version")); + } + + if (win64 == YesNoType.NotSet) + { + this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Win64")); + } + + if (!this.Messaging.EncounteredError) + { + WixBundleHarvestedBundlePackageAttributes bundleAttributes = 0; + bundleAttributes |= (YesNoType.Yes == perMachine) ? WixBundleHarvestedBundlePackageAttributes.PerMachine : 0; + bundleAttributes |= (YesNoType.Yes == win64) ? WixBundleHarvestedBundlePackageAttributes.Win64 : 0; + + var symbol = this.Core.AddSymbol(new WixBundleHarvestedBundlePackageSymbol(sourceLineNumbers, new Identifier(AccessModifier.Section, packagePayloadId)) + { + Attributes = bundleAttributes, + BundleId = bundleId, + DisplayName = displayName, + EngineVersion = engineVersion, + ManifestNamespace = manifestNamespace, + ProtocolVersion = protocolVersion, + Version = version, + }); + + if (installSize.HasValue) + { + symbol.InstallSize = installSize.Value; + } + + this.Core.AddSymbol(new WixBundlePackageRelatedBundleSymbol(sourceLineNumbers) + { + PackagePayloadRef = packagePayloadId, + BundleId = upgradeCode, + Action = RelatedBundleActionType.Upgrade, + }); + + var depId = new Identifier(AccessModifier.Section, this.Core.CreateIdentifier("dep", packagePayloadId, providerKey)); + this.Core.AddSymbol(new WixBundleHarvestedDependencyProviderSymbol(sourceLineNumbers, depId) + { + PackagePayloadRef = packagePayloadId, + ProviderKey = providerKey, + Version = version, + }); + } + + var context = new Dictionary + { + ["Id"] = packagePayloadId, + }; + + foreach (var child in node.Elements()) + { + if (CompilerCore.WixNamespace == child.Name.Namespace) + { + switch (child.Name.LocalName) + { + case "RemoteRelatedBundle": + this.ParseRemoteRelatedBundleElement(child, packagePayloadId); + break; + default: + this.Core.UnexpectedElement(node, child); + break; + } + } + else + { + this.Core.ParseExtensionElement(node, child, context); + } + } + } + + private void ParseRemoteRelatedBundleElement(XElement node, string payloadId) + { + var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); + string id = null; + RelatedBundleActionType? actionType = null; + + foreach (var attrib in node.Attributes()) + { + if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) + { + switch (attrib.Name.LocalName) + { + case "Id": + id = this.Core.GetAttributeGuidValue(sourceLineNumbers, attrib, false); + break; + case "Action": + var action = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + switch (action) + { + case "Detect": + case "detect": + actionType = RelatedBundleActionType.Detect; + break; + case "Upgrade": + case "upgrade": + actionType = RelatedBundleActionType.Upgrade; + break; + case "Addon": + case "addon": + actionType = RelatedBundleActionType.Addon; + break; + case "Patch": + case "patch": + actionType = RelatedBundleActionType.Patch; + break; + case "": + break; + default: + this.Core.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, "Action", action, "Detect", "Upgrade", "Addon", "Patch")); + break; + } + break; + default: + this.Core.UnexpectedAttribute(node, attrib); + break; + } + } + else + { + this.Core.ParseExtensionAttribute(node, attrib); + } + } + + if (null == id) + { + this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id")); + } + + if (!actionType.HasValue) + { + this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Action")); + } + + var context = new Dictionary + { + ["PayloadId"] = payloadId, + }; + + this.Core.ParseForExtensionElements(node, context); + + if (!this.Core.EncounteredError) + { + this.Core.AddSymbol(new WixBundlePackageRelatedBundleSymbol(sourceLineNumbers) + { + PackagePayloadRef = payloadId, + BundleId = id, + Action = actionType.Value, + }); + } + } + /// /// Parse CommandLine element. /// diff --git a/src/wix/WixToolset.Core/ExtensibilityServices/ParseHelper.cs b/src/wix/WixToolset.Core/ExtensibilityServices/ParseHelper.cs index 654b56dc..bab1dd34 100644 --- a/src/wix/WixToolset.Core/ExtensibilityServices/ParseHelper.cs +++ b/src/wix/WixToolset.Core/ExtensibilityServices/ParseHelper.cs @@ -714,7 +714,7 @@ namespace WixToolset.Core.ExtensibilityServices return keyPath; } - public void ParseForExtensionElements(IEnumerable extensions, Intermediate intermediate, IntermediateSection section, XElement element) + public void ParseForExtensionElements(IEnumerable extensions, Intermediate intermediate, IntermediateSection section, XElement element, IDictionary context = null) { var checkInnerText = false; @@ -728,7 +728,7 @@ namespace WixToolset.Core.ExtensibilityServices } else { - this.ParseExtensionElement(extensions, intermediate, section, element, childElement); + this.ParseExtensionElement(extensions, intermediate, section, element, childElement, context); } } else diff --git a/src/wix/test/WixToolsetTest.CoreIntegration/BundlePackageFixture.cs b/src/wix/test/WixToolsetTest.CoreIntegration/BundlePackageFixture.cs index 2925abb1..621d0871 100644 --- a/src/wix/test/WixToolsetTest.CoreIntegration/BundlePackageFixture.cs +++ b/src/wix/test/WixToolsetTest.CoreIntegration/BundlePackageFixture.cs @@ -204,6 +204,93 @@ namespace WixToolsetTest.CoreIntegration } } + [Fact] + public void CanBuildBundleWithRemoteBundlePackage() + { + var folder = TestData.Get(@"TestData"); + + using (var fs = new DisposableFileSystem()) + { + var baseFolder = fs.GetFolder(); + var parentIntermediateFolder = Path.Combine(baseFolder, "obj", "Parent"); + var binFolder = Path.Combine(baseFolder, "bin"); + var parentBundlePath = Path.Combine(binFolder, "parent.exe"); + var parentPdbPath = Path.Combine(binFolder, "parent.wixpdb"); + var parentBaFolderPath = Path.Combine(baseFolder, "parentba"); + var extractFolderPath = Path.Combine(baseFolder, "extract"); + + var result = WixRunner.Execute(new[] + { + "build", + Path.Combine(folder, "BundlePackage", "RemoteBundlePackage.wxs"), + "-bindpath", Path.Combine(folder, "SimpleBundle", "data"), + "-bindpath", binFolder, + "-intermediateFolder", parentIntermediateFolder, + "-o", parentBundlePath, + }); + + result.AssertSuccess(); + + Assert.True(File.Exists(parentBundlePath)); + + var chainBundleId = "{216BDA7F-74BD-45E8-957B-500552F05629}"; + string parentBundleId; + using (var wixOutput = WixOutput.Read(parentPdbPath)) + { + + var intermediate = Intermediate.Load(wixOutput); + var section = intermediate.Sections.Single(); + + var bundleSymbol = section.Symbols.OfType().Single(); + parentBundleId = bundleSymbol.BundleId; + } + + var extractResult = BundleExtractor.ExtractBAContainer(null, parentBundlePath, parentBaFolderPath, extractFolderPath); + extractResult.AssertSuccess(); + + var ignoreAttributesByElementName = new Dictionary> + { + { "BundlePackage", new List { "Size" } }, + }; + var bundlePackages = extractResult.SelectManifestNodes("/burn:BurnManifest/burn:Chain/burn:BundlePackage") + .Cast() + .Select(e => e.GetTestXml(ignoreAttributesByElementName)) + .ToArray(); + WixAssert.CompareLineByLine(new string[] + { + $"" + + "" + + "" + + "" + + "", + }, bundlePackages); + + var registrations = extractResult.SelectManifestNodes("/burn:BurnManifest/burn:Registration") + .Cast() + .Select(e => e.GetTestXml()) + .ToArray(); + WixAssert.CompareLineByLine(new string[] + { + $"" + + "" + + "" + }, registrations); + + ignoreAttributesByElementName = new Dictionary> + { + { "WixPackageProperties", new List { "DownloadSize", "PackageSize" } }, + }; + var packageElements = extractResult.SelectBADataNodes("/ba:BootstrapperApplicationData/ba:WixPackageProperties") + .Cast() + .Select(e => e.GetTestXml(ignoreAttributesByElementName)) + .ToArray(); + WixAssert.CompareLineByLine(new string[] + { + "", + }, packageElements); + } + } + [Fact] public void CanBuildBundleWithV3BundlePackage() { diff --git a/src/wix/test/WixToolsetTest.CoreIntegration/TestData/BundlePackage/RemoteBundlePackage.wxs b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/BundlePackage/RemoteBundlePackage.wxs new file mode 100644 index 00000000..1a2b17f5 --- /dev/null +++ b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/BundlePackage/RemoteBundlePackage.wxs @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + -- cgit v1.2.3-55-g6feb