@joebigelow / wix / commits / c455d229

Add SetVariable.

Sean Hall committed Mar 27, 2020 at 14:30 UTC c455d2290ef903ff36d540903e27d76d473cb67c
7 files changed +217 -33
src/WixToolset.Core.Burn/Bind/SetVariableSearchFacade.cs new
+33
@@ -0,0 +1,33 @@
1 +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2 +
3 +namespace WixToolset.Core.Burn
4 +{
5 + using System.Xml;
6 + using WixToolset.Data.Tuples;
7 +
8 + internal class SetVariableSearchFacade : BaseSearchFacade
9 + {
10 + public SetVariableSearchFacade(WixSearchTuple searchTuple, WixSetVariableTuple setVariableTuple)
11 + {
12 + this.SearchTuple = searchTuple;
13 + this.SetVariableTuple = setVariableTuple;
14 + }
15 +
16 + private WixSetVariableTuple SetVariableTuple { get; }
17 +
18 + public override void WriteXml(XmlTextWriter writer)
19 + {
20 + writer.WriteStartElement("SetVariable");
21 +
22 + base.WriteXml(writer);
23 +
24 + if (this.SetVariableTuple.Type != null)
25 + {
26 + writer.WriteAttributeString("Value", this.SetVariableTuple.Value);
27 + writer.WriteAttributeString("Type", this.SetVariableTuple.Type);
28 + }
29 +
30 + writer.WriteEndElement();
31 + }
32 + }
33 +}
src/WixToolset.Core.Burn/Bundles/OrderSearchesCommand.cs
+8 -1
@@ -36,13 +36,16 @@ namespace WixToolset.Core.Burn.Bundles
36 t.Definition.Type == TupleDefinitionType.WixProductSearch ||
37 t.Definition.Type == TupleDefinitionType.WixRegistrySearch)
38 .ToDictionary(t => t.Id.Id);
39 + var setVariablesById = this.Section.Tuples
40 + .OfType<WixSetVariableTuple>()
41 + .ToDictionary(t => t.Id.Id);
42 var extensionSearchesById = this.Section.Tuples
43 .Where(t => t.Definition.HasTag(BurnConstants.BundleExtensionSearchTupleDefinitionTag))
44 .ToDictionary(t => t.Id.Id);
45 var searchTuples = this.Section.Tuples.OfType<WixSearchTuple>().ToList();
46
47 this.ExtensionSearchTuplesByExtensionId = new Dictionary<string, IList<IntermediateTuple>>();
45 - this.OrderedSearchFacades = new List<ISearchFacade>(legacySearchesById.Keys.Count + extensionSearchesById.Keys.Count);
48 + this.OrderedSearchFacades = new List<ISearchFacade>(legacySearchesById.Keys.Count + setVariablesById.Keys.Count + extensionSearchesById.Keys.Count);
49
50 foreach (var searchTuple in searchTuples)
51 {
@@ -50,6 +53,10 @@ namespace WixToolset.Core.Burn.Bundles
53 {
54 this.OrderedSearchFacades.Add(new LegacySearchFacade(searchTuple, specificSearchTuple));
55 }
56 + else if (setVariablesById.TryGetValue(searchTuple.Id.Id, out var setVariableTuple))
57 + {
58 + this.OrderedSearchFacades.Add(new SetVariableSearchFacade(searchTuple, setVariableTuple));
59 + }
60 else if (extensionSearchesById.TryGetValue(searchTuple.Id.Id, out var extensionSearchTuple))
61 {
62 this.OrderedSearchFacades.Add(new ExtensionSearchFacade(searchTuple));
src/WixToolset.Core/Compiler.cs
+6
@@ -6221,6 +6221,12 @@ namespace WixToolset.Core
6221 case "SetProperty":
6222 this.ParseSetPropertyElement(child);
6223 break;
6224 + case "SetVariable":
6225 + this.ParseSetVariableElement(child);
6226 + break;
6227 + case "SetVariableRef":
6228 + this.ParseSimpleRefElement(child, "WixSetVariable");
6229 + break;
6230 case "SFPCatalog":
6231 string parentName = null;
6232 this.ParseSFPCatalogElement(child, ref parentName);
src/WixToolset.Core/Compiler_Bundle.cs
+110 -32
@@ -323,6 +323,12 @@ namespace WixToolset.Core
323 case "RelatedBundle":
324 this.ParseRelatedBundleElement(child);
325 break;
326 + case "SetVariable":
327 + this.ParseSetVariableElement(child);
328 + break;
329 + case "SetVariableRef":
330 + this.ParseSimpleRefElement(child, "WixSetVariable");
331 + break;
332 case "Update":
333 this.ParseUpdateElement(child);
334 break;
@@ -2704,6 +2710,78 @@ namespace WixToolset.Core
2710 }
2711 }
2712
2713 + /// <summary>
2714 + /// Parse SetVariable element
2715 + /// </summary>
2716 + /// <param name="node">Element to parse</param>
2717 + private void ParseSetVariableElement(XElement node)
2718 + {
2719 + var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node);
2720 + Identifier id = null;
2721 + string variable = null;
2722 + string condition = null;
2723 + string after = null;
2724 + string value = null;
2725 + string type = null;
2726 +
2727 + foreach (var attrib in node.Attributes())
2728 + {
2729 + if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace)
2730 + {
2731 + switch (attrib.Name.LocalName)
2732 + {
2733 + case "Id":
2734 + id = this.Core.GetAttributeIdentifier(sourceLineNumbers, attrib);
2735 + break;
2736 + case "Variable":
2737 + variable = this.Core.GetAttributeValue(sourceLineNumbers, attrib);
2738 + break;
2739 + case "Condition":
2740 + condition = this.Core.GetAttributeValue(sourceLineNumbers, attrib);
2741 + break;
2742 + case "After":
2743 + after = this.Core.GetAttributeValue(sourceLineNumbers, attrib);
2744 + break;
2745 + case "Value":
2746 + value = this.Core.GetAttributeValue(sourceLineNumbers, attrib);
2747 + break;
2748 + case "Type":
2749 + type = this.Core.GetAttributeValue(sourceLineNumbers, attrib);
2750 + break;
2751 +
2752 + default:
2753 + this.Core.UnexpectedAttribute(node, attrib);
2754 + break;
2755 + }
2756 + }
2757 + else
2758 + {
2759 + this.Core.ParseExtensionAttribute(node, attrib, null);
2760 + }
2761 + }
2762 +
2763 + type = this.ValidateVariableTypeWithValue(sourceLineNumbers, type, value);
2764 +
2765 + this.Core.ParseForExtensionElements(node);
2766 +
2767 + if (id == null)
2768 + {
2769 + id = this.Core.CreateIdentifier("sbv", variable, condition, after, value, type);
2770 + }
2771 +
2772 + this.Core.CreateWixSearchTuple(sourceLineNumbers, node.Name.LocalName, id, variable, condition, after);
2773 +
2774 + if (!this.Messaging.EncounteredError)
2775 + {
2776 + var tuple = new WixSetVariableTuple(sourceLineNumbers, id)
2777 + {
2778 + Value = value,
2779 + Type = type,
2780 + };
2781 + this.Core.AddTuple(tuple);
2782 + }
2783 + }
2784 +
2785 /// <summary>
2786 /// Parse Variable element
2787 /// </summary>
@@ -2764,64 +2842,64 @@ namespace WixToolset.Core
2842 this.Core.Write(ErrorMessages.ReservedNamespaceViolation(sourceLineNumbers, node.Name.LocalName, "Name", "Wix"));
2843 }
2844
2767 - if (null == type && null != value)
2845 + type = this.ValidateVariableTypeWithValue(sourceLineNumbers, type, value);
2846 +
2847 + this.Core.ParseForExtensionElements(node);
2848 +
2849 + if (!this.Core.EncounteredError)
2850 + {
2851 + var tuple = new WixBundleVariableTuple(sourceLineNumbers, new Identifier(AccessModifier.Private, name))
2852 + {
2853 + Value = value,
2854 + Type = type,
2855 + Hidden = hidden,
2856 + Persisted = persisted
2857 + };
2858 +
2859 + this.Core.AddTuple(tuple);
2860 + }
2861 + }
2862 +
2863 + private string ValidateVariableTypeWithValue(SourceLineNumber sourceLineNumbers, string type, string value)
2864 + {
2865 + var newType = type;
2866 + if (newType == null && value != null)
2867 {
2868 // Infer the type from the current value...
2869 if (value.StartsWith("v", StringComparison.OrdinalIgnoreCase))
2870 {
2871 // Version constructor does not support simple "v#" syntax so check to see if the value is
2872 // non-negative real quick.
2774 - if (Int32.TryParse(value.Substring(1), NumberStyles.None, CultureInfo.InvariantCulture.NumberFormat, out var number))
2873 + if (Int32.TryParse(value.Substring(1), NumberStyles.None, CultureInfo.InvariantCulture.NumberFormat, out var _))
2874 {
2776 - type = "version";
2875 + newType = "version";
2876 }
2778 - else
2877 + else if (Version.TryParse(value.Substring(1), out var _))
2878 {
2780 - // Sadly, Version doesn't have a TryParse() method until .NET 4, so we have to try/catch to see if it parses.
2781 - try
2782 - {
2783 - var version = new Version(value.Substring(1));
2784 - type = "version";
2785 - }
2786 - catch (Exception)
2787 - {
2788 - }
2879 + newType = "version";
2880 }
2881 }
2882
2883 // Not a version, check for numeric.
2793 - if (null == type)
2884 + if (newType == null)
2885 {
2795 - if (Int64.TryParse(value, NumberStyles.Integer, CultureInfo.InvariantCulture.NumberFormat, out var number))
2886 + if (Int64.TryParse(value, NumberStyles.Integer, CultureInfo.InvariantCulture.NumberFormat, out var _))
2887 {
2797 - type = "numeric";
2888 + newType = "numeric";
2889 }
2890 else
2891 {
2801 - type = "string";
2892 + newType = "string";
2893 }
2894 }
2895 }
2896
2806 - if (null == value && null != type)
2897 + if (value == null && newType != null)
2898 {
2899 this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, "Variable", "Value", "Type"));
2900 }
2901
2811 - this.Core.ParseForExtensionElements(node);
2812 -
2813 - if (!this.Core.EncounteredError)
2814 - {
2815 - var tuple = new WixBundleVariableTuple(sourceLineNumbers, new Identifier(AccessModifier.Private, name))
2816 - {
2817 - Value = value,
2818 - Type = type,
2819 - Hidden = hidden,
2820 - Persisted = persisted
2821 - };
2822 -
2823 - this.Core.AddTuple(tuple);
2824 - }
2902 + return newType;
2903 }
2904
2905 private class RemotePayload
src/test/WixToolsetTest.CoreIntegration/BundleManifestFixture.cs
+44
@@ -113,5 +113,49 @@ namespace WixToolsetTest.CoreIntegration
113 "</BundleExtension>", bundleExtensionDatas[0].GetTestXml());
114 }
115 }
116 +
117 + [Fact]
118 + public void PopulatesManifestWithSetVariables()
119 + {
120 + var burnStubPath = TestData.Get(@"TestData\.Data\burn.exe");
121 + var folder = TestData.Get(@"TestData");
122 +
123 + using (var fs = new DisposableFileSystem())
124 + {
125 + var baseFolder = fs.GetFolder();
126 + var intermediateFolder = Path.Combine(baseFolder, "obj");
127 + var bundlePath = Path.Combine(baseFolder, @"bin\test.exe");
128 + var baFolderPath = Path.Combine(baseFolder, "ba");
129 + var extractFolderPath = Path.Combine(baseFolder, "extract");
130 +
131 + var result = WixRunner.Execute(new[]
132 + {
133 + "build",
134 + Path.Combine(folder, "SetVariable", "Simple.wxs"),
135 + Path.Combine(folder, "BundleWithPackageGroupRef", "MinimalPackageGroup.wxs"),
136 + Path.Combine(folder, "BundleWithPackageGroupRef", "Bundle.wxs"),
137 + "-bindpath", Path.Combine(folder, "SimpleBundle", "data"),
138 + "-intermediateFolder", intermediateFolder,
139 + "-burnStub", burnStubPath,
140 + "-o", bundlePath
141 + });
142 +
143 + result.AssertSuccess();
144 +
145 + Assert.True(File.Exists(bundlePath));
146 +
147 + var extractResult = BundleExtractor.ExtractBAContainer(null, bundlePath, baFolderPath, extractFolderPath);
148 + extractResult.AssertSuccess();
149 +
150 + var setVariables = extractResult.SelectManifestNodes("/burn:BurnManifest/burn:SetVariable");
151 + Assert.Equal(6, setVariables.Count);
152 + Assert.Equal("<SetVariable Id='SetCoercedNumber' Variable='CoercedNumber' Value='2' Type='numeric' />", setVariables[0].GetTestXml());
153 + Assert.Equal("<SetVariable Id='SetCoercedString' Variable='CoercedString' Value='Bar' Type='string' />", setVariables[1].GetTestXml());
154 + Assert.Equal("<SetVariable Id='SetCoercedVersion' Variable='CoercedVersion' Value='v2.0' Type='version' />", setVariables[2].GetTestXml());
155 + Assert.Equal("<SetVariable Id='SetNeedsFormatting' Variable='NeedsFormatting' Value='[One] [Two] [Three]' Type='string' />", setVariables[3].GetTestXml());
156 + Assert.Equal("<SetVariable Id='SetVersionString' Variable='VersionString' Value='v1.0' Type='string' />", setVariables[4].GetTestXml());
157 + Assert.Equal("<SetVariable Id='SetUnset' Variable='Unset' Condition='VersionString = v2.0' />", setVariables[5].GetTestXml());
158 + }
159 + }
160 }
161 }
src/test/WixToolsetTest.CoreIntegration/TestData/SetVariable/Simple.wxs new
+15
@@ -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 + <PackageGroupRef Id="MinimalPackageGroup" />
6 + </PackageGroup>
7 +
8 + <SetVariable Id="SetCoercedNumber" Variable="CoercedNumber" Value="2" />
9 + <SetVariable Id="SetCoercedString" Variable="CoercedString" Value="Bar" />
10 + <SetVariable Id="SetCoercedVersion" Variable="CoercedVersion" Value="v2.0" />
11 + <SetVariable Id="SetNeedsFormatting" Variable="NeedsFormatting" Value="[One] [Two] [Three]" />
12 + <SetVariable Id="SetVersionString" Variable="VersionString" Value="v1.0" Type="string" />
13 + <SetVariable Id="SetUnset" Variable="Unset" Condition="VersionString = v2.0" />
14 + </Fragment>
15 +</Wix>
src/test/WixToolsetTest.CoreIntegration/WixToolsetTest.CoreIntegration.csproj
+1
@@ -112,6 +112,7 @@
112 <Content Include="TestData\SetProperty\Package.en-us.wxl" CopyToOutputDirectory="PreserveNewest" />
113 <Content Include="TestData\SetProperty\Package.wxs" CopyToOutputDirectory="PreserveNewest" />
114 <Content Include="TestData\SetProperty\PackageComponents.wxs" CopyToOutputDirectory="PreserveNewest" />
115 + <Content Include="TestData\SetVariable\Simple.wxs" CopyToOutputDirectory="PreserveNewest" />
116 <Content Include="TestData\SimpleBundle\data\test.msi" CopyToOutputDirectory="PreserveNewest" />
117 <Content Include="TestData\SimpleBundle\Bundle.en-us.wxl" CopyToOutputDirectory="PreserveNewest" />
118 <Content Include="TestData\SimpleBundle\Bundle.wxs" CopyToOutputDirectory="PreserveNewest" />