@joebigelow / wix-1 / commits / 24e8f28d

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.

Rob Mensching committed Feb 7, 2022 at 21:28 UTC 24e8f28dc9bea0a72a82abc6cafebe2364c94ef1
33 files changed +711 -202
src/api/wix/WixToolset.Extensibility/Data/IBindContext.cs
-15
@@ -52,11 +52,6 @@ namespace WixToolset.Extensibility.Data
52 /// </summary>
53 IReadOnlyCollection<IFileSystemExtension> FileSystemExtensions { get; set; }
54
55 - /// <summary>
56 - /// Set of ICEs to execute.
57 - /// </summary>
58 - IReadOnlyCollection<string> Ices { get; set; }
59 -
55 /// <summary>
56 /// Intermedaite folder.
57 /// </summary>
@@ -97,16 +92,6 @@ namespace WixToolset.Extensibility.Data
92 /// </summary>
93 int? ResolvedLcid { get; set; }
94
100 - /// <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 -
95 /// <summary>
96 /// Skip creation of output.
97 /// </summary>
src/test/burn/Directory.wixproj.props
+1
@@ -7,6 +7,7 @@
7 <DefaultCompressionLevel>None</DefaultCompressionLevel>
8 <CompilerAdditionalOptions>-wx</CompilerAdditionalOptions>
9 <SuppressSpecificWarnings>1154;$(SuppressSpecificWarnings)</SuppressSpecificWarnings>
10 + <SuppressValidation>true</SuppressValidation>
11 <ForTestingUseOnlyWixextPath>$(BaseOutputPath)$(Configuration)\netstandard2.0\ForTestingUseOnly.wixext.dll</ForTestingUseOnlyWixextPath>
12 </PropertyGroup>
13 </Project>
src/test/wix/TestData/WixprojPackageCsprojWebApplicationNetCore/Package.wxs
+1 -1
@@ -1,5 +1,5 @@
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
4 <StandardDirectory Id='ProgramFiles6432Folder'>
5 <Directory Id='ApplicationFolder' Name='~Web App'>
src/test/wix/TestData/WixprojPackageVcxprojWindowsApp/Package.wxs
+1 -1
@@ -1,5 +1,5 @@
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
4 <StandardDirectory Id='ProgramFiles6432Folder'>
5 <Directory Id='ApplicationFolder' Name='Test App'>
src/test/wix/TestData/WixprojPackageVcxprojWindowsAppMultiArch/Package.wxs
+1 -1
@@ -1,5 +1,5 @@
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
4 <StandardDirectory Id='ProgramFilesFolder'>
5 <Directory Id='Application32Folder' Name='Test App (32-bit)' />
src/wix/WixToolset.BuildTasks/WindowsInstallerValidation.cs new
+59
@@ -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 +}
src/wix/WixToolset.BuildTasks/WixBuild.cs
+1 -8
@@ -64,13 +64,8 @@ namespace WixToolset.BuildTasks
64 public ITaskItem UnreferencedSymbolsFile { get; set; }
65
66 public ITaskItem WixProjectFile { get; set; }
67 - public string[] WixVariables { get; set; }
68 -
69 - public bool SuppressValidation { get; set; }
67
71 - public string[] SuppressIces { get; set; }
72 -
73 - public string AdditionalCub { get; set; }
68 + public string[] WixVariables { get; set; }
69
70 protected override void BuildCommandLine(WixCommandLineBuilder commandLineBuilder)
71 {
@@ -85,8 +80,6 @@ namespace WixToolset.BuildTasks
80 commandLineBuilder.AppendArrayIfNotNull("-d ", this.DefineConstants);
81 commandLineBuilder.AppendArrayIfNotNull("-I ", this.IncludeSearchPaths);
82 commandLineBuilder.AppendExtensions(this.Extensions, this.ExtensionDirectory, this.ReferencePaths);
88 - commandLineBuilder.AppendIfTrue("-sval", this.SuppressValidation);
89 - commandLineBuilder.AppendArrayIfNotNull("-sice ", this.SuppressIces);
83 commandLineBuilder.AppendSwitchIfNotNull("-usf ", this.UnreferencedSymbolsFile);
84 commandLineBuilder.AppendSwitchIfNotNull("-cc ", this.CabinetCachePath);
85 commandLineBuilder.AppendSwitchIfNotNull("-intermediatefolder ", this.IntermediateDirectory);
src/wix/WixToolset.Core.Native/FileSystem.cs
+2 -2
@@ -62,14 +62,14 @@ namespace WixToolset.Core.Native
62
63 private static void EnsureDirectoryWithoutFile(string path)
64 {
65 - File.Delete(path);
66 -
65 var directory = Path.GetDirectoryName(path);
66
67 if (!String.IsNullOrEmpty(directory))
68 {
69 Directory.CreateDirectory(directory);
70 }
71 +
72 + File.Delete(path);
73 }
74
75 [DllImport("Kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
src/wix/WixToolset.Core.WindowsInstaller/Bind/BindDatabaseCommand.cs
+1 -30
@@ -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.
22 internal static readonly Guid WixComponentGuidNamespace = new Guid("{3064E5C6-FB63-4FE9-AC49-E446A792EFA5}");
23
24 - public BindDatabaseCommand(IBindContext context, IEnumerable<IWindowsInstallerBackendBinderExtension> backendExtension, string cubeFile) : this(context, backendExtension, null, cubeFile)
25 - {
26 - }
27 -
28 - public BindDatabaseCommand(IBindContext context, IEnumerable<IWindowsInstallerBackendBinderExtension> backendExtension, IEnumerable<SubStorage> subStorages, string cubeFile)
24 + public BindDatabaseCommand(IBindContext context, IEnumerable<IWindowsInstallerBackendBinderExtension> backendExtension, IEnumerable<SubStorage> subStorages = null)
25 {
26 this.ServiceProvider = context.ServiceProvider;
27
@@ -53,11 +49,6 @@ namespace WixToolset.Core.WindowsInstaller.Bind
49
50 this.SubStorages = subStorages;
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 -
52 this.BackendExtensions = backendExtension;
53 }
54
@@ -109,12 +100,6 @@ namespace WixToolset.Core.WindowsInstaller.Bind
100
101 private bool SuppressValidation { get; }
102
112 - private IEnumerable<string> Ices { get; }
113 -
114 - private IEnumerable<string> SuppressedIces { get; }
115 -
116 - private IEnumerable<string> CubeFiles { get; }
117 -
103 public IBindResult Execute()
104 {
105 if (!this.Intermediate.HasLevel(Data.IntermediateLevels.Linked) || !this.Intermediate.HasLevel(Data.IntermediateLevels.Resolved))
@@ -507,20 +492,6 @@ namespace WixToolset.Core.WindowsInstaller.Bind
492 return null;
493 }
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 -
495 // Process uncompressed files.
496 if (!this.SuppressLayout && uncompressedFiles.Any())
497 {
src/wix/WixToolset.Core.WindowsInstaller/CommandLine/ValidateSubcommand.cs new
+131
@@ -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 +}
src/wix/WixToolset.Core.WindowsInstaller/CommandLine/WindowsInstallerCommand.cs
+5
@@ -48,6 +48,10 @@ namespace WixToolset.Core.WindowsInstaller.CommandLine
48 case "inscribe":
49 this.Subcommand = new InscribeSubcommand(this.ServiceProvider);
50 return true;
51 +
52 + case "validate":
53 + this.Subcommand = new ValidateSubcommand(this.ServiceProvider);
54 + return true;
55 }
56
57 return false;
@@ -68,6 +72,7 @@ namespace WixToolset.Core.WindowsInstaller.CommandLine
72 Console.WriteLine("Commands:");
73 Console.WriteLine();
74 Console.WriteLine(" inscribe Updates MSI database with cabinet signature information.");
75 + Console.WriteLine(" validate Validates MSI database using standard or custom ICEs.");
76 }
77 }
78 }
src/wix/WixToolset.Core.WindowsInstaller/MsiBackend.cs
+1 -1
@@ -27,7 +27,7 @@ namespace WixToolset.Core.WindowsInstaller
27 var dispose = true;
28 try
29 {
30 - var command = new BindDatabaseCommand(context, backendExtensions, "darice.cub");
30 + var command = new BindDatabaseCommand(context, backendExtensions);
31 result = command.Execute();
32
33 foreach (var extension in backendExtensions)
src/wix/WixToolset.Core.WindowsInstaller/MsmBackend.cs
+1 -1
@@ -26,7 +26,7 @@ namespace WixToolset.Core.WindowsInstaller
26 IBindResult result = null;
27 try
28 {
29 - var command = new BindDatabaseCommand(context, backendExtensions, "mergemod.cub");
29 + var command = new BindDatabaseCommand(context, backendExtensions);
30 result = command.Execute();
31
32 foreach (var extension in backendExtensions)
src/wix/WixToolset.Core.WindowsInstaller/MspBackend.cs
+1 -1
@@ -52,7 +52,7 @@ namespace WixToolset.Core.WindowsInstaller
52 IBindResult result = null;
53 try
54 {
55 - var command = new BindDatabaseCommand(context, backendExtensions, subStorages, null);
55 + var command = new BindDatabaseCommand(context, backendExtensions, subStorages);
56 result = command.Execute();
57
58 foreach (var extension in backendExtensions)
src/wix/WixToolset.Core.WindowsInstaller/Validate/ValidateDatabaseCommand.cs renamed
+22 -25
@@ -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.
2
3 -namespace WixToolset.Core.WindowsInstaller.Bind
3 +namespace WixToolset.Core.WindowsInstaller.Validate
4 {
5 using System;
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.
19 private static readonly string[] WellKnownSuppressedIces = new[] { "ICE08", "ICE33", "ICE47", "ICE66" };
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 {
23 this.Messaging = messaging;
24 - this.BackendHelper = backendHelper;
24 this.Data = data;
26 - this.OutputPath = outputPath;
25 + this.DatabasePath = databasePath;
26 this.CubeFiles = cubeFiles;
27 this.Ices = ices;
28 this.SuppressedIces = suppressedIces == null ? WellKnownSuppressedIces : suppressedIces.Union(WellKnownSuppressedIces);
29
30 this.IntermediateFolder = intermediateFolder;
32 - this.OutputSourceLineNumber = new SourceLineNumber(outputPath);
31 + this.OutputSourceLineNumber = new SourceLineNumber(databasePath);
32 }
33
34 public IEnumerable<ITrackedFile> TrackedFiles { get; private set; }
@@ -41,11 +40,9 @@ namespace WixToolset.Core.WindowsInstaller.Bind
40
41 private IMessaging Messaging { get; }
42
44 - private IBackendHelper BackendHelper { get; }
45 -
43 private WindowsInstallerData Data { get; }
44
48 - private string OutputPath { get; }
45 + private string DatabasePath { get; }
46
47 private IEnumerable<string> CubeFiles { get; }
48
@@ -64,34 +61,34 @@ namespace WixToolset.Core.WindowsInstaller.Bind
61
62 public void Execute()
63 {
67 - var trackedFiles = new List<ITrackedFile>();
64 var stopwatch = Stopwatch.StartNew();
65
66 this.Messaging.Write(VerboseMessages.ValidatingDatabase());
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 -
68 // Copy the database to a temporary location so it can be manipulated.
69 // Ensure it is not read-only.
78 - var workingDatabasePath = Path.Combine(workingFolder, Path.GetFileName(this.OutputPath));
79 - FileSystem.CopyFile(this.OutputPath, workingDatabasePath, allowHardlink: false);
80 -
81 - var trackWorkingDatabase = this.BackendHelper.TrackFile(workingDatabasePath, TrackedFileType.Temporary);
82 - trackedFiles.Add(trackWorkingDatabase);
70 + var workingDatabaseFilename = String.Concat(Path.GetFileNameWithoutExtension(this.DatabasePath), "_validate", Path.GetExtension(this.DatabasePath));
71 + var workingDatabasePath = Path.Combine(this.IntermediateFolder, workingDatabaseFilename);
72 + try
73 + {
74 + FileSystem.CopyFile(this.DatabasePath, workingDatabasePath, allowHardlink: false);
75
84 - var attributes = File.GetAttributes(workingDatabasePath);
85 - File.SetAttributes(workingDatabasePath, attributes & ~FileAttributes.ReadOnly);
76 + var attributes = File.GetAttributes(workingDatabasePath);
77 + File.SetAttributes(workingDatabasePath, attributes & ~FileAttributes.ReadOnly);
78
87 - var validator = new WindowsInstallerValidator(this, workingDatabasePath, this.CubeFiles, this.Ices, this.SuppressedIces);
88 - validator.Execute();
79 + var validator = new WindowsInstallerValidator(this, workingDatabasePath, this.CubeFiles, this.Ices, this.SuppressedIces);
80 + validator.Execute();
81 + }
82 + finally
83 + {
84 + if (File.Exists(workingDatabasePath))
85 + {
86 + File.Delete(workingDatabasePath);
87 + }
88 + }
89
90 stopwatch.Stop();
91 this.Messaging.Write(VerboseMessages.ValidatedDatabase(stopwatch.ElapsedMilliseconds));
92 -
93 -
94 - this.TrackedFiles = trackedFiles;
92 }
93
94 private void LogValidationMessage(ValidationMessage message)
src/wix/WixToolset.Core/BindContext.cs
-6
@@ -36,8 +36,6 @@ namespace WixToolset.Core
36
37 public IReadOnlyCollection<IFileSystemExtension> FileSystemExtensions { get; set; }
38
39 - public IReadOnlyCollection<string> Ices { get; set; }
40 -
39 public string IntermediateFolder { get; set; }
40
41 public Intermediate IntermediateRepresentation { get; set; }
@@ -54,10 +52,6 @@ namespace WixToolset.Core
52
53 public int? ResolvedLcid { get; set; }
54
57 - public IReadOnlyCollection<string> SuppressIces { get; set; }
58 -
59 - public bool SuppressValidation { get; set; }
60 -
55 public bool SuppressLayout { get; set; }
56
57 public CancellationToken CancellationToken { get; set; }
src/wix/WixToolset.Core/CommandLine/BuildCommand.cs
-27
@@ -349,14 +349,11 @@ namespace WixToolset.Core.CommandLine
349 context.ExpectedEmbeddedFiles = resolveResult.ExpectedEmbeddedFiles;
350 context.Extensions = this.ExtensionManager.GetServices<IBinderExtension>();
351 context.FileSystemExtensions = this.ExtensionManager.GetServices<IFileSystemExtension>();
352 - context.Ices = this.commandLine.Ices;
352 context.IntermediateFolder = intermediateFolder;
353 context.IntermediateRepresentation = resolveResult.IntermediateRepresentation;
354 context.OutputPath = this.OutputFile;
355 context.PdbType = this.PdbType;
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;
357 context.CancellationToken = cancellationToken;
358
359 var binder = this.ServiceProvider.GetService<IBinder>();
@@ -540,12 +537,6 @@ namespace WixToolset.Core.CommandLine
537
538 public string TrackingFile { get; private set; }
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 -
540 public bool ResetAcls { get; set; }
541
542 public CommandLine(IServiceProvider serviceProvider, IMessaging messaging)
@@ -627,13 +618,6 @@ namespace WixToolset.Core.CommandLine
618 parser.GetNextArgumentOrError(arg, this.IncludeSearchPaths);
619 return true;
620
630 - case "ice":
631 - {
632 - var value = parser.GetNextArgumentOrError(arg);
633 - this.Ices.Add(value);
634 - return true;
635 - }
636 -
621 case "intermediatefolder":
622 this.IntermediateFolder = parser.GetNextArgumentAsDirectoryOrError(arg);
623 return true;
@@ -670,17 +654,6 @@ namespace WixToolset.Core.CommandLine
654 return false;
655 }
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 -
657 case "resetacls":
658 this.ResetAcls = true;
659 return true;
src/wix/WixToolset.Sdk/tools/wix.targets
+32 -7
@@ -168,6 +168,10 @@
168 <UsingTask TaskName="ResolveWixReferences" Condition=" '$(WixTasksPath64)' != '' " AssemblyFile="$(WixTasksPath)" Architecture="x86" />
169 <UsingTask TaskName="ResolveWixReferences" Condition=" '$(WixTasksPath64)' != '' " AssemblyFile="$(WixTasksPath64)" Architecture="x64" />
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 +
175 <!--
176 ***********************************************************************************************
177 ***********************************************************************************************
@@ -553,6 +557,10 @@
557 ================================================================================================
558 -->
559 <PropertyGroup>
560 + <CompileDependsOn>
561 + $(CompileDependsOn);
562 + WindowsInstallerValidation
563 + </CompileDependsOn>
564 <CoreCompileDependsOn>
565 AssignTargetPaths;
566 CreateManifestResourceNames;
@@ -604,9 +612,6 @@
612 Pedantic="$(Pedantic)"
613 ReferencePaths="$(ReferencePaths)"
614
607 - SuppressSpecificWarnings="$(SuppressSpecificWarnings)"
608 - TreatSpecificWarningsAsErrors="$(TreatSpecificWarningsAsErrors)"
609 -
615 BindInputPaths="@(LinkerBindInputPaths)"
616 BindFiles="$(BindFiles)"
617 BindTrackingFile="$(IntermediateOutputPath)$(BindTrackingFilePrefix)%(CultureGroup.Identity)$(BindTrackingFileExtension)"
@@ -619,12 +624,10 @@
624 WixProjectFile="$(ProjectPath)"
625 WixVariables="$(WixVariables)"
626
622 - SuppressValidation="$(SuppressValidation)"
623 - SuppressIces="$(SuppressIces)"
624 - AdditionalCub="$(AdditionalCub)"
625 -
627 SuppressAllWarnings="$(SuppressAllWarnings)"
628 + SuppressSpecificWarnings="$(SuppressSpecificWarnings)"
629 TreatWarningsAsErrors="$(TreatWarningsAsErrors)"
630 + TreatSpecificWarningsAsErrors="$(TreatSpecificWarningsAsErrors)"
631 VerboseOutput="$(VerboseOutput)"
632
633 RunAsSeparateProcess="$(RunWixToolsOutOfProc)"
@@ -636,6 +639,28 @@
639 </ItemGroup>
640 </Target>
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 +
664 <!--
665 ================================================================================================
666 _CreateProjectDefineConstants
src/wix/test/WixToolsetTest.CoreIntegration/ModuleFixture.cs
+92 -1
@@ -15,7 +15,7 @@ namespace WixToolsetTest.CoreIntegration
15 public class ModuleFixture
16 {
17 [Fact]
18 - public void CanBuildSimpleModule()
18 + public void CanBuildAndValidateSimpleModule()
19 {
20 var folder = TestData.Get(@"TestData\SimpleModule");
21
@@ -73,6 +73,30 @@ namespace WixToolsetTest.CoreIntegration
73 "File1.243FB739_4D05_472F_9CFB_EF6B1017B6DE",
74 "File2.243FB739_4D05_472F_9CFB_EF6B1017B6DE",
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();
100 }
101 }
102
@@ -109,5 +133,72 @@ namespace WixToolsetTest.CoreIntegration
133 }, rows);
134 }
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 + }
203 }
204 }
src/wix/test/WixToolsetTest.CoreIntegration/MsiQueryFixture.cs
-65
@@ -8,9 +8,6 @@ namespace WixToolsetTest.CoreIntegration
8 using Example.Extension;
9 using WixBuildTools.TestSupport;
10 using WixToolset.Core.TestPackage;
11 - using WixToolset.Data;
12 - using WixToolset.Data.Symbols;
13 - using WixToolset.Data.WindowsInstaller;
11 using Xunit;
12
13 public class MsiQueryFixture
@@ -834,68 +831,6 @@ namespace WixToolsetTest.CoreIntegration
831 }
832 }
833
837 - [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 -
834 [Fact]
835 public void CanPublishComponentWithMultipleFeatureComponents()
836 {
src/wix/test/WixToolsetTest.CoreIntegration/TestData/BindVariables/PackageWithBindVariables.wxs
+1 -1
@@ -1,5 +1,5 @@
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
4 <Property Id="TestPackageManufacturer" Value="!(bind.Property.Manufacturer)" />
5 <Property Id="TestPackageName" Value="!(bind.Property.ProductName)" />
src/wix/test/WixToolsetTest.CoreIntegration/TestData/SimpleMerge/.data/test.msm
Binary files a/src/wix/test/WixToolsetTest.CoreIntegration/TestData/SimpleMerge/.data/test.msm and /dev/null differ
src/wix/test/WixToolsetTest.CoreIntegration/TestData/SimpleMerge/Package.wxs
-3
@@ -1,7 +1,5 @@
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">
3 -
4 -
3 <MajorUpgrade DowngradeErrorMessage="!(loc.DowngradeError)" />
4
5 <Feature Id="ProductFeature" Title="!(loc.FeatureTitle)">
@@ -12,7 +10,6 @@
10 <Fragment>
11 <StandardDirectory Id="ProgramFilesFolder">
12 <Directory Id="INSTALLFOLDER" Name="MsiPackage">
15 - <!-- -->
13 <Merge Id="TestMsm" Language="1033" SourceFile="test.msm" />
14 </Directory>
15 </StandardDirectory>
src/wix/test/WixToolsetTest.CoreIntegration/TestData/Validation/PackageWithIceIssues.wxs new
+32
@@ -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>
src/wix/test/WixToolsetTest.CoreIntegration/ValidationFixture.cs new
+133
@@ -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 +}
src/wix/test/WixToolsetTest.Sdk/MsbuildFixture.cs
+77 -4
@@ -271,6 +271,7 @@ namespace WixToolsetTest.Sdk
271 var result = MsbuildUtilities.BuildProject(buildSystem, projectPath, new[]
272 {
273 wixpdbType == null ? String.Empty : $"-p:WixPdbType={wixpdbType}",
274 + "-p:SuppressValidation=true"
275 });
276 result.AssertSuccess();
277
@@ -323,9 +324,44 @@ namespace WixToolsetTest.Sdk
324 [InlineData(BuildSystem.DotNetCoreSdk)]
325 [InlineData(BuildSystem.MSBuild)]
326 [InlineData(BuildSystem.MSBuild64)]
326 - public void CanBuildSimpleMsiPackageWithIceSuppressions(BuildSystem buildSystem)
327 + public void CannotBuildMsiPackageWithIceIssues(BuildSystem buildSystem)
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");
365
366 using (var fs = new TestDataFolderFileSystem())
367 {
@@ -336,8 +372,45 @@ namespace WixToolsetTest.Sdk
372
373 var result = MsbuildUtilities.BuildProject(buildSystem, projectPath, new[]
374 {
339 - MsbuildUtilities.GetQuotedPropertySwitch(buildSystem, "SuppressIces", "ICE45;ICE46"),
340 - });
375 + $"-p:TreatWarningsAsErrors=true",
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);
414 result.AssertSuccess();
415 }
416 }
src/wix/test/WixToolsetTest.Sdk/MsbuildUtilities.cs
+2 -1
@@ -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");
21 public static readonly string WixPropsPath = Path.Combine(WixMsbuildPath, "build", "WixToolset.Sdk.props");
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 {
25 var allArgs = new List<string>
26 {
27 $"-verbosity:{verbosityLevel}",
28 $"-p:Configuration={configuration}",
29 + $"-p:SuppressValidation={suppressValidation}",
30 GetQuotedPropertySwitch(buildSystem, "WixMSBuildProps", MsbuildUtilities.WixPropsPath),
31 // Node reuse means that child msbuild processes can stay around after the build completes.
32 // Under that scenario, the root msbuild does not reliably close its streams which causes us to hang.
src/wix/test/WixToolsetTest.Sdk/TestData/MsiPackageWithIceError/MsiPackage/MsiPackage.wixproj new
+65
@@ -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>
src/wix/test/WixToolsetTest.Sdk/TestData/MsiPackageWithIceError/MsiPackage/Package.en-us.wxl new
+11
@@ -0,0 +1,11 @@
1 +<?xml version="1.0" encoding="utf-8"?>
2 +
3 +<!--
4 +This file contains the declaration of all the localizable strings.
5 +-->
6 +<WixLocalization xmlns="http://wixtoolset.org/schemas/v4/wxl" Culture="en-US">
7 +
8 + <String Id="DowngradeError">A newer version of [ProductName] is already installed.</String>
9 + <String Id="FeatureTitle">MsiPackage</String>
10 +
11 +</WixLocalization>
src/wix/test/WixToolsetTest.Sdk/TestData/MsiPackageWithIceError/MsiPackage/Package.wxs new
+26
@@ -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>
src/wix/test/WixToolsetTest.Sdk/TestData/MsiPackageWithIceError/MsiPackage/PackageComponents.wxs new
+10
@@ -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>
src/wix/test/WixToolsetTest.Sdk/TestData/MsiPackageWithIceError/MsiPackage/data/test.txt new
+1
@@ -0,0 +1 @@
1 +This is test.txt.
\ No newline at end of file
src/wix/test/WixToolsetTest.Sdk/TestData/SimpleMsiPackage/MsiPackage/Package.wxs
+1 -1
@@ -12,7 +12,7 @@
12 </Package>
13
14 <Fragment>
15 - <StandardDirectory Id="ProgramFilesFolder">
15 + <StandardDirectory Id="ProgramFiles6432Folder">
16 <Directory Id="INSTALLFOLDER" Name="MsiPackage" />
17 </StandardDirectory>
18 </Fragment>