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>