aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSean Hall <r.sean.hall@gmail.com>2020-03-27 14:30:35 +1000
committerSean Hall <r.sean.hall@gmail.com>2020-03-30 21:30:04 +1000
commitc455d2290ef903ff36d540903e27d76d473cb67c (patch)
treeb72ab75702810bc14e6f9bd31af3e1b67739f153
parent0baf6e26ec7ab2ff0b6ad36e9d44f3d68819b5d6 (diff)
downloadwix-c455d2290ef903ff36d540903e27d76d473cb67c.tar.gz
wix-c455d2290ef903ff36d540903e27d76d473cb67c.tar.bz2
wix-c455d2290ef903ff36d540903e27d76d473cb67c.zip
Add SetVariable.
-rw-r--r--src/WixToolset.Core.Burn/Bind/SetVariableSearchFacade.cs33
-rw-r--r--src/WixToolset.Core.Burn/Bundles/OrderSearchesCommand.cs9
-rw-r--r--src/WixToolset.Core/Compiler.cs6
-rw-r--r--src/WixToolset.Core/Compiler_Bundle.cs142
-rw-r--r--src/test/WixToolsetTest.CoreIntegration/BundleManifestFixture.cs44
-rw-r--r--src/test/WixToolsetTest.CoreIntegration/TestData/SetVariable/Simple.wxs15
-rw-r--r--src/test/WixToolsetTest.CoreIntegration/WixToolsetTest.CoreIntegration.csproj1
7 files changed, 217 insertions, 33 deletions
diff --git a/src/WixToolset.Core.Burn/Bind/SetVariableSearchFacade.cs b/src/WixToolset.Core.Burn/Bind/SetVariableSearchFacade.cs
new file mode 100644
index 00000000..0fe60422
--- /dev/null
+++ b/src/WixToolset.Core.Burn/Bind/SetVariableSearchFacade.cs
@@ -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
3namespace 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}
diff --git a/src/WixToolset.Core.Burn/Bundles/OrderSearchesCommand.cs b/src/WixToolset.Core.Burn/Bundles/OrderSearchesCommand.cs
index 55b31ed3..3f720115 100644
--- a/src/WixToolset.Core.Burn/Bundles/OrderSearchesCommand.cs
+++ b/src/WixToolset.Core.Burn/Bundles/OrderSearchesCommand.cs
@@ -36,13 +36,16 @@ namespace WixToolset.Core.Burn.Bundles
36 t.Definition.Type == TupleDefinitionType.WixProductSearch || 36 t.Definition.Type == TupleDefinitionType.WixProductSearch ||
37 t.Definition.Type == TupleDefinitionType.WixRegistrySearch) 37 t.Definition.Type == TupleDefinitionType.WixRegistrySearch)
38 .ToDictionary(t => t.Id.Id); 38 .ToDictionary(t => t.Id.Id);
39 var setVariablesById = this.Section.Tuples
40 .OfType<WixSetVariableTuple>()
41 .ToDictionary(t => t.Id.Id);
39 var extensionSearchesById = this.Section.Tuples 42 var extensionSearchesById = this.Section.Tuples
40 .Where(t => t.Definition.HasTag(BurnConstants.BundleExtensionSearchTupleDefinitionTag)) 43 .Where(t => t.Definition.HasTag(BurnConstants.BundleExtensionSearchTupleDefinitionTag))
41 .ToDictionary(t => t.Id.Id); 44 .ToDictionary(t => t.Id.Id);
42 var searchTuples = this.Section.Tuples.OfType<WixSearchTuple>().ToList(); 45 var searchTuples = this.Section.Tuples.OfType<WixSearchTuple>().ToList();
43 46
44 this.ExtensionSearchTuplesByExtensionId = new Dictionary<string, IList<IntermediateTuple>>(); 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);
46 49
47 foreach (var searchTuple in searchTuples) 50 foreach (var searchTuple in searchTuples)
48 { 51 {
@@ -50,6 +53,10 @@ namespace WixToolset.Core.Burn.Bundles
50 { 53 {
51 this.OrderedSearchFacades.Add(new LegacySearchFacade(searchTuple, specificSearchTuple)); 54 this.OrderedSearchFacades.Add(new LegacySearchFacade(searchTuple, specificSearchTuple));
52 } 55 }
56 else if (setVariablesById.TryGetValue(searchTuple.Id.Id, out var setVariableTuple))
57 {
58 this.OrderedSearchFacades.Add(new SetVariableSearchFacade(searchTuple, setVariableTuple));
59 }
53 else if (extensionSearchesById.TryGetValue(searchTuple.Id.Id, out var extensionSearchTuple)) 60 else if (extensionSearchesById.TryGetValue(searchTuple.Id.Id, out var extensionSearchTuple))
54 { 61 {
55 this.OrderedSearchFacades.Add(new ExtensionSearchFacade(searchTuple)); 62 this.OrderedSearchFacades.Add(new ExtensionSearchFacade(searchTuple));
diff --git a/src/WixToolset.Core/Compiler.cs b/src/WixToolset.Core/Compiler.cs
index 6f122f7b..7638c11e 100644
--- a/src/WixToolset.Core/Compiler.cs
+++ b/src/WixToolset.Core/Compiler.cs
@@ -6221,6 +6221,12 @@ namespace WixToolset.Core
6221 case "SetProperty": 6221 case "SetProperty":
6222 this.ParseSetPropertyElement(child); 6222 this.ParseSetPropertyElement(child);
6223 break; 6223 break;
6224 case "SetVariable":
6225 this.ParseSetVariableElement(child);
6226 break;
6227 case "SetVariableRef":
6228 this.ParseSimpleRefElement(child, "WixSetVariable");
6229 break;
6224 case "SFPCatalog": 6230 case "SFPCatalog":
6225 string parentName = null; 6231 string parentName = null;
6226 this.ParseSFPCatalogElement(child, ref parentName); 6232 this.ParseSFPCatalogElement(child, ref parentName);
diff --git a/src/WixToolset.Core/Compiler_Bundle.cs b/src/WixToolset.Core/Compiler_Bundle.cs
index a840e448..5d7072d0 100644
--- a/src/WixToolset.Core/Compiler_Bundle.cs
+++ b/src/WixToolset.Core/Compiler_Bundle.cs
@@ -323,6 +323,12 @@ namespace WixToolset.Core
323 case "RelatedBundle": 323 case "RelatedBundle":
324 this.ParseRelatedBundleElement(child); 324 this.ParseRelatedBundleElement(child);
325 break; 325 break;
326 case "SetVariable":
327 this.ParseSetVariableElement(child);
328 break;
329 case "SetVariableRef":
330 this.ParseSimpleRefElement(child, "WixSetVariable");
331 break;
326 case "Update": 332 case "Update":
327 this.ParseUpdateElement(child); 333 this.ParseUpdateElement(child);
328 break; 334 break;
@@ -2705,6 +2711,78 @@ namespace WixToolset.Core
2705 } 2711 }
2706 2712
2707 /// <summary> 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>
2708 /// Parse Variable element 2786 /// Parse Variable element
2709 /// </summary> 2787 /// </summary>
2710 /// <param name="node">Element to parse</param> 2788 /// <param name="node">Element to parse</param>
@@ -2764,64 +2842,64 @@ namespace WixToolset.Core
2764 this.Core.Write(ErrorMessages.ReservedNamespaceViolation(sourceLineNumbers, node.Name.LocalName, "Name", "Wix")); 2842 this.Core.Write(ErrorMessages.ReservedNamespaceViolation(sourceLineNumbers, node.Name.LocalName, "Name", "Wix"));
2765 } 2843 }
2766 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)
2768 { 2867 {
2769 // Infer the type from the current value... 2868 // Infer the type from the current value...
2770 if (value.StartsWith("v", StringComparison.OrdinalIgnoreCase)) 2869 if (value.StartsWith("v", StringComparison.OrdinalIgnoreCase))
2771 { 2870 {
2772 // Version constructor does not support simple "v#" syntax so check to see if the value is 2871 // Version constructor does not support simple "v#" syntax so check to see if the value is
2773 // non-negative real quick. 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 _))
2775 { 2874 {
2776 type = "version"; 2875 newType = "version";
2777 } 2876 }
2778 else 2877 else if (Version.TryParse(value.Substring(1), out var _))
2779 { 2878 {
2780 // Sadly, Version doesn't have a TryParse() method until .NET 4, so we have to try/catch to see if it parses. 2879 newType = "version";
2781 try
2782 {
2783 var version = new Version(value.Substring(1));
2784 type = "version";
2785 }
2786 catch (Exception)
2787 {
2788 }
2789 } 2880 }
2790 } 2881 }
2791 2882
2792 // Not a version, check for numeric. 2883 // Not a version, check for numeric.
2793 if (null == type) 2884 if (newType == null)
2794 { 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 _))
2796 { 2887 {
2797 type = "numeric"; 2888 newType = "numeric";
2798 } 2889 }
2799 else 2890 else
2800 { 2891 {
2801 type = "string"; 2892 newType = "string";
2802 } 2893 }
2803 } 2894 }
2804 } 2895 }
2805 2896
2806 if (null == value && null != type) 2897 if (value == null && newType != null)
2807 { 2898 {
2808 this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, "Variable", "Value", "Type")); 2899 this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, "Variable", "Value", "Type"));
2809 } 2900 }
2810 2901
2811 this.Core.ParseForExtensionElements(node); 2902 return newType;
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 }
2825 } 2903 }
2826 2904
2827 private class RemotePayload 2905 private class RemotePayload
diff --git a/src/test/WixToolsetTest.CoreIntegration/BundleManifestFixture.cs b/src/test/WixToolsetTest.CoreIntegration/BundleManifestFixture.cs
index 80f7b875..174ac21b 100644
--- a/src/test/WixToolsetTest.CoreIntegration/BundleManifestFixture.cs
+++ b/src/test/WixToolsetTest.CoreIntegration/BundleManifestFixture.cs
@@ -113,5 +113,49 @@ namespace WixToolsetTest.CoreIntegration
113 "</BundleExtension>", bundleExtensionDatas[0].GetTestXml()); 113 "</BundleExtension>", bundleExtensionDatas[0].GetTestXml());
114 } 114 }
115 } 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 }
116 } 160 }
117} 161}
diff --git a/src/test/WixToolsetTest.CoreIntegration/TestData/SetVariable/Simple.wxs b/src/test/WixToolsetTest.CoreIntegration/TestData/SetVariable/Simple.wxs
new file mode 100644
index 00000000..96c92e54
--- /dev/null
+++ b/src/test/WixToolsetTest.CoreIntegration/TestData/SetVariable/Simple.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 <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>
diff --git a/src/test/WixToolsetTest.CoreIntegration/WixToolsetTest.CoreIntegration.csproj b/src/test/WixToolsetTest.CoreIntegration/WixToolsetTest.CoreIntegration.csproj
index 324d04ff..921c77f9 100644
--- a/src/test/WixToolsetTest.CoreIntegration/WixToolsetTest.CoreIntegration.csproj
+++ b/src/test/WixToolsetTest.CoreIntegration/WixToolsetTest.CoreIntegration.csproj
@@ -112,6 +112,7 @@
112 <Content Include="TestData\SetProperty\Package.en-us.wxl" CopyToOutputDirectory="PreserveNewest" /> 112 <Content Include="TestData\SetProperty\Package.en-us.wxl" CopyToOutputDirectory="PreserveNewest" />
113 <Content Include="TestData\SetProperty\Package.wxs" CopyToOutputDirectory="PreserveNewest" /> 113 <Content Include="TestData\SetProperty\Package.wxs" CopyToOutputDirectory="PreserveNewest" />
114 <Content Include="TestData\SetProperty\PackageComponents.wxs" CopyToOutputDirectory="PreserveNewest" /> 114 <Content Include="TestData\SetProperty\PackageComponents.wxs" CopyToOutputDirectory="PreserveNewest" />
115 <Content Include="TestData\SetVariable\Simple.wxs" CopyToOutputDirectory="PreserveNewest" />
115 <Content Include="TestData\SimpleBundle\data\test.msi" CopyToOutputDirectory="PreserveNewest" /> 116 <Content Include="TestData\SimpleBundle\data\test.msi" CopyToOutputDirectory="PreserveNewest" />
116 <Content Include="TestData\SimpleBundle\Bundle.en-us.wxl" CopyToOutputDirectory="PreserveNewest" /> 117 <Content Include="TestData\SimpleBundle\Bundle.en-us.wxl" CopyToOutputDirectory="PreserveNewest" />
117 <Content Include="TestData\SimpleBundle\Bundle.wxs" CopyToOutputDirectory="PreserveNewest" /> 118 <Content Include="TestData\SimpleBundle\Bundle.wxs" CopyToOutputDirectory="PreserveNewest" />