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" />