@joebigelow / wix-1 / commits / dd3ab394

Expose bind variables from build command and via MSBuild WixVariables property

Also, resolves bind variables in path fields. Fixes 6995 and 7017

Rob Mensching committed Nov 15, 2022 at 23:38 UTC dd3ab394ec6e37c24827294605857730f8e7a1a5
27 files changed +517 -123
src/api/wix/WixToolset.Data/ErrorMessages.cs
+12 -12
@@ -598,9 +598,9 @@ namespace WixToolset.Data
598 return Message(sourceLineNumbers, Ids.ExpectedVariable, "A required variable was missing in the expression '{0}'.", expression);
599 }
600
601 - public static Message ExpectedWixVariableValue(string variableId)
601 + public static Message ExpectedBindVariableValue(string variableId)
602 {
603 - return Message(null, Ids.ExpectedWixVariableValue, "The WiX variable '{0}' was declared without a value. Please specify a value for the variable.", variableId);
603 + return Message(null, Ids.ExpectedBindVariableValue, "The bind variable '{0}' was declared without a value. Please specify a value for the variable.", variableId);
604 }
605
606 public static Message FamilyNameTooLong(SourceLineNumber sourceLineNumbers, string elementName, string attributeName, string value, int length)
@@ -1081,9 +1081,9 @@ namespace WixToolset.Data
1081 return Message(null, Ids.IllegalWarningIdAsError, "Illegal value '{0}' for the -wx<N> command line option. Specify a particular warning number, like '-wx6' to display the warning with ID 6 as an error, or '-wx' alone to suppress all warnings.", warningId);
1082 }
1083
1084 - public static Message IllegalWixVariablePrefix(SourceLineNumber sourceLineNumbers, string variableId)
1084 + public static Message IllegalBindVariablePrefix(SourceLineNumber sourceLineNumbers, string variableId)
1085 {
1086 - return Message(sourceLineNumbers, Ids.IllegalWixVariablePrefix, "The WiX variable $(wix.{0}) uses an illegal prefix '$'. Please use the '!' prefix instead.", variableId);
1086 + return Message(sourceLineNumbers, Ids.IllegalBindVariablePrefix, "The bind variable $(wix.{0}) uses an illegal prefix '$'. Please use the '!' prefix instead.", variableId);
1087 }
1088
1089 public static Message IllegalYesNoAlwaysValue(SourceLineNumber sourceLineNumbers, string elementName, string attributeName, string value)
@@ -2231,14 +2231,14 @@ namespace WixToolset.Data
2231 return Message(null, Ids.WixFileNotFound, "The file '{0}' cannot be found.", file);
2232 }
2233
2234 - public static Message WixVariableCollision(SourceLineNumber sourceLineNumbers, string variableId)
2234 + public static Message BindVariableCollision(SourceLineNumber sourceLineNumbers, string variableId)
2235 {
2236 - return Message(sourceLineNumbers, Ids.WixVariableCollision, "The WiX variable '{0}' is declared in more than one location. Please remove one of the declarations.", variableId);
2236 + return Message(sourceLineNumbers, Ids.BindVariableCollision, "The bind variable '{0}' is declared in more than one location. Please remove one of the declarations.", variableId);
2237 }
2238
2239 - public static Message WixVariableUnknown(SourceLineNumber sourceLineNumbers, string variableId)
2239 + public static Message BindVariableUnknown(SourceLineNumber sourceLineNumbers, string variableId)
2240 {
2241 - return Message(sourceLineNumbers, Ids.WixVariableUnknown, "The WiX variable !(wix.{0}) is unknown. Please ensure the variable is declared on the command line for light.exe, via a WixVariable element, or inline using the syntax !(wix.{0}=some value which doesn't contain parenthesis).", variableId);
2241 + return Message(sourceLineNumbers, Ids.BindVariableUnknown, "The bind variable !(wix.{0}) is unknown. Please ensure the variable is declared on the command line for wix.exe, via a BindVariable element, or inline using the syntax !(wix.{0}=some value which doesn't contain parenthesis).", variableId);
2242 }
2243
2244 public static Message NoSourceFiles()
@@ -2474,10 +2474,10 @@ namespace WixToolset.Data
2474 VersionIndependentProgIdsCannotHaveIcons = 192,
2475 IllegalAttributeValueWithOtherAttribute = 193,
2476 InvalidMergeLanguage = 194,
2477 - WixVariableCollision = 195,
2478 - ExpectedWixVariableValue = 196,
2479 - WixVariableUnknown = 197,
2480 - IllegalWixVariablePrefix = 198,
2477 + BindVariableCollision = 195,
2478 + ExpectedBindVariableValue = 196,
2479 + BindVariableUnknown = 197,
2480 + IllegalBindVariablePrefix = 198,
2481 InvalidWixXmlNamespace = 199,
2482 UnhandledExtensionElement = 200,
2483 UnhandledExtensionAttribute = 201,
src/api/wix/WixToolset.Extensibility/Data/ILibraryContext.cs
+5
@@ -27,6 +27,11 @@ namespace WixToolset.Extensibility.Data
27 /// </summary>
28 IReadOnlyCollection<IBindPath> BindPaths { get; set; }
29
30 + /// <summary>
31 + /// Bind variables used when binding files.
32 + /// </summary>
33 + IDictionary<string, string> BindVariables { get; set; }
34 +
35 /// <summary>
36 /// Collection of extensions used during creation of library.
37 /// </summary>
src/api/wix/WixToolset.Extensibility/Data/IResolveContext.cs
+5
@@ -22,6 +22,11 @@ namespace WixToolset.Extensibility.Data
22 /// </summary>
23 IReadOnlyCollection<IBindPath> BindPaths { get; set; }
24
25 + /// <summary>
26 + /// Bind variables used during resolution.
27 + /// </summary>
28 + IDictionary<string, string> BindVariables { get; set; }
29 +
30 /// <summary>
31 /// Resolve extensions.
32 /// </summary>
src/wix/WixToolset.BuildTasks/WixBuild.cs
+22
@@ -45,6 +45,8 @@ namespace WixToolset.BuildTasks
45
46 public ITaskItem[] BindPaths { get; set; }
47
48 + public ITaskItem[] BindVariables { get; set; }
49 +
50 public bool BindFiles { get; set; }
51
52 public ITaskItem BindTrackingFile { get; set; }
@@ -77,6 +79,7 @@ namespace WixToolset.BuildTasks
79
80 commandLineBuilder.AppendIfTrue("-bindFiles", this.BindFiles);
81 commandLineBuilder.AppendArrayIfNotNull("-bindPath ", this.CalculateBindPathStrings());
82 + commandLineBuilder.AppendArrayIfNotNull("-bindVariable ", this.CalculateBindVariableStrings());
83 commandLineBuilder.AppendArrayIfNotNull("-loc ", this.LocalizationFiles);
84 commandLineBuilder.AppendArrayIfNotNull("-lib ", this.LibraryFiles);
85 commandLineBuilder.AppendTextIfNotWhitespace(this.AdditionalOptions);
@@ -103,5 +106,24 @@ namespace WixToolset.BuildTasks
106 }
107 }
108 }
109 +
110 + private IEnumerable<string> CalculateBindVariableStrings()
111 + {
112 + if (null != this.BindVariables)
113 + {
114 + foreach (var item in this.BindVariables)
115 + {
116 + var value = item.ItemSpec;
117 +
118 + var variableName = item.GetMetadata("Name");
119 + if (!String.IsNullOrEmpty(variableName))
120 + {
121 + value = String.Concat(variableName, "=", value);
122 + }
123 +
124 + yield return value;
125 + }
126 + }
127 + }
128 }
129 }
src/wix/WixToolset.Core/Bind/ResolveFieldsCommand.cs
+30 -20
@@ -88,25 +88,21 @@ namespace WixToolset.Core.Bind
88
89 var beforeErrorCount = this.Messaging.ErrorCount;
90
91 - // Check to make sure we're in a scenario where we can handle variable resolution.
92 - if (null != delayedFields)
91 + // resolve localization and wix variables
92 + if (fieldType == IntermediateFieldType.String)
93 {
94 - // resolve localization and wix variables
95 - if (fieldType == IntermediateFieldType.String)
94 + var original = field.AsString();
95 + if (!String.IsNullOrEmpty(original))
96 {
97 - var original = field.AsString();
98 - if (!String.IsNullOrEmpty(original))
97 + var resolution = this.VariableResolver.ResolveVariables(symbol.SourceLineNumbers, original, !this.AllowUnresolvedVariables);
98 + if (resolution.UpdatedValue)
99 {
100 - var resolution = this.VariableResolver.ResolveVariables(symbol.SourceLineNumbers, original, !this.AllowUnresolvedVariables);
101 - if (resolution.UpdatedValue)
102 - {
103 - field.Set(resolution.Value);
104 - }
105 -
106 - if (resolution.DelayedResolve)
107 - {
108 - delayedFields.Add(new DelayedField(symbol, field));
109 - }
100 + field.Set(resolution.Value);
101 + }
102 +
103 + if (resolution.DelayedResolve)
104 + {
105 + delayedFields.Add(new DelayedField(symbol, field));
106 }
107 }
108 }
@@ -136,13 +132,27 @@ namespace WixToolset.Core.Bind
132 // If the file is embedded and if the previous value has a bind variable in the path
133 // which gets modified by resolving the previous value again then switch to that newly
134 // resolved path instead of using the embedded file.
139 - if (fieldValue.Embed && field.PreviousValue != null)
135 + if (fieldValue.Embed)
136 + {
137 + if (field.PreviousValue != null)
138 + {
139 + var resolution = this.VariableResolver.ResolveVariables(symbol.SourceLineNumbers, field.PreviousValue.AsString(), errorOnUnknown: false);
140 +
141 + if (resolution.UpdatedValue && !resolution.IsDefault)
142 + {
143 + fieldValue = new IntermediateFieldPathValue { Path = resolution.Value };
144 + }
145 + }
146 + }
147 + else // resolve path field for bind variables.
148 {
141 - var resolution = this.VariableResolver.ResolveVariables(symbol.SourceLineNumbers, field.PreviousValue.AsString(), errorOnUnknown: false);
149 + var resolution = this.VariableResolver.ResolveVariables(symbol.SourceLineNumbers, fieldValue.Path, errorOnUnknown: false);
150
143 - if (resolution.UpdatedValue && !resolution.IsDefault)
151 + if (resolution.UpdatedValue)
152 {
145 - fieldValue = new IntermediateFieldPathValue { Path = resolution.Value };
153 + field.Set(resolution.Value);
154 +
155 + fieldValue = field.AsPath();
156 }
157 }
158
src/wix/WixToolset.Core/CommandLine/BuildCommand.cs
+60 -21
@@ -10,6 +10,7 @@ namespace WixToolset.Core.CommandLine
10 using System.Threading.Tasks;
11 using System.Xml.Linq;
12 using WixToolset.Data;
13 + using WixToolset.Data.Bind;
14 using WixToolset.Extensibility;
15 using WixToolset.Extensibility.Data;
16 using WixToolset.Extensibility.Services;
@@ -115,7 +116,7 @@ namespace WixToolset.Core.CommandLine
116 {
117 using (new IntermediateFieldContext("wix.lib"))
118 {
118 - this.LibraryPhase(wixobjs, wxls, inputsOutputs.LibraryPaths, creator, this.commandLine.BindFiles, this.commandLine.BindPaths, inputsOutputs.OutputPath, cancellationToken);
119 + this.LibraryPhase(wixobjs, wxls, inputsOutputs.LibraryPaths, creator, this.commandLine.BindFiles, this.commandLine.BindPaths, this.commandLine.BindVariables, inputsOutputs.OutputPath, cancellationToken);
120 }
121 }
122 else
@@ -148,7 +149,7 @@ namespace WixToolset.Core.CommandLine
149 {
150 using (new IntermediateFieldContext("wix.bind"))
151 {
151 - this.BindPhase(wixipl, wxls, filterCultures, this.commandLine.CabCachePath, this.commandLine.CabbingThreadCount, this.commandLine.BindPaths, inputsOutputs, cancellationToken);
152 + this.BindPhase(wixipl, wxls, filterCultures, this.commandLine.CabCachePath, this.commandLine.CabbingThreadCount, this.commandLine.BindPaths, this.commandLine.BindVariables, inputsOutputs, cancellationToken);
153 }
154 }
155 }
@@ -206,7 +207,7 @@ namespace WixToolset.Core.CommandLine
207 return intermediates;
208 }
209
209 - private void LibraryPhase(IReadOnlyCollection<Intermediate> intermediates, IReadOnlyCollection<Localization> localizations, IEnumerable<string> libraryFiles, ISymbolDefinitionCreator creator, bool bindFiles, IReadOnlyCollection<IBindPath> bindPaths, string outputPath, CancellationToken cancellationToken)
210 + private void LibraryPhase(IReadOnlyCollection<Intermediate> intermediates, IReadOnlyCollection<Localization> localizations, IEnumerable<string> libraryFiles, ISymbolDefinitionCreator creator, bool bindFiles, IReadOnlyCollection<IBindPath> bindPaths, Dictionary<string, string> bindVariables, string outputPath, CancellationToken cancellationToken)
211 {
212 var libraries = this.LoadLibraries(libraryFiles, creator);
213
@@ -218,6 +219,7 @@ namespace WixToolset.Core.CommandLine
219 var context = this.ServiceProvider.GetService<ILibraryContext>();
220 context.BindFiles = bindFiles;
221 context.BindPaths = bindPaths;
222 + context.BindVariables = bindVariables;
223 context.Extensions = this.ExtensionManager.GetServices<ILibrarianExtension>();
224 context.Localizations = localizations;
225 context.IntermediateFolder = this.IntermediateFolder;
@@ -266,12 +268,13 @@ namespace WixToolset.Core.CommandLine
268 return linker.Link(context);
269 }
270
269 - private void BindPhase(Intermediate output, IReadOnlyCollection<Localization> localizations, IReadOnlyCollection<string> filterCultures, string cabCachePath, int cabbingThreadCount, IReadOnlyCollection<IBindPath> bindPaths, InputsAndOutputs inputsOutputs, CancellationToken cancellationToken)
271 + private void BindPhase(Intermediate output, IReadOnlyCollection<Localization> localizations, IReadOnlyCollection<string> filterCultures, string cabCachePath, int cabbingThreadCount, IReadOnlyCollection<IBindPath> bindPaths, Dictionary<string, string> bindVariables, InputsAndOutputs inputsOutputs, CancellationToken cancellationToken)
272 {
273 IResolveResult resolveResult;
274 {
275 var context = this.ServiceProvider.GetService<IResolveContext>();
276 context.BindPaths = bindPaths;
277 + context.BindVariables = bindVariables;
278 context.Extensions = this.ExtensionManager.GetServices<IResolverExtension>();
279 context.ExtensionData = this.ExtensionManager.GetServices<IExtensionData>();
280 context.FilterCultures = filterCultures;
@@ -466,6 +469,8 @@ namespace WixToolset.Core.CommandLine
469
470 public List<IBindPath> BindPaths { get; } = new List<IBindPath>();
471
472 + public Dictionary<string, string> BindVariables { get; } = new Dictionary<string, string>();
473 +
474 public string CabCachePath { get; private set; }
475
476 public int CabbingThreadCount { get; private set; }
@@ -564,6 +569,24 @@ namespace WixToolset.Core.CommandLine
569 return true;
570 }
571
572 + case "bv":
573 + case "bindvariable":
574 + {
575 + var value = parser.GetNextArgumentOrError(arg);
576 + if (value != null && TryParseNameValuePair(value, out var parsedName, out var parsedValue))
577 + {
578 + if (this.BindVariables.TryGetValue(parsedName, out var collisionValue))
579 + {
580 + parser.ReportErrorArgument(arg, LinkerErrors.DuplicateBindPathVariableOnCommandLine(arg, parsedName, parsedValue, collisionValue));
581 + }
582 + else
583 + {
584 + this.BindVariables.Add(parsedName, parsedValue);
585 + }
586 + }
587 + return true;
588 + }
589 +
590 case "cc":
591 case "cabcache":
592 this.CabCachePath = parser.GetNextArgumentOrError(arg);
@@ -651,20 +674,20 @@ namespace WixToolset.Core.CommandLine
674 return true;
675
676 case "pdbtype":
677 + {
678 + var value = parser.GetNextArgumentOrError(arg);
679 + if (Enum.TryParse(value, true, out PdbType pdbType))
680 {
655 - var value = parser.GetNextArgumentOrError(arg);
656 - if (Enum.TryParse(value, true, out PdbType pdbType))
657 - {
658 - this.PdbType = pdbType;
659 - }
660 - else if (!String.IsNullOrEmpty(value))
661 - {
662 - parser.ReportErrorArgument(arg, ErrorMessages.IllegalCommandLineArgumentValue(arg, value, Enum.GetNames(typeof(PdbType)).Select(s => s.ToLowerInvariant())));
663 - }
664 -
665 - return true;
681 + this.PdbType = pdbType;
682 + }
683 + else if (!String.IsNullOrEmpty(value))
684 + {
685 + parser.ReportErrorArgument(arg, ErrorMessages.IllegalCommandLineArgumentValue(arg, value, Enum.GetNames(typeof(PdbType)).Select(s => s.ToLowerInvariant())));
686 }
687
688 + return true;
689 + }
690 +
691 case "resetacls":
692 this.ResetAcls = true;
693 return true;
@@ -870,18 +893,16 @@ namespace WixToolset.Core.CommandLine
893
894 private bool TryParseBindPath(string argument, string bindPath, out IBindPath bp)
895 {
873 - var namedPath = bindPath.Split(BindPathSplit, 2);
874 -
896 bp = this.ServiceProvider.GetService<IBindPath>();
897
877 - if (1 == namedPath.Length)
898 + if (TryParseNameValuePair(bindPath, out var name, out var path))
899 {
879 - bp.Path = namedPath[0];
900 + bp.Name = name;
901 + bp.Path = path;
902 }
903 else
904 {
883 - bp.Name = namedPath[0];
884 - bp.Path = namedPath[1];
905 + bp.Path = bindPath;
906 }
907
908 if (File.Exists(bp.Path))
@@ -892,6 +913,24 @@ namespace WixToolset.Core.CommandLine
913
914 return true;
915 }
916 +
917 + private static bool TryParseNameValuePair(string nameValuePair, out string key, out string value)
918 + {
919 + var split = nameValuePair.Split(BindPathSplit, 2);
920 +
921 + if (1 == split.Length)
922 + {
923 + key = null;
924 + value = null;
925 +
926 + return false;
927 + }
928 +
929 + key = split[0];
930 + value = split[1];
931 +
932 + return true;
933 + }
934 }
935
936 private class InputsAndOutputs
src/wix/WixToolset.Core/Librarian.cs
+5
@@ -99,6 +99,11 @@ namespace WixToolset.Core
99 {
100 var variableResolver = this.ServiceProvider.GetService<IVariableResolver>();
101
102 + foreach (var bindVariable in context.BindVariables)
103 + {
104 + variableResolver.AddVariable(null, bindVariable.Key, bindVariable.Value, false);
105 + }
106 +
107 var bindPaths = context.BindPaths.Where(b => b.Stage == BindStage.Normal).ToList();
108
109 foreach (var symbol in sections.SelectMany(s => s.Symbols))
src/wix/WixToolset.Core/LibraryContext.cs
+2
@@ -25,6 +25,8 @@ namespace WixToolset.Core
25
26 public IReadOnlyCollection<IBindPath> BindPaths { get; set; }
27
28 + public IDictionary<string, string> BindVariables { get; set; }
29 +
30 public IReadOnlyCollection<ILibrarianExtension> Extensions { get; set; }
31
32 public string LibraryId { get; set; }
src/wix/WixToolset.Core/Linker.cs
+1 -1
@@ -333,7 +333,7 @@ namespace WixToolset.Core
333 }
334 else if (!symbol.Overridable || (collidingSymbol.Overridable && symbol.Overridable))
335 {
336 - this.Messaging.Write(ErrorMessages.WixVariableCollision(symbol.SourceLineNumbers, id));
336 + this.Messaging.Write(ErrorMessages.BindVariableCollision(symbol.SourceLineNumbers, id));
337 }
338 }
339 else
src/wix/WixToolset.Core/LinkerErrors.cs
+6
@@ -6,6 +6,11 @@ namespace WixToolset.Core
6
7 internal static class LinkerErrors
8 {
9 + public static Message DuplicateBindPathVariableOnCommandLine(string argument, string bindName, string bindValue, string collisionValue)
10 + {
11 + return Message(null, Ids.DuplicateBindPathVariableOnCommandLine, "", argument, bindName, bindValue, collisionValue);
12 + }
13 +
14 public static Message OrphanedPayload(SourceLineNumber sourceLineNumbers, string payloadId)
15 {
16 return Message(sourceLineNumbers, Ids.OrphanedPayload, "Found orphaned Payload '{0}'. Make sure to reference it from a Package, the BootstrapperApplication, or the Bundle or move it into its own Fragment so it only gets linked in when actually used.", payloadId);
@@ -55,6 +60,7 @@ namespace WixToolset.Core
60 UnscheduledRollbackBoundary = 7004,
61 UncompressedPayloadInContainer = 7005,
62 BAContainerCannotContainRemotePayload = 7006,
63 + DuplicateBindPathVariableOnCommandLine = 7007,
64 } // last available is 7099. 7100 is WindowsInstallerBackendWarnings.
65 }
66 }
src/wix/WixToolset.Core/ResolveContext.cs
+3 -4
@@ -8,8 +8,7 @@ namespace WixToolset.Core
8 using WixToolset.Data;
9 using WixToolset.Extensibility;
10 using WixToolset.Extensibility.Data;
11 - using WixToolset.Extensibility.Services;
12 -
11 +
12 internal class ResolveContext : IResolveContext
13 {
14 internal ResolveContext(IServiceProvider serviceProvider)
@@ -21,6 +20,8 @@ namespace WixToolset.Core
20
21 public IReadOnlyCollection<IBindPath> BindPaths { get; set; }
22
23 + public IDictionary<string, string> BindVariables { get; set; }
24 +
25 public IReadOnlyCollection<IResolverExtension> Extensions { get; set; }
26
27 public IReadOnlyCollection<IExtensionData> ExtensionData { get; set; }
@@ -33,8 +34,6 @@ namespace WixToolset.Core
34
35 public IReadOnlyCollection<Localization> Localizations { get; set; }
36
36 - public IVariableResolver VariableResolver { get; set; }
37 -
37 public bool AllowUnresolvedVariables { get; set; }
38
39 public string OutputPath { get; set; }
src/wix/WixToolset.Core/Resolver.cs
+5
@@ -187,6 +187,11 @@ namespace WixToolset.Core
187 variableResolver.AddLocalization(localization);
188 }
189
190 + foreach (var bindVariable in context.BindVariables)
191 + {
192 + variableResolver.AddVariable(null, bindVariable.Key, bindVariable.Value, false);
193 + }
194 +
195 // Gather all the wix variables.
196 var wixVariableSymbols = context.IntermediateRepresentation.Sections.SelectMany(s => s.Symbols).OfType<WixVariableSymbol>();
197 foreach (var symbol in wixVariableSymbols)
src/wix/WixToolset.Core/VariableResolver.cs
+3 -6
@@ -23,7 +23,6 @@ namespace WixToolset.Core
23 /// </summary>
24 internal VariableResolver(IServiceProvider serviceProvider)
25 {
26 - this.ServiceProvider = serviceProvider;
26 this.Messaging = serviceProvider.GetService<IMessaging>();
27
28 this.locVariables = new Dictionary<string, BindVariable>();
@@ -31,8 +30,6 @@ namespace WixToolset.Core
30 this.localizedControls = new Dictionary<string, LocalizedControl>();
31 }
32
34 - private IServiceProvider ServiceProvider { get; }
35 -
33 private IMessaging Messaging { get; }
34
35 public int VariableCount => this.wixVariables.Count;
@@ -47,7 +44,7 @@ namespace WixToolset.Core
44 }
45 }
46
50 - foreach (KeyValuePair<string, LocalizedControl> localizedControl in localization.LocalizedControls)
47 + foreach (var localizedControl in localization.LocalizedControls)
48 {
49 if (!this.localizedControls.ContainsKey(localizedControl.Key))
50 {
@@ -62,7 +59,7 @@ namespace WixToolset.Core
59
60 if (!TryAddWixVariable(this.wixVariables, bindVariable))
61 {
65 - this.Messaging.Write(ErrorMessages.WixVariableCollision(sourceLineNumber, name));
62 + this.Messaging.Write(ErrorMessages.BindVariableCollision(sourceLineNumber, name));
63 }
64 }
65
@@ -166,7 +163,7 @@ namespace WixToolset.Core
163 }
164 else if ("wix" == variableNamespace && errorOnUnknown) // unresolved wix variable
165 {
169 - this.Messaging.Write(ErrorMessages.WixVariableUnknown(sourceLineNumbers, variableId));
166 + this.Messaging.Write(ErrorMessages.BindVariableUnknown(sourceLineNumbers, variableId));
167 }
168
169 start = parsed.Index + parsed.Length;
src/wix/WixToolset.Sdk/tools/wix.targets
+3 -1
@@ -41,7 +41,7 @@
41 </ItemGroup>
42
43 <ItemGroup>
44 - <AvailableItemName Include="BindPath;WixLibrary;WixExtension" />
44 + <AvailableItemName Include="BindPath;BindVariable;WixLibrary;WixExtension" />
45 </ItemGroup>
46
47 <!--
@@ -170,6 +170,7 @@
170 <LinkerBindInputPaths Include="$(LinkerBindInputPaths)" Condition=" '$(LinkerBindInputPaths)' != '' " />
171 <BindPath Include="$(BindPath)" Condition=" '$(BindPath)' != '' " />
172 <BindPath Include="@(BindInputPaths);@(LinkerBindInputPaths)" />
173 + <BindVariable Include="$(WixVariables)" Condition=" '$(WixVariables)' != '' " />
174 </ItemGroup>
175
176 <!--
@@ -601,6 +602,7 @@
602 Pedantic="$(Pedantic)"
603
604 BindPaths="@(BindPath)"
605 + BindVariables="@(BindVariable)"
606 BindFiles="$(BindFiles)"
607 BindTrackingFile="$(IntermediateOutputPath)$(BindTrackingFilePrefix)%(CultureGroup.Identity)$(BindTrackingFileExtension)"
608
src/wix/test/WixToolsetTest.Core/VariableResolverFixture.cs renamed
+2 -3
@@ -1,7 +1,6 @@
1 -
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
4 -namespace WixToolsetTest.CoreIntegration
3 +namespace WixToolsetTest.Core
4 {
5 using System.Collections.Generic;
6 using WixInternal.TestSupport;
@@ -26,7 +25,7 @@ namespace WixToolsetTest.CoreIntegration
25 { "ProductNameEditionVersion", new BindVariable() { Id = "ProductNameEditionVersion", Value = "!(loc.ProductNameEdition) v1.2.3" } },
26 };
27
29 - var localization = new Localization(0, null, "x-none", variables, new Dictionary<string,LocalizedControl>());
28 + var localization = new Localization(0, null, "x-none", variables, new Dictionary<string, LocalizedControl>());
29
30 variableResolver.AddLocalization(localization);
31
src/wix/test/WixToolsetTest.CoreIntegration/TestData/WixVariable/Bundle.wxs new
+11
@@ -0,0 +1,11 @@
1 +<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">
2 + <Bundle Name="MsiPackage-Bundle" Version="!(wix.VersionVar)" Manufacturer="Example Corporation" UpgradeCode="047730a5-30fe-4a62-a520-da9381b8226a">
3 + <BootstrapperApplication>
4 + <BootstrapperApplicationDll SourceFile="fakeba.dll" />
5 + </BootstrapperApplication>
6 +
7 + <Chain>
8 + <MsiPackage SourceFile="test1.msi" />
9 + </Chain>
10 + </Bundle>
11 +</Wix>
src/wix/test/WixToolsetTest.CoreIntegration/TestData/WixVariable/PackageWithBindVariableVersion.wxs new
+33
@@ -0,0 +1,33 @@
1 +<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">
2 + <Package Version="!(wix.VersionVar)"
3 + Name="MsiPackage"
4 + Manufacturer="Example Corporation"
5 + UpgradeCode="047730a5-30fe-4a62-a520-da9381b8226a"
6 + Scope="perUser">
7 + <MajorUpgrade DowngradeErrorMessage="Downgrade not allowed" />
8 + <MediaTemplate EmbedCab="true" />
9 +
10 + <Feature Id="ProductFeature" Title="Feature title">
11 + <ComponentGroupRef Id="ProductComponents" />
12 + </Feature>
13 +
14 + <WixVariable Id="VersionVar" Value="v1.1.1.1" Overridable="true" />
15 + </Package>
16 +
17 + <Fragment>
18 + <StandardDirectory Id="DesktopFolder">
19 + <Directory Id="INSTALLFOLDER" Name="MsiPackage !(wix.VersionVar) and !(bind.property.ProductVersion)" />
20 + </StandardDirectory>
21 + </Fragment>
22 +
23 + <Fragment>
24 + <ComponentGroup Id="ProductComponents" Directory="INSTALLFOLDER">
25 + <Component>
26 + <File Source="test.txt" />
27 + </Component>
28 + <Component Id="Shared.dll" Shared="yes">
29 + <File Name="Shared.dll" Source="test.txt" />
30 + </Component>
31 + </ComponentGroup>
32 + </Fragment>
33 +</Wix>
src/wix/test/WixToolsetTest.CoreIntegration/TestData/WixVariable/PackageWithReplaceableVersion.wxs new
+22
@@ -0,0 +1,22 @@
1 +<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">
2 + <Package Version="!(wix.VersionVar)"
3 + Name="MsiPackage"
4 + Manufacturer="Example Corporation"
5 + UpgradeCode="047730a5-30fe-4a62-a520-da9381b8226a"
6 + Scope="perUser">
7 + <MajorUpgrade DowngradeErrorMessage="Downgrade not allowed" />
8 + <MediaTemplate EmbedCab="true" />
9 +
10 + <Feature Id="ProductFeature" Title="Feature title">
11 + <Component Directory="INSTALLFOLDER">
12 + <File Source="!(wix.DataBindVariable)\test.txt" />
13 + </Component>
14 + </Feature>
15 + </Package>
16 +
17 + <Fragment>
18 + <StandardDirectory Id="DesktopFolder">
19 + <Directory Id="INSTALLFOLDER" Name="MsiPackage !(wix.VersionVar)" />
20 + </StandardDirectory>
21 + </Fragment>
22 +</Wix>
src/wix/test/WixToolsetTest.CoreIntegration/WixVariableFixture.cs new
+174
@@ -0,0 +1,174 @@
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 WixToolsetTest.CoreIntegration
4 +{
5 + using System.IO;
6 + using System.Linq;
7 + using System.Xml;
8 + using WixInternal.Core.TestPackage;
9 + using WixInternal.TestSupport;
10 + using Xunit;
11 +
12 + public class WixVariableFixture
13 + {
14 + [Fact]
15 + public void CanBuildMsiWithBindVariable()
16 + {
17 + var folder = TestData.Get(@"TestData");
18 +
19 + using (var fs = new DisposableFileSystem())
20 + {
21 + var baseFolder = fs.GetFolder();
22 + var intermediateFolder = Path.Combine(baseFolder, "obj");
23 + var msiPath = Path.Combine(baseFolder, "bin", "test1.msi");
24 +
25 + var result = WixRunner.Execute(new[]
26 + {
27 + "build",
28 + Path.Combine(folder, "WixVariable", "PackageWithReplaceableVersion.wxs"),
29 + "-bindpath", Path.Combine(folder, "SingleFile"/*, this part of the path is added as a bind variable: "data"*/),
30 + "-bindvariable", "DataBindVariable=data",
31 + "-bindvariable", "VersionVar=4.3.2.1",
32 + "-intermediateFolder", intermediateFolder,
33 + "-o", msiPath
34 + });
35 +
36 + result.AssertSuccess();
37 +
38 + var productVersion = GetProductVersionFromMsi(msiPath);
39 + Assert.Equal("4.3.2.1", productVersion);
40 + }
41 + }
42 +
43 + [Fact]
44 + public void CanBuildMsiWithDefaultedBindVariable()
45 + {
46 + var folder = TestData.Get(@"TestData");
47 +
48 + using (var fs = new DisposableFileSystem())
49 + {
50 + var baseFolder = fs.GetFolder();
51 + var intermediateFolder = Path.Combine(baseFolder, "obj");
52 + var msiPath = Path.Combine(baseFolder, "bin", "test1.msi");
53 +
54 + var result = WixRunner.Execute(new[]
55 + {
56 + "build",
57 + Path.Combine(folder, "WixVariable", "PackageWithBindVariableVersion.wxs"),
58 + "-bindpath", Path.Combine(folder, "SingleFile", "data"),
59 + "-intermediateFolder", intermediateFolder,
60 + "-o", msiPath
61 + });
62 +
63 + result.AssertSuccess();
64 +
65 + var productVersion = GetProductVersionFromMsi(msiPath);
66 + Assert.Equal("1.1.1.1", productVersion);
67 +
68 + var directoryTable = Query.QueryDatabase(msiPath, new[] { "Directory" }).OrderBy(s => s).ToArray();
69 + WixAssert.CompareLineByLine(new[]
70 + {
71 + "Directory:DesktopFolder\tTARGETDIR\tDesktop",
72 + "Directory:INSTALLFOLDER\tDesktopFolder\tfcuah1wu|MsiPackage v1.1.1.1 and 1.1.1.1",
73 + "Directory:TARGETDIR\t\tSourceDir"
74 + }, directoryTable);
75 + }
76 + }
77 +
78 + [Fact]
79 + public void CanBuildMsiWithPrefixedVersionBindVariable()
80 + {
81 + var folder = TestData.Get(@"TestData");
82 +
83 + using (var fs = new DisposableFileSystem())
84 + {
85 + var baseFolder = fs.GetFolder();
86 + var intermediateFolder = Path.Combine(baseFolder, "obj");
87 + var msiPath = Path.Combine(baseFolder, "bin", "test1.msi");
88 +
89 + var result = WixRunner.Execute(new[]
90 + {
91 + "build",
92 + Path.Combine(folder, "WixVariable", "PackageWithBindVariableVersion.wxs"),
93 + "-bindpath", Path.Combine(folder, "SingleFile", "data"),
94 + "-intermediateFolder", intermediateFolder,
95 + "-bindvariable", "VersionVar=v9.8.7.6",
96 + "-o", msiPath
97 + });
98 +
99 + result.AssertSuccess();
100 +
101 + var productVersion = GetProductVersionFromMsi(msiPath);
102 + Assert.Equal("9.8.7.6", productVersion);
103 +
104 + var directoryTable = Query.QueryDatabase(msiPath, new[] { "Directory" }).OrderBy(s => s).ToArray();
105 + WixAssert.CompareLineByLine(new[]
106 + {
107 + "Directory:DesktopFolder\tTARGETDIR\tDesktop",
108 + "Directory:INSTALLFOLDER\tDesktopFolder\tpja2bznq|MsiPackage v9.8.7.6 and 9.8.7.6",
109 + "Directory:TARGETDIR\t\tSourceDir"
110 + }, directoryTable);
111 + }
112 + }
113 +
114 + [Fact]
115 + public void CanBuildBundleWithBindVariable()
116 + {
117 + var folder = TestData.Get(@"TestData");
118 +
119 + using (var fs = new DisposableFileSystem())
120 + {
121 + var baseFolder = fs.GetFolder();
122 + var intermediateFolder = Path.Combine(baseFolder, "obj");
123 + var msiPath = Path.Combine(baseFolder, "bin", "test1.msi");
124 + var msi2Path = Path.Combine(baseFolder, "bin", "test2.msi");
125 + var bundlePath = Path.Combine(baseFolder, "bin", "bundle.exe");
126 +
127 + var result = WixRunner.Execute(new[]
128 + {
129 + "build",
130 + Path.Combine(folder, "WixVariable", "PackageWithReplaceableVersion.wxs"),
131 + "-bindpath", Path.Combine(folder, "SingleFile"/*, this part of the path is added as a bind variable: "data"*/),
132 + "-bv", "DataBindVariable=data",
133 + "-bv", "VersionVar=255.255.65535",
134 + "-intermediateFolder", intermediateFolder,
135 + "-o", msiPath
136 + });
137 +
138 + result.AssertSuccess();
139 +
140 + var result3 = WixRunner.Execute(new[]
141 +{
142 + "build",
143 + Path.Combine(folder, "WixVariable", "Bundle.wxs"),
144 + "-bindpath", Path.Combine(folder, "SimpleBundle", "data"),
145 + "-bindpath", Path.Combine(baseFolder, "bin"),
146 + "-intermediateFolder", intermediateFolder,
147 + "-bv", "VersionVar=2022.3.9-preview.0-build.5+0987654321abcdef1234567890",
148 + "-o", bundlePath
149 + });
150 +
151 + result3.AssertSuccess();
152 +
153 + var productVersion = GetProductVersionFromMsi(msiPath);
154 + WixAssert.StringEqual("255.255.65535", productVersion);
155 +
156 + var extractResult = BundleExtractor.ExtractAllContainers(null, bundlePath, Path.Combine(baseFolder, "ba"), Path.Combine(baseFolder, "attached"), Path.Combine(baseFolder, "extract"));
157 + extractResult.AssertSuccess();
158 +
159 + var bundleVersion = extractResult.SelectManifestNodes("/burn:BurnManifest/burn:Registration/@Version")
160 + .Cast<XmlAttribute>()
161 + .Single();
162 + WixAssert.StringEqual("2022.3.9-preview.0-build.5+0987654321abcdef1234567890", bundleVersion.Value);
163 + }
164 + }
165 +
166 + private static string GetProductVersionFromMsi(string msiPath)
167 + {
168 + var propertyTable = Query.QueryDatabase(msiPath, new[] { "Property" }).Select(r => r.Split('\t')).ToDictionary(r => r[0].Substring("Property:".Length), r => r[1]);
169 + Assert.True(propertyTable.TryGetValue("ProductVersion", out var productVersion));
170 +
171 + return productVersion;
172 + }
173 + }
174 +}
src/wix/test/WixToolsetTest.Sdk/MsbuildFixture.cs
+64 -28
@@ -229,6 +229,42 @@ namespace WixToolsetTest.Sdk
229 }
230 }
231
232 + [Theory]
233 + [InlineData(BuildSystem.DotNetCoreSdk)]
234 + [InlineData(BuildSystem.MSBuild)]
235 + [InlineData(BuildSystem.MSBuild64)]
236 + public void CanBuildMsiPackageWithBindVariables(BuildSystem buildSystem)
237 + {
238 + var sourceFolder = TestData.Get("TestData", "MsiPackageWithBindVariables");
239 +
240 + var baseFolder = String.Empty;
241 +
242 + using (var fs = new TestDataFolderFileSystem())
243 + {
244 + fs.Initialize(sourceFolder);
245 + baseFolder = fs.BaseFolder;
246 +
247 + var binFolder = Path.Combine(baseFolder, @"bin\");
248 + var projectPath = Path.Combine(baseFolder, "MsiPackageWithBindVariables.wixproj");
249 +
250 + var result = MsbuildUtilities.BuildProject(buildSystem, projectPath, new[] {
251 + MsbuildUtilities.GetQuotedPropertySwitch(buildSystem, "WixMSBuildProps", MsbuildFixture.WixPropsPath)
252 + });
253 + result.AssertSuccess();
254 +
255 + var paths = Directory.EnumerateFiles(binFolder, @"*.*", SearchOption.AllDirectories)
256 + .Select(s => s.Substring(baseFolder.Length + 1))
257 + .OrderBy(s => s)
258 + .ToArray();
259 + WixAssert.CompareLineByLine(new[]
260 + {
261 + @"bin\Release\en-US\cab1.cab",
262 + @"bin\Release\en-US\MsiPackageWithBindVariables.msi",
263 + @"bin\Release\en-US\MsiPackageWithBindVariables.wixpdb",
264 + }, paths);
265 + }
266 + }
267 +
268 [Theory]
269 [InlineData(BuildSystem.DotNetCoreSdk)]
270 [InlineData(BuildSystem.MSBuild)]
@@ -299,33 +335,6 @@ namespace WixToolsetTest.Sdk
335 }
336 }
337
302 - private void AssertWixpdb(BuildSystem buildSystem, string debugType, string[] expectedOutputFiles)
303 - {
304 - var sourceFolder = TestData.Get(@"TestData\SimpleMsiPackage\MsiPackage");
305 -
306 - using (var fs = new TestDataFolderFileSystem())
307 - {
308 - fs.Initialize(sourceFolder);
309 - var baseFolder = fs.BaseFolder;
310 - var binFolder = Path.Combine(baseFolder, @"bin\");
311 - var projectPath = Path.Combine(baseFolder, "MsiPackage.wixproj");
312 -
313 - var result = MsbuildUtilities.BuildProject(buildSystem, projectPath, new[]
314 - {
315 - MsbuildUtilities.GetQuotedPropertySwitch(buildSystem, "WixMSBuildProps", MsbuildFixture.WixPropsPath),
316 - debugType == null ? String.Empty : $"-p:DebugType={debugType}",
317 - "-p:SuppressValidation=true"
318 - });
319 - result.AssertSuccess();
320 -
321 - var paths = Directory.EnumerateFiles(binFolder, @"*.*", SearchOption.AllDirectories)
322 - .Select(s => s.Substring(baseFolder.Length + 1))
323 - .OrderBy(s => s)
324 - .ToArray();
325 - WixAssert.CompareLineByLine(expectedOutputFiles, paths);
326 - }
327 - }
328 -
338 [Theory]
339 [InlineData(BuildSystem.DotNetCoreSdk)]
340 [InlineData(BuildSystem.MSBuild)]
@@ -474,7 +483,7 @@ namespace WixToolsetTest.Sdk
483 var path = Directory.EnumerateFiles(binFolder, @"*.*", SearchOption.AllDirectories)
484 .Select(s => s.Substring(baseFolder.Length + 1))
485 .Single();
477 - WixAssert.StringEqual(@"bin\x86\Release\SimpleWixlib.wixlib", path);
486 + WixAssert.StringEqual(@"bin\Release\SimpleWixlib.wixlib", path);
487 }
488 }
489
@@ -637,6 +646,33 @@ namespace WixToolsetTest.Sdk
646 }
647 }
648
649 + private void AssertWixpdb(BuildSystem buildSystem, string debugType, string[] expectedOutputFiles)
650 + {
651 + var sourceFolder = TestData.Get(@"TestData\SimpleMsiPackage\MsiPackage");
652 +
653 + using (var fs = new TestDataFolderFileSystem())
654 + {
655 + fs.Initialize(sourceFolder);
656 + var baseFolder = fs.BaseFolder;
657 + var binFolder = Path.Combine(baseFolder, @"bin\");
658 + var projectPath = Path.Combine(baseFolder, "MsiPackage.wixproj");
659 +
660 + var result = MsbuildUtilities.BuildProject(buildSystem, projectPath, new[]
661 + {
662 + MsbuildUtilities.GetQuotedPropertySwitch(buildSystem, "WixMSBuildProps", MsbuildFixture.WixPropsPath),
663 + debugType == null ? String.Empty : $"-p:DebugType={debugType}",
664 + "-p:SuppressValidation=true"
665 + });
666 + result.AssertSuccess();
667 +
668 + var paths = Directory.EnumerateFiles(binFolder, @"*.*", SearchOption.AllDirectories)
669 + .Select(s => s.Substring(baseFolder.Length + 1))
670 + .OrderBy(s => s)
671 + .ToArray();
672 + WixAssert.CompareLineByLine(expectedOutputFiles, paths);
673 + }
674 + }
675 +
676 private static string ExtractWarningFromMessage(string message, string baseFolder)
677 {
678 const string prefix = ": warning ";
src/wix/test/WixToolsetTest.Sdk/TestData/MsiPackageWithBindVariables/MsiPackageWithBindVariables.wixproj new
+16
@@ -0,0 +1,16 @@
1 +<Project>
2 + <Import Project="$(WixMSBuildProps)" />
3 + <PropertyGroup>
4 + <WixVariables>DataFolderVar=data</WixVariables>
5 + </PropertyGroup>
6 +
7 + <ItemGroup>
8 + <Compile Include="Package.wxs" />
9 +
10 + <EmbeddedResource Include="Package.en-us.wxl" />
11 +
12 + <BindVariable Include="VersionVar=1.2.3" />
13 + </ItemGroup>
14 +
15 + <Import Project="$(WixTargetsPath)" />
16 +</Project>
src/wix/test/WixToolsetTest.Sdk/TestData/MsiPackageWithBindVariables/Package.en-us.wxl new
+11
@@ -0,0 +1,11 @@
1 +<?xml version="1.0" encoding="utf-8"?>
2 +
3 +<!--
4 +This file contains the declaration of all the localizable strings.
5 +-->
6 +<WixLocalization xmlns="http://wixtoolset.org/schemas/v4/wxl" Culture="en-US">
7 +
8 + <String Id="DowngradeError" Value="A newer version of [ProductName] is already installed." />
9 + <String Id="FeatureTitle" Value="MsiPackage" />
10 +
11 +</WixLocalization>
src/wix/test/WixToolsetTest.Sdk/TestData/MsiPackageWithBindVariables/Package.wxs new
+17
@@ -0,0 +1,17 @@
1 +<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">
2 + <Package Name="MsiPackage" Language="1033" Version="!(wix.VersionVar)" Manufacturer="Example Corporation" UpgradeCode="047730a5-30fe-4a62-a520-da9381b8226a">
3 + <MajorUpgrade DowngradeErrorMessage="!(loc.DowngradeError)" />
4 +
5 + <Feature Id="ProductFeature" Title="!(loc.FeatureTitle)">
6 + <Component Directory="INSTALLFOLDER">
7 + <File Source="!(wix.DataFolderVar)\test.txt" />
8 + </Component>
9 + </Feature>
10 + </Package>
11 +
12 + <Fragment>
13 + <StandardDirectory Id="ProgramFiles6432Folder">
14 + <Directory Id="INSTALLFOLDER" Name="MsiPackage" />
15 + </StandardDirectory>
16 + </Fragment>
17 +</Wix>
src/wix/test/WixToolsetTest.Sdk/TestData/MsiPackageWithBindVariables/data/test.txt new
+1
@@ -0,0 +1 @@
1 +This is test.txt.
\ No newline at end of file
src/wix/test/WixToolsetTest.Sdk/TestData/Wixlib/SimpleWixlib/Library.wxs
+1 -1
@@ -8,7 +8,7 @@
8 <Fragment>
9 <ComponentGroup Id="ProductComponents" Directory="WixLibFolder">
10 <Component Id="TextFile" Guid="2D93B748-4926-4185-BC84-9F1D6883AF20">
11 - <File Source="Library.txt" />
11 + <File Source="!(wix.SubfolderVar)\Library.txt" />
12 </Component>
13 </ComponentGroup>
14 </Fragment>
src/wix/test/WixToolsetTest.Sdk/TestData/Wixlib/SimpleWixlib/SimpleWixlib.wixproj
+3 -26
@@ -1,34 +1,11 @@
1 <?xml version="1.0" encoding="utf-8"?>
2 -<Project ToolsVersion="15.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
2 +<Project>
3 <Import Project="$(WixMSBuildProps)" />
4 +
5 <PropertyGroup>
5 - <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
6 - <Platform Condition=" '$(Platform)' == '' ">x86</Platform>
6 <OutputType>Library</OutputType>
7 <BindFiles>true</BindFiles>
9 - </PropertyGroup>
10 -
11 - <PropertyGroup>
12 - <ProjectGuid>{9F84998B-7F45-4CB3-8795-915801DBBB74}</ProjectGuid>
13 - </PropertyGroup>
14 -
15 - <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
16 - <PlatformName>$(Platform)</PlatformName>
17 - <OutputPath>bin\$(Platform)\$(Configuration)\</OutputPath>
18 - <DefineConstants>Debug</DefineConstants>
19 - </PropertyGroup>
20 - <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
21 - <PlatformName>$(Platform)</PlatformName>
22 - <OutputPath>bin\$(Platform)\$(Configuration)\</OutputPath>
23 - </PropertyGroup>
24 - <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x64' ">
25 - <PlatformName>$(Platform)</PlatformName>
26 - <OutputPath>bin\$(Platform)\$(Configuration)\</OutputPath>
27 - <DefineConstants>Debug</DefineConstants>
28 - </PropertyGroup>
29 - <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x64' ">
30 - <PlatformName>$(Platform)</PlatformName>
31 - <OutputPath>bin\$(Platform)\$(Configuration)\</OutputPath>
8 + <WixVariables>SubfolderVar=subfolder</WixVariables>
9 </PropertyGroup>
10
11 <ItemGroup>
src/wix/test/WixToolsetTest.Sdk/TestData/Wixlib/SimpleWixlib/data/subfolder/Library.txt renamed