diff options
author | Rob Mensching <rob@firegiant.com> | 2022-02-07 21:28:07 -0800 |
---|---|---|
committer | Rob Mensching <rob@firegiant.com> | 2022-02-08 09:42:04 -0800 |
commit | 24e8f28dc9bea0a72a82abc6cafebe2364c94ef1 (patch) | |
tree | d4fedc72d9e24e9ea347ce703b930804227845a6 | |
parent | 6f97699cc2bbcd5395590a77df43583103f71e54 (diff) | |
download | wix-24e8f28dc9bea0a72a82abc6cafebe2364c94ef1.tar.gz wix-24e8f28dc9bea0a72a82abc6cafebe2364c94ef1.tar.bz2 wix-24e8f28dc9bea0a72a82abc6cafebe2364c94ef1.zip |
Make validation independent of the build command
In MSBuild this adds a new WindowsInstallerValidation target that
automatically runs validation after a successful build. From the
command-line the "wix msi" command gets a "validate" subcommand that
will validate an MSI or MSM file.
33 files changed, 711 insertions, 202 deletions
diff --git a/src/api/wix/WixToolset.Extensibility/Data/IBindContext.cs b/src/api/wix/WixToolset.Extensibility/Data/IBindContext.cs index d0c65683..671da292 100644 --- a/src/api/wix/WixToolset.Extensibility/Data/IBindContext.cs +++ b/src/api/wix/WixToolset.Extensibility/Data/IBindContext.cs | |||
@@ -53,11 +53,6 @@ namespace WixToolset.Extensibility.Data | |||
53 | IReadOnlyCollection<IFileSystemExtension> FileSystemExtensions { get; set; } | 53 | IReadOnlyCollection<IFileSystemExtension> FileSystemExtensions { get; set; } |
54 | 54 | ||
55 | /// <summary> | 55 | /// <summary> |
56 | /// Set of ICEs to execute. | ||
57 | /// </summary> | ||
58 | IReadOnlyCollection<string> Ices { get; set; } | ||
59 | |||
60 | /// <summary> | ||
61 | /// Intermedaite folder. | 56 | /// Intermedaite folder. |
62 | /// </summary> | 57 | /// </summary> |
63 | string IntermediateFolder { get; set; } | 58 | string IntermediateFolder { get; set; } |
@@ -98,16 +93,6 @@ namespace WixToolset.Extensibility.Data | |||
98 | int? ResolvedLcid { get; set; } | 93 | int? ResolvedLcid { get; set; } |
99 | 94 | ||
100 | /// <summary> | 95 | /// <summary> |
101 | /// Set of ICEs to skip. | ||
102 | /// </summary> | ||
103 | IReadOnlyCollection<string> SuppressIces { get; set; } | ||
104 | |||
105 | /// <summary> | ||
106 | /// Skip all ICEs. | ||
107 | /// </summary> | ||
108 | bool SuppressValidation { get; set; } | ||
109 | |||
110 | /// <summary> | ||
111 | /// Skip creation of output. | 96 | /// Skip creation of output. |
112 | /// </summary> | 97 | /// </summary> |
113 | bool SuppressLayout { get; set; } | 98 | bool SuppressLayout { get; set; } |
diff --git a/src/test/burn/Directory.wixproj.props b/src/test/burn/Directory.wixproj.props index af5ef196..21ab5107 100644 --- a/src/test/burn/Directory.wixproj.props +++ b/src/test/burn/Directory.wixproj.props | |||
@@ -7,6 +7,7 @@ | |||
7 | <DefaultCompressionLevel>None</DefaultCompressionLevel> | 7 | <DefaultCompressionLevel>None</DefaultCompressionLevel> |
8 | <CompilerAdditionalOptions>-wx</CompilerAdditionalOptions> | 8 | <CompilerAdditionalOptions>-wx</CompilerAdditionalOptions> |
9 | <SuppressSpecificWarnings>1154;$(SuppressSpecificWarnings)</SuppressSpecificWarnings> | 9 | <SuppressSpecificWarnings>1154;$(SuppressSpecificWarnings)</SuppressSpecificWarnings> |
10 | <SuppressValidation>true</SuppressValidation> | ||
10 | <ForTestingUseOnlyWixextPath>$(BaseOutputPath)$(Configuration)\netstandard2.0\ForTestingUseOnly.wixext.dll</ForTestingUseOnlyWixextPath> | 11 | <ForTestingUseOnlyWixextPath>$(BaseOutputPath)$(Configuration)\netstandard2.0\ForTestingUseOnly.wixext.dll</ForTestingUseOnlyWixextPath> |
11 | </PropertyGroup> | 12 | </PropertyGroup> |
12 | </Project> | 13 | </Project> |
diff --git a/src/test/wix/TestData/WixprojPackageCsprojWebApplicationNetCore/Package.wxs b/src/test/wix/TestData/WixprojPackageCsprojWebApplicationNetCore/Package.wxs index c228bb33..cbc8cae1 100644 --- a/src/test/wix/TestData/WixprojPackageCsprojWebApplicationNetCore/Package.wxs +++ b/src/test/wix/TestData/WixprojPackageCsprojWebApplicationNetCore/Package.wxs | |||
@@ -1,5 +1,5 @@ | |||
1 | <Wix xmlns="http://wixtoolset.org/schemas/v4/wxs"> | 1 | <Wix xmlns="http://wixtoolset.org/schemas/v4/wxs"> |
2 | <Package Name='~WebApp' Manufacturer='WiX Toolset' Version='0.0.1' UpgradeCode='00000000-0000-0000-0000-000000000000'> | 2 | <Package Name='~WebApp' Manufacturer='WiX Toolset' Version='0.0.1' UpgradeCode='41a2c17e-1976-465b-bcde-eae03516ca68'> |
3 | 3 | ||
4 | <StandardDirectory Id='ProgramFiles6432Folder'> | 4 | <StandardDirectory Id='ProgramFiles6432Folder'> |
5 | <Directory Id='ApplicationFolder' Name='~Web App'> | 5 | <Directory Id='ApplicationFolder' Name='~Web App'> |
diff --git a/src/test/wix/TestData/WixprojPackageVcxprojWindowsApp/Package.wxs b/src/test/wix/TestData/WixprojPackageVcxprojWindowsApp/Package.wxs index c0370683..fe849608 100644 --- a/src/test/wix/TestData/WixprojPackageVcxprojWindowsApp/Package.wxs +++ b/src/test/wix/TestData/WixprojPackageVcxprojWindowsApp/Package.wxs | |||
@@ -1,5 +1,5 @@ | |||
1 | <Wix xmlns="http://wixtoolset.org/schemas/v4/wxs"> | 1 | <Wix xmlns="http://wixtoolset.org/schemas/v4/wxs"> |
2 | <Package Name='!(loc.PackageName)' Manufacturer='WiX Toolset' Version='0.0.1' UpgradeCode='00000000-0000-0000-0000-000000000000'> | 2 | <Package Name='!(loc.PackageName)' Manufacturer='WiX Toolset' Version='0.0.1' UpgradeCode='41a2c17e-1976-465b-bcde-eae03516ca68'> |
3 | 3 | ||
4 | <StandardDirectory Id='ProgramFiles6432Folder'> | 4 | <StandardDirectory Id='ProgramFiles6432Folder'> |
5 | <Directory Id='ApplicationFolder' Name='Test App'> | 5 | <Directory Id='ApplicationFolder' Name='Test App'> |
diff --git a/src/test/wix/TestData/WixprojPackageVcxprojWindowsAppMultiArch/Package.wxs b/src/test/wix/TestData/WixprojPackageVcxprojWindowsAppMultiArch/Package.wxs index 9d3df756..ad95dac3 100644 --- a/src/test/wix/TestData/WixprojPackageVcxprojWindowsAppMultiArch/Package.wxs +++ b/src/test/wix/TestData/WixprojPackageVcxprojWindowsAppMultiArch/Package.wxs | |||
@@ -1,5 +1,5 @@ | |||
1 | <Wix xmlns="http://wixtoolset.org/schemas/v4/wxs"> | 1 | <Wix xmlns="http://wixtoolset.org/schemas/v4/wxs"> |
2 | <Package Name='WixprojPackageVcxprojWindowsApp' Manufacturer='WiX Toolset' Version='0.0.1' UpgradeCode='00000000-0000-0000-0000-000000000000'> | 2 | <Package Name='WixprojPackageVcxprojWindowsApp' Manufacturer='WiX Toolset' Version='0.0.1' UpgradeCode='41a2c17e-1976-465b-bcde-eae03516ca68'> |
3 | 3 | ||
4 | <StandardDirectory Id='ProgramFilesFolder'> | 4 | <StandardDirectory Id='ProgramFilesFolder'> |
5 | <Directory Id='Application32Folder' Name='Test App (32-bit)' /> | 5 | <Directory Id='Application32Folder' Name='Test App (32-bit)' /> |
diff --git a/src/wix/WixToolset.BuildTasks/WindowsInstallerValidation.cs b/src/wix/WixToolset.BuildTasks/WindowsInstallerValidation.cs new file mode 100644 index 00000000..ae708c0e --- /dev/null +++ b/src/wix/WixToolset.BuildTasks/WindowsInstallerValidation.cs | |||
@@ -0,0 +1,59 @@ | |||
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.BuildTasks | ||
4 | { | ||
5 | using Microsoft.Build.Framework; | ||
6 | |||
7 | /// <summary> | ||
8 | /// An MSBuild task to run WiX to detach bundle engine to be signed. | ||
9 | /// </summary> | ||
10 | public sealed partial class WindowsInstallerValidation : WixExeBaseTask | ||
11 | { | ||
12 | /// <summary> | ||
13 | /// Gets or sets the path to the database to validate. | ||
14 | /// </summary> | ||
15 | [Required] | ||
16 | public ITaskItem DatabaseFile { get; set; } | ||
17 | |||
18 | /// <summary> | ||
19 | /// Gets or sets the intermedidate folder to use. | ||
20 | /// </summary> | ||
21 | public ITaskItem IntermediateDirectory { get; set; } | ||
22 | |||
23 | /// <summary> | ||
24 | /// Gets or sets the paths to ICE CUBes to execute. | ||
25 | /// </summary> | ||
26 | public string[] CubeFiles { get; set; } | ||
27 | |||
28 | /// <summary> | ||
29 | /// Gets or sets the ICEs to execute. | ||
30 | /// </summary> | ||
31 | public string[] Ices { get; set; } | ||
32 | |||
33 | /// <summary> | ||
34 | /// Gets or sets the ICEs to suppress. | ||
35 | /// </summary> | ||
36 | public string[] SuppressIces { get; set; } | ||
37 | |||
38 | /// <summary> | ||
39 | /// Gets or sets the .wixpdb for the database. | ||
40 | /// </summary> | ||
41 | public ITaskItem WixpdbFile { get; set; } | ||
42 | |||
43 | protected override void BuildCommandLine(WixCommandLineBuilder commandLineBuilder) | ||
44 | { | ||
45 | commandLineBuilder.AppendTextUnquoted("msi validate"); | ||
46 | |||
47 | commandLineBuilder.AppendFileNameIfNotNull(this.DatabaseFile); | ||
48 | commandLineBuilder.AppendSwitchIfNotNull("-pdb ", this.WixpdbFile); | ||
49 | commandLineBuilder.AppendSwitchIfNotNull("-intermediatefolder ", this.IntermediateDirectory); | ||
50 | commandLineBuilder.AppendArrayIfNotNull("-cub ", this.CubeFiles); | ||
51 | commandLineBuilder.AppendArrayIfNotNull("-ice ", this.Ices); | ||
52 | commandLineBuilder.AppendArrayIfNotNull("-sice ", this.SuppressIces); | ||
53 | |||
54 | base.BuildCommandLine(commandLineBuilder); | ||
55 | |||
56 | commandLineBuilder.AppendTextIfNotWhitespace(this.AdditionalOptions); | ||
57 | } | ||
58 | } | ||
59 | } | ||
diff --git a/src/wix/WixToolset.BuildTasks/WixBuild.cs b/src/wix/WixToolset.BuildTasks/WixBuild.cs index 2d35c391..11de0242 100644 --- a/src/wix/WixToolset.BuildTasks/WixBuild.cs +++ b/src/wix/WixToolset.BuildTasks/WixBuild.cs | |||
@@ -64,13 +64,8 @@ namespace WixToolset.BuildTasks | |||
64 | public ITaskItem UnreferencedSymbolsFile { get; set; } | 64 | public ITaskItem UnreferencedSymbolsFile { get; set; } |
65 | 65 | ||
66 | public ITaskItem WixProjectFile { get; set; } | 66 | public ITaskItem WixProjectFile { get; set; } |
67 | public string[] WixVariables { get; set; } | ||
68 | |||
69 | public bool SuppressValidation { get; set; } | ||
70 | 67 | ||
71 | public string[] SuppressIces { get; set; } | 68 | public string[] WixVariables { get; set; } |
72 | |||
73 | public string AdditionalCub { get; set; } | ||
74 | 69 | ||
75 | protected override void BuildCommandLine(WixCommandLineBuilder commandLineBuilder) | 70 | protected override void BuildCommandLine(WixCommandLineBuilder commandLineBuilder) |
76 | { | 71 | { |
@@ -85,8 +80,6 @@ namespace WixToolset.BuildTasks | |||
85 | commandLineBuilder.AppendArrayIfNotNull("-d ", this.DefineConstants); | 80 | commandLineBuilder.AppendArrayIfNotNull("-d ", this.DefineConstants); |
86 | commandLineBuilder.AppendArrayIfNotNull("-I ", this.IncludeSearchPaths); | 81 | commandLineBuilder.AppendArrayIfNotNull("-I ", this.IncludeSearchPaths); |
87 | commandLineBuilder.AppendExtensions(this.Extensions, this.ExtensionDirectory, this.ReferencePaths); | 82 | commandLineBuilder.AppendExtensions(this.Extensions, this.ExtensionDirectory, this.ReferencePaths); |
88 | commandLineBuilder.AppendIfTrue("-sval", this.SuppressValidation); | ||
89 | commandLineBuilder.AppendArrayIfNotNull("-sice ", this.SuppressIces); | ||
90 | commandLineBuilder.AppendSwitchIfNotNull("-usf ", this.UnreferencedSymbolsFile); | 83 | commandLineBuilder.AppendSwitchIfNotNull("-usf ", this.UnreferencedSymbolsFile); |
91 | commandLineBuilder.AppendSwitchIfNotNull("-cc ", this.CabinetCachePath); | 84 | commandLineBuilder.AppendSwitchIfNotNull("-cc ", this.CabinetCachePath); |
92 | commandLineBuilder.AppendSwitchIfNotNull("-intermediatefolder ", this.IntermediateDirectory); | 85 | commandLineBuilder.AppendSwitchIfNotNull("-intermediatefolder ", this.IntermediateDirectory); |
diff --git a/src/wix/WixToolset.Core.Native/FileSystem.cs b/src/wix/WixToolset.Core.Native/FileSystem.cs index d843a9e8..3dc336d6 100644 --- a/src/wix/WixToolset.Core.Native/FileSystem.cs +++ b/src/wix/WixToolset.Core.Native/FileSystem.cs | |||
@@ -62,14 +62,14 @@ namespace WixToolset.Core.Native | |||
62 | 62 | ||
63 | private static void EnsureDirectoryWithoutFile(string path) | 63 | private static void EnsureDirectoryWithoutFile(string path) |
64 | { | 64 | { |
65 | File.Delete(path); | ||
66 | |||
67 | var directory = Path.GetDirectoryName(path); | 65 | var directory = Path.GetDirectoryName(path); |
68 | 66 | ||
69 | if (!String.IsNullOrEmpty(directory)) | 67 | if (!String.IsNullOrEmpty(directory)) |
70 | { | 68 | { |
71 | Directory.CreateDirectory(directory); | 69 | Directory.CreateDirectory(directory); |
72 | } | 70 | } |
71 | |||
72 | File.Delete(path); | ||
73 | } | 73 | } |
74 | 74 | ||
75 | [DllImport("Kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)] | 75 | [DllImport("Kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)] |
diff --git a/src/wix/WixToolset.Core.WindowsInstaller/Bind/BindDatabaseCommand.cs b/src/wix/WixToolset.Core.WindowsInstaller/Bind/BindDatabaseCommand.cs index f2a8b9c6..ab471702 100644 --- a/src/wix/WixToolset.Core.WindowsInstaller/Bind/BindDatabaseCommand.cs +++ b/src/wix/WixToolset.Core.WindowsInstaller/Bind/BindDatabaseCommand.cs | |||
@@ -21,11 +21,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
21 | // As outlined in RFC 4122, this is our namespace for generating name-based (version 3) UUIDs. | 21 | // As outlined in RFC 4122, this is our namespace for generating name-based (version 3) UUIDs. |
22 | internal static readonly Guid WixComponentGuidNamespace = new Guid("{3064E5C6-FB63-4FE9-AC49-E446A792EFA5}"); | 22 | internal static readonly Guid WixComponentGuidNamespace = new Guid("{3064E5C6-FB63-4FE9-AC49-E446A792EFA5}"); |
23 | 23 | ||
24 | public BindDatabaseCommand(IBindContext context, IEnumerable<IWindowsInstallerBackendBinderExtension> backendExtension, string cubeFile) : this(context, backendExtension, null, cubeFile) | 24 | public BindDatabaseCommand(IBindContext context, IEnumerable<IWindowsInstallerBackendBinderExtension> backendExtension, IEnumerable<SubStorage> subStorages = null) |
25 | { | ||
26 | } | ||
27 | |||
28 | public BindDatabaseCommand(IBindContext context, IEnumerable<IWindowsInstallerBackendBinderExtension> backendExtension, IEnumerable<SubStorage> subStorages, string cubeFile) | ||
29 | { | 25 | { |
30 | this.ServiceProvider = context.ServiceProvider; | 26 | this.ServiceProvider = context.ServiceProvider; |
31 | 27 | ||
@@ -53,11 +49,6 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
53 | 49 | ||
54 | this.SubStorages = subStorages; | 50 | this.SubStorages = subStorages; |
55 | 51 | ||
56 | this.SuppressValidation = context.SuppressValidation; | ||
57 | this.Ices = context.Ices; | ||
58 | this.SuppressedIces = context.SuppressIces; | ||
59 | this.CubeFiles = String.IsNullOrEmpty(cubeFile) ? null : new[] { cubeFile }; | ||
60 | |||
61 | this.BackendExtensions = backendExtension; | 52 | this.BackendExtensions = backendExtension; |
62 | } | 53 | } |
63 | 54 | ||
@@ -109,12 +100,6 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
109 | 100 | ||
110 | private bool SuppressValidation { get; } | 101 | private bool SuppressValidation { get; } |
111 | 102 | ||
112 | private IEnumerable<string> Ices { get; } | ||
113 | |||
114 | private IEnumerable<string> SuppressedIces { get; } | ||
115 | |||
116 | private IEnumerable<string> CubeFiles { get; } | ||
117 | |||
118 | public IBindResult Execute() | 103 | public IBindResult Execute() |
119 | { | 104 | { |
120 | if (!this.Intermediate.HasLevel(Data.IntermediateLevels.Linked) || !this.Intermediate.HasLevel(Data.IntermediateLevels.Resolved)) | 105 | if (!this.Intermediate.HasLevel(Data.IntermediateLevels.Linked) || !this.Intermediate.HasLevel(Data.IntermediateLevels.Resolved)) |
@@ -507,20 +492,6 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
507 | return null; | 492 | return null; |
508 | } | 493 | } |
509 | 494 | ||
510 | // Validate the output if there are CUBe files and we're not explicitly suppressing validation. | ||
511 | if (this.CubeFiles != null && !this.SuppressValidation) | ||
512 | { | ||
513 | var command = new ValidateDatabaseCommand(this.Messaging, this.WindowsInstallerBackendHelper, this.IntermediateFolder, data, this.OutputPath, this.CubeFiles, this.Ices, this.SuppressedIces); | ||
514 | command.Execute(); | ||
515 | |||
516 | trackedFiles.AddRange(command.TrackedFiles); | ||
517 | } | ||
518 | |||
519 | if (this.Messaging.EncounteredError) | ||
520 | { | ||
521 | return null; | ||
522 | } | ||
523 | |||
524 | // Process uncompressed files. | 495 | // Process uncompressed files. |
525 | if (!this.SuppressLayout && uncompressedFiles.Any()) | 496 | if (!this.SuppressLayout && uncompressedFiles.Any()) |
526 | { | 497 | { |
diff --git a/src/wix/WixToolset.Core.WindowsInstaller/CommandLine/ValidateSubcommand.cs b/src/wix/WixToolset.Core.WindowsInstaller/CommandLine/ValidateSubcommand.cs new file mode 100644 index 00000000..7d77aa30 --- /dev/null +++ b/src/wix/WixToolset.Core.WindowsInstaller/CommandLine/ValidateSubcommand.cs | |||
@@ -0,0 +1,131 @@ | |||
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.WindowsInstaller.CommandLine | ||
4 | { | ||
5 | using System; | ||
6 | using System.Collections.Generic; | ||
7 | using System.IO; | ||
8 | using System.Threading; | ||
9 | using System.Threading.Tasks; | ||
10 | using WixToolset.Core.WindowsInstaller.Validate; | ||
11 | using WixToolset.Data.WindowsInstaller; | ||
12 | using WixToolset.Extensibility.Services; | ||
13 | |||
14 | internal class ValidateSubcommand : WindowsInstallerSubcommandBase | ||
15 | { | ||
16 | public ValidateSubcommand(IServiceProvider serviceProvider) | ||
17 | { | ||
18 | this.Messaging = serviceProvider.GetService<IMessaging>(); | ||
19 | } | ||
20 | |||
21 | private IMessaging Messaging { get; } | ||
22 | |||
23 | private string DatabasePath { get; set; } | ||
24 | |||
25 | private string WixpdbPath { get; set; } | ||
26 | |||
27 | private string IntermediateFolder { get; set; } | ||
28 | |||
29 | private List<string> CubeFiles { get; } = new List<string>(); | ||
30 | |||
31 | private List<string> Ices { get; } = new List<string>(); | ||
32 | |||
33 | private List<string> SuppressIces { get; } = new List<string>(); | ||
34 | |||
35 | public override Task<int> ExecuteAsync(CancellationToken cancellationToken) | ||
36 | { | ||
37 | WindowsInstallerData data = null; | ||
38 | |||
39 | if (String.IsNullOrEmpty(this.DatabasePath)) | ||
40 | { | ||
41 | Console.Error.WriteLine("Input MSI or MSM database is required"); | ||
42 | return Task.FromResult(-1); | ||
43 | } | ||
44 | |||
45 | if (this.CubeFiles.Count == 0) | ||
46 | { | ||
47 | var ext = Path.GetExtension(this.DatabasePath); | ||
48 | switch (ext.ToLowerInvariant()) | ||
49 | { | ||
50 | case ".msi": | ||
51 | this.CubeFiles.Add("darice.cub"); | ||
52 | break; | ||
53 | |||
54 | case ".msm": | ||
55 | this.CubeFiles.Add("mergemod.cub"); | ||
56 | break; | ||
57 | |||
58 | default: | ||
59 | Console.Error.WriteLine("Unknown extension: {0}. Use the -cub switch to specify the path to the ICE CUBe file", ext); | ||
60 | return Task.FromResult(-1); | ||
61 | } | ||
62 | } | ||
63 | |||
64 | if (String.IsNullOrEmpty(this.WixpdbPath)) | ||
65 | { | ||
66 | this.WixpdbPath = Path.ChangeExtension(this.DatabasePath, ".wixpdb"); | ||
67 | } | ||
68 | |||
69 | if (String.IsNullOrEmpty(this.IntermediateFolder)) | ||
70 | { | ||
71 | this.IntermediateFolder = Path.GetTempPath(); | ||
72 | } | ||
73 | |||
74 | if (File.Exists(this.WixpdbPath)) | ||
75 | { | ||
76 | data = WindowsInstallerData.Load(this.WixpdbPath); | ||
77 | } | ||
78 | |||
79 | var command = new ValidateDatabaseCommand(this.Messaging, this.IntermediateFolder, this.DatabasePath, data, this.CubeFiles, this.Ices, this.SuppressIces); | ||
80 | command.Execute(); | ||
81 | |||
82 | return Task.FromResult(this.Messaging.EncounteredError ? 1 : 0); | ||
83 | } | ||
84 | |||
85 | public override bool TryParseArgument(ICommandLineParser parser, string argument) | ||
86 | { | ||
87 | if (parser.IsSwitch(argument)) | ||
88 | { | ||
89 | var parameter = argument.Substring(1); | ||
90 | switch (parameter.ToLowerInvariant()) | ||
91 | { | ||
92 | case "cub": | ||
93 | { | ||
94 | var value = parser.GetNextArgumentOrError(argument); | ||
95 | this.CubeFiles.Add(value); | ||
96 | return true; | ||
97 | } | ||
98 | |||
99 | case "ice": | ||
100 | { | ||
101 | var value = parser.GetNextArgumentOrError(argument); | ||
102 | this.Ices.Add(value); | ||
103 | return true; | ||
104 | } | ||
105 | |||
106 | case "intermediatefolder": | ||
107 | this.IntermediateFolder = parser.GetNextArgumentAsDirectoryOrError(argument); | ||
108 | return true; | ||
109 | |||
110 | case "pdb": | ||
111 | this.WixpdbPath = parser.GetNextArgumentAsFilePathOrError(argument); | ||
112 | return true; | ||
113 | |||
114 | case "sice": | ||
115 | { | ||
116 | var value = parser.GetNextArgumentOrError(argument); | ||
117 | this.SuppressIces.Add(value); | ||
118 | return true; | ||
119 | } | ||
120 | } | ||
121 | } | ||
122 | else if (String.IsNullOrEmpty(this.DatabasePath)) | ||
123 | { | ||
124 | this.DatabasePath = argument; | ||
125 | return true; | ||
126 | } | ||
127 | |||
128 | return false; | ||
129 | } | ||
130 | } | ||
131 | } | ||
diff --git a/src/wix/WixToolset.Core.WindowsInstaller/CommandLine/WindowsInstallerCommand.cs b/src/wix/WixToolset.Core.WindowsInstaller/CommandLine/WindowsInstallerCommand.cs index db178ddf..a0da7fa4 100644 --- a/src/wix/WixToolset.Core.WindowsInstaller/CommandLine/WindowsInstallerCommand.cs +++ b/src/wix/WixToolset.Core.WindowsInstaller/CommandLine/WindowsInstallerCommand.cs | |||
@@ -48,6 +48,10 @@ namespace WixToolset.Core.WindowsInstaller.CommandLine | |||
48 | case "inscribe": | 48 | case "inscribe": |
49 | this.Subcommand = new InscribeSubcommand(this.ServiceProvider); | 49 | this.Subcommand = new InscribeSubcommand(this.ServiceProvider); |
50 | return true; | 50 | return true; |
51 | |||
52 | case "validate": | ||
53 | this.Subcommand = new ValidateSubcommand(this.ServiceProvider); | ||
54 | return true; | ||
51 | } | 55 | } |
52 | 56 | ||
53 | return false; | 57 | return false; |
@@ -68,6 +72,7 @@ namespace WixToolset.Core.WindowsInstaller.CommandLine | |||
68 | Console.WriteLine("Commands:"); | 72 | Console.WriteLine("Commands:"); |
69 | Console.WriteLine(); | 73 | Console.WriteLine(); |
70 | Console.WriteLine(" inscribe Updates MSI database with cabinet signature information."); | 74 | Console.WriteLine(" inscribe Updates MSI database with cabinet signature information."); |
75 | Console.WriteLine(" validate Validates MSI database using standard or custom ICEs."); | ||
71 | } | 76 | } |
72 | } | 77 | } |
73 | } | 78 | } |
diff --git a/src/wix/WixToolset.Core.WindowsInstaller/MsiBackend.cs b/src/wix/WixToolset.Core.WindowsInstaller/MsiBackend.cs index 37de1904..33aa7a74 100644 --- a/src/wix/WixToolset.Core.WindowsInstaller/MsiBackend.cs +++ b/src/wix/WixToolset.Core.WindowsInstaller/MsiBackend.cs | |||
@@ -27,7 +27,7 @@ namespace WixToolset.Core.WindowsInstaller | |||
27 | var dispose = true; | 27 | var dispose = true; |
28 | try | 28 | try |
29 | { | 29 | { |
30 | var command = new BindDatabaseCommand(context, backendExtensions, "darice.cub"); | 30 | var command = new BindDatabaseCommand(context, backendExtensions); |
31 | result = command.Execute(); | 31 | result = command.Execute(); |
32 | 32 | ||
33 | foreach (var extension in backendExtensions) | 33 | foreach (var extension in backendExtensions) |
diff --git a/src/wix/WixToolset.Core.WindowsInstaller/MsmBackend.cs b/src/wix/WixToolset.Core.WindowsInstaller/MsmBackend.cs index 450bf888..02ea5f45 100644 --- a/src/wix/WixToolset.Core.WindowsInstaller/MsmBackend.cs +++ b/src/wix/WixToolset.Core.WindowsInstaller/MsmBackend.cs | |||
@@ -26,7 +26,7 @@ namespace WixToolset.Core.WindowsInstaller | |||
26 | IBindResult result = null; | 26 | IBindResult result = null; |
27 | try | 27 | try |
28 | { | 28 | { |
29 | var command = new BindDatabaseCommand(context, backendExtensions, "mergemod.cub"); | 29 | var command = new BindDatabaseCommand(context, backendExtensions); |
30 | result = command.Execute(); | 30 | result = command.Execute(); |
31 | 31 | ||
32 | foreach (var extension in backendExtensions) | 32 | foreach (var extension in backendExtensions) |
diff --git a/src/wix/WixToolset.Core.WindowsInstaller/MspBackend.cs b/src/wix/WixToolset.Core.WindowsInstaller/MspBackend.cs index 1ef9671b..d1f5eb99 100644 --- a/src/wix/WixToolset.Core.WindowsInstaller/MspBackend.cs +++ b/src/wix/WixToolset.Core.WindowsInstaller/MspBackend.cs | |||
@@ -52,7 +52,7 @@ namespace WixToolset.Core.WindowsInstaller | |||
52 | IBindResult result = null; | 52 | IBindResult result = null; |
53 | try | 53 | try |
54 | { | 54 | { |
55 | var command = new BindDatabaseCommand(context, backendExtensions, subStorages, null); | 55 | var command = new BindDatabaseCommand(context, backendExtensions, subStorages); |
56 | result = command.Execute(); | 56 | result = command.Execute(); |
57 | 57 | ||
58 | foreach (var extension in backendExtensions) | 58 | foreach (var extension in backendExtensions) |
diff --git a/src/wix/WixToolset.Core.WindowsInstaller/Bind/ValidateDatabaseCommand.cs b/src/wix/WixToolset.Core.WindowsInstaller/Validate/ValidateDatabaseCommand.cs index cf1e21c2..fe2fd2c2 100644 --- a/src/wix/WixToolset.Core.WindowsInstaller/Bind/ValidateDatabaseCommand.cs +++ b/src/wix/WixToolset.Core.WindowsInstaller/Validate/ValidateDatabaseCommand.cs | |||
@@ -1,6 +1,6 @@ | |||
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. | 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 | 2 | ||
3 | namespace WixToolset.Core.WindowsInstaller.Bind | 3 | namespace WixToolset.Core.WindowsInstaller.Validate |
4 | { | 4 | { |
5 | using System; | 5 | using System; |
6 | using System.Collections.Generic; | 6 | using System.Collections.Generic; |
@@ -18,18 +18,17 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
18 | // Set of ICEs that have equivalent-or-better checks in WiX. | 18 | // Set of ICEs that have equivalent-or-better checks in WiX. |
19 | private static readonly string[] WellKnownSuppressedIces = new[] { "ICE08", "ICE33", "ICE47", "ICE66" }; | 19 | private static readonly string[] WellKnownSuppressedIces = new[] { "ICE08", "ICE33", "ICE47", "ICE66" }; |
20 | 20 | ||
21 | public ValidateDatabaseCommand(IMessaging messaging, IBackendHelper backendHelper, string intermediateFolder, WindowsInstallerData data, string outputPath, IEnumerable<string> cubeFiles, IEnumerable<string> ices, IEnumerable<string> suppressedIces) | 21 | public ValidateDatabaseCommand(IMessaging messaging, string intermediateFolder, string databasePath, WindowsInstallerData data, IEnumerable<string> cubeFiles, IEnumerable<string> ices, IEnumerable<string> suppressedIces) |
22 | { | 22 | { |
23 | this.Messaging = messaging; | 23 | this.Messaging = messaging; |
24 | this.BackendHelper = backendHelper; | ||
25 | this.Data = data; | 24 | this.Data = data; |
26 | this.OutputPath = outputPath; | 25 | this.DatabasePath = databasePath; |
27 | this.CubeFiles = cubeFiles; | 26 | this.CubeFiles = cubeFiles; |
28 | this.Ices = ices; | 27 | this.Ices = ices; |
29 | this.SuppressedIces = suppressedIces == null ? WellKnownSuppressedIces : suppressedIces.Union(WellKnownSuppressedIces); | 28 | this.SuppressedIces = suppressedIces == null ? WellKnownSuppressedIces : suppressedIces.Union(WellKnownSuppressedIces); |
30 | 29 | ||
31 | this.IntermediateFolder = intermediateFolder; | 30 | this.IntermediateFolder = intermediateFolder; |
32 | this.OutputSourceLineNumber = new SourceLineNumber(outputPath); | 31 | this.OutputSourceLineNumber = new SourceLineNumber(databasePath); |
33 | } | 32 | } |
34 | 33 | ||
35 | public IEnumerable<ITrackedFile> TrackedFiles { get; private set; } | 34 | public IEnumerable<ITrackedFile> TrackedFiles { get; private set; } |
@@ -41,11 +40,9 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
41 | 40 | ||
42 | private IMessaging Messaging { get; } | 41 | private IMessaging Messaging { get; } |
43 | 42 | ||
44 | private IBackendHelper BackendHelper { get; } | ||
45 | |||
46 | private WindowsInstallerData Data { get; } | 43 | private WindowsInstallerData Data { get; } |
47 | 44 | ||
48 | private string OutputPath { get; } | 45 | private string DatabasePath { get; } |
49 | 46 | ||
50 | private IEnumerable<string> CubeFiles { get; } | 47 | private IEnumerable<string> CubeFiles { get; } |
51 | 48 | ||
@@ -64,34 +61,34 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
64 | 61 | ||
65 | public void Execute() | 62 | public void Execute() |
66 | { | 63 | { |
67 | var trackedFiles = new List<ITrackedFile>(); | ||
68 | var stopwatch = Stopwatch.StartNew(); | 64 | var stopwatch = Stopwatch.StartNew(); |
69 | 65 | ||
70 | this.Messaging.Write(VerboseMessages.ValidatingDatabase()); | 66 | this.Messaging.Write(VerboseMessages.ValidatingDatabase()); |
71 | 67 | ||
72 | // Ensure the temporary files can be created the working folder. | ||
73 | var workingFolder = Path.Combine(this.IntermediateFolder, "_validate"); | ||
74 | Directory.CreateDirectory(workingFolder); | ||
75 | |||
76 | // Copy the database to a temporary location so it can be manipulated. | 68 | // Copy the database to a temporary location so it can be manipulated. |
77 | // Ensure it is not read-only. | 69 | // Ensure it is not read-only. |
78 | var workingDatabasePath = Path.Combine(workingFolder, Path.GetFileName(this.OutputPath)); | 70 | var workingDatabaseFilename = String.Concat(Path.GetFileNameWithoutExtension(this.DatabasePath), "_validate", Path.GetExtension(this.DatabasePath)); |
79 | FileSystem.CopyFile(this.OutputPath, workingDatabasePath, allowHardlink: false); | 71 | var workingDatabasePath = Path.Combine(this.IntermediateFolder, workingDatabaseFilename); |
80 | 72 | try | |
81 | var trackWorkingDatabase = this.BackendHelper.TrackFile(workingDatabasePath, TrackedFileType.Temporary); | 73 | { |
82 | trackedFiles.Add(trackWorkingDatabase); | 74 | FileSystem.CopyFile(this.DatabasePath, workingDatabasePath, allowHardlink: false); |
83 | 75 | ||
84 | var attributes = File.GetAttributes(workingDatabasePath); | 76 | var attributes = File.GetAttributes(workingDatabasePath); |
85 | File.SetAttributes(workingDatabasePath, attributes & ~FileAttributes.ReadOnly); | 77 | File.SetAttributes(workingDatabasePath, attributes & ~FileAttributes.ReadOnly); |
86 | 78 | ||
87 | var validator = new WindowsInstallerValidator(this, workingDatabasePath, this.CubeFiles, this.Ices, this.SuppressedIces); | 79 | var validator = new WindowsInstallerValidator(this, workingDatabasePath, this.CubeFiles, this.Ices, this.SuppressedIces); |
88 | validator.Execute(); | 80 | validator.Execute(); |
81 | } | ||
82 | finally | ||
83 | { | ||
84 | if (File.Exists(workingDatabasePath)) | ||
85 | { | ||
86 | File.Delete(workingDatabasePath); | ||
87 | } | ||
88 | } | ||
89 | 89 | ||
90 | stopwatch.Stop(); | 90 | stopwatch.Stop(); |
91 | this.Messaging.Write(VerboseMessages.ValidatedDatabase(stopwatch.ElapsedMilliseconds)); | 91 | this.Messaging.Write(VerboseMessages.ValidatedDatabase(stopwatch.ElapsedMilliseconds)); |
92 | |||
93 | |||
94 | this.TrackedFiles = trackedFiles; | ||
95 | } | 92 | } |
96 | 93 | ||
97 | private void LogValidationMessage(ValidationMessage message) | 94 | private void LogValidationMessage(ValidationMessage message) |
diff --git a/src/wix/WixToolset.Core/BindContext.cs b/src/wix/WixToolset.Core/BindContext.cs index 052382f1..9dd6aa46 100644 --- a/src/wix/WixToolset.Core/BindContext.cs +++ b/src/wix/WixToolset.Core/BindContext.cs | |||
@@ -36,8 +36,6 @@ namespace WixToolset.Core | |||
36 | 36 | ||
37 | public IReadOnlyCollection<IFileSystemExtension> FileSystemExtensions { get; set; } | 37 | public IReadOnlyCollection<IFileSystemExtension> FileSystemExtensions { get; set; } |
38 | 38 | ||
39 | public IReadOnlyCollection<string> Ices { get; set; } | ||
40 | |||
41 | public string IntermediateFolder { get; set; } | 39 | public string IntermediateFolder { get; set; } |
42 | 40 | ||
43 | public Intermediate IntermediateRepresentation { get; set; } | 41 | public Intermediate IntermediateRepresentation { get; set; } |
@@ -54,10 +52,6 @@ namespace WixToolset.Core | |||
54 | 52 | ||
55 | public int? ResolvedLcid { get; set; } | 53 | public int? ResolvedLcid { get; set; } |
56 | 54 | ||
57 | public IReadOnlyCollection<string> SuppressIces { get; set; } | ||
58 | |||
59 | public bool SuppressValidation { get; set; } | ||
60 | |||
61 | public bool SuppressLayout { get; set; } | 55 | public bool SuppressLayout { get; set; } |
62 | 56 | ||
63 | public CancellationToken CancellationToken { get; set; } | 57 | public CancellationToken CancellationToken { get; set; } |
diff --git a/src/wix/WixToolset.Core/CommandLine/BuildCommand.cs b/src/wix/WixToolset.Core/CommandLine/BuildCommand.cs index 3ea47279..d289b557 100644 --- a/src/wix/WixToolset.Core/CommandLine/BuildCommand.cs +++ b/src/wix/WixToolset.Core/CommandLine/BuildCommand.cs | |||
@@ -349,14 +349,11 @@ namespace WixToolset.Core.CommandLine | |||
349 | context.ExpectedEmbeddedFiles = resolveResult.ExpectedEmbeddedFiles; | 349 | context.ExpectedEmbeddedFiles = resolveResult.ExpectedEmbeddedFiles; |
350 | context.Extensions = this.ExtensionManager.GetServices<IBinderExtension>(); | 350 | context.Extensions = this.ExtensionManager.GetServices<IBinderExtension>(); |
351 | context.FileSystemExtensions = this.ExtensionManager.GetServices<IFileSystemExtension>(); | 351 | context.FileSystemExtensions = this.ExtensionManager.GetServices<IFileSystemExtension>(); |
352 | context.Ices = this.commandLine.Ices; | ||
353 | context.IntermediateFolder = intermediateFolder; | 352 | context.IntermediateFolder = intermediateFolder; |
354 | context.IntermediateRepresentation = resolveResult.IntermediateRepresentation; | 353 | context.IntermediateRepresentation = resolveResult.IntermediateRepresentation; |
355 | context.OutputPath = this.OutputFile; | 354 | context.OutputPath = this.OutputFile; |
356 | context.PdbType = this.PdbType; | 355 | context.PdbType = this.PdbType; |
357 | context.PdbPath = this.PdbType == PdbType.None ? null : this.PdbFile ?? Path.ChangeExtension(this.OutputFile, ".wixpdb"); | 356 | context.PdbPath = this.PdbType == PdbType.None ? null : this.PdbFile ?? Path.ChangeExtension(this.OutputFile, ".wixpdb"); |
358 | context.SuppressIces = this.commandLine.SuppressIces; | ||
359 | context.SuppressValidation = this.commandLine.SuppressValidation; | ||
360 | context.CancellationToken = cancellationToken; | 357 | context.CancellationToken = cancellationToken; |
361 | 358 | ||
362 | var binder = this.ServiceProvider.GetService<IBinder>(); | 359 | var binder = this.ServiceProvider.GetService<IBinder>(); |
@@ -540,12 +537,6 @@ namespace WixToolset.Core.CommandLine | |||
540 | 537 | ||
541 | public string TrackingFile { get; private set; } | 538 | public string TrackingFile { get; private set; } |
542 | 539 | ||
543 | public List<string> Ices { get; } = new List<string>(); | ||
544 | |||
545 | public List<string> SuppressIces { get; } = new List<string>(); | ||
546 | |||
547 | public bool SuppressValidation { get; set; } | ||
548 | |||
549 | public bool ResetAcls { get; set; } | 540 | public bool ResetAcls { get; set; } |
550 | 541 | ||
551 | public CommandLine(IServiceProvider serviceProvider, IMessaging messaging) | 542 | public CommandLine(IServiceProvider serviceProvider, IMessaging messaging) |
@@ -627,13 +618,6 @@ namespace WixToolset.Core.CommandLine | |||
627 | parser.GetNextArgumentOrError(arg, this.IncludeSearchPaths); | 618 | parser.GetNextArgumentOrError(arg, this.IncludeSearchPaths); |
628 | return true; | 619 | return true; |
629 | 620 | ||
630 | case "ice": | ||
631 | { | ||
632 | var value = parser.GetNextArgumentOrError(arg); | ||
633 | this.Ices.Add(value); | ||
634 | return true; | ||
635 | } | ||
636 | |||
637 | case "intermediatefolder": | 621 | case "intermediatefolder": |
638 | this.IntermediateFolder = parser.GetNextArgumentAsDirectoryOrError(arg); | 622 | this.IntermediateFolder = parser.GetNextArgumentAsDirectoryOrError(arg); |
639 | return true; | 623 | return true; |
@@ -670,17 +654,6 @@ namespace WixToolset.Core.CommandLine | |||
670 | return false; | 654 | return false; |
671 | } | 655 | } |
672 | 656 | ||
673 | case "sice": | ||
674 | { | ||
675 | var value = parser.GetNextArgumentOrError(arg); | ||
676 | this.SuppressIces.Add(value); | ||
677 | return true; | ||
678 | } | ||
679 | |||
680 | case "sval": | ||
681 | this.SuppressValidation = true; | ||
682 | return true; | ||
683 | |||
684 | case "resetacls": | 657 | case "resetacls": |
685 | this.ResetAcls = true; | 658 | this.ResetAcls = true; |
686 | return true; | 659 | return true; |
diff --git a/src/wix/WixToolset.Sdk/tools/wix.targets b/src/wix/WixToolset.Sdk/tools/wix.targets index 487c5cb3..bbb73a52 100644 --- a/src/wix/WixToolset.Sdk/tools/wix.targets +++ b/src/wix/WixToolset.Sdk/tools/wix.targets | |||
@@ -168,6 +168,10 @@ | |||
168 | <UsingTask TaskName="ResolveWixReferences" Condition=" '$(WixTasksPath64)' != '' " AssemblyFile="$(WixTasksPath)" Architecture="x86" /> | 168 | <UsingTask TaskName="ResolveWixReferences" Condition=" '$(WixTasksPath64)' != '' " AssemblyFile="$(WixTasksPath)" Architecture="x86" /> |
169 | <UsingTask TaskName="ResolveWixReferences" Condition=" '$(WixTasksPath64)' != '' " AssemblyFile="$(WixTasksPath64)" Architecture="x64" /> | 169 | <UsingTask TaskName="ResolveWixReferences" Condition=" '$(WixTasksPath64)' != '' " AssemblyFile="$(WixTasksPath64)" Architecture="x64" /> |
170 | 170 | ||
171 | <UsingTask TaskName="WindowsInstallerValidation" Condition=" '$(WixTasksPath64)' == '' " AssemblyFile="$(WixTasksPath)" /> | ||
172 | <UsingTask TaskName="WindowsInstallerValidation" Condition=" '$(WixTasksPath64)' != '' " AssemblyFile="$(WixTasksPath)" Architecture="x86" /> | ||
173 | <UsingTask TaskName="WindowsInstallerValidation" Condition=" '$(WixTasksPath64)' != '' " AssemblyFile="$(WixTasksPath64)" Architecture="x64" /> | ||
174 | |||
171 | <!-- | 175 | <!-- |
172 | *********************************************************************************************** | 176 | *********************************************************************************************** |
173 | *********************************************************************************************** | 177 | *********************************************************************************************** |
@@ -553,6 +557,10 @@ | |||
553 | ================================================================================================ | 557 | ================================================================================================ |
554 | --> | 558 | --> |
555 | <PropertyGroup> | 559 | <PropertyGroup> |
560 | <CompileDependsOn> | ||
561 | $(CompileDependsOn); | ||
562 | WindowsInstallerValidation | ||
563 | </CompileDependsOn> | ||
556 | <CoreCompileDependsOn> | 564 | <CoreCompileDependsOn> |
557 | AssignTargetPaths; | 565 | AssignTargetPaths; |
558 | CreateManifestResourceNames; | 566 | CreateManifestResourceNames; |
@@ -604,9 +612,6 @@ | |||
604 | Pedantic="$(Pedantic)" | 612 | Pedantic="$(Pedantic)" |
605 | ReferencePaths="$(ReferencePaths)" | 613 | ReferencePaths="$(ReferencePaths)" |
606 | 614 | ||
607 | SuppressSpecificWarnings="$(SuppressSpecificWarnings)" | ||
608 | TreatSpecificWarningsAsErrors="$(TreatSpecificWarningsAsErrors)" | ||
609 | |||
610 | BindInputPaths="@(LinkerBindInputPaths)" | 615 | BindInputPaths="@(LinkerBindInputPaths)" |
611 | BindFiles="$(BindFiles)" | 616 | BindFiles="$(BindFiles)" |
612 | BindTrackingFile="$(IntermediateOutputPath)$(BindTrackingFilePrefix)%(CultureGroup.Identity)$(BindTrackingFileExtension)" | 617 | BindTrackingFile="$(IntermediateOutputPath)$(BindTrackingFilePrefix)%(CultureGroup.Identity)$(BindTrackingFileExtension)" |
@@ -619,12 +624,10 @@ | |||
619 | WixProjectFile="$(ProjectPath)" | 624 | WixProjectFile="$(ProjectPath)" |
620 | WixVariables="$(WixVariables)" | 625 | WixVariables="$(WixVariables)" |
621 | 626 | ||
622 | SuppressValidation="$(SuppressValidation)" | ||
623 | SuppressIces="$(SuppressIces)" | ||
624 | AdditionalCub="$(AdditionalCub)" | ||
625 | |||
626 | SuppressAllWarnings="$(SuppressAllWarnings)" | 627 | SuppressAllWarnings="$(SuppressAllWarnings)" |
628 | SuppressSpecificWarnings="$(SuppressSpecificWarnings)" | ||
627 | TreatWarningsAsErrors="$(TreatWarningsAsErrors)" | 629 | TreatWarningsAsErrors="$(TreatWarningsAsErrors)" |
630 | TreatSpecificWarningsAsErrors="$(TreatSpecificWarningsAsErrors)" | ||
628 | VerboseOutput="$(VerboseOutput)" | 631 | VerboseOutput="$(VerboseOutput)" |
629 | 632 | ||
630 | RunAsSeparateProcess="$(RunWixToolsOutOfProc)" | 633 | RunAsSeparateProcess="$(RunWixToolsOutOfProc)" |
@@ -636,6 +639,28 @@ | |||
636 | </ItemGroup> | 639 | </ItemGroup> |
637 | </Target> | 640 | </Target> |
638 | 641 | ||
642 | <Target | ||
643 | Name="WindowsInstallerValidation" | ||
644 | DependsOnTargets="CoreCompile" | ||
645 | Condition=" ('$(OutputType)' == 'Package' or '$(OutputType)' == 'Module') and '$(SuppressValidation)'!='true' "> | ||
646 | <WindowsInstallerValidation | ||
647 | DatabaseFile="$(IntermediateOutputPath)%(CultureGroup.OutputFolder)$(TargetFileName)" | ||
648 | WixpdbFile="$(IntermediateOutputPath)%(CultureGroup.OutputFolder)$(TargetPdbFileName)" | ||
649 | IntermediateDirectory="$(IntermediateOutputPath)%(CultureGroup.OutputFolder)" | ||
650 | Ices="$(Ices)" | ||
651 | SuppressIces="$(SuppressIces)" | ||
652 | CubeFiles="$(AdditionalCub)" | ||
653 | |||
654 | AdditionalOptions="$(ValidationAdditionalOptions)" | ||
655 | |||
656 | NoLogo="true" | ||
657 | SuppressAllWarnings="$(SuppressAllWarnings)" | ||
658 | SuppressSpecificWarnings="$(SuppressSpecificWarnings)" | ||
659 | TreatWarningsAsErrors="$(TreatWarningsAsErrors)" | ||
660 | TreatSpecificWarningsAsErrors="$(TreatSpecificWarningsAsErrors)" | ||
661 | VerboseOutput="$(VerboseOutput)" /> | ||
662 | </Target> | ||
663 | |||
639 | <!-- | 664 | <!-- |
640 | ================================================================================================ | 665 | ================================================================================================ |
641 | _CreateProjectDefineConstants | 666 | _CreateProjectDefineConstants |
diff --git a/src/wix/test/WixToolsetTest.CoreIntegration/ModuleFixture.cs b/src/wix/test/WixToolsetTest.CoreIntegration/ModuleFixture.cs index 1c5e68f0..41418711 100644 --- a/src/wix/test/WixToolsetTest.CoreIntegration/ModuleFixture.cs +++ b/src/wix/test/WixToolsetTest.CoreIntegration/ModuleFixture.cs | |||
@@ -15,7 +15,7 @@ namespace WixToolsetTest.CoreIntegration | |||
15 | public class ModuleFixture | 15 | public class ModuleFixture |
16 | { | 16 | { |
17 | [Fact] | 17 | [Fact] |
18 | public void CanBuildSimpleModule() | 18 | public void CanBuildAndValidateSimpleModule() |
19 | { | 19 | { |
20 | var folder = TestData.Get(@"TestData\SimpleModule"); | 20 | var folder = TestData.Get(@"TestData\SimpleModule"); |
21 | 21 | ||
@@ -73,6 +73,30 @@ namespace WixToolsetTest.CoreIntegration | |||
73 | "File1.243FB739_4D05_472F_9CFB_EF6B1017B6DE", | 73 | "File1.243FB739_4D05_472F_9CFB_EF6B1017B6DE", |
74 | "File2.243FB739_4D05_472F_9CFB_EF6B1017B6DE", | 74 | "File2.243FB739_4D05_472F_9CFB_EF6B1017B6DE", |
75 | }, files.Select(f => Path.Combine(f.Path, f.Name)).ToArray()); | 75 | }, files.Select(f => Path.Combine(f.Path, f.Name)).ToArray()); |
76 | |||
77 | var rows = Query.QueryDatabase(msmPath, new[] { "_SummaryInformation" }); | ||
78 | WixAssert.CompareLineByLine(new[] | ||
79 | { | ||
80 | "_SummaryInformation:Title\tMerge Module", | ||
81 | "_SummaryInformation:Subject\tMergeModule1", | ||
82 | "_SummaryInformation:Author\tExample Company", | ||
83 | "_SummaryInformation:Keywords\tMergeModule, MSI, database", | ||
84 | "_SummaryInformation:Comments\tThis merge module contains the logic and data required to install MergeModule1.", | ||
85 | "_SummaryInformation:Template\tIntel;1033", | ||
86 | "_SummaryInformation:CodePage\t1252", | ||
87 | "_SummaryInformation:PageCount\t200", | ||
88 | "_SummaryInformation:WordCount\t0", | ||
89 | "_SummaryInformation:CharacterCount\t0", | ||
90 | "_SummaryInformation:Security\t2", | ||
91 | }, rows); | ||
92 | |||
93 | var validationResult = WixRunner.Execute(new[] | ||
94 | { | ||
95 | "msi", "validate", | ||
96 | "-intermediateFolder", intermediateFolder, | ||
97 | msmPath | ||
98 | }); | ||
99 | validationResult.AssertSuccess(); | ||
76 | } | 100 | } |
77 | } | 101 | } |
78 | 102 | ||
@@ -109,5 +133,72 @@ namespace WixToolsetTest.CoreIntegration | |||
109 | }, rows); | 133 | }, rows); |
110 | } | 134 | } |
111 | } | 135 | } |
136 | |||
137 | [Fact] | ||
138 | public void CanMergeModule() | ||
139 | { | ||
140 | var msmFolder = TestData.Get(@"TestData\SimpleModule"); | ||
141 | var folder = TestData.Get(@"TestData\SimpleMerge"); | ||
142 | |||
143 | using (var fs = new DisposableFileSystem()) | ||
144 | { | ||
145 | var intermediateFolder = fs.GetFolder(); | ||
146 | var msiPath = Path.Combine(intermediateFolder, @"bin\test.msi"); | ||
147 | var cabPath = Path.Combine(intermediateFolder, @"bin\cab1.cab"); | ||
148 | |||
149 | var msmResult = WixRunner.Execute(new[] | ||
150 | { | ||
151 | "build", | ||
152 | Path.Combine(msmFolder, "Module.wxs"), | ||
153 | "-loc", Path.Combine(msmFolder, "Module.en-us.wxl"), | ||
154 | "-bindpath", Path.Combine(msmFolder, "data"), | ||
155 | "-intermediateFolder", intermediateFolder, | ||
156 | "-o", Path.Combine(intermediateFolder, "bin", "test", "test.msm") | ||
157 | }); | ||
158 | |||
159 | msmResult.AssertSuccess(); | ||
160 | |||
161 | var result = WixRunner.Execute(new[] | ||
162 | { | ||
163 | "build", | ||
164 | Path.Combine(folder, "Package.wxs"), | ||
165 | "-loc", Path.Combine(folder, "Package.en-us.wxl"), | ||
166 | "-bindpath", Path.Combine(intermediateFolder, "bin", "test"), | ||
167 | "-intermediateFolder", intermediateFolder, | ||
168 | "-o", msiPath | ||
169 | }); | ||
170 | |||
171 | result.AssertSuccess(); | ||
172 | |||
173 | var validationResult = WixRunner.Execute(new[] | ||
174 | { | ||
175 | "msi", "validate", | ||
176 | "-intermediateFolder", intermediateFolder, | ||
177 | msiPath | ||
178 | }); | ||
179 | validationResult.AssertSuccess(); | ||
180 | |||
181 | var intermediate = Intermediate.Load(Path.Combine(intermediateFolder, @"bin\test.wixpdb")); | ||
182 | var section = intermediate.Sections.Single(); | ||
183 | Assert.Empty(section.Symbols.OfType<FileSymbol>()); | ||
184 | |||
185 | var data = WindowsInstallerData.Load(Path.Combine(intermediateFolder, @"bin\test.wixpdb")); | ||
186 | Assert.Empty(data.Tables["File"].Rows); | ||
187 | |||
188 | var results = Query.QueryDatabase(msiPath, new[] { "File" }); | ||
189 | WixAssert.CompareLineByLine(new[] | ||
190 | { | ||
191 | "File:File1.243FB739_4D05_472F_9CFB_EF6B1017B6DE\tModuleComponent1.243FB739_4D05_472F_9CFB_EF6B1017B6DE\tfile1.txt\t17\t\t\t512\t1", | ||
192 | "File:File2.243FB739_4D05_472F_9CFB_EF6B1017B6DE\tModuleComponent2.243FB739_4D05_472F_9CFB_EF6B1017B6DE\tfile2.txt\t17\t\t\t512\t2", | ||
193 | }, results); | ||
194 | |||
195 | var files = Query.GetCabinetFiles(cabPath); | ||
196 | WixAssert.CompareLineByLine(new[] | ||
197 | { | ||
198 | "File1.243FB739_4D05_472F_9CFB_EF6B1017B6DE", | ||
199 | "File2.243FB739_4D05_472F_9CFB_EF6B1017B6DE" | ||
200 | }, files.Select(f => f.Name).ToArray()); | ||
201 | } | ||
202 | } | ||
112 | } | 203 | } |
113 | } | 204 | } |
diff --git a/src/wix/test/WixToolsetTest.CoreIntegration/MsiQueryFixture.cs b/src/wix/test/WixToolsetTest.CoreIntegration/MsiQueryFixture.cs index 2b3bfc88..f361a274 100644 --- a/src/wix/test/WixToolsetTest.CoreIntegration/MsiQueryFixture.cs +++ b/src/wix/test/WixToolsetTest.CoreIntegration/MsiQueryFixture.cs | |||
@@ -8,9 +8,6 @@ namespace WixToolsetTest.CoreIntegration | |||
8 | using Example.Extension; | 8 | using Example.Extension; |
9 | using WixBuildTools.TestSupport; | 9 | using WixBuildTools.TestSupport; |
10 | using WixToolset.Core.TestPackage; | 10 | using WixToolset.Core.TestPackage; |
11 | using WixToolset.Data; | ||
12 | using WixToolset.Data.Symbols; | ||
13 | using WixToolset.Data.WindowsInstaller; | ||
14 | using Xunit; | 11 | using Xunit; |
15 | 12 | ||
16 | public class MsiQueryFixture | 13 | public class MsiQueryFixture |
@@ -835,68 +832,6 @@ namespace WixToolsetTest.CoreIntegration | |||
835 | } | 832 | } |
836 | 833 | ||
837 | [Fact] | 834 | [Fact] |
838 | public void CanMergeModule() | ||
839 | { | ||
840 | var msmFolder = TestData.Get(@"TestData\SimpleModule"); | ||
841 | var folder = TestData.Get(@"TestData\SimpleMerge"); | ||
842 | |||
843 | using (var fs = new DisposableFileSystem()) | ||
844 | { | ||
845 | var intermediateFolder = fs.GetFolder(); | ||
846 | var msiPath = Path.Combine(intermediateFolder, @"bin\test.msi"); | ||
847 | var cabPath = Path.Combine(intermediateFolder, @"bin\cab1.cab"); | ||
848 | |||
849 | var msmResult = WixRunner.Execute(new[] | ||
850 | { | ||
851 | "build", | ||
852 | Path.Combine(msmFolder, "Module.wxs"), | ||
853 | "-loc", Path.Combine(msmFolder, "Module.en-us.wxl"), | ||
854 | "-bindpath", Path.Combine(msmFolder, "data"), | ||
855 | "-intermediateFolder", intermediateFolder, | ||
856 | "-o", Path.Combine(intermediateFolder, "bin", "test", "test.msm") | ||
857 | }); | ||
858 | |||
859 | msmResult.AssertSuccess(); | ||
860 | |||
861 | var result = WixRunner.Execute(new[] | ||
862 | { | ||
863 | "build", | ||
864 | Path.Combine(folder, "Package.wxs"), | ||
865 | "-loc", Path.Combine(folder, "Package.en-us.wxl"), | ||
866 | "-bindpath", Path.Combine(intermediateFolder, "bin", "test"), | ||
867 | "-intermediateFolder", intermediateFolder, | ||
868 | "-o", msiPath | ||
869 | }); | ||
870 | |||
871 | result.AssertSuccess(); | ||
872 | |||
873 | Assert.True(File.Exists(msiPath)); | ||
874 | Assert.True(File.Exists(Path.Combine(intermediateFolder, @"bin\test.wixpdb"))); | ||
875 | |||
876 | var intermediate = Intermediate.Load(Path.Combine(intermediateFolder, @"bin\test.wixpdb")); | ||
877 | var section = intermediate.Sections.Single(); | ||
878 | Assert.Empty(section.Symbols.OfType<FileSymbol>()); | ||
879 | |||
880 | var data = WindowsInstallerData.Load(Path.Combine(intermediateFolder, @"bin\test.wixpdb")); | ||
881 | Assert.Empty(data.Tables["File"].Rows); | ||
882 | |||
883 | var results = Query.QueryDatabase(msiPath, new[] { "File" }); | ||
884 | WixAssert.CompareLineByLine(new[] | ||
885 | { | ||
886 | "File:File1.243FB739_4D05_472F_9CFB_EF6B1017B6DE\tModuleComponent1.243FB739_4D05_472F_9CFB_EF6B1017B6DE\tfile1.txt\t17\t\t\t512\t1", | ||
887 | "File:File2.243FB739_4D05_472F_9CFB_EF6B1017B6DE\tModuleComponent2.243FB739_4D05_472F_9CFB_EF6B1017B6DE\tfile2.txt\t17\t\t\t512\t2", | ||
888 | }, results); | ||
889 | |||
890 | var files = Query.GetCabinetFiles(cabPath); | ||
891 | WixAssert.CompareLineByLine(new[] | ||
892 | { | ||
893 | "File1.243FB739_4D05_472F_9CFB_EF6B1017B6DE", | ||
894 | "File2.243FB739_4D05_472F_9CFB_EF6B1017B6DE" | ||
895 | }, files.Select(f => f.Name).ToArray()); | ||
896 | } | ||
897 | } | ||
898 | |||
899 | [Fact] | ||
900 | public void CanPublishComponentWithMultipleFeatureComponents() | 835 | public void CanPublishComponentWithMultipleFeatureComponents() |
901 | { | 836 | { |
902 | var folder = TestData.Get(@"TestData\PublishComponent"); | 837 | var folder = TestData.Get(@"TestData\PublishComponent"); |
diff --git a/src/wix/test/WixToolsetTest.CoreIntegration/TestData/BindVariables/PackageWithBindVariables.wxs b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/BindVariables/PackageWithBindVariables.wxs index 377f7e11..2a0c374f 100644 --- a/src/wix/test/WixToolsetTest.CoreIntegration/TestData/BindVariables/PackageWithBindVariables.wxs +++ b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/BindVariables/PackageWithBindVariables.wxs | |||
@@ -1,5 +1,5 @@ | |||
1 | <Wix xmlns="http://wixtoolset.org/schemas/v4/wxs"> | 1 | <Wix xmlns="http://wixtoolset.org/schemas/v4/wxs"> |
2 | <Package Name="PacakgeWithBindVariables" Version="!(bind.fileversion.TestBinaryFile)" Manufacturer="Example Corporation" UpgradeCode="00000000-0000-0000-0000-000000000000"> | 2 | <Package Name="PacakgeWithBindVariables" Version="!(bind.fileversion.TestBinaryFile)" Manufacturer="Example Corporation" UpgradeCode="41a2c17e-1976-465b-bcde-eae03516ca68"> |
3 | 3 | ||
4 | <Property Id="TestPackageManufacturer" Value="!(bind.Property.Manufacturer)" /> | 4 | <Property Id="TestPackageManufacturer" Value="!(bind.Property.Manufacturer)" /> |
5 | <Property Id="TestPackageName" Value="!(bind.Property.ProductName)" /> | 5 | <Property Id="TestPackageName" Value="!(bind.Property.ProductName)" /> |
diff --git a/src/wix/test/WixToolsetTest.CoreIntegration/TestData/SimpleMerge/.data/test.msm b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/SimpleMerge/.data/test.msm deleted file mode 100644 index 6f179aba..00000000 --- a/src/wix/test/WixToolsetTest.CoreIntegration/TestData/SimpleMerge/.data/test.msm +++ /dev/null | |||
Binary files differ | |||
diff --git a/src/wix/test/WixToolsetTest.CoreIntegration/TestData/SimpleMerge/Package.wxs b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/SimpleMerge/Package.wxs index 3c999812..41dd19fc 100644 --- a/src/wix/test/WixToolsetTest.CoreIntegration/TestData/SimpleMerge/Package.wxs +++ b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/SimpleMerge/Package.wxs | |||
@@ -1,7 +1,5 @@ | |||
1 | <Wix xmlns="http://wixtoolset.org/schemas/v4/wxs"> | 1 | <Wix xmlns="http://wixtoolset.org/schemas/v4/wxs"> |
2 | <Package Name="MsiPackage" Codepage="1252" Language="1033" Version="1.0.0.0" Manufacturer="Example Corporation" UpgradeCode="047730a5-30fe-4a62-a520-da9381b8226a" Compressed="yes" InstallerVersion="200" Scope="perMachine"> | 2 | <Package Name="MsiPackage" Codepage="1252" Language="1033" Version="1.0.0.0" Manufacturer="Example Corporation" UpgradeCode="047730a5-30fe-4a62-a520-da9381b8226a" Compressed="yes" InstallerVersion="200" Scope="perMachine"> |
3 | |||
4 | |||
5 | <MajorUpgrade DowngradeErrorMessage="!(loc.DowngradeError)" /> | 3 | <MajorUpgrade DowngradeErrorMessage="!(loc.DowngradeError)" /> |
6 | 4 | ||
7 | <Feature Id="ProductFeature" Title="!(loc.FeatureTitle)"> | 5 | <Feature Id="ProductFeature" Title="!(loc.FeatureTitle)"> |
@@ -12,7 +10,6 @@ | |||
12 | <Fragment> | 10 | <Fragment> |
13 | <StandardDirectory Id="ProgramFilesFolder"> | 11 | <StandardDirectory Id="ProgramFilesFolder"> |
14 | <Directory Id="INSTALLFOLDER" Name="MsiPackage"> | 12 | <Directory Id="INSTALLFOLDER" Name="MsiPackage"> |
15 | <!-- --> | ||
16 | <Merge Id="TestMsm" Language="1033" SourceFile="test.msm" /> | 13 | <Merge Id="TestMsm" Language="1033" SourceFile="test.msm" /> |
17 | </Directory> | 14 | </Directory> |
18 | </StandardDirectory> | 15 | </StandardDirectory> |
diff --git a/src/wix/test/WixToolsetTest.CoreIntegration/TestData/Validation/PackageWithIceIssues.wxs b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/Validation/PackageWithIceIssues.wxs new file mode 100644 index 00000000..4d3acdf7 --- /dev/null +++ b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/Validation/PackageWithIceIssues.wxs | |||
@@ -0,0 +1,32 @@ | |||
1 | <Wix xmlns="http://wixtoolset.org/schemas/v4/wxs"> | ||
2 | <Package Name="ValidationPackage" Version="1.0.0.0" Manufacturer="Example Corporation" UpgradeCode="047730a5-30fe-4a62-a520-da9381b8226a"> | ||
3 | <MajorUpgrade DowngradeErrorMessage="Downgrade message" /> | ||
4 | |||
5 | <Property Id="MyProperty" Value="1" /> | ||
6 | <Launch Condition="Myproperty" Message="Invalid cased Property Id below causes ICE46" /> | ||
7 | |||
8 | <CustomAction Id="CausesICE12Error" Directory="INSTALLFOLDER" Value="Test" /> | ||
9 | |||
10 | <Feature Id="ProductFeature" Title="Product Feature"> | ||
11 | <ComponentGroupRef Id="ProductComponents" /> | ||
12 | </Feature> | ||
13 | |||
14 | <InstallExecuteSequence> | ||
15 | <Custom Action="CausesICE12Error" Before="AppSearch" /> | ||
16 | </InstallExecuteSequence> | ||
17 | </Package> | ||
18 | |||
19 | <Fragment> | ||
20 | <StandardDirectory Id="ProgramFiles6432Folder"> | ||
21 | <Directory Id="INSTALLFOLDER" Name="MsiPackage" /> | ||
22 | </StandardDirectory> | ||
23 | </Fragment> | ||
24 | |||
25 | <Fragment> | ||
26 | <ComponentGroup Id="ProductComponents" Directory="INSTALLFOLDER"> | ||
27 | <Component> | ||
28 | <File Source="test.txt" /> | ||
29 | </Component> | ||
30 | </ComponentGroup> | ||
31 | </Fragment> | ||
32 | </Wix> | ||
diff --git a/src/wix/test/WixToolsetTest.CoreIntegration/ValidationFixture.cs b/src/wix/test/WixToolsetTest.CoreIntegration/ValidationFixture.cs new file mode 100644 index 00000000..48339b89 --- /dev/null +++ b/src/wix/test/WixToolsetTest.CoreIntegration/ValidationFixture.cs | |||
@@ -0,0 +1,133 @@ | |||
1 | // Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. | ||
2 | |||
3 | namespace WixToolsetTest.CoreIntegration | ||
4 | { | ||
5 | using System.IO; | ||
6 | using System.Linq; | ||
7 | using WixBuildTools.TestSupport; | ||
8 | using WixToolset.Core.TestPackage; | ||
9 | using Xunit; | ||
10 | |||
11 | public class ValidationFixture | ||
12 | { | ||
13 | [Fact] | ||
14 | public void CanValidateMsiWithIceIssues() | ||
15 | { | ||
16 | var folder = TestData.Get(@"TestData"); | ||
17 | |||
18 | using (var fs = new DisposableFileSystem()) | ||
19 | { | ||
20 | var baseFolder = fs.GetFolder(); | ||
21 | var intermediateFolder = Path.Combine(baseFolder, "obj"); | ||
22 | var msiPath = Path.Combine(baseFolder, @"bin", "test.msi"); | ||
23 | |||
24 | var result = WixRunner.Execute(new[] | ||
25 | { | ||
26 | "build", | ||
27 | Path.Combine(folder, "Validation", "PackageWithIceIssues.wxs"), | ||
28 | "-bindpath", Path.Combine(folder, "SingleFile", "data"), | ||
29 | "-intermediateFolder", intermediateFolder, | ||
30 | "-o", msiPath, | ||
31 | }); | ||
32 | |||
33 | result.AssertSuccess(); | ||
34 | |||
35 | var validationResult = WixRunner.Execute(new[] | ||
36 | { | ||
37 | "msi", "validate", | ||
38 | "-intermediateFolder", intermediateFolder, | ||
39 | msiPath | ||
40 | }); | ||
41 | |||
42 | Assert.Equal(1, validationResult.ExitCode); | ||
43 | |||
44 | var messages = validationResult.Messages.Select(m => m.ToString()).ToArray(); | ||
45 | WixAssert.CompareLineByLine(new[] | ||
46 | { | ||
47 | @"ICE12: CustomAction: CausesICE12Error is of type: 35. Therefore it must come after CostFinalize @ 1000 in Seq Table: InstallExecuteSequence. CA Seq#: 49", | ||
48 | @"ICE46: Property 'Myproperty' referenced in column 'LaunchCondition'.'Condition' of row 'Myproperty' differs from a defined property by case only." | ||
49 | }, messages); | ||
50 | } | ||
51 | } | ||
52 | |||
53 | [Fact] | ||
54 | public void CanValidateMsiSuppressIceError() | ||
55 | { | ||
56 | var folder = TestData.Get(@"TestData"); | ||
57 | |||
58 | using (var fs = new DisposableFileSystem()) | ||
59 | { | ||
60 | var baseFolder = fs.GetFolder(); | ||
61 | var intermediateFolder = Path.Combine(baseFolder, "obj"); | ||
62 | var msiPath = Path.Combine(baseFolder, @"bin", "test.msi"); | ||
63 | |||
64 | var result = WixRunner.Execute(new[] | ||
65 | { | ||
66 | "build", | ||
67 | Path.Combine(folder, "Validation", "PackageWithIceIssues.wxs"), | ||
68 | "-bindpath", Path.Combine(folder, "SingleFile", "data"), | ||
69 | "-intermediateFolder", intermediateFolder, | ||
70 | "-o", msiPath, | ||
71 | }); | ||
72 | |||
73 | result.AssertSuccess(); | ||
74 | |||
75 | var validationResult = WixRunner.Execute(warningsAsErrors: false, new[] | ||
76 | { | ||
77 | "msi", "validate", | ||
78 | "-intermediateFolder", intermediateFolder, | ||
79 | "-sice", "ICE12", | ||
80 | msiPath | ||
81 | }); | ||
82 | |||
83 | validationResult.AssertSuccess(); | ||
84 | |||
85 | var messages = validationResult.Messages.Select(m => m.ToString()).ToArray(); | ||
86 | WixAssert.CompareLineByLine(new[] | ||
87 | { | ||
88 | @"ICE46: Property 'Myproperty' referenced in column 'LaunchCondition'.'Condition' of row 'Myproperty' differs from a defined property by case only." | ||
89 | }, messages); | ||
90 | } | ||
91 | } | ||
92 | |||
93 | [Fact] | ||
94 | public void CanValidateMsiWithWarningsAsErrors() | ||
95 | { | ||
96 | var folder = TestData.Get(@"TestData"); | ||
97 | |||
98 | using (var fs = new DisposableFileSystem()) | ||
99 | { | ||
100 | var baseFolder = fs.GetFolder(); | ||
101 | var intermediateFolder = Path.Combine(baseFolder, "obj"); | ||
102 | var msiPath = Path.Combine(baseFolder, @"bin", "test.msi"); | ||
103 | |||
104 | var result = WixRunner.Execute(new[] | ||
105 | { | ||
106 | "build", | ||
107 | Path.Combine(folder, "Validation", "PackageWithIceIssues.wxs"), | ||
108 | "-bindpath", Path.Combine(folder, "SingleFile", "data"), | ||
109 | "-intermediateFolder", intermediateFolder, | ||
110 | "-o", msiPath, | ||
111 | }); | ||
112 | |||
113 | result.AssertSuccess(); | ||
114 | |||
115 | var validationResult = WixRunner.Execute(warningsAsErrors: true, new[] | ||
116 | { | ||
117 | "msi", "validate", | ||
118 | "-intermediateFolder", intermediateFolder, | ||
119 | "-sice", "ICE12", | ||
120 | msiPath | ||
121 | }); | ||
122 | |||
123 | Assert.Equal(1, validationResult.ExitCode); | ||
124 | |||
125 | var messages = validationResult.Messages.Select(m => m.ToString()).ToArray(); | ||
126 | WixAssert.CompareLineByLine(new[] | ||
127 | { | ||
128 | @"ICE46: Property 'Myproperty' referenced in column 'LaunchCondition'.'Condition' of row 'Myproperty' differs from a defined property by case only." | ||
129 | }, messages); | ||
130 | } | ||
131 | } | ||
132 | } | ||
133 | } | ||
diff --git a/src/wix/test/WixToolsetTest.Sdk/MsbuildFixture.cs b/src/wix/test/WixToolsetTest.Sdk/MsbuildFixture.cs index 3a9ce776..1a82c035 100644 --- a/src/wix/test/WixToolsetTest.Sdk/MsbuildFixture.cs +++ b/src/wix/test/WixToolsetTest.Sdk/MsbuildFixture.cs | |||
@@ -271,6 +271,7 @@ namespace WixToolsetTest.Sdk | |||
271 | var result = MsbuildUtilities.BuildProject(buildSystem, projectPath, new[] | 271 | var result = MsbuildUtilities.BuildProject(buildSystem, projectPath, new[] |
272 | { | 272 | { |
273 | wixpdbType == null ? String.Empty : $"-p:WixPdbType={wixpdbType}", | 273 | wixpdbType == null ? String.Empty : $"-p:WixPdbType={wixpdbType}", |
274 | "-p:SuppressValidation=true" | ||
274 | }); | 275 | }); |
275 | result.AssertSuccess(); | 276 | result.AssertSuccess(); |
276 | 277 | ||
@@ -323,9 +324,44 @@ namespace WixToolsetTest.Sdk | |||
323 | [InlineData(BuildSystem.DotNetCoreSdk)] | 324 | [InlineData(BuildSystem.DotNetCoreSdk)] |
324 | [InlineData(BuildSystem.MSBuild)] | 325 | [InlineData(BuildSystem.MSBuild)] |
325 | [InlineData(BuildSystem.MSBuild64)] | 326 | [InlineData(BuildSystem.MSBuild64)] |
326 | public void CanBuildSimpleMsiPackageWithIceSuppressions(BuildSystem buildSystem) | 327 | public void CannotBuildMsiPackageWithIceIssues(BuildSystem buildSystem) |
327 | { | 328 | { |
328 | var sourceFolder = TestData.Get(@"TestData\SimpleMsiPackage\MsiPackage"); | 329 | var sourceFolder = TestData.Get(@"TestData\MsiPackageWithIceError\MsiPackage"); |
330 | |||
331 | using (var fs = new TestDataFolderFileSystem()) | ||
332 | { | ||
333 | fs.Initialize(sourceFolder); | ||
334 | var baseFolder = fs.BaseFolder; | ||
335 | var binFolder = Path.Combine(baseFolder, @"bin\"); | ||
336 | var projectPath = Path.Combine(baseFolder, "MsiPackage.wixproj"); | ||
337 | |||
338 | var result = MsbuildUtilities.BuildProject(buildSystem, projectPath, suppressValidation: false); | ||
339 | Assert.Equal(1, result.ExitCode); | ||
340 | |||
341 | var iceIssues = result.Output.Where(line => line.Contains(": error") || line.Contains(": warning")) | ||
342 | .Select(line => line.Replace(baseFolder, "<baseFolder>") | ||
343 | .Replace("1>", String.Empty) // remove any multi-proc markers | ||
344 | .Replace("WIX204", "WIX0204") // normalize error number reporting because MSBuild is not consistent on zero padding | ||
345 | .Trim()) | ||
346 | .OrderBy(s => s, StringComparer.OrdinalIgnoreCase) | ||
347 | .ToArray(); | ||
348 | WixAssert.CompareLineByLine(new[] | ||
349 | { | ||
350 | @"<baseFolder>\Package.wxs(17): error WIX0204: ICE12: CustomAction: CausesICE12Error is of type: 35. Therefore it must come after CostFinalize @ 1000 in Seq Table: InstallExecuteSequence. CA Seq#: 49 [<baseFolder>\MsiPackage.wixproj]", | ||
351 | @"<baseFolder>\Package.wxs(17): error WIX0204: ICE12: CustomAction: CausesICE12Error is of type: 35. Therefore it must come after CostFinalize @ 1000 in Seq Table: InstallExecuteSequence. CA Seq#: 49 [<baseFolder>\MsiPackage.wixproj]", | ||
352 | @"<baseFolder>\Package.wxs(8): warning WIX1076: ICE46: Property 'Myproperty' referenced in column 'LaunchCondition'.'Condition' of row 'Myproperty' differs from a defined property by case only. [<baseFolder>\MsiPackage.wixproj]", | ||
353 | @"<baseFolder>\Package.wxs(8): warning WIX1076: ICE46: Property 'Myproperty' referenced in column 'LaunchCondition'.'Condition' of row 'Myproperty' differs from a defined property by case only. [<baseFolder>\MsiPackage.wixproj]", | ||
354 | }, iceIssues); | ||
355 | } | ||
356 | } | ||
357 | |||
358 | [Theory] | ||
359 | [InlineData(BuildSystem.DotNetCoreSdk)] | ||
360 | [InlineData(BuildSystem.MSBuild)] | ||
361 | [InlineData(BuildSystem.MSBuild64)] | ||
362 | public void CannotBuildMsiPackageWithIceWarningsAsErrors(BuildSystem buildSystem) | ||
363 | { | ||
364 | var sourceFolder = TestData.Get(@"TestData\MsiPackageWithIceError\MsiPackage"); | ||
329 | 365 | ||
330 | using (var fs = new TestDataFolderFileSystem()) | 366 | using (var fs = new TestDataFolderFileSystem()) |
331 | { | 367 | { |
@@ -336,8 +372,45 @@ namespace WixToolsetTest.Sdk | |||
336 | 372 | ||
337 | var result = MsbuildUtilities.BuildProject(buildSystem, projectPath, new[] | 373 | var result = MsbuildUtilities.BuildProject(buildSystem, projectPath, new[] |
338 | { | 374 | { |
339 | MsbuildUtilities.GetQuotedPropertySwitch(buildSystem, "SuppressIces", "ICE45;ICE46"), | 375 | $"-p:TreatWarningsAsErrors=true", |
340 | }); | 376 | MsbuildUtilities.GetQuotedPropertySwitch(buildSystem, "SuppressIces", "ICE12"), |
377 | }, suppressValidation: false); | ||
378 | Assert.Equal(1, result.ExitCode); | ||
379 | |||
380 | var iceIssues = result.Output.Where(line => (line.Contains(": error") || line.Contains(": warning"))) | ||
381 | .Select(line => line.Replace(baseFolder, "<baseFolder>") | ||
382 | .Replace("1>", String.Empty) // remove any multi-proc markers | ||
383 | .Replace("WIX204", "WIX0204") // normalize error number reporting because MSBuild is not consistent on zero padding | ||
384 | .Trim()) | ||
385 | .OrderBy(s => s, StringComparer.OrdinalIgnoreCase) | ||
386 | .ToArray(); | ||
387 | WixAssert.CompareLineByLine(new[] | ||
388 | { | ||
389 | @"<baseFolder>\Package.wxs(8): error WIX1076: ICE46: Property 'Myproperty' referenced in column 'LaunchCondition'.'Condition' of row 'Myproperty' differs from a defined property by case only. [<baseFolder>\MsiPackage.wixproj]", | ||
390 | @"<baseFolder>\Package.wxs(8): error WIX1076: ICE46: Property 'Myproperty' referenced in column 'LaunchCondition'.'Condition' of row 'Myproperty' differs from a defined property by case only. [<baseFolder>\MsiPackage.wixproj]", | ||
391 | }, iceIssues); | ||
392 | } | ||
393 | } | ||
394 | |||
395 | [Theory] | ||
396 | [InlineData(BuildSystem.DotNetCoreSdk)] | ||
397 | [InlineData(BuildSystem.MSBuild)] | ||
398 | [InlineData(BuildSystem.MSBuild64)] | ||
399 | public void CanBuildMsiPackageWithIceSuppressions(BuildSystem buildSystem) | ||
400 | { | ||
401 | var sourceFolder = TestData.Get(@"TestData\MsiPackageWithIceError\MsiPackage"); | ||
402 | |||
403 | using (var fs = new TestDataFolderFileSystem()) | ||
404 | { | ||
405 | fs.Initialize(sourceFolder); | ||
406 | var baseFolder = fs.BaseFolder; | ||
407 | var binFolder = Path.Combine(baseFolder, @"bin\"); | ||
408 | var projectPath = Path.Combine(baseFolder, "MsiPackage.wixproj"); | ||
409 | |||
410 | var result = MsbuildUtilities.BuildProject(buildSystem, projectPath, new[] | ||
411 | { | ||
412 | MsbuildUtilities.GetQuotedPropertySwitch(buildSystem, "SuppressIces", "ICE12"), | ||
413 | }, suppressValidation: false); | ||
341 | result.AssertSuccess(); | 414 | result.AssertSuccess(); |
342 | } | 415 | } |
343 | } | 416 | } |
diff --git a/src/wix/test/WixToolsetTest.Sdk/MsbuildUtilities.cs b/src/wix/test/WixToolsetTest.Sdk/MsbuildUtilities.cs index 28e0c219..875e3279 100644 --- a/src/wix/test/WixToolsetTest.Sdk/MsbuildUtilities.cs +++ b/src/wix/test/WixToolsetTest.Sdk/MsbuildUtilities.cs | |||
@@ -20,12 +20,13 @@ namespace WixToolsetTest.Sdk | |||
20 | public static readonly string WixMsbuildPath = Path.Combine(Path.GetDirectoryName(new Uri(typeof(MsbuildUtilities).Assembly.CodeBase).AbsolutePath), "..", "publish", "WixToolset.Sdk"); | 20 | public static readonly string WixMsbuildPath = Path.Combine(Path.GetDirectoryName(new Uri(typeof(MsbuildUtilities).Assembly.CodeBase).AbsolutePath), "..", "publish", "WixToolset.Sdk"); |
21 | public static readonly string WixPropsPath = Path.Combine(WixMsbuildPath, "build", "WixToolset.Sdk.props"); | 21 | public static readonly string WixPropsPath = Path.Combine(WixMsbuildPath, "build", "WixToolset.Sdk.props"); |
22 | 22 | ||
23 | public static MsbuildRunnerResult BuildProject(BuildSystem buildSystem, string projectPath, string[] arguments = null, string configuration = "Release", bool? outOfProc = null, string verbosityLevel = "normal") | 23 | public static MsbuildRunnerResult BuildProject(BuildSystem buildSystem, string projectPath, string[] arguments = null, string configuration = "Release", bool? outOfProc = null, string verbosityLevel = "normal", bool suppressValidation = true) |
24 | { | 24 | { |
25 | var allArgs = new List<string> | 25 | var allArgs = new List<string> |
26 | { | 26 | { |
27 | $"-verbosity:{verbosityLevel}", | 27 | $"-verbosity:{verbosityLevel}", |
28 | $"-p:Configuration={configuration}", | 28 | $"-p:Configuration={configuration}", |
29 | $"-p:SuppressValidation={suppressValidation}", | ||
29 | GetQuotedPropertySwitch(buildSystem, "WixMSBuildProps", MsbuildUtilities.WixPropsPath), | 30 | GetQuotedPropertySwitch(buildSystem, "WixMSBuildProps", MsbuildUtilities.WixPropsPath), |
30 | // Node reuse means that child msbuild processes can stay around after the build completes. | 31 | // Node reuse means that child msbuild processes can stay around after the build completes. |
31 | // Under that scenario, the root msbuild does not reliably close its streams which causes us to hang. | 32 | // Under that scenario, the root msbuild does not reliably close its streams which causes us to hang. |
diff --git a/src/wix/test/WixToolsetTest.Sdk/TestData/MsiPackageWithIceError/MsiPackage/MsiPackage.wixproj b/src/wix/test/WixToolsetTest.Sdk/TestData/MsiPackageWithIceError/MsiPackage/MsiPackage.wixproj new file mode 100644 index 00000000..acbcd85d --- /dev/null +++ b/src/wix/test/WixToolsetTest.Sdk/TestData/MsiPackageWithIceError/MsiPackage/MsiPackage.wixproj | |||
@@ -0,0 +1,65 @@ | |||
1 | <?xml version="1.0" encoding="utf-8"?> | ||
2 | <Project ToolsVersion="15.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> | ||
3 | <Import Project="$(WixMSBuildProps)" /> | ||
4 | <PropertyGroup> | ||
5 | <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> | ||
6 | <Platform Condition=" '$(Platform)' == '' ">x86</Platform> | ||
7 | </PropertyGroup> | ||
8 | |||
9 | <PropertyGroup> | ||
10 | <ProjectGuid>7fb77005-c6e0-454f-8c2d-0a4a79c918ba</ProjectGuid> | ||
11 | </PropertyGroup> | ||
12 | |||
13 | <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' "> | ||
14 | <PlatformName>$(Platform)</PlatformName> | ||
15 | <OutputPath>bin\$(Platform)\$(Configuration)\</OutputPath> | ||
16 | <DefineConstants>Debug</DefineConstants> | ||
17 | </PropertyGroup> | ||
18 | <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' "> | ||
19 | <PlatformName>$(Platform)</PlatformName> | ||
20 | <OutputPath>bin\$(Platform)\$(Configuration)\</OutputPath> | ||
21 | </PropertyGroup> | ||
22 | <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x64' "> | ||
23 | <PlatformName>$(Platform)</PlatformName> | ||
24 | <OutputPath>bin\$(Platform)\$(Configuration)\</OutputPath> | ||
25 | <DefineConstants>Debug</DefineConstants> | ||
26 | </PropertyGroup> | ||
27 | <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x64' "> | ||
28 | <PlatformName>$(Platform)</PlatformName> | ||
29 | <OutputPath>bin\$(Platform)\$(Configuration)\</OutputPath> | ||
30 | </PropertyGroup> | ||
31 | |||
32 | <ItemGroup> | ||
33 | <Compile Include="Package.wxs" /> | ||
34 | <Compile Include="PackageComponents.wxs" /> | ||
35 | </ItemGroup> | ||
36 | |||
37 | <ItemGroup> | ||
38 | <EmbeddedResource Include="Package.en-us.wxl" /> | ||
39 | </ItemGroup> | ||
40 | |||
41 | <ItemGroup> | ||
42 | <BindInputPaths Include="data" /> | ||
43 | </ItemGroup> | ||
44 | |||
45 | <Import Project="$(WixTargetsPath)" /> | ||
46 | |||
47 | <Target Name="SignCabs"> | ||
48 | <!-- It would be cool to actually sign, but signtool.exe is not always easy to find, so we'll | ||
49 | mock it up instead. | ||
50 | <Error Text="Could not find pfx at: $(TestCertificate)" Condition=" !Exists('$(TestCertificate)') " /> | ||
51 | <Exec Command='signtool.exe sign /v /f $(TestCertificate) /p password %(SignCabs.FullPath)' /> | ||
52 | --> | ||
53 | <Message Importance="high" Text="TEST: SignCabs: @(SignCabs)" /> | ||
54 | </Target> | ||
55 | |||
56 | <Target Name="SignMsi"> | ||
57 | <!-- It would be cool to actually sign, but signtool.exe is not always easy to find, so we'll | ||
58 | mock it up instead. | ||
59 | <Error Text="Could not find pfx at: $(TestCertificate)" Condition=" !Exists('$(TestCertificate)') " /> | ||
60 | <Exec Command='signtool.exe sign /v /f $(TestCertificate) /p password "%(SignMsi.FullPath)" ' /> | ||
61 | --> | ||
62 | <Message Importance="high" Text="TEST: SignMsi: @(SignMsi)" /> | ||
63 | </Target> | ||
64 | |||
65 | </Project> | ||
diff --git a/src/wix/test/WixToolsetTest.Sdk/TestData/MsiPackageWithIceError/MsiPackage/Package.en-us.wxl b/src/wix/test/WixToolsetTest.Sdk/TestData/MsiPackageWithIceError/MsiPackage/Package.en-us.wxl new file mode 100644 index 00000000..38c12ac1 --- /dev/null +++ b/src/wix/test/WixToolsetTest.Sdk/TestData/MsiPackageWithIceError/MsiPackage/Package.en-us.wxl | |||
@@ -0,0 +1,11 @@ | |||
1 | <?xml version="1.0" encoding="utf-8"?> | ||
2 | |||
3 | <!-- | ||
4 | This file contains the declaration of all the localizable strings. | ||
5 | --> | ||
6 | <WixLocalization xmlns="http://wixtoolset.org/schemas/v4/wxl" Culture="en-US"> | ||
7 | |||
8 | <String Id="DowngradeError">A newer version of [ProductName] is already installed.</String> | ||
9 | <String Id="FeatureTitle">MsiPackage</String> | ||
10 | |||
11 | </WixLocalization> | ||
diff --git a/src/wix/test/WixToolsetTest.Sdk/TestData/MsiPackageWithIceError/MsiPackage/Package.wxs b/src/wix/test/WixToolsetTest.Sdk/TestData/MsiPackageWithIceError/MsiPackage/Package.wxs new file mode 100644 index 00000000..e187ed7b --- /dev/null +++ b/src/wix/test/WixToolsetTest.Sdk/TestData/MsiPackageWithIceError/MsiPackage/Package.wxs | |||
@@ -0,0 +1,26 @@ | |||
1 | <Wix xmlns="http://wixtoolset.org/schemas/v4/wxs"> | ||
2 | <Package Name="MsiPackage" Language="1033" Version="1.0.0.0" Manufacturer="Example Corporation" UpgradeCode="047730a5-30fe-4a62-a520-da9381b8226a" Compressed="yes" InstallerVersion="200"> | ||
3 | <MajorUpgrade DowngradeErrorMessage="!(loc.DowngradeError)" /> | ||
4 | |||
5 | <Property Id="MyProperty" Value="1" /> | ||
6 | <Property Id="ReInStAlLmOdE" Value="Mixed-case Property Id causes ICE46" /> | ||
7 | |||
8 | <Launch Condition="Myproperty" Message="Invalid cased Property Id below causes ICE46" /> | ||
9 | |||
10 | <CustomAction Id="CausesICE12Error" Directory="INSTALLFOLDER" Value="Test" /> | ||
11 | |||
12 | <Feature Id="ProductFeature" Title="!(loc.FeatureTitle)"> | ||
13 | <ComponentGroupRef Id="ProductComponents" /> | ||
14 | </Feature> | ||
15 | |||
16 | <InstallExecuteSequence> | ||
17 | <Custom Action="CausesICE12Error" Before="AppSearch" /> | ||
18 | </InstallExecuteSequence> | ||
19 | </Package> | ||
20 | |||
21 | <Fragment> | ||
22 | <StandardDirectory Id="ProgramFiles6432Folder"> | ||
23 | <Directory Id="INSTALLFOLDER" Name="MsiPackage" /> | ||
24 | </StandardDirectory> | ||
25 | </Fragment> | ||
26 | </Wix> | ||
diff --git a/src/wix/test/WixToolsetTest.Sdk/TestData/MsiPackageWithIceError/MsiPackage/PackageComponents.wxs b/src/wix/test/WixToolsetTest.Sdk/TestData/MsiPackageWithIceError/MsiPackage/PackageComponents.wxs new file mode 100644 index 00000000..e26c4509 --- /dev/null +++ b/src/wix/test/WixToolsetTest.Sdk/TestData/MsiPackageWithIceError/MsiPackage/PackageComponents.wxs | |||
@@ -0,0 +1,10 @@ | |||
1 | <?xml version="1.0" encoding="utf-8"?> | ||
2 | <Wix xmlns="http://wixtoolset.org/schemas/v4/wxs"> | ||
3 | <Fragment> | ||
4 | <ComponentGroup Id="ProductComponents" Directory="INSTALLFOLDER"> | ||
5 | <Component> | ||
6 | <File Source="test.txt" /> | ||
7 | </Component> | ||
8 | </ComponentGroup> | ||
9 | </Fragment> | ||
10 | </Wix> | ||
diff --git a/src/wix/test/WixToolsetTest.Sdk/TestData/MsiPackageWithIceError/MsiPackage/data/test.txt b/src/wix/test/WixToolsetTest.Sdk/TestData/MsiPackageWithIceError/MsiPackage/data/test.txt new file mode 100644 index 00000000..cd0db0e1 --- /dev/null +++ b/src/wix/test/WixToolsetTest.Sdk/TestData/MsiPackageWithIceError/MsiPackage/data/test.txt | |||
@@ -0,0 +1 @@ | |||
This is test.txt. \ No newline at end of file | |||
diff --git a/src/wix/test/WixToolsetTest.Sdk/TestData/SimpleMsiPackage/MsiPackage/Package.wxs b/src/wix/test/WixToolsetTest.Sdk/TestData/SimpleMsiPackage/MsiPackage/Package.wxs index 0a133c7d..30be1ace 100644 --- a/src/wix/test/WixToolsetTest.Sdk/TestData/SimpleMsiPackage/MsiPackage/Package.wxs +++ b/src/wix/test/WixToolsetTest.Sdk/TestData/SimpleMsiPackage/MsiPackage/Package.wxs | |||
@@ -12,7 +12,7 @@ | |||
12 | </Package> | 12 | </Package> |
13 | 13 | ||
14 | <Fragment> | 14 | <Fragment> |
15 | <StandardDirectory Id="ProgramFilesFolder"> | 15 | <StandardDirectory Id="ProgramFiles6432Folder"> |
16 | <Directory Id="INSTALLFOLDER" Name="MsiPackage" /> | 16 | <Directory Id="INSTALLFOLDER" Name="MsiPackage" /> |
17 | </StandardDirectory> | 17 | </StandardDirectory> |
18 | </Fragment> | 18 | </Fragment> |