diff options
26 files changed, 926 insertions, 278 deletions
diff --git a/src/api/wix/WixToolset.Data/ErrorMessages.cs b/src/api/wix/WixToolset.Data/ErrorMessages.cs index 80738f5e..a833452d 100644 --- a/src/api/wix/WixToolset.Data/ErrorMessages.cs +++ b/src/api/wix/WixToolset.Data/ErrorMessages.cs | |||
@@ -1184,6 +1184,11 @@ namespace WixToolset.Data | |||
1184 | return Message(null, Ids.InvalidCommandLineFileName, "Invalid file name specified on the command line: '{0}'. Error message: '{1}'", fileName, error); | 1184 | return Message(null, Ids.InvalidCommandLineFileName, "Invalid file name specified on the command line: '{0}'. Error message: '{1}'", fileName, error); |
1185 | } | 1185 | } |
1186 | 1186 | ||
1187 | public static Message InvalidBundleCondition(SourceLineNumber sourceLineNumbers, string elementName, string attributeName, string condition) | ||
1188 | { | ||
1189 | return Message(sourceLineNumbers, Ids.InvalidBundleCondition, "The {0}/@{1} attribute's value '{2}' is not a valid bundle condition.", elementName, attributeName, condition); | ||
1190 | } | ||
1191 | |||
1187 | public static Message InvalidDateTimeFormat(SourceLineNumber sourceLineNumbers, string elementName, string attributeName, string value) | 1192 | public static Message InvalidDateTimeFormat(SourceLineNumber sourceLineNumbers, string elementName, string attributeName, string value) |
1188 | { | 1193 | { |
1189 | return Message(sourceLineNumbers, Ids.InvalidDateTimeFormat, "The {0}/@{1} attribute's value '{2}' is not a valid date/time value. A date/time value should follow the format YYYY-MM-DDTHH:mm:ss.", elementName, attributeName, value); | 1194 | return Message(sourceLineNumbers, Ids.InvalidDateTimeFormat, "The {0}/@{1} attribute's value '{2}' is not a valid date/time value. A date/time value should follow the format YYYY-MM-DDTHH:mm:ss.", elementName, attributeName, value); |
@@ -2686,6 +2691,7 @@ namespace WixToolset.Data | |||
2686 | MultiplePackagePayloads3 = 406, | 2691 | MultiplePackagePayloads3 = 406, |
2687 | MissingPackagePayload = 407, | 2692 | MissingPackagePayload = 407, |
2688 | ExpectedAttributeWithoutOtherAttributes = 408, | 2693 | ExpectedAttributeWithoutOtherAttributes = 408, |
2694 | InvalidBundleCondition = 409, | ||
2689 | } | 2695 | } |
2690 | } | 2696 | } |
2691 | } | 2697 | } |
diff --git a/src/api/wix/WixToolset.Data/WarningMessages.cs b/src/api/wix/WixToolset.Data/WarningMessages.cs index b749bcf4..f555fd93 100644 --- a/src/api/wix/WixToolset.Data/WarningMessages.cs +++ b/src/api/wix/WixToolset.Data/WarningMessages.cs | |||
@@ -593,6 +593,11 @@ namespace WixToolset.Data | |||
593 | return Message(null, Ids.UnableToResetAcls, "Unable to reset acls on destination files. Exception detail: {0}", error); | 593 | return Message(null, Ids.UnableToResetAcls, "Unable to reset acls on destination files. Exception detail: {0}", error); |
594 | } | 594 | } |
595 | 595 | ||
596 | public static Message UnavailableBundleConditionVariable(SourceLineNumber sourceLineNumbers, string elementName, string attributeName, string variable, string illegalValueList) | ||
597 | { | ||
598 | return Message(sourceLineNumbers, Ids.UnavailableBundleConditionVariable, "{0}/@{1} contains the built-in Variable '{2}', which is not available when it is evaluated. (Unavailable Variables are: {3}.). Rewrite the condition to avoid Variables that are never valid during its evaluation.", elementName, attributeName, variable, illegalValueList); | ||
599 | } | ||
600 | |||
596 | public static Message UnclearShortcut(SourceLineNumber sourceLineNumbers, string shortcutId, string fileId, string componentId) | 601 | public static Message UnclearShortcut(SourceLineNumber sourceLineNumbers, string shortcutId, string fileId, string componentId) |
597 | { | 602 | { |
598 | return Message(sourceLineNumbers, Ids.UnclearShortcut, "Because it is an advertised shortcut, the target of shortcut '{0}' will be the keypath of component '{2}' rather than parent file '{1}'. To eliminate this warning, you can (1) make the Shortcut element a child of the File element that is the keypath of component '{2}', (2) make file '{1}' the keypath of component '{2}', or (3) remove the @Advertise attribute so the shortcut is a non-advertised shortcut.", shortcutId, fileId, componentId); | 603 | return Message(sourceLineNumbers, Ids.UnclearShortcut, "Because it is an advertised shortcut, the target of shortcut '{0}' will be the keypath of component '{2}' rather than parent file '{1}'. To eliminate this warning, you can (1) make the Shortcut element a child of the File element that is the keypath of component '{2}', (2) make file '{1}' the keypath of component '{2}', or (3) remove the @Advertise attribute so the shortcut is a non-advertised shortcut.", shortcutId, fileId, componentId); |
@@ -804,6 +809,7 @@ namespace WixToolset.Data | |||
804 | DetectConditionRecommended = 1153, | 809 | DetectConditionRecommended = 1153, |
805 | CollidingModularizationTypes = 1156, | 810 | CollidingModularizationTypes = 1156, |
806 | InvalidEnvironmentVariable = 1157, | 811 | InvalidEnvironmentVariable = 1157, |
812 | UnavailableBundleConditionVariable = 1159, | ||
807 | } | 813 | } |
808 | } | 814 | } |
809 | } | 815 | } |
diff --git a/src/api/wix/WixToolset.Extensibility/Data/BundleConditionPhase.cs b/src/api/wix/WixToolset.Extensibility/Data/BundleConditionPhase.cs new file mode 100644 index 00000000..6d876bcc --- /dev/null +++ b/src/api/wix/WixToolset.Extensibility/Data/BundleConditionPhase.cs | |||
@@ -0,0 +1,35 @@ | |||
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.Extensibility.Data | ||
4 | { | ||
5 | /// <summary> | ||
6 | /// The Burn execution phase during which a Condition will be evaluated. | ||
7 | /// </summary> | ||
8 | public enum BundleConditionPhase | ||
9 | { | ||
10 | /// <summary> | ||
11 | /// Condition is evaluated by the engine before loading the BootstrapperApplication (Bundle/@Condition). | ||
12 | /// </summary> | ||
13 | Startup, | ||
14 | |||
15 | /// <summary> | ||
16 | /// Condition is evaluated during Detect (ExePackage/@DetectCondition). | ||
17 | /// </summary> | ||
18 | Detect, | ||
19 | |||
20 | /// <summary> | ||
21 | /// Condition is evaluated during Plan (ExePackage/@InstallCondition). | ||
22 | /// </summary> | ||
23 | Plan, | ||
24 | |||
25 | /// <summary> | ||
26 | /// Condition is evaluated during Apply (MsiProperty/@Condition). | ||
27 | /// </summary> | ||
28 | Execute, | ||
29 | |||
30 | /// <summary> | ||
31 | /// Condition is evaluated after Apply. | ||
32 | /// </summary> | ||
33 | Shutdown, | ||
34 | } | ||
35 | } | ||
diff --git a/src/api/wix/WixToolset.Extensibility/Services/IBackendHelper.cs b/src/api/wix/WixToolset.Extensibility/Services/IBackendHelper.cs index 29b8f8e6..23ad44f5 100644 --- a/src/api/wix/WixToolset.Extensibility/Services/IBackendHelper.cs +++ b/src/api/wix/WixToolset.Extensibility/Services/IBackendHelper.cs | |||
@@ -74,17 +74,6 @@ namespace WixToolset.Extensibility.Services | |||
74 | string GenerateIdentifier(string prefix, params string[] args); | 74 | string GenerateIdentifier(string prefix, params string[] args); |
75 | 75 | ||
76 | /// <summary> | 76 | /// <summary> |
77 | /// Validates path is relative and canonicalizes it. | ||
78 | /// For example, "a\..\c\.\d.exe" => "c\d.exe". | ||
79 | /// </summary> | ||
80 | /// <param name="sourceLineNumbers"></param> | ||
81 | /// <param name="elementName"></param> | ||
82 | /// <param name="attributeName"></param> | ||
83 | /// <param name="relativePath"></param> | ||
84 | /// <returns>The original value if not relative, otherwise the canonicalized relative path.</returns> | ||
85 | string GetCanonicalRelativePath(SourceLineNumber sourceLineNumbers, string elementName, string attributeName, string relativePath); | ||
86 | |||
87 | /// <summary> | ||
88 | /// Gets a valid code page from the given web name or integer value. | 77 | /// Gets a valid code page from the given web name or integer value. |
89 | /// </summary> | 78 | /// </summary> |
90 | /// <param name="value">A code page web name or integer value as a string.</param> | 79 | /// <param name="value">A code page web name or integer value as a string.</param> |
diff --git a/src/api/wix/WixToolset.Extensibility/Services/IBundleValidator.cs b/src/api/wix/WixToolset.Extensibility/Services/IBundleValidator.cs new file mode 100644 index 00000000..fc88a443 --- /dev/null +++ b/src/api/wix/WixToolset.Extensibility/Services/IBundleValidator.cs | |||
@@ -0,0 +1,56 @@ | |||
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.Extensibility.Services | ||
4 | { | ||
5 | using WixToolset.Data; | ||
6 | using WixToolset.Extensibility.Data; | ||
7 | |||
8 | /// <summary> | ||
9 | /// Interface provided to help with bundle validation. | ||
10 | /// </summary> | ||
11 | public interface IBundleValidator | ||
12 | { | ||
13 | |||
14 | /// <summary> | ||
15 | /// Validates path is relative and canonicalizes it. | ||
16 | /// For example, "a\..\c\.\d.exe" => "c\d.exe". | ||
17 | /// </summary> | ||
18 | /// <param name="sourceLineNumbers"></param> | ||
19 | /// <param name="elementName"></param> | ||
20 | /// <param name="attributeName"></param> | ||
21 | /// <param name="relativePath"></param> | ||
22 | /// <returns>The original value if not relative, otherwise the canonicalized relative path.</returns> | ||
23 | string GetCanonicalRelativePath(SourceLineNumber sourceLineNumbers, string elementName, string attributeName, string relativePath); | ||
24 | |||
25 | /// <summary> | ||
26 | /// Validates an MsiProperty name value and displays an error for an illegal value. | ||
27 | /// </summary> | ||
28 | /// <param name="sourceLineNumbers"></param> | ||
29 | /// <param name="elementName"></param> | ||
30 | /// <param name="attributeName"></param> | ||
31 | /// <param name="propertyName"></param> | ||
32 | /// <returns>Whether the name is valid.</returns> | ||
33 | bool ValidateBundleMsiPropertyName(SourceLineNumber sourceLineNumbers, string elementName, string attributeName, string propertyName); | ||
34 | |||
35 | /// <summary> | ||
36 | /// Validates a Bundle variable name and displays an error for an illegal value. | ||
37 | /// </summary> | ||
38 | /// <param name="sourceLineNumbers"></param> | ||
39 | /// <param name="elementName"></param> | ||
40 | /// <param name="attributeName"></param> | ||
41 | /// <param name="variableName"></param> | ||
42 | /// <returns>Whether the name is valid.</returns> | ||
43 | bool ValidateBundleVariableName(SourceLineNumber sourceLineNumbers, string elementName, string attributeName, string variableName); | ||
44 | |||
45 | /// <summary> | ||
46 | /// Validates a bundle condition and displays an error for an illegal value. | ||
47 | /// </summary> | ||
48 | /// <param name="sourceLineNumbers"></param> | ||
49 | /// <param name="elementName"></param> | ||
50 | /// <param name="attributeName"></param> | ||
51 | /// <param name="condition"></param> | ||
52 | /// <param name="phase"></param> | ||
53 | /// <returns>Whether the condition is valid.</returns> | ||
54 | bool ValidateBundleCondition(SourceLineNumber sourceLineNumbers, string elementName, string attributeName, string condition, BundleConditionPhase phase); | ||
55 | } | ||
56 | } | ||
diff --git a/src/api/wix/WixToolset.Extensibility/Services/IBurnBackendHelper.cs b/src/api/wix/WixToolset.Extensibility/Services/IBurnBackendHelper.cs index ef5fcc65..1b6a2828 100644 --- a/src/api/wix/WixToolset.Extensibility/Services/IBurnBackendHelper.cs +++ b/src/api/wix/WixToolset.Extensibility/Services/IBurnBackendHelper.cs | |||
@@ -7,7 +7,7 @@ namespace WixToolset.Extensibility.Services | |||
7 | /// <summary> | 7 | /// <summary> |
8 | /// Interface provided to help Burn backend extensions. | 8 | /// Interface provided to help Burn backend extensions. |
9 | /// </summary> | 9 | /// </summary> |
10 | public interface IBurnBackendHelper : IBackendHelper | 10 | public interface IBurnBackendHelper : IBackendHelper, IBundleValidator |
11 | { | 11 | { |
12 | /// <summary> | 12 | /// <summary> |
13 | /// Adds the given XML to the BootstrapperApplicationData manifest. | 13 | /// Adds the given XML to the BootstrapperApplicationData manifest. |
diff --git a/src/api/wix/WixToolset.Extensibility/Services/IParseHelper.cs b/src/api/wix/WixToolset.Extensibility/Services/IParseHelper.cs index fbe5aae4..de2c6f9f 100644 --- a/src/api/wix/WixToolset.Extensibility/Services/IParseHelper.cs +++ b/src/api/wix/WixToolset.Extensibility/Services/IParseHelper.cs | |||
@@ -13,7 +13,7 @@ namespace WixToolset.Extensibility.Services | |||
13 | /// <summary> | 13 | /// <summary> |
14 | /// Interface provided to help compiler extensions parse. | 14 | /// Interface provided to help compiler extensions parse. |
15 | /// </summary> | 15 | /// </summary> |
16 | public interface IParseHelper | 16 | public interface IParseHelper : IBundleValidator |
17 | { | 17 | { |
18 | /// <summary> | 18 | /// <summary> |
19 | /// Creates a version 3 name-based UUID. | 19 | /// Creates a version 3 name-based UUID. |
@@ -323,17 +323,6 @@ namespace WixToolset.Extensibility.Services | |||
323 | YesNoDefaultType GetAttributeYesNoDefaultValue(SourceLineNumber sourceLineNumbers, XAttribute attribute); | 323 | YesNoDefaultType GetAttributeYesNoDefaultValue(SourceLineNumber sourceLineNumbers, XAttribute attribute); |
324 | 324 | ||
325 | /// <summary> | 325 | /// <summary> |
326 | /// Validates path is relative and canonicalizes it. | ||
327 | /// For example, "a\..\c\.\d.exe" => "c\d.exe". | ||
328 | /// </summary> | ||
329 | /// <param name="sourceLineNumbers"></param> | ||
330 | /// <param name="elementName"></param> | ||
331 | /// <param name="attributeName"></param> | ||
332 | /// <param name="relativePath"></param> | ||
333 | /// <returns>The original value if not relative, otherwise the canonicalized relative path.</returns> | ||
334 | string GetCanonicalRelativePath(SourceLineNumber sourceLineNumbers, string elementName, string attributeName, string relativePath); | ||
335 | |||
336 | /// <summary> | ||
337 | /// Gets a source line number for an element. | 326 | /// Gets a source line number for an element. |
338 | /// </summary> | 327 | /// </summary> |
339 | /// <param name="element">Element to get source line number.</param> | 328 | /// <param name="element">Element to get source line number.</param> |
diff --git a/src/burn/test/BurnUnitTest/VariableTest.cpp b/src/burn/test/BurnUnitTest/VariableTest.cpp index 53105e69..d0361c0e 100644 --- a/src/burn/test/BurnUnitTest/VariableTest.cpp +++ b/src/burn/test/BurnUnitTest/VariableTest.cpp | |||
@@ -381,6 +381,7 @@ namespace Bootstrapper | |||
381 | Assert::True(EvaluateConditionHelper(&variables, L"(PROP3 = \"NOT\" OR PROP1 = \"VAL1\") AND PROP2 = \"VAL2\"")); | 381 | Assert::True(EvaluateConditionHelper(&variables, L"(PROP3 = \"NOT\" OR PROP1 = \"VAL1\") AND PROP2 = \"VAL2\"")); |
382 | Assert::True(EvaluateConditionHelper(&variables, L"PROP3 = \"NOT\" OR (PROP1 = \"VAL1\" AND PROP2 = \"VAL2\")")); | 382 | Assert::True(EvaluateConditionHelper(&variables, L"PROP3 = \"NOT\" OR (PROP1 = \"VAL1\" AND PROP2 = \"VAL2\")")); |
383 | 383 | ||
384 | Assert::True(EvaluateFailureConditionHelper(&variables, L"")); | ||
384 | Assert::True(EvaluateFailureConditionHelper(&variables, L"=")); | 385 | Assert::True(EvaluateFailureConditionHelper(&variables, L"=")); |
385 | Assert::True(EvaluateFailureConditionHelper(&variables, L"(PROP1")); | 386 | Assert::True(EvaluateFailureConditionHelper(&variables, L"(PROP1")); |
386 | Assert::True(EvaluateFailureConditionHelper(&variables, L"(PROP1 = \"")); | 387 | Assert::True(EvaluateFailureConditionHelper(&variables, L"(PROP1 = \"")); |
diff --git a/src/ext/Bal/test/WixToolsetTest.Bal/BalExtensionFixture.cs b/src/ext/Bal/test/WixToolsetTest.Bal/BalExtensionFixture.cs index ef4ee49a..9aea8c1d 100644 --- a/src/ext/Bal/test/WixToolsetTest.Bal/BalExtensionFixture.cs +++ b/src/ext/Bal/test/WixToolsetTest.Bal/BalExtensionFixture.cs | |||
@@ -2,6 +2,7 @@ | |||
2 | 2 | ||
3 | namespace WixToolsetTest.Bal | 3 | namespace WixToolsetTest.Bal |
4 | { | 4 | { |
5 | using System; | ||
5 | using System.IO; | 6 | using System.IO; |
6 | using System.Linq; | 7 | using System.Linq; |
7 | using System.Xml; | 8 | using System.Xml; |
@@ -138,20 +139,33 @@ namespace WixToolsetTest.Bal | |||
138 | { | 139 | { |
139 | var baseFolder = fs.GetFolder(); | 140 | var baseFolder = fs.GetFolder(); |
140 | var bundleFile = Path.Combine(baseFolder, "bin", "test.exe"); | 141 | var bundleFile = Path.Combine(baseFolder, "bin", "test.exe"); |
141 | var bundleSourceFolder = TestData.Get(@"TestData\Overridable"); | 142 | var bundleSourceFolder = TestData.Get(@"TestData"); |
142 | var intermediateFolder = Path.Combine(baseFolder, "obj"); | 143 | var intermediateFolder = Path.Combine(baseFolder, "obj"); |
143 | var baFolderPath = Path.Combine(baseFolder, "ba"); | 144 | var baFolderPath = Path.Combine(baseFolder, "ba"); |
144 | var extractFolderPath = Path.Combine(baseFolder, "extract"); | 145 | var extractFolderPath = Path.Combine(baseFolder, "extract"); |
145 | 146 | ||
146 | var compileResult = WixRunner.Execute(new[] | 147 | var result = WixRunner.Execute(new[] |
147 | { | 148 | { |
148 | "build", | 149 | "build", |
149 | Path.Combine(bundleSourceFolder, "WrongCaseBundle.wxs"), | 150 | Path.Combine(bundleSourceFolder, "Overridable", "WrongCaseBundle.wxs"), |
151 | "-loc", Path.Combine(bundleSourceFolder, "Overridable", "WrongCaseBundle.wxl"), | ||
152 | "-bindpath", Path.Combine(bundleSourceFolder, "WixStdBa", "Data"), | ||
150 | "-ext", TestData.Get(@"WixToolset.Bal.wixext.dll"), | 153 | "-ext", TestData.Get(@"WixToolset.Bal.wixext.dll"), |
151 | "-intermediateFolder", intermediateFolder, | 154 | "-intermediateFolder", intermediateFolder, |
152 | "-o", bundleFile, | 155 | "-o", bundleFile, |
153 | }); | 156 | }); |
154 | Assert.Equal((int)BalErrors.Ids.NonUpperCaseOverridableVariable, compileResult.ExitCode); | 157 | |
158 | Assert.InRange(result.ExitCode, 2, Int32.MaxValue); | ||
159 | |||
160 | var messages = result.Messages.Select(m => m.ToString()).ToList(); | ||
161 | messages.Sort(); | ||
162 | |||
163 | WixAssert.CompareLineByLine(new[] | ||
164 | { | ||
165 | "bal:Condition/@Condition contains the built-in Variable 'WixBundleAction', which is not available when it is evaluated. (Unavailable Variables are: 'WixBundleAction'.). Rewrite the condition to avoid Variables that are never valid during its evaluation.", | ||
166 | "Overridable variable 'Test1' must be 'TEST1' with Bundle/@CommandLineVariables value 'upperCase'.", | ||
167 | "The *Package/@bal:DisplayInternalUICondition attribute's value '=' is not a valid bundle condition.", | ||
168 | }, messages.ToArray()); | ||
155 | } | 169 | } |
156 | } | 170 | } |
157 | } | 171 | } |
diff --git a/src/ext/Bal/test/WixToolsetTest.Bal/TestData/Overridable/WrongCaseBundle.wxl b/src/ext/Bal/test/WixToolsetTest.Bal/TestData/Overridable/WrongCaseBundle.wxl new file mode 100644 index 00000000..223a7874 --- /dev/null +++ b/src/ext/Bal/test/WixToolsetTest.Bal/TestData/Overridable/WrongCaseBundle.wxl | |||
@@ -0,0 +1,4 @@ | |||
1 | <WixLocalization xmlns="http://wixtoolset.org/schemas/v4/wxl" Culture="en-US"> | ||
2 | <String Id="NonsenseDetectCondition">WixBundleAction = 4</String> | ||
3 | <String Id="NonsensePlanCondition">=</String> | ||
4 | </WixLocalization> | ||
diff --git a/src/ext/Bal/test/WixToolsetTest.Bal/TestData/Overridable/WrongCaseBundle.wxs b/src/ext/Bal/test/WixToolsetTest.Bal/TestData/Overridable/WrongCaseBundle.wxs index 91380c69..547af644 100644 --- a/src/ext/Bal/test/WixToolsetTest.Bal/TestData/Overridable/WrongCaseBundle.wxs +++ b/src/ext/Bal/test/WixToolsetTest.Bal/TestData/Overridable/WrongCaseBundle.wxs | |||
@@ -8,6 +8,8 @@ | |||
8 | <Variable Name="Test1" bal:Overridable="yes" /> | 8 | <Variable Name="Test1" bal:Overridable="yes" /> |
9 | <Chain> | 9 | <Chain> |
10 | <ExePackage Permanent="yes" DetectCondition="none" SourceFile="runtimes\win-x86\native\wixnative.exe" /> | 10 | <ExePackage Permanent="yes" DetectCondition="none" SourceFile="runtimes\win-x86\native\wixnative.exe" /> |
11 | <MsiPackage SourceFile="test.msi" bal:DisplayInternalUICondition="!(loc.NonsensePlanCondition)" /> | ||
11 | </Chain> | 12 | </Chain> |
13 | <bal:Condition Condition="!(loc.NonsenseDetectCondition)" Message="Unsupported" /> | ||
12 | </Bundle> | 14 | </Bundle> |
13 | </Wix> | 15 | </Wix> |
diff --git a/src/ext/Bal/wixext/BalBurnBackendExtension.cs b/src/ext/Bal/wixext/BalBurnBackendExtension.cs index 854b8b35..3b19ae78 100644 --- a/src/ext/Bal/wixext/BalBurnBackendExtension.cs +++ b/src/ext/Bal/wixext/BalBurnBackendExtension.cs | |||
@@ -10,6 +10,7 @@ namespace WixToolset.Bal | |||
10 | using WixToolset.Data.Burn; | 10 | using WixToolset.Data.Burn; |
11 | using WixToolset.Data.Symbols; | 11 | using WixToolset.Data.Symbols; |
12 | using WixToolset.Extensibility; | 12 | using WixToolset.Extensibility; |
13 | using WixToolset.Extensibility.Data; | ||
13 | 14 | ||
14 | public class BalBurnBackendExtension : BaseBurnBackendBinderExtension | 15 | public class BalBurnBackendExtension : BaseBurnBackendBinderExtension |
15 | { | 16 | { |
@@ -31,6 +32,8 @@ namespace WixToolset.Bal | |||
31 | { | 32 | { |
32 | base.SymbolsFinalized(section); | 33 | base.SymbolsFinalized(section); |
33 | 34 | ||
35 | this.VerifyBalConditions(section); | ||
36 | this.VerifyBalPackageInfos(section); | ||
34 | this.VerifyOverridableVariables(section); | 37 | this.VerifyOverridableVariables(section); |
35 | 38 | ||
36 | var baSymbol = section.Symbols.OfType<WixBootstrapperApplicationDllSymbol>().SingleOrDefault(); | 39 | var baSymbol = section.Symbols.OfType<WixBootstrapperApplicationDllSymbol>().SingleOrDefault(); |
@@ -100,7 +103,7 @@ namespace WixToolset.Bal | |||
100 | { | 103 | { |
101 | foreach (var payloadPropertiesSymbol in payloadPropertiesSymbols) | 104 | foreach (var payloadPropertiesSymbol in payloadPropertiesSymbols) |
102 | { | 105 | { |
103 | if (string.Equals(payloadPropertiesSymbol.Name, "bafunctions.dll", StringComparison.OrdinalIgnoreCase) && | 106 | if (String.Equals(payloadPropertiesSymbol.Name, "bafunctions.dll", StringComparison.OrdinalIgnoreCase) && |
104 | BurnConstants.BurnUXContainerName == payloadPropertiesSymbol.ContainerRef) | 107 | BurnConstants.BurnUXContainerName == payloadPropertiesSymbol.ContainerRef) |
105 | { | 108 | { |
106 | this.Messaging.Write(BalWarnings.UnmarkedBAFunctionsDLL(payloadPropertiesSymbol.SourceLineNumbers)); | 109 | this.Messaging.Write(BalWarnings.UnmarkedBAFunctionsDLL(payloadPropertiesSymbol.SourceLineNumbers)); |
@@ -120,6 +123,24 @@ namespace WixToolset.Bal | |||
120 | } | 123 | } |
121 | } | 124 | } |
122 | 125 | ||
126 | private void VerifyBalConditions(IntermediateSection section) | ||
127 | { | ||
128 | var balConditionSymbols = section.Symbols.OfType<WixBalConditionSymbol>().ToList(); | ||
129 | foreach (var balConditionSymbol in balConditionSymbols) | ||
130 | { | ||
131 | this.BackendHelper.ValidateBundleCondition(balConditionSymbol.SourceLineNumbers, "bal:Condition", "Condition", balConditionSymbol.Condition, BundleConditionPhase.Detect); | ||
132 | } | ||
133 | } | ||
134 | |||
135 | private void VerifyBalPackageInfos(IntermediateSection section) | ||
136 | { | ||
137 | var balPackageInfoSymbols = section.Symbols.OfType<WixBalPackageInfoSymbol>().ToList(); | ||
138 | foreach (var balPackageInfoSymbol in balPackageInfoSymbols) | ||
139 | { | ||
140 | this.BackendHelper.ValidateBundleCondition(balPackageInfoSymbol.SourceLineNumbers, "*Package", "bal:DisplayInternalUICondition", balPackageInfoSymbol.DisplayInternalUICondition, BundleConditionPhase.Plan); | ||
141 | } | ||
142 | } | ||
143 | |||
123 | private void VerifyOverridableVariables(IntermediateSection section) | 144 | private void VerifyOverridableVariables(IntermediateSection section) |
124 | { | 145 | { |
125 | var bundleSymbol = section.Symbols.OfType<WixBundleSymbol>().Single(); | 146 | var bundleSymbol = section.Symbols.OfType<WixBundleSymbol>().Single(); |
diff --git a/src/wix/WixToolset.Core.Burn/Bind/BindBundleCommand.cs b/src/wix/WixToolset.Core.Burn/Bind/BindBundleCommand.cs index 16e63492..a73992da 100644 --- a/src/wix/WixToolset.Core.Burn/Bind/BindBundleCommand.cs +++ b/src/wix/WixToolset.Core.Burn/Bind/BindBundleCommand.cs | |||
@@ -150,7 +150,7 @@ namespace WixToolset.Core.Burn | |||
150 | // Process the explicitly authored payloads. | 150 | // Process the explicitly authored payloads. |
151 | ISet<string> processedPayloads; | 151 | ISet<string> processedPayloads; |
152 | { | 152 | { |
153 | var command = new ProcessPayloadsCommand(this.BackendHelper, this.PayloadHarvester, payloadSymbols.Values, bundleSymbol.DefaultPackagingType, layoutDirectory); | 153 | var command = new ProcessPayloadsCommand(this.InternalBurnBackendHelper, this.PayloadHarvester, payloadSymbols.Values, bundleSymbol.DefaultPackagingType, layoutDirectory); |
154 | command.Execute(); | 154 | command.Execute(); |
155 | 155 | ||
156 | fileTransfers.AddRange(command.FileTransfers); | 156 | fileTransfers.AddRange(command.FileTransfers); |
@@ -228,7 +228,7 @@ namespace WixToolset.Core.Burn | |||
228 | { | 228 | { |
229 | var toProcess = payloadSymbols.Values.Where(r => !processedPayloads.Contains(r.Id.Id)).ToList(); | 229 | var toProcess = payloadSymbols.Values.Where(r => !processedPayloads.Contains(r.Id.Id)).ToList(); |
230 | 230 | ||
231 | var command = new ProcessPayloadsCommand(this.BackendHelper, this.PayloadHarvester, toProcess, bundleSymbol.DefaultPackagingType, layoutDirectory); | 231 | var command = new ProcessPayloadsCommand(this.InternalBurnBackendHelper, this.PayloadHarvester, toProcess, bundleSymbol.DefaultPackagingType, layoutDirectory); |
232 | command.Execute(); | 232 | command.Execute(); |
233 | 233 | ||
234 | fileTransfers.AddRange(command.FileTransfers); | 234 | fileTransfers.AddRange(command.FileTransfers); |
@@ -381,6 +381,17 @@ namespace WixToolset.Core.Burn | |||
381 | return; | 381 | return; |
382 | } | 382 | } |
383 | 383 | ||
384 | // Now that extensions can't change anything else, verify everything is still valid. | ||
385 | { | ||
386 | var command = new PerformBundleBackendValidationCommand(this.Messaging, this.InternalBurnBackendHelper, section, facades); | ||
387 | command.Execute(); | ||
388 | } | ||
389 | |||
390 | if (this.Messaging.EncounteredError) | ||
391 | { | ||
392 | return; | ||
393 | } | ||
394 | |||
384 | // Generate data for all manifests. | 395 | // Generate data for all manifests. |
385 | { | 396 | { |
386 | var command = new GenerateManifestDataFromIRCommand(this.Messaging, section, this.BackendExtensions, this.InternalBurnBackendHelper, extensionSearchSymbolsById); | 397 | var command = new GenerateManifestDataFromIRCommand(this.Messaging, section, this.BackendExtensions, this.InternalBurnBackendHelper, extensionSearchSymbolsById); |
diff --git a/src/wix/WixToolset.Core.Burn/Bundles/PerformBundleBackendValidationCommand.cs b/src/wix/WixToolset.Core.Burn/Bundles/PerformBundleBackendValidationCommand.cs new file mode 100644 index 00000000..ee18ff2c --- /dev/null +++ b/src/wix/WixToolset.Core.Burn/Bundles/PerformBundleBackendValidationCommand.cs | |||
@@ -0,0 +1,156 @@ | |||
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.Bundles | ||
4 | { | ||
5 | using System; | ||
6 | using System.Collections.Generic; | ||
7 | using WixToolset.Data; | ||
8 | using WixToolset.Data.Symbols; | ||
9 | using WixToolset.Extensibility.Data; | ||
10 | using WixToolset.Extensibility.Services; | ||
11 | |||
12 | internal class PerformBundleBackendValidationCommand | ||
13 | { | ||
14 | public PerformBundleBackendValidationCommand(IMessaging messaging, IBurnBackendHelper burnBackendHelper, IntermediateSection section, IDictionary<string, PackageFacade> packageFacadesById) | ||
15 | { | ||
16 | this.Messaging = messaging; | ||
17 | this.BackendHelper = burnBackendHelper; | ||
18 | this.Section = section; | ||
19 | this.PackageFacadesById = packageFacadesById; | ||
20 | } | ||
21 | |||
22 | public IMessaging Messaging { get; } | ||
23 | |||
24 | public IBurnBackendHelper BackendHelper { get; } | ||
25 | |||
26 | public IntermediateSection Section { get; } | ||
27 | |||
28 | public IDictionary<string, PackageFacade> PackageFacadesById { get; } | ||
29 | |||
30 | public void Execute() | ||
31 | { | ||
32 | foreach (var symbol in this.Section.Symbols) | ||
33 | { | ||
34 | if (symbol is WixBundleSymbol wixBundleSymbol) | ||
35 | { | ||
36 | this.ValidateBundle(wixBundleSymbol); | ||
37 | } | ||
38 | else if (symbol is WixBundleMsiPropertySymbol wixBundleMsiPropertySymbol) | ||
39 | { | ||
40 | this.ValidateMsiProperty(wixBundleMsiPropertySymbol); | ||
41 | } | ||
42 | else if (symbol is WixBundleVariableSymbol wixBundleVariableSymbol) | ||
43 | { | ||
44 | this.ValidateVariable(wixBundleVariableSymbol); | ||
45 | } | ||
46 | else if (symbol is WixBundlePackageCommandLineSymbol wixBundlePackageCommandLineSymbol) | ||
47 | { | ||
48 | this.ValidatePackageCommandLine(wixBundlePackageCommandLineSymbol); | ||
49 | } | ||
50 | else if (symbol is WixSearchSymbol wixSearchSymbol) | ||
51 | { | ||
52 | this.ValidateSearch(wixSearchSymbol); | ||
53 | } | ||
54 | } | ||
55 | |||
56 | foreach (var packageFacade in this.PackageFacadesById.Values) | ||
57 | { | ||
58 | if (packageFacade.SpecificPackageSymbol is WixBundleExePackageSymbol wixBundleExePackageSymbol) | ||
59 | { | ||
60 | this.ValidateExePackage(wixBundleExePackageSymbol, packageFacade.PackageSymbol); | ||
61 | } | ||
62 | else if (packageFacade.SpecificPackageSymbol is WixBundleMsiPackageSymbol wixBundleMsiPackageSymbol) | ||
63 | { | ||
64 | this.ValidateMsiPackage(wixBundleMsiPackageSymbol, packageFacade.PackageSymbol); | ||
65 | } | ||
66 | else if (packageFacade.SpecificPackageSymbol is WixBundleMspPackageSymbol wixBundleMspPackageSymbol) | ||
67 | { | ||
68 | this.ValidateMspPackage(wixBundleMspPackageSymbol, packageFacade.PackageSymbol); | ||
69 | } | ||
70 | else if (packageFacade.SpecificPackageSymbol is WixBundleMsuPackageSymbol wixBundleMsuPackageSymbol) | ||
71 | { | ||
72 | this.ValidateMsuPackage(wixBundleMsuPackageSymbol, packageFacade.PackageSymbol); | ||
73 | } | ||
74 | } | ||
75 | } | ||
76 | |||
77 | private void ValidateBundle(WixBundleSymbol symbol) | ||
78 | { | ||
79 | if (symbol.Condition != null) | ||
80 | { | ||
81 | this.BackendHelper.ValidateBundleCondition(symbol.SourceLineNumbers, "Bundle", "Condition", symbol.Condition, BundleConditionPhase.Startup); | ||
82 | } | ||
83 | } | ||
84 | |||
85 | private void ValidateChainPackage(WixBundlePackageSymbol symbol, string elementName) | ||
86 | { | ||
87 | if (!String.IsNullOrEmpty(symbol.InstallCondition)) | ||
88 | { | ||
89 | this.BackendHelper.ValidateBundleCondition(symbol.SourceLineNumbers, elementName, "InstallCondition", symbol.InstallCondition, BundleConditionPhase.Plan); | ||
90 | } | ||
91 | } | ||
92 | |||
93 | private void ValidateExePackage(WixBundleExePackageSymbol symbol, WixBundlePackageSymbol packageSymbol) | ||
94 | { | ||
95 | this.ValidateChainPackage(packageSymbol, "ExePackage"); | ||
96 | |||
97 | if (!packageSymbol.Permanent) | ||
98 | { | ||
99 | this.BackendHelper.ValidateBundleCondition(symbol.SourceLineNumbers, "ExePackage", "DetectCondition", symbol.DetectCondition, BundleConditionPhase.Detect); | ||
100 | } | ||
101 | } | ||
102 | |||
103 | private void ValidateMsiPackage(WixBundleMsiPackageSymbol symbol, WixBundlePackageSymbol packageSymbol) | ||
104 | { | ||
105 | this.ValidateChainPackage(packageSymbol, "MsiPackage"); | ||
106 | } | ||
107 | |||
108 | private void ValidateMsiProperty(WixBundleMsiPropertySymbol symbol) | ||
109 | { | ||
110 | this.BackendHelper.ValidateBundleMsiPropertyName(symbol.SourceLineNumbers, "MsiProperty", "Name", symbol.Name); | ||
111 | |||
112 | if (symbol.Condition != null) | ||
113 | { | ||
114 | this.BackendHelper.ValidateBundleCondition(symbol.SourceLineNumbers, "MsiProperty", "Condition", symbol.Condition, BundleConditionPhase.Execute); | ||
115 | } | ||
116 | } | ||
117 | |||
118 | private void ValidateMspPackage(WixBundleMspPackageSymbol symbol, WixBundlePackageSymbol packageSymbol) | ||
119 | { | ||
120 | this.ValidateChainPackage(packageSymbol, "MspPackage"); | ||
121 | } | ||
122 | |||
123 | private void ValidateMsuPackage(WixBundleMsuPackageSymbol symbol, WixBundlePackageSymbol packageSymbol) | ||
124 | { | ||
125 | this.ValidateChainPackage(packageSymbol, "MsuPackage"); | ||
126 | |||
127 | if (!packageSymbol.Permanent) | ||
128 | { | ||
129 | this.BackendHelper.ValidateBundleCondition(symbol.SourceLineNumbers, "MsuPackage", "DetectCondition", symbol.DetectCondition, BundleConditionPhase.Detect); | ||
130 | } | ||
131 | } | ||
132 | |||
133 | private void ValidatePackageCommandLine(WixBundlePackageCommandLineSymbol symbol) | ||
134 | { | ||
135 | if (symbol.Condition != null) | ||
136 | { | ||
137 | this.BackendHelper.ValidateBundleCondition(symbol.SourceLineNumbers, "CommandLine", "Condition", symbol.Condition, BundleConditionPhase.Execute); | ||
138 | } | ||
139 | } | ||
140 | |||
141 | private void ValidateSearch(WixSearchSymbol symbol) | ||
142 | { | ||
143 | this.BackendHelper.ValidateBundleVariableName(symbol.SourceLineNumbers, "*Search", "Variable", symbol.Variable); | ||
144 | |||
145 | if (symbol.Condition != null) | ||
146 | { | ||
147 | this.BackendHelper.ValidateBundleCondition(symbol.SourceLineNumbers, "*Search", "Condition", symbol.Condition, BundleConditionPhase.Detect); | ||
148 | } | ||
149 | } | ||
150 | |||
151 | private void ValidateVariable(WixBundleVariableSymbol symbol) | ||
152 | { | ||
153 | this.BackendHelper.ValidateBundleVariableName(symbol.SourceLineNumbers, "Variable", "Name", symbol.Id.Id); | ||
154 | } | ||
155 | } | ||
156 | } | ||
diff --git a/src/wix/WixToolset.Core.Burn/Bundles/ProcessPayloadsCommand.cs b/src/wix/WixToolset.Core.Burn/Bundles/ProcessPayloadsCommand.cs index 3bd1f938..c3285884 100644 --- a/src/wix/WixToolset.Core.Burn/Bundles/ProcessPayloadsCommand.cs +++ b/src/wix/WixToolset.Core.Burn/Bundles/ProcessPayloadsCommand.cs | |||
@@ -15,7 +15,7 @@ namespace WixToolset.Core.Burn.Bundles | |||
15 | 15 | ||
16 | internal class ProcessPayloadsCommand | 16 | internal class ProcessPayloadsCommand |
17 | { | 17 | { |
18 | public ProcessPayloadsCommand(IBackendHelper backendHelper, IPayloadHarvester payloadHarvester, IEnumerable<WixBundlePayloadSymbol> payloads, PackagingType defaultPackaging, string layoutDirectory) | 18 | public ProcessPayloadsCommand(IBurnBackendHelper backendHelper, IPayloadHarvester payloadHarvester, IEnumerable<WixBundlePayloadSymbol> payloads, PackagingType defaultPackaging, string layoutDirectory) |
19 | { | 19 | { |
20 | this.BackendHelper = backendHelper; | 20 | this.BackendHelper = backendHelper; |
21 | this.PayloadHarvester = payloadHarvester; | 21 | this.PayloadHarvester = payloadHarvester; |
@@ -28,7 +28,7 @@ namespace WixToolset.Core.Burn.Bundles | |||
28 | 28 | ||
29 | public IEnumerable<ITrackedFile> TrackedFiles { get; private set; } | 29 | public IEnumerable<ITrackedFile> TrackedFiles { get; private set; } |
30 | 30 | ||
31 | private IBackendHelper BackendHelper { get; } | 31 | private IBurnBackendHelper BackendHelper { get; } |
32 | 32 | ||
33 | private IPayloadHarvester PayloadHarvester { get; } | 33 | private IPayloadHarvester PayloadHarvester { get; } |
34 | 34 | ||
diff --git a/src/wix/WixToolset.Core.Burn/ExtensibilityServices/BurnBackendHelper.cs b/src/wix/WixToolset.Core.Burn/ExtensibilityServices/BurnBackendHelper.cs index e4d2b0c9..d77606fb 100644 --- a/src/wix/WixToolset.Core.Burn/ExtensibilityServices/BurnBackendHelper.cs +++ b/src/wix/WixToolset.Core.Burn/ExtensibilityServices/BurnBackendHelper.cs | |||
@@ -20,6 +20,7 @@ namespace WixToolset.Core.Burn.ExtensibilityServices | |||
20 | public static readonly XmlWriterSettings WriterSettings = new XmlWriterSettings { ConformanceLevel = ConformanceLevel.Fragment }; | 20 | public static readonly XmlWriterSettings WriterSettings = new XmlWriterSettings { ConformanceLevel = ConformanceLevel.Fragment }; |
21 | 21 | ||
22 | private readonly IBackendHelper backendHelper; | 22 | private readonly IBackendHelper backendHelper; |
23 | private readonly IBundleValidator bundleValidator; | ||
23 | 24 | ||
24 | private ManifestData BootstrapperApplicationManifestData { get; } = new ManifestData(); | 25 | private ManifestData BootstrapperApplicationManifestData { get; } = new ManifestData(); |
25 | 26 | ||
@@ -28,49 +29,105 @@ namespace WixToolset.Core.Burn.ExtensibilityServices | |||
28 | public BurnBackendHelper(IServiceProvider serviceProvider) | 29 | public BurnBackendHelper(IServiceProvider serviceProvider) |
29 | { | 30 | { |
30 | this.backendHelper = serviceProvider.GetService<IBackendHelper>(); | 31 | this.backendHelper = serviceProvider.GetService<IBackendHelper>(); |
32 | this.bundleValidator = serviceProvider.GetService<IBundleValidator>(); | ||
31 | } | 33 | } |
32 | 34 | ||
33 | #region IBackendHelper interfaces | 35 | #region IBackendHelper interfaces |
34 | 36 | ||
35 | public IFileFacade CreateFileFacade(FileSymbol file, AssemblySymbol assembly) => this.backendHelper.CreateFileFacade(file, assembly); | 37 | public IFileFacade CreateFileFacade(FileSymbol file, AssemblySymbol assembly) |
36 | 38 | { | |
37 | public IFileFacade CreateFileFacade(FileRow fileRow) => this.backendHelper.CreateFileFacade(fileRow); | 39 | return this.backendHelper.CreateFileFacade(file, assembly); |
40 | } | ||
38 | 41 | ||
39 | public IFileFacade CreateFileFacadeFromMergeModule(FileSymbol fileSymbol) => this.backendHelper.CreateFileFacadeFromMergeModule(fileSymbol); | 42 | public IFileFacade CreateFileFacade(FileRow fileRow) |
43 | { | ||
44 | return this.backendHelper.CreateFileFacade(fileRow); | ||
45 | } | ||
40 | 46 | ||
41 | public IFileTransfer CreateFileTransfer(string source, string destination, bool move, SourceLineNumber sourceLineNumbers = null) => this.backendHelper.CreateFileTransfer(source, destination, move, sourceLineNumbers); | 47 | public IFileFacade CreateFileFacadeFromMergeModule(FileSymbol fileSymbol) |
48 | { | ||
49 | return this.backendHelper.CreateFileFacadeFromMergeModule(fileSymbol); | ||
50 | } | ||
42 | 51 | ||
43 | public string CreateGuid() => this.backendHelper.CreateGuid(); | 52 | public IFileTransfer CreateFileTransfer(string source, string destination, bool move, SourceLineNumber sourceLineNumbers = null) |
53 | { | ||
54 | return this.backendHelper.CreateFileTransfer(source, destination, move, sourceLineNumbers); | ||
55 | } | ||
44 | 56 | ||
45 | public string CreateGuid(Guid namespaceGuid, string value) => this.backendHelper.CreateGuid(namespaceGuid, value); | 57 | public string CreateGuid() |
58 | { | ||
59 | return this.backendHelper.CreateGuid(); | ||
60 | } | ||
46 | 61 | ||
47 | public IResolvedDirectory CreateResolvedDirectory(string directoryParent, string name) => this.backendHelper.CreateResolvedDirectory(directoryParent, name); | 62 | public string CreateGuid(Guid namespaceGuid, string value) |
63 | { | ||
64 | return this.backendHelper.CreateGuid(namespaceGuid, value); | ||
65 | } | ||
48 | 66 | ||
49 | public IReadOnlyList<ITrackedFile> ExtractEmbeddedFiles(IEnumerable<IExpectedExtractFile> embeddedFiles) => this.backendHelper.ExtractEmbeddedFiles(embeddedFiles); | 67 | public IResolvedDirectory CreateResolvedDirectory(string directoryParent, string name) |
68 | { | ||
69 | return this.backendHelper.CreateResolvedDirectory(directoryParent, name); | ||
70 | } | ||
50 | 71 | ||
51 | public string GenerateIdentifier(string prefix, params string[] args) => this.backendHelper.GenerateIdentifier(prefix, args); | 72 | public IReadOnlyList<ITrackedFile> ExtractEmbeddedFiles(IEnumerable<IExpectedExtractFile> embeddedFiles) |
73 | { | ||
74 | return this.backendHelper.ExtractEmbeddedFiles(embeddedFiles); | ||
75 | } | ||
52 | 76 | ||
53 | public string GetCanonicalRelativePath(SourceLineNumber sourceLineNumbers, string elementName, string attributeName, string relativePath) => this.backendHelper.GetCanonicalRelativePath(sourceLineNumbers, elementName, attributeName, relativePath); | 77 | public string GenerateIdentifier(string prefix, params string[] args) |
78 | { | ||
79 | return this.backendHelper.GenerateIdentifier(prefix, args); | ||
80 | } | ||
54 | 81 | ||
55 | public int GetValidCodePage(string value, bool allowNoChange, bool onlyAnsi = false, SourceLineNumber sourceLineNumbers = null) => this.backendHelper.GetValidCodePage(value, allowNoChange, onlyAnsi, sourceLineNumbers); | 82 | public int GetValidCodePage(string value, bool allowNoChange, bool onlyAnsi = false, SourceLineNumber sourceLineNumbers = null) |
83 | { | ||
84 | return this.backendHelper.GetValidCodePage(value, allowNoChange, onlyAnsi, sourceLineNumbers); | ||
85 | } | ||
56 | 86 | ||
57 | public string GetMsiFileName(string value, bool source, bool longName) => this.backendHelper.GetMsiFileName(value, source, longName); | 87 | public string GetMsiFileName(string value, bool source, bool longName) |
88 | { | ||
89 | return this.backendHelper.GetMsiFileName(value, source, longName); | ||
90 | } | ||
58 | 91 | ||
59 | public bool IsValidBinderVariable(string variable) => this.backendHelper.IsValidBinderVariable(variable); | 92 | public bool IsValidBinderVariable(string variable) |
93 | { | ||
94 | return this.backendHelper.IsValidBinderVariable(variable); | ||
95 | } | ||
60 | 96 | ||
61 | public bool IsValidFourPartVersion(string version) => this.backendHelper.IsValidFourPartVersion(version); | 97 | public bool IsValidFourPartVersion(string version) |
98 | { | ||
99 | return this.backendHelper.IsValidFourPartVersion(version); | ||
100 | } | ||
62 | 101 | ||
63 | public bool IsValidIdentifier(string id) => this.backendHelper.IsValidIdentifier(id); | 102 | public bool IsValidIdentifier(string id) |
103 | { | ||
104 | return this.backendHelper.IsValidIdentifier(id); | ||
105 | } | ||
64 | 106 | ||
65 | public bool IsValidLongFilename(string filename, bool allowWildcards, bool allowRelative) => this.backendHelper.IsValidLongFilename(filename, allowWildcards, allowRelative); | 107 | public bool IsValidLongFilename(string filename, bool allowWildcards, bool allowRelative) |
108 | { | ||
109 | return this.backendHelper.IsValidLongFilename(filename, allowWildcards, allowRelative); | ||
110 | } | ||
66 | 111 | ||
67 | public bool IsValidShortFilename(string filename, bool allowWildcards) => this.backendHelper.IsValidShortFilename(filename, allowWildcards); | 112 | public bool IsValidShortFilename(string filename, bool allowWildcards) |
113 | { | ||
114 | return this.backendHelper.IsValidShortFilename(filename, allowWildcards); | ||
115 | } | ||
68 | 116 | ||
69 | public void ResolveDelayedFields(IEnumerable<IDelayedField> delayedFields, Dictionary<string, string> variableCache) => this.backendHelper.ResolveDelayedFields(delayedFields, variableCache); | 117 | public void ResolveDelayedFields(IEnumerable<IDelayedField> delayedFields, Dictionary<string, string> variableCache) |
118 | { | ||
119 | this.backendHelper.ResolveDelayedFields(delayedFields, variableCache); | ||
120 | } | ||
70 | 121 | ||
71 | public string[] SplitMsiFileName(string value) => this.backendHelper.SplitMsiFileName(value); | 122 | public string[] SplitMsiFileName(string value) |
123 | { | ||
124 | return this.backendHelper.SplitMsiFileName(value); | ||
125 | } | ||
72 | 126 | ||
73 | public ITrackedFile TrackFile(string path, TrackedFileType type, SourceLineNumber sourceLineNumbers = null) => this.backendHelper.TrackFile(path, type, sourceLineNumbers); | 127 | public ITrackedFile TrackFile(string path, TrackedFileType type, SourceLineNumber sourceLineNumbers = null) |
128 | { | ||
129 | return this.backendHelper.TrackFile(path, type, sourceLineNumbers); | ||
130 | } | ||
74 | 131 | ||
75 | #endregion | 132 | #endregion |
76 | 133 | ||
@@ -100,6 +157,28 @@ namespace WixToolset.Core.Burn.ExtensibilityServices | |||
100 | 157 | ||
101 | #endregion | 158 | #endregion |
102 | 159 | ||
160 | #region IBundleValidator | ||
161 | public string GetCanonicalRelativePath(SourceLineNumber sourceLineNumbers, string elementName, string attributeName, string relativePath) | ||
162 | { | ||
163 | return this.bundleValidator.GetCanonicalRelativePath(sourceLineNumbers, elementName, attributeName, relativePath); | ||
164 | } | ||
165 | |||
166 | public bool ValidateBundleMsiPropertyName(SourceLineNumber sourceLineNumbers, string elementName, string attributeName, string propertyName) | ||
167 | { | ||
168 | return this.bundleValidator.ValidateBundleMsiPropertyName(sourceLineNumbers, elementName, attributeName, propertyName); | ||
169 | } | ||
170 | |||
171 | public bool ValidateBundleVariableName(SourceLineNumber sourceLineNumbers, string elementName, string attributeName, string variableName) | ||
172 | { | ||
173 | return this.bundleValidator.ValidateBundleVariableName(sourceLineNumbers, elementName, attributeName, variableName); | ||
174 | } | ||
175 | |||
176 | public bool ValidateBundleCondition(SourceLineNumber sourceLineNumbers, string elementName, string attributeName, string condition, BundleConditionPhase phase) | ||
177 | { | ||
178 | return this.bundleValidator.ValidateBundleCondition(sourceLineNumbers, elementName, attributeName, condition, phase); | ||
179 | } | ||
180 | #endregion | ||
181 | |||
103 | #region IInternalBurnBackendHelper interfaces | 182 | #region IInternalBurnBackendHelper interfaces |
104 | 183 | ||
105 | public void WriteBootstrapperApplicationData(XmlWriter writer) | 184 | public void WriteBootstrapperApplicationData(XmlWriter writer) |
diff --git a/src/wix/WixToolset.Core.WindowsInstaller/ExtensibilityServices/WindowsInstallerBackendHelper.cs b/src/wix/WixToolset.Core.WindowsInstaller/ExtensibilityServices/WindowsInstallerBackendHelper.cs index 8305b5e6..b3b4421a 100644 --- a/src/wix/WixToolset.Core.WindowsInstaller/ExtensibilityServices/WindowsInstallerBackendHelper.cs +++ b/src/wix/WixToolset.Core.WindowsInstaller/ExtensibilityServices/WindowsInstallerBackendHelper.cs | |||
@@ -23,45 +23,100 @@ namespace WixToolset.Core.WindowsInstaller.ExtensibilityServices | |||
23 | 23 | ||
24 | #region IBackendHelper interfaces | 24 | #region IBackendHelper interfaces |
25 | 25 | ||
26 | public IFileFacade CreateFileFacade(FileSymbol file, AssemblySymbol assembly) => this.backendHelper.CreateFileFacade(file, assembly); | 26 | public IFileFacade CreateFileFacade(FileSymbol file, AssemblySymbol assembly) |
27 | 27 | { | |
28 | public IFileFacade CreateFileFacade(FileRow fileRow) => this.backendHelper.CreateFileFacade(fileRow); | 28 | return this.backendHelper.CreateFileFacade(file, assembly); |
29 | } | ||
29 | 30 | ||
30 | public IFileFacade CreateFileFacadeFromMergeModule(FileSymbol fileSymbol) => this.backendHelper.CreateFileFacadeFromMergeModule(fileSymbol); | 31 | public IFileFacade CreateFileFacade(FileRow fileRow) |
32 | { | ||
33 | return this.backendHelper.CreateFileFacade(fileRow); | ||
34 | } | ||
31 | 35 | ||
32 | public IFileTransfer CreateFileTransfer(string source, string destination, bool move, SourceLineNumber sourceLineNumbers = null) => this.backendHelper.CreateFileTransfer(source, destination, move, sourceLineNumbers); | 36 | public IFileFacade CreateFileFacadeFromMergeModule(FileSymbol fileSymbol) |
37 | { | ||
38 | return this.backendHelper.CreateFileFacadeFromMergeModule(fileSymbol); | ||
39 | } | ||
33 | 40 | ||
34 | public string CreateGuid() => this.backendHelper.CreateGuid(); | 41 | public IFileTransfer CreateFileTransfer(string source, string destination, bool move, SourceLineNumber sourceLineNumbers = null) |
42 | { | ||
43 | return this.backendHelper.CreateFileTransfer(source, destination, move, sourceLineNumbers); | ||
44 | } | ||
35 | 45 | ||
36 | public string CreateGuid(Guid namespaceGuid, string value) => this.backendHelper.CreateGuid(namespaceGuid, value); | 46 | public string CreateGuid() |
47 | { | ||
48 | return this.backendHelper.CreateGuid(); | ||
49 | } | ||
37 | 50 | ||
38 | public IResolvedDirectory CreateResolvedDirectory(string directoryParent, string name) => this.backendHelper.CreateResolvedDirectory(directoryParent, name); | 51 | public string CreateGuid(Guid namespaceGuid, string value) |
52 | { | ||
53 | return this.backendHelper.CreateGuid(namespaceGuid, value); | ||
54 | } | ||
39 | 55 | ||
40 | public IReadOnlyList<ITrackedFile> ExtractEmbeddedFiles(IEnumerable<IExpectedExtractFile> embeddedFiles) => this.backendHelper.ExtractEmbeddedFiles(embeddedFiles); | 56 | public IResolvedDirectory CreateResolvedDirectory(string directoryParent, string name) |
57 | { | ||
58 | return this.backendHelper.CreateResolvedDirectory(directoryParent, name); | ||
59 | } | ||
41 | 60 | ||
42 | public string GenerateIdentifier(string prefix, params string[] args) => this.backendHelper.GenerateIdentifier(prefix, args); | 61 | public IReadOnlyList<ITrackedFile> ExtractEmbeddedFiles(IEnumerable<IExpectedExtractFile> embeddedFiles) |
62 | { | ||
63 | return this.backendHelper.ExtractEmbeddedFiles(embeddedFiles); | ||
64 | } | ||
43 | 65 | ||
44 | public string GetCanonicalRelativePath(SourceLineNumber sourceLineNumbers, string elementName, string attributeName, string relativePath) => this.backendHelper.GetCanonicalRelativePath(sourceLineNumbers, elementName, attributeName, relativePath); | 66 | public string GenerateIdentifier(string prefix, params string[] args) |
67 | { | ||
68 | return this.backendHelper.GenerateIdentifier(prefix, args); | ||
69 | } | ||
45 | 70 | ||
46 | public int GetValidCodePage(string value, bool allowNoChange, bool onlyAnsi = false, SourceLineNumber sourceLineNumbers = null) => this.backendHelper.GetValidCodePage(value, allowNoChange, onlyAnsi, sourceLineNumbers); | 71 | public int GetValidCodePage(string value, bool allowNoChange, bool onlyAnsi = false, SourceLineNumber sourceLineNumbers = null) |
72 | { | ||
73 | return this.backendHelper.GetValidCodePage(value, allowNoChange, onlyAnsi, sourceLineNumbers); | ||
74 | } | ||
47 | 75 | ||
48 | public string GetMsiFileName(string value, bool source, bool longName) => this.backendHelper.GetMsiFileName(value, source, longName); | 76 | public string GetMsiFileName(string value, bool source, bool longName) |
77 | { | ||
78 | return this.backendHelper.GetMsiFileName(value, source, longName); | ||
79 | } | ||
49 | 80 | ||
50 | public bool IsValidBinderVariable(string variable) => this.backendHelper.IsValidBinderVariable(variable); | 81 | public bool IsValidBinderVariable(string variable) |
82 | { | ||
83 | return this.backendHelper.IsValidBinderVariable(variable); | ||
84 | } | ||
51 | 85 | ||
52 | public bool IsValidFourPartVersion(string version) => this.backendHelper.IsValidFourPartVersion(version); | 86 | public bool IsValidFourPartVersion(string version) |
87 | { | ||
88 | return this.backendHelper.IsValidFourPartVersion(version); | ||
89 | } | ||
53 | 90 | ||
54 | public bool IsValidIdentifier(string id) => this.backendHelper.IsValidIdentifier(id); | 91 | public bool IsValidIdentifier(string id) |
92 | { | ||
93 | return this.backendHelper.IsValidIdentifier(id); | ||
94 | } | ||
55 | 95 | ||
56 | public bool IsValidLongFilename(string filename, bool allowWildcards, bool allowRelative) => this.backendHelper.IsValidLongFilename(filename, allowWildcards, allowRelative); | 96 | public bool IsValidLongFilename(string filename, bool allowWildcards, bool allowRelative) |
97 | { | ||
98 | return this.backendHelper.IsValidLongFilename(filename, allowWildcards, allowRelative); | ||
99 | } | ||
57 | 100 | ||
58 | public bool IsValidShortFilename(string filename, bool allowWildcards) => this.backendHelper.IsValidShortFilename(filename, allowWildcards); | 101 | public bool IsValidShortFilename(string filename, bool allowWildcards) |
102 | { | ||
103 | return this.backendHelper.IsValidShortFilename(filename, allowWildcards); | ||
104 | } | ||
59 | 105 | ||
60 | public void ResolveDelayedFields(IEnumerable<IDelayedField> delayedFields, Dictionary<string, string> variableCache) => this.backendHelper.ResolveDelayedFields(delayedFields, variableCache); | 106 | public void ResolveDelayedFields(IEnumerable<IDelayedField> delayedFields, Dictionary<string, string> variableCache) |
107 | { | ||
108 | this.backendHelper.ResolveDelayedFields(delayedFields, variableCache); | ||
109 | } | ||
61 | 110 | ||
62 | public string[] SplitMsiFileName(string value) => this.backendHelper.SplitMsiFileName(value); | 111 | public string[] SplitMsiFileName(string value) |
112 | { | ||
113 | return this.backendHelper.SplitMsiFileName(value); | ||
114 | } | ||
63 | 115 | ||
64 | public ITrackedFile TrackFile(string path, TrackedFileType type, SourceLineNumber sourceLineNumbers = null) => this.backendHelper.TrackFile(path, type, sourceLineNumbers); | 116 | public ITrackedFile TrackFile(string path, TrackedFileType type, SourceLineNumber sourceLineNumbers = null) |
117 | { | ||
118 | return this.backendHelper.TrackFile(path, type, sourceLineNumbers); | ||
119 | } | ||
65 | 120 | ||
66 | #endregion | 121 | #endregion |
67 | 122 | ||
diff --git a/src/wix/WixToolset.Core/Common.cs b/src/wix/WixToolset.Core/Common.cs index 848f009a..8e341c52 100644 --- a/src/wix/WixToolset.Core/Common.cs +++ b/src/wix/WixToolset.Core/Common.cs | |||
@@ -27,27 +27,6 @@ namespace WixToolset.Core | |||
27 | internal static readonly char[] IllegalRelativeLongFilenameCharacters = new[] { '?', '*', '|', '>', '<', ':', '\"' }; // like illegal, but we allow '\' and '/' | 27 | internal static readonly char[] IllegalRelativeLongFilenameCharacters = new[] { '?', '*', '|', '>', '<', ':', '\"' }; // like illegal, but we allow '\' and '/' |
28 | internal static readonly char[] IllegalWildcardLongFilenameCharacters = new[] { '\\', '/', '|', '>', '<', ':', '\"' }; // like illegal: but we allow '*' and '?' | 28 | internal static readonly char[] IllegalWildcardLongFilenameCharacters = new[] { '\\', '/', '|', '>', '<', ':', '\"' }; // like illegal: but we allow '*' and '?' |
29 | 29 | ||
30 | public static string GetCanonicalRelativePath(SourceLineNumber sourceLineNumbers, string elementName, string attributeName, string relativePath, IMessaging messageHandler) | ||
31 | { | ||
32 | const string root = @"C:\"; | ||
33 | if (!Path.IsPathRooted(relativePath)) | ||
34 | { | ||
35 | var normalizedPath = Path.GetFullPath(root + relativePath); | ||
36 | if (normalizedPath.StartsWith(root)) | ||
37 | { | ||
38 | var canonicalizedPath = normalizedPath.Substring(root.Length); | ||
39 | if (canonicalizedPath != relativePath) | ||
40 | { | ||
41 | messageHandler.Write(WarningMessages.PathCanonicalized(sourceLineNumbers, elementName, attributeName, relativePath, canonicalizedPath)); | ||
42 | } | ||
43 | return canonicalizedPath; | ||
44 | } | ||
45 | } | ||
46 | |||
47 | messageHandler.Write(ErrorMessages.PayloadMustBeRelativeToCache(sourceLineNumbers, elementName, attributeName, relativePath)); | ||
48 | return relativePath; | ||
49 | } | ||
50 | |||
51 | /// <summary> | 30 | /// <summary> |
52 | /// Gets a valid code page from the given web name or integer value. | 31 | /// Gets a valid code page from the given web name or integer value. |
53 | /// </summary> | 32 | /// </summary> |
diff --git a/src/wix/WixToolset.Core/CompilerCore.cs b/src/wix/WixToolset.Core/CompilerCore.cs index dc44f1b6..7effa0b9 100644 --- a/src/wix/WixToolset.Core/CompilerCore.cs +++ b/src/wix/WixToolset.Core/CompilerCore.cs | |||
@@ -17,24 +17,6 @@ namespace WixToolset.Core | |||
17 | using WixToolset.Extensibility.Data; | 17 | using WixToolset.Extensibility.Data; |
18 | using WixToolset.Extensibility.Services; | 18 | using WixToolset.Extensibility.Services; |
19 | 19 | ||
20 | internal enum ValueListKind | ||
21 | { | ||
22 | /// <summary> | ||
23 | /// A list of values with nothing before the final value. | ||
24 | /// </summary> | ||
25 | None, | ||
26 | |||
27 | /// <summary> | ||
28 | /// A list of values with 'and' before the final value. | ||
29 | /// </summary> | ||
30 | And, | ||
31 | |||
32 | /// <summary> | ||
33 | /// A list of values with 'or' before the final value. | ||
34 | /// </summary> | ||
35 | Or | ||
36 | } | ||
37 | |||
38 | /// <summary> | 20 | /// <summary> |
39 | /// Core class for the compiler. | 21 | /// Core class for the compiler. |
40 | /// </summary> | 22 | /// </summary> |
@@ -43,80 +25,6 @@ namespace WixToolset.Core | |||
43 | internal static readonly XNamespace W3SchemaPrefix = "http://www.w3.org/"; | 25 | internal static readonly XNamespace W3SchemaPrefix = "http://www.w3.org/"; |
44 | internal static readonly XNamespace WixNamespace = "http://wixtoolset.org/schemas/v4/wxs"; | 26 | internal static readonly XNamespace WixNamespace = "http://wixtoolset.org/schemas/v4/wxs"; |
45 | 27 | ||
46 | // Built-in variables (from burn\engine\variable.cpp, "vrgBuiltInVariables", around line 113) | ||
47 | private static readonly List<string> BuiltinBundleVariables = new List<string>( | ||
48 | new string[] { | ||
49 | "AdminToolsFolder", | ||
50 | "AppDataFolder", | ||
51 | "CommonAppDataFolder", | ||
52 | "CommonFiles64Folder", | ||
53 | "CommonFilesFolder", | ||
54 | "CompatibilityMode", | ||
55 | "Date", | ||
56 | "DesktopFolder", | ||
57 | "FavoritesFolder", | ||
58 | "FontsFolder", | ||
59 | "InstallerName", | ||
60 | "InstallerVersion", | ||
61 | "LocalAppDataFolder", | ||
62 | "LogonUser", | ||
63 | "MyPicturesFolder", | ||
64 | "NativeMachine", | ||
65 | "NTProductType", | ||
66 | "NTSuiteBackOffice", | ||
67 | "NTSuiteDataCenter", | ||
68 | "NTSuiteEnterprise", | ||
69 | "NTSuitePersonal", | ||
70 | "NTSuiteSmallBusiness", | ||
71 | "NTSuiteSmallBusinessRestricted", | ||
72 | "NTSuiteWebServer", | ||
73 | "PersonalFolder", | ||
74 | "Privileged", | ||
75 | "ProgramFiles64Folder", | ||
76 | "ProgramFiles6432Folder", | ||
77 | "ProgramFilesFolder", | ||
78 | "ProgramMenuFolder", | ||
79 | "RebootPending", | ||
80 | "SendToFolder", | ||
81 | "ServicePackLevel", | ||
82 | "StartMenuFolder", | ||
83 | "StartupFolder", | ||
84 | "System64Folder", | ||
85 | "SystemFolder", | ||
86 | "TempFolder", | ||
87 | "TemplateFolder", | ||
88 | "TerminalServer", | ||
89 | "UserLanguageID", | ||
90 | "UserUILanguageID", | ||
91 | "VersionMsi", | ||
92 | "VersionNT", | ||
93 | "VersionNT64", | ||
94 | "WindowsFolder", | ||
95 | "WindowsVolume", | ||
96 | "WixBundleAction", | ||
97 | "WixBundleCommandLineAction", | ||
98 | "WixBundleForcedRestartPackage", | ||
99 | "WixBundleElevated", | ||
100 | "WixBundleInstalled", | ||
101 | "WixBundleProviderKey", | ||
102 | "WixBundleTag", | ||
103 | "WixBundleVersion", | ||
104 | }); | ||
105 | |||
106 | private static readonly List<string> DisallowedMsiProperties = new List<string>( | ||
107 | new string[] { | ||
108 | "ACTION", | ||
109 | "ADDLOCAL", | ||
110 | "ADDSOURCE", | ||
111 | "ADDDEFAULT", | ||
112 | "ADVERTISE", | ||
113 | "ALLUSERS", | ||
114 | "REBOOT", | ||
115 | "REINSTALL", | ||
116 | "REINSTALLMODE", | ||
117 | "REMOVE" | ||
118 | }); | ||
119 | |||
120 | private readonly Dictionary<XNamespace, ICompilerExtension> extensions; | 28 | private readonly Dictionary<XNamespace, ICompilerExtension> extensions; |
121 | private readonly IParseHelper parseHelper; | 29 | private readonly IParseHelper parseHelper; |
122 | private readonly Intermediate intermediate; | 30 | private readonly Intermediate intermediate; |
@@ -857,11 +765,7 @@ namespace WixToolset.Core | |||
857 | 765 | ||
858 | if (!String.IsNullOrEmpty(value)) | 766 | if (!String.IsNullOrEmpty(value)) |
859 | { | 767 | { |
860 | if (CompilerCore.BuiltinBundleVariables.Contains(value)) | 768 | this.parseHelper.ValidateBundleVariableName(sourceLineNumbers, attribute.Parent.Name.LocalName, attribute.Name.LocalName, value); |
861 | { | ||
862 | string illegalValues = CompilerCore.CreateValueList(ValueListKind.Or, CompilerCore.BuiltinBundleVariables); | ||
863 | this.Write(ErrorMessages.IllegalAttributeValueWithIllegalList(sourceLineNumbers, attribute.Parent.Name.LocalName, attribute.Name.LocalName, value, illegalValues)); | ||
864 | } | ||
865 | } | 769 | } |
866 | 770 | ||
867 | return value; | 771 | return value; |
@@ -879,11 +783,7 @@ namespace WixToolset.Core | |||
879 | 783 | ||
880 | if (0 < value.Length) | 784 | if (0 < value.Length) |
881 | { | 785 | { |
882 | if (CompilerCore.DisallowedMsiProperties.Contains(value)) | 786 | this.parseHelper.ValidateBundleMsiPropertyName(sourceLineNumbers, attribute.Parent.Name.LocalName, attribute.Name.LocalName, value); |
883 | { | ||
884 | string illegalValues = CompilerCore.CreateValueList(ValueListKind.Or, CompilerCore.DisallowedMsiProperties); | ||
885 | this.Write(ErrorMessages.DisallowedMsiProperty(sourceLineNumbers, value, illegalValues)); | ||
886 | } | ||
887 | } | 787 | } |
888 | 788 | ||
889 | return value; | 789 | return value; |
@@ -1095,74 +995,5 @@ namespace WixToolset.Core | |||
1095 | { | 995 | { |
1096 | return this.parseHelper.ScheduleActionSymbol(this.ActiveSection, sourceLineNumbers, access, sequence, actionName, condition, beforeAction, afterAction, overridable); | 996 | return this.parseHelper.ScheduleActionSymbol(this.ActiveSection, sourceLineNumbers, access, sequence, actionName, condition, beforeAction, afterAction, overridable); |
1097 | } | 997 | } |
1098 | |||
1099 | private static string CreateValueList(ValueListKind kind, IEnumerable<string> values) | ||
1100 | { | ||
1101 | // Ideally, we could denote the list kind (and the list itself) directly in the | ||
1102 | // message XML, and detect and expand in the MessageHandler.GenerateMessageString() | ||
1103 | // method. Doing so would make vararg-style messages much easier, but impacts | ||
1104 | // every single message we format. For now, callers just have to know when a | ||
1105 | // message takes a list of values in a single string argument, the caller will | ||
1106 | // have to do the expansion themselves. (And, unfortunately, hard-code the knowledge | ||
1107 | // that the list is an 'and' or 'or' list.) | ||
1108 | |||
1109 | // For a localizable solution, we need to be able to get the list format string | ||
1110 | // from resources. We aren't currently localized right now, so the values are | ||
1111 | // just hard-coded. | ||
1112 | const string valueFormat = "'{0}'"; | ||
1113 | const string valueSeparator = ", "; | ||
1114 | string terminalTerm = String.Empty; | ||
1115 | |||
1116 | switch (kind) | ||
1117 | { | ||
1118 | case ValueListKind.None: | ||
1119 | terminalTerm = ""; | ||
1120 | break; | ||
1121 | case ValueListKind.And: | ||
1122 | terminalTerm = "and "; | ||
1123 | break; | ||
1124 | case ValueListKind.Or: | ||
1125 | terminalTerm = "or "; | ||
1126 | break; | ||
1127 | } | ||
1128 | |||
1129 | StringBuilder list = new StringBuilder(); | ||
1130 | |||
1131 | // This weird construction helps us determine when we're adding the last value | ||
1132 | // to the list. Instead of adding them as we encounter them, we cache the current | ||
1133 | // value and append the *previous* one. | ||
1134 | string previousValue = null; | ||
1135 | bool haveValues = false; | ||
1136 | foreach (string value in values) | ||
1137 | { | ||
1138 | if (null != previousValue) | ||
1139 | { | ||
1140 | if (haveValues) | ||
1141 | { | ||
1142 | list.Append(valueSeparator); | ||
1143 | } | ||
1144 | list.AppendFormat(valueFormat, previousValue); | ||
1145 | haveValues = true; | ||
1146 | } | ||
1147 | |||
1148 | previousValue = value; | ||
1149 | } | ||
1150 | |||
1151 | // If we have no previous value, that means that the list contained no values, and | ||
1152 | // something has gone very wrong. | ||
1153 | Debug.Assert(null != previousValue); | ||
1154 | if (null != previousValue) | ||
1155 | { | ||
1156 | if (haveValues) | ||
1157 | { | ||
1158 | list.Append(valueSeparator); | ||
1159 | list.Append(terminalTerm); | ||
1160 | } | ||
1161 | list.AppendFormat(valueFormat, previousValue); | ||
1162 | haveValues = true; | ||
1163 | } | ||
1164 | |||
1165 | return list.ToString(); | ||
1166 | } | ||
1167 | } | 998 | } |
1168 | } | 999 | } |
diff --git a/src/wix/WixToolset.Core/ExtensibilityServices/BackendHelper.cs b/src/wix/WixToolset.Core/ExtensibilityServices/BackendHelper.cs index 9d657e1a..3348ad0b 100644 --- a/src/wix/WixToolset.Core/ExtensibilityServices/BackendHelper.cs +++ b/src/wix/WixToolset.Core/ExtensibilityServices/BackendHelper.cs | |||
@@ -64,11 +64,6 @@ namespace WixToolset.Core.ExtensibilityServices | |||
64 | return Common.GenerateIdentifier(prefix, args); | 64 | return Common.GenerateIdentifier(prefix, args); |
65 | } | 65 | } |
66 | 66 | ||
67 | public string GetCanonicalRelativePath(SourceLineNumber sourceLineNumbers, string elementName, string attributeName, string relativePath) | ||
68 | { | ||
69 | return Common.GetCanonicalRelativePath(sourceLineNumbers, elementName, attributeName, relativePath, this.Messaging); | ||
70 | } | ||
71 | |||
72 | public int GetValidCodePage(string value, bool allowNoChange = false, bool onlyAnsi = false, SourceLineNumber sourceLineNumbers = null) | 67 | public int GetValidCodePage(string value, bool allowNoChange = false, bool onlyAnsi = false, SourceLineNumber sourceLineNumbers = null) |
73 | { | 68 | { |
74 | return Common.GetValidCodePage(value, allowNoChange, onlyAnsi, sourceLineNumbers); | 69 | return Common.GetValidCodePage(value, allowNoChange, onlyAnsi, sourceLineNumbers); |
diff --git a/src/wix/WixToolset.Core/ExtensibilityServices/BundleValidator.cs b/src/wix/WixToolset.Core/ExtensibilityServices/BundleValidator.cs new file mode 100644 index 00000000..0149fe94 --- /dev/null +++ b/src/wix/WixToolset.Core/ExtensibilityServices/BundleValidator.cs | |||
@@ -0,0 +1,326 @@ | |||
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.ExtensibilityServices | ||
4 | { | ||
5 | using System; | ||
6 | using System.Collections.Generic; | ||
7 | using System.Diagnostics; | ||
8 | using System.IO; | ||
9 | using System.Text; | ||
10 | using WixToolset.Data; | ||
11 | using WixToolset.Extensibility.Data; | ||
12 | using WixToolset.Extensibility.Services; | ||
13 | |||
14 | internal class BundleValidator : IBundleValidator | ||
15 | { | ||
16 | public BundleValidator(IServiceProvider serviceProvider) | ||
17 | { | ||
18 | this.Messaging = serviceProvider.GetService<IMessaging>(); | ||
19 | } | ||
20 | |||
21 | protected IMessaging Messaging { get; } | ||
22 | |||
23 | private enum ValueListKind | ||
24 | { | ||
25 | /// <summary> | ||
26 | /// A list of values with nothing before the final value. | ||
27 | /// </summary> | ||
28 | None, | ||
29 | |||
30 | /// <summary> | ||
31 | /// A list of values with 'and' before the final value. | ||
32 | /// </summary> | ||
33 | And, | ||
34 | |||
35 | /// <summary> | ||
36 | /// A list of values with 'or' before the final value. | ||
37 | /// </summary> | ||
38 | Or, | ||
39 | } | ||
40 | |||
41 | // Built-in variables (from burn\engine\variable.cpp, "vrgBuiltInVariables", around line 207) | ||
42 | private static readonly List<string> BuiltinBundleVariables = new List<string>( | ||
43 | new string[] { | ||
44 | "AdminToolsFolder", | ||
45 | "AppDataFolder", | ||
46 | "CommonAppDataFolder", | ||
47 | "CommonFiles64Folder", | ||
48 | "CommonFilesFolder", | ||
49 | "CompatibilityMode", | ||
50 | "Date", | ||
51 | "DesktopFolder", | ||
52 | "FavoritesFolder", | ||
53 | "FontsFolder", | ||
54 | "InstallerName", | ||
55 | "InstallerVersion", | ||
56 | "LocalAppDataFolder", | ||
57 | "LogonUser", | ||
58 | "MyPicturesFolder", | ||
59 | "NativeMachine", | ||
60 | "NTProductType", | ||
61 | "NTSuiteBackOffice", | ||
62 | "NTSuiteDataCenter", | ||
63 | "NTSuiteEnterprise", | ||
64 | "NTSuitePersonal", | ||
65 | "NTSuiteSmallBusiness", | ||
66 | "NTSuiteSmallBusinessRestricted", | ||
67 | "NTSuiteWebServer", | ||
68 | "PersonalFolder", | ||
69 | "Privileged", | ||
70 | "ProgramFiles64Folder", | ||
71 | "ProgramFiles6432Folder", | ||
72 | "ProgramFilesFolder", | ||
73 | "ProgramMenuFolder", | ||
74 | "RebootPending", | ||
75 | "SendToFolder", | ||
76 | "ServicePackLevel", | ||
77 | "StartMenuFolder", | ||
78 | "StartupFolder", | ||
79 | "System64Folder", | ||
80 | "SystemFolder", | ||
81 | "TempFolder", | ||
82 | "TemplateFolder", | ||
83 | "TerminalServer", | ||
84 | "UserLanguageID", | ||
85 | "UserUILanguageID", | ||
86 | "VersionMsi", | ||
87 | "VersionNT", | ||
88 | "VersionNT64", | ||
89 | "WindowsFolder", | ||
90 | "WindowsVolume", | ||
91 | "WixBundleAction", | ||
92 | "WixBundleCommandLineAction", | ||
93 | "WixBundleForcedRestartPackage", | ||
94 | "WixBundleElevated", | ||
95 | "WixBundleInstalled", | ||
96 | "WixBundleProviderKey", | ||
97 | "WixBundleTag", | ||
98 | "WixBundleVersion", | ||
99 | }); | ||
100 | |||
101 | private static readonly List<string> DisallowedMsiProperties = new List<string>( | ||
102 | new string[] { | ||
103 | "ACTION", | ||
104 | "ADDLOCAL", | ||
105 | "ADDSOURCE", | ||
106 | "ADDDEFAULT", | ||
107 | "ADVERTISE", | ||
108 | "ALLUSERS", | ||
109 | "REBOOT", | ||
110 | "REINSTALL", | ||
111 | "REINSTALLMODE", | ||
112 | "REMOVE" | ||
113 | }); | ||
114 | |||
115 | private static readonly List<string> UnavailableStartupVariables = new List<string>( | ||
116 | new string[] { | ||
117 | "RebootPending", | ||
118 | "WixBundleAction", | ||
119 | "WixBundleInstalled", | ||
120 | }); | ||
121 | |||
122 | private static readonly List<string> UnavailableDetectVariables = new List<string>( | ||
123 | new string[] { | ||
124 | "WixBundleAction", | ||
125 | }); | ||
126 | |||
127 | public string GetCanonicalRelativePath(SourceLineNumber sourceLineNumbers, string elementName, string attributeName, string relativePath) | ||
128 | { | ||
129 | const string root = @"C:\"; | ||
130 | if (!Path.IsPathRooted(relativePath)) | ||
131 | { | ||
132 | var normalizedPath = Path.GetFullPath(root + relativePath); | ||
133 | if (normalizedPath.StartsWith(root)) | ||
134 | { | ||
135 | var canonicalizedPath = normalizedPath.Substring(root.Length); | ||
136 | if (canonicalizedPath != relativePath) | ||
137 | { | ||
138 | this.Messaging.Write(WarningMessages.PathCanonicalized(sourceLineNumbers, elementName, attributeName, relativePath, canonicalizedPath)); | ||
139 | } | ||
140 | return canonicalizedPath; | ||
141 | } | ||
142 | } | ||
143 | |||
144 | this.Messaging.Write(ErrorMessages.PayloadMustBeRelativeToCache(sourceLineNumbers, elementName, attributeName, relativePath)); | ||
145 | return relativePath; | ||
146 | } | ||
147 | |||
148 | public bool ValidateBundleVariableName(SourceLineNumber sourceLineNumbers, string elementName, string attributeName, string variableName) | ||
149 | { | ||
150 | if (String.IsNullOrEmpty(variableName)) | ||
151 | { | ||
152 | this.Messaging.Write(ErrorMessages.IllegalEmptyAttributeValue(sourceLineNumbers, elementName, attributeName)); | ||
153 | |||
154 | return false; | ||
155 | } | ||
156 | else if (BuiltinBundleVariables.Contains(variableName)) | ||
157 | { | ||
158 | var illegalValues = CreateValueList(ValueListKind.Or, BuiltinBundleVariables); | ||
159 | this.Messaging.Write(ErrorMessages.IllegalAttributeValueWithIllegalList(sourceLineNumbers, elementName, attributeName, variableName, illegalValues)); | ||
160 | |||
161 | return false; | ||
162 | } | ||
163 | else | ||
164 | { | ||
165 | return true; | ||
166 | } | ||
167 | } | ||
168 | |||
169 | public bool ValidateBundleMsiPropertyName(SourceLineNumber sourceLineNumbers, string elementName, string attributeName, string propertyName) | ||
170 | { | ||
171 | if (String.IsNullOrEmpty(propertyName)) | ||
172 | { | ||
173 | this.Messaging.Write(ErrorMessages.IllegalEmptyAttributeValue(sourceLineNumbers, elementName, attributeName)); | ||
174 | |||
175 | return false; | ||
176 | } | ||
177 | else if (DisallowedMsiProperties.Contains(propertyName)) | ||
178 | { | ||
179 | var illegalValues = CreateValueList(ValueListKind.Or, DisallowedMsiProperties); | ||
180 | this.Messaging.Write(ErrorMessages.DisallowedMsiProperty(sourceLineNumbers, propertyName, illegalValues)); | ||
181 | |||
182 | return false; | ||
183 | } | ||
184 | else | ||
185 | { | ||
186 | return true; | ||
187 | } | ||
188 | } | ||
189 | |||
190 | public bool ValidateBundleCondition(SourceLineNumber sourceLineNumbers, string elementName, string attributeName, string condition, BundleConditionPhase phase) | ||
191 | { | ||
192 | if (!this.TryParseCondition(sourceLineNumbers, elementName, attributeName, condition)) | ||
193 | { | ||
194 | return false; | ||
195 | } | ||
196 | |||
197 | |||
198 | // TODO: These lists are incomplete. | ||
199 | List<string> unavailableVariables = null; | ||
200 | switch (phase) | ||
201 | { | ||
202 | case BundleConditionPhase.Startup: | ||
203 | unavailableVariables = UnavailableStartupVariables; | ||
204 | break; | ||
205 | case BundleConditionPhase.Detect: | ||
206 | unavailableVariables = UnavailableDetectVariables; | ||
207 | break; | ||
208 | } | ||
209 | |||
210 | if (unavailableVariables != null) | ||
211 | { | ||
212 | return this.ValidateBundleConditionUnavailableVariables(sourceLineNumbers, elementName, attributeName, condition, unavailableVariables); | ||
213 | } | ||
214 | else | ||
215 | { | ||
216 | return true; | ||
217 | } | ||
218 | } | ||
219 | |||
220 | private bool ValidateBundleConditionUnavailableVariables(SourceLineNumber sourceLineNumbers, string elementName, string attributeName, string condition, List<string> unavailableVariables) | ||
221 | { | ||
222 | foreach (var variableName in unavailableVariables) | ||
223 | { | ||
224 | //TODO: use the results of parsing to validate that the restricted variables are actually used as variables | ||
225 | if (condition.Contains(variableName)) | ||
226 | { | ||
227 | var illegalValues = CreateValueList(ValueListKind.Or, unavailableVariables); | ||
228 | this.Messaging.Write(WarningMessages.UnavailableBundleConditionVariable(sourceLineNumbers, elementName, attributeName, variableName, illegalValues)); | ||
229 | |||
230 | return false; | ||
231 | } | ||
232 | } | ||
233 | |||
234 | return true; | ||
235 | } | ||
236 | |||
237 | private bool TryParseCondition(SourceLineNumber sourceLineNumbers, string elementName, string attributeName, string condition) | ||
238 | { | ||
239 | if (String.IsNullOrEmpty(condition)) | ||
240 | { | ||
241 | this.Messaging.Write(ErrorMessages.IllegalEmptyAttributeValue(sourceLineNumbers, elementName, attributeName)); | ||
242 | |||
243 | return false; | ||
244 | } | ||
245 | //TODO: Actually parse the condition to definitively tell which Variables are referenced. | ||
246 | else if (condition.Trim() == "=") | ||
247 | { | ||
248 | this.Messaging.Write(ErrorMessages.InvalidBundleCondition(sourceLineNumbers, elementName, attributeName, condition)); | ||
249 | return false; | ||
250 | } | ||
251 | else | ||
252 | { | ||
253 | return true; | ||
254 | } | ||
255 | } | ||
256 | |||
257 | private static string CreateValueList(ValueListKind kind, IEnumerable<string> values) | ||
258 | { | ||
259 | // Ideally, we could denote the list kind (and the list itself) directly in the | ||
260 | // message XML, and detect and expand in the MessageHandler.GenerateMessageString() | ||
261 | // method. Doing so would make vararg-style messages much easier, but impacts | ||
262 | // every single message we format. For now, callers just have to know when a | ||
263 | // message takes a list of values in a single string argument, the caller will | ||
264 | // have to do the expansion themselves. (And, unfortunately, hard-code the knowledge | ||
265 | // that the list is an 'and' or 'or' list.) | ||
266 | |||
267 | // For a localizable solution, we need to be able to get the list format string | ||
268 | // from resources. We aren't currently localized right now, so the values are | ||
269 | // just hard-coded. | ||
270 | const string valueFormat = "'{0}'"; | ||
271 | const string valueSeparator = ", "; | ||
272 | var terminalTerm = String.Empty; | ||
273 | |||
274 | switch (kind) | ||
275 | { | ||
276 | case ValueListKind.None: | ||
277 | terminalTerm = ""; | ||
278 | break; | ||
279 | case ValueListKind.And: | ||
280 | terminalTerm = "and "; | ||
281 | break; | ||
282 | case ValueListKind.Or: | ||
283 | terminalTerm = "or "; | ||
284 | break; | ||
285 | } | ||
286 | |||
287 | var list = new StringBuilder(); | ||
288 | |||
289 | // This weird construction helps us determine when we're adding the last value | ||
290 | // to the list. Instead of adding them as we encounter them, we cache the current | ||
291 | // value and append the *previous* one. | ||
292 | string previousValue = null; | ||
293 | var haveValues = false; | ||
294 | foreach (var value in values) | ||
295 | { | ||
296 | if (null != previousValue) | ||
297 | { | ||
298 | if (haveValues) | ||
299 | { | ||
300 | list.Append(valueSeparator); | ||
301 | } | ||
302 | list.AppendFormat(valueFormat, previousValue); | ||
303 | haveValues = true; | ||
304 | } | ||
305 | |||
306 | previousValue = value; | ||
307 | } | ||
308 | |||
309 | // If we have no previous value, that means that the list contained no values, and | ||
310 | // something has gone very wrong. | ||
311 | Debug.Assert(null != previousValue); | ||
312 | if (null != previousValue) | ||
313 | { | ||
314 | if (haveValues) | ||
315 | { | ||
316 | list.Append(valueSeparator); | ||
317 | list.Append(terminalTerm); | ||
318 | } | ||
319 | list.AppendFormat(valueFormat, previousValue); | ||
320 | //haveValues = true; | ||
321 | } | ||
322 | |||
323 | return list.ToString(); | ||
324 | } | ||
325 | } | ||
326 | } | ||
diff --git a/src/wix/WixToolset.Core/ExtensibilityServices/ParseHelper.cs b/src/wix/WixToolset.Core/ExtensibilityServices/ParseHelper.cs index 1a678b0d..fa4f50ba 100644 --- a/src/wix/WixToolset.Core/ExtensibilityServices/ParseHelper.cs +++ b/src/wix/WixToolset.Core/ExtensibilityServices/ParseHelper.cs | |||
@@ -22,11 +22,14 @@ namespace WixToolset.Core.ExtensibilityServices | |||
22 | { | 22 | { |
23 | this.ServiceProvider = serviceProvider; | 23 | this.ServiceProvider = serviceProvider; |
24 | 24 | ||
25 | this.BundleValidator = serviceProvider.GetService<IBundleValidator>(); | ||
25 | this.Messaging = serviceProvider.GetService<IMessaging>(); | 26 | this.Messaging = serviceProvider.GetService<IMessaging>(); |
26 | } | 27 | } |
27 | 28 | ||
28 | private IServiceProvider ServiceProvider { get; } | 29 | private IServiceProvider ServiceProvider { get; } |
29 | 30 | ||
31 | private IBundleValidator BundleValidator { get; } | ||
32 | |||
30 | private IMessaging Messaging { get; } | 33 | private IMessaging Messaging { get; } |
31 | 34 | ||
32 | private ISymbolDefinitionCreator Creator { get; set; } | 35 | private ISymbolDefinitionCreator Creator { get; set; } |
@@ -239,11 +242,14 @@ namespace WixToolset.Core.ExtensibilityServices | |||
239 | 242 | ||
240 | public void CreateWixSearchSymbol(IntermediateSection section, SourceLineNumber sourceLineNumbers, string elementName, Identifier id, string variable, string condition, string after, string bundleExtensionId) | 243 | public void CreateWixSearchSymbol(IntermediateSection section, SourceLineNumber sourceLineNumbers, string elementName, Identifier id, string variable, string condition, string after, string bundleExtensionId) |
241 | { | 244 | { |
242 | // TODO: verify variable is not a standard bundle variable | ||
243 | if (variable == null) | 245 | if (variable == null) |
244 | { | 246 | { |
245 | this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, elementName, "Variable")); | 247 | this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, elementName, "Variable")); |
246 | } | 248 | } |
249 | else | ||
250 | { | ||
251 | this.BundleValidator.ValidateBundleVariableName(sourceLineNumbers, elementName, "Variable", variable); | ||
252 | } | ||
247 | 253 | ||
248 | section.AddSymbol(new WixSearchSymbol(sourceLineNumbers, id) | 254 | section.AddSymbol(new WixSearchSymbol(sourceLineNumbers, id) |
249 | { | 255 | { |
@@ -623,11 +629,6 @@ namespace WixToolset.Core.ExtensibilityServices | |||
623 | } | 629 | } |
624 | } | 630 | } |
625 | 631 | ||
626 | public string GetCanonicalRelativePath(SourceLineNumber sourceLineNumbers, string elementName, string attributeName, string relativePath) | ||
627 | { | ||
628 | return Common.GetCanonicalRelativePath(sourceLineNumbers, elementName, attributeName, relativePath, this.Messaging); | ||
629 | } | ||
630 | |||
631 | public SourceLineNumber GetSourceLineNumbers(XElement element) | 632 | public SourceLineNumber GetSourceLineNumbers(XElement element) |
632 | { | 633 | { |
633 | return Preprocessor.GetSourceLineNumbers(element); | 634 | return Preprocessor.GetSourceLineNumbers(element); |
@@ -858,5 +859,27 @@ namespace WixToolset.Core.ExtensibilityServices | |||
858 | 859 | ||
859 | return extension != null; | 860 | return extension != null; |
860 | } | 861 | } |
862 | |||
863 | #region IBundleValidator | ||
864 | public string GetCanonicalRelativePath(SourceLineNumber sourceLineNumbers, string elementName, string attributeName, string relativePath) | ||
865 | { | ||
866 | return this.BundleValidator.GetCanonicalRelativePath(sourceLineNumbers, elementName, attributeName, relativePath); | ||
867 | } | ||
868 | |||
869 | public bool ValidateBundleMsiPropertyName(SourceLineNumber sourceLineNumbers, string elementName, string attributeName, string propertyName) | ||
870 | { | ||
871 | return this.BundleValidator.ValidateBundleMsiPropertyName(sourceLineNumbers, elementName, attributeName, propertyName); | ||
872 | } | ||
873 | |||
874 | public bool ValidateBundleVariableName(SourceLineNumber sourceLineNumbers, string elementName, string attributeName, string variableName) | ||
875 | { | ||
876 | return this.BundleValidator.ValidateBundleVariableName(sourceLineNumbers, elementName, attributeName, variableName); | ||
877 | } | ||
878 | |||
879 | public bool ValidateBundleCondition(SourceLineNumber sourceLineNumbers, string elementName, string attributeName, string condition, BundleConditionPhase phase) | ||
880 | { | ||
881 | return this.BundleValidator.ValidateBundleCondition(sourceLineNumbers, elementName, attributeName, condition, phase); | ||
882 | } | ||
883 | #endregion | ||
861 | } | 884 | } |
862 | } | 885 | } |
diff --git a/src/wix/WixToolset.Core/WixToolsetServiceProvider.cs b/src/wix/WixToolset.Core/WixToolsetServiceProvider.cs index a74ba6b3..9fbf6717 100644 --- a/src/wix/WixToolset.Core/WixToolsetServiceProvider.cs +++ b/src/wix/WixToolset.Core/WixToolsetServiceProvider.cs | |||
@@ -20,6 +20,7 @@ namespace WixToolset.Core | |||
20 | // Singletons. | 20 | // Singletons. |
21 | this.AddService((provider, singletons) => AddSingleton<IExtensionManager>(singletons, new ExtensionManager(provider))); | 21 | this.AddService((provider, singletons) => AddSingleton<IExtensionManager>(singletons, new ExtensionManager(provider))); |
22 | this.AddService((provider, singletons) => AddSingleton<IMessaging>(singletons, new Messaging())); | 22 | this.AddService((provider, singletons) => AddSingleton<IMessaging>(singletons, new Messaging())); |
23 | this.AddService((provider, singletons) => AddSingleton<IBundleValidator>(singletons, new BundleValidator(provider))); | ||
23 | this.AddService((provider, singletons) => AddSingleton<ISymbolDefinitionCreator>(singletons, new SymbolDefinitionCreator(provider))); | 24 | this.AddService((provider, singletons) => AddSingleton<ISymbolDefinitionCreator>(singletons, new SymbolDefinitionCreator(provider))); |
24 | this.AddService((provider, singletons) => AddSingleton<IParseHelper>(singletons, new ParseHelper(provider))); | 25 | this.AddService((provider, singletons) => AddSingleton<IParseHelper>(singletons, new ParseHelper(provider))); |
25 | this.AddService((provider, singletons) => AddSingleton<IPreprocessHelper>(singletons, new PreprocessHelper(provider))); | 26 | this.AddService((provider, singletons) => AddSingleton<IPreprocessHelper>(singletons, new PreprocessHelper(provider))); |
diff --git a/src/wix/test/WixToolsetTest.CoreIntegration/BadInputFixture.cs b/src/wix/test/WixToolsetTest.CoreIntegration/BadInputFixture.cs index f91c0ab0..e5d6ecf1 100644 --- a/src/wix/test/WixToolsetTest.CoreIntegration/BadInputFixture.cs +++ b/src/wix/test/WixToolsetTest.CoreIntegration/BadInputFixture.cs | |||
@@ -4,6 +4,7 @@ namespace WixToolsetTest.CoreIntegration | |||
4 | { | 4 | { |
5 | using System; | 5 | using System; |
6 | using System.IO; | 6 | using System.IO; |
7 | using System.Linq; | ||
7 | using WixBuildTools.TestSupport; | 8 | using WixBuildTools.TestSupport; |
8 | using WixToolset.Core.TestPackage; | 9 | using WixToolset.Core.TestPackage; |
9 | using Xunit; | 10 | using Xunit; |
@@ -129,5 +130,47 @@ namespace WixToolsetTest.CoreIntegration | |||
129 | Assert.Equal(193, result.ExitCode); | 130 | Assert.Equal(193, result.ExitCode); |
130 | } | 131 | } |
131 | } | 132 | } |
133 | |||
134 | [Fact] | ||
135 | public void GuardsAgainstVariousBundleValuesFromLoc() | ||
136 | { | ||
137 | var folder = TestData.Get(@"TestData"); | ||
138 | |||
139 | using (var fs = new DisposableFileSystem()) | ||
140 | { | ||
141 | var baseFolder = fs.GetFolder(); | ||
142 | var intermediateFolder = Path.Combine(baseFolder, "obj"); | ||
143 | |||
144 | var result = WixRunner.Execute(new[] | ||
145 | { | ||
146 | "build", | ||
147 | Path.Combine(folder, "BundleWithInvalid", "BundleWithInvalidLocValues.wxs"), | ||
148 | "-loc", Path.Combine(folder, "BundleWithInvalid", "BundleWithInvalidLocValues.wxl"), | ||
149 | "-bindpath", Path.Combine(folder, ".Data"), | ||
150 | "-bindpath", Path.Combine(folder, "DecompileSingleFileCompressed"), | ||
151 | "-bindpath", Path.Combine(folder, "SimpleBundle", "data"), | ||
152 | "-intermediateFolder", intermediateFolder, | ||
153 | "-o", Path.Combine(baseFolder, @"bin\test.exe") | ||
154 | }); | ||
155 | |||
156 | Assert.InRange(result.ExitCode, 2, Int32.MaxValue); | ||
157 | |||
158 | var messages = result.Messages.Select(m => m.ToString()).ToList(); | ||
159 | messages.Sort(); | ||
160 | |||
161 | WixAssert.CompareLineByLine(new[] | ||
162 | { | ||
163 | "*Search/@Condition contains the built-in Variable 'WixBundleAction', which is not available when it is evaluated. (Unavailable Variables are: 'WixBundleAction'.). Rewrite the condition to avoid Variables that are never valid during its evaluation.", | ||
164 | "Bundle/@Condition contains the built-in Variable 'WixBundleInstalled', which is not available when it is evaluated. (Unavailable Variables are: 'RebootPending', 'WixBundleAction', or 'WixBundleInstalled'.). Rewrite the condition to avoid Variables that are never valid during its evaluation.", | ||
165 | "ExePackage/@DetectCondition contains the built-in Variable 'WixBundleAction', which is not available when it is evaluated. (Unavailable Variables are: 'WixBundleAction'.). Rewrite the condition to avoid Variables that are never valid during its evaluation.", | ||
166 | "The *Search/@Variable attribute's value, 'WixBundleInstalled', is one of the illegal options: 'AdminToolsFolder', 'AppDataFolder', 'CommonAppDataFolder', 'CommonFiles64Folder', 'CommonFilesFolder', 'CompatibilityMode', 'Date', 'DesktopFolder', 'FavoritesFolder', 'FontsFolder', 'InstallerName', 'InstallerVersion', 'LocalAppDataFolder', 'LogonUser', 'MyPicturesFolder', 'NativeMachine', 'NTProductType', 'NTSuiteBackOffice', 'NTSuiteDataCenter', 'NTSuiteEnterprise', 'NTSuitePersonal', 'NTSuiteSmallBusiness', 'NTSuiteSmallBusinessRestricted', 'NTSuiteWebServer', 'PersonalFolder', 'Privileged', 'ProgramFiles64Folder', 'ProgramFiles6432Folder', 'ProgramFilesFolder', 'ProgramMenuFolder', 'RebootPending', 'SendToFolder', 'ServicePackLevel', 'StartMenuFolder', 'StartupFolder', 'System64Folder', 'SystemFolder', 'TempFolder', 'TemplateFolder', 'TerminalServer', 'UserLanguageID', 'UserUILanguageID', 'VersionMsi', 'VersionNT', 'VersionNT64', 'WindowsFolder', 'WindowsVolume', 'WixBundleAction', 'WixBundleCommandLineAction', 'WixBundleForcedRestartPackage', 'WixBundleElevated', 'WixBundleInstalled', 'WixBundleProviderKey', 'WixBundleTag', or 'WixBundleVersion'.", | ||
167 | "The CommandLine/@Condition attribute's value '=' is not a valid bundle condition.", | ||
168 | "The MsiPackage/@InstallCondition attribute's value '=' is not a valid bundle condition.", | ||
169 | "The MsiProperty/@Condition attribute's value '=' is not a valid bundle condition.", | ||
170 | //"The Variable/@Name attribute's value, 'WixBundleInstalled', is one of the illegal options: 'AdminToolsFolder', 'AppDataFolder', 'CommonAppDataFolder', 'CommonFiles64Folder', 'CommonFilesFolder', 'CompatibilityMode', 'Date', 'DesktopFolder', 'FavoritesFolder', 'FontsFolder', 'InstallerName', 'InstallerVersion', 'LocalAppDataFolder', 'LogonUser', 'MyPicturesFolder', 'NativeMachine', 'NTProductType', 'NTSuiteBackOffice', 'NTSuiteDataCenter', 'NTSuiteEnterprise', 'NTSuitePersonal', 'NTSuiteSmallBusiness', 'NTSuiteSmallBusinessRestricted', 'NTSuiteWebServer', 'PersonalFolder', 'Privileged', 'ProgramFiles64Folder', 'ProgramFiles6432Folder', 'ProgramFilesFolder', 'ProgramMenuFolder', 'RebootPending', 'SendToFolder', 'ServicePackLevel', 'StartMenuFolder', 'StartupFolder', 'System64Folder', 'SystemFolder', 'TempFolder', 'TemplateFolder', 'TerminalServer', 'UserLanguageID', 'UserUILanguageID', 'VersionMsi', 'VersionNT', 'VersionNT64', 'WindowsFolder', 'WindowsVolume', 'WixBundleAction', 'WixBundleCommandLineAction', 'WixBundleForcedRestartPackage', 'WixBundleElevated', 'WixBundleInstalled', 'WixBundleProviderKey', 'WixBundleTag', or 'WixBundleVersion'.", | ||
171 | "The 'REINSTALLMODE' MsiProperty is controlled by the bootstrapper and cannot be authored. (Illegal properties are: 'ACTION', 'ADDLOCAL', 'ADDSOURCE', 'ADDDEFAULT', 'ADVERTISE', 'ALLUSERS', 'REBOOT', 'REINSTALL', 'REINSTALLMODE', or 'REMOVE'.) Remove the MsiProperty element.", | ||
172 | }, messages.ToArray()); | ||
173 | } | ||
174 | } | ||
132 | } | 175 | } |
133 | } | 176 | } |
diff --git a/src/wix/test/WixToolsetTest.CoreIntegration/TestData/BundleWithInvalid/BundleWithInvalidLocValues.wxl b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/BundleWithInvalid/BundleWithInvalidLocValues.wxl new file mode 100644 index 00000000..0b5fac56 --- /dev/null +++ b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/BundleWithInvalid/BundleWithInvalidLocValues.wxl | |||
@@ -0,0 +1,8 @@ | |||
1 | <WixLocalization xmlns="http://wixtoolset.org/schemas/v4/wxl" Culture="en-US"> | ||
2 | <String Id="BuiltinMsiPropertyName">REINSTALLMODE</String> | ||
3 | <String Id="BuiltinBurnVariableName">WixBundleInstalled</String> | ||
4 | <String Id="NonsenseDetectCondition">WixBundleAction = 4</String> | ||
5 | <String Id="NonsenseExecuteCondition">=</String> | ||
6 | <String Id="NonsenseGlobalCondition">WixBundleInstalled <> 1</String> | ||
7 | <String Id="NonsensePlanCondition">=</String> | ||
8 | </WixLocalization> | ||
diff --git a/src/wix/test/WixToolsetTest.CoreIntegration/TestData/BundleWithInvalid/BundleWithInvalidLocValues.wxs b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/BundleWithInvalid/BundleWithInvalidLocValues.wxs new file mode 100644 index 00000000..504f6e48 --- /dev/null +++ b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/BundleWithInvalid/BundleWithInvalidLocValues.wxs | |||
@@ -0,0 +1,18 @@ | |||
1 | <Wix xmlns="http://wixtoolset.org/schemas/v4/wxs"> | ||
2 | <Bundle Name="BundleWithInvalidUpgradeCode" Condition="!(loc.NonsenseGlobalCondition)" | ||
3 | Version="1.0.0.0" Manufacturer="Example Corporation" UpgradeCode="{F2A56B65-2105-44C8-A532-A93A8C169D07}"> | ||
4 | <BootstrapperApplication> | ||
5 | <BootstrapperApplicationDll SourceFile="fakeba.dll" /> | ||
6 | </BootstrapperApplication> | ||
7 | <Chain> | ||
8 | <MsiPackage SourceFile="example.msi" InstallCondition="!(loc.NonsensePlanCondition)"> | ||
9 | <MsiProperty Condition="!(loc.NonsenseExecuteCondition)" Name="!(loc.BuiltinMsiPropertyName)" Value="1" /> | ||
10 | </MsiPackage> | ||
11 | <ExePackage DetectCondition="!(loc.NonsenseDetectCondition)" UninstallArguments="-uninstall" SourceFile="burn.exe"> | ||
12 | <CommandLine Condition="!(loc.NonsenseExecuteCondition)" /> | ||
13 | </ExePackage> | ||
14 | </Chain> | ||
15 | <Variable Name="!(loc.BuiltinBurnVariableName)" Value="1" /> | ||
16 | <SetVariable Id="Builtin" Condition="!(loc.NonsenseDetectCondition)" Variable="!(loc.BuiltinBurnVariableName)" Value="1" /> | ||
17 | </Bundle> | ||
18 | </Wix> | ||