diff options
Diffstat (limited to 'src')
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 | |||
| 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 | } | ||
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" /> |
