From 933d4fc340f989239b77bfef4212f80d0a4a65f2 Mon Sep 17 00:00:00 2001 From: Rob Mensching Date: Mon, 10 Jan 2022 14:19:16 -0800 Subject: Support "inscribing" Burn bundles --- src/api/wix/WixToolset.Data/WarningMessages.cs | 2 +- .../DetachBundleEngineForSigning.cs | 64 ++++++++++++ .../ReattachSignedBundleEngine.cs | 71 +++++++++++++ .../WixToolset.BuildTasks/ToolsetTask_InProc.cs | 2 +- src/wix/WixToolset.Core.Burn/BundleBackend.cs | 11 +- src/wix/WixToolset.Core.Burn/Bundles/BurnReader.cs | 5 - src/wix/WixToolset.Core.Burn/BurnCommand.cs | 78 ++++++++++++++ .../BurnExtensionCommandLine.cs | 41 ++++++++ .../WixToolset.Core.Burn/BurnExtensionFactory.cs | 13 ++- src/wix/WixToolset.Core.Burn/BurnSubcommandBase.cs | 15 +++ src/wix/WixToolset.Core.Burn/DetachSubcommand.cs | 80 +++++++++++++++ .../Inscribe/InscribeBundleCommand.cs | 37 ++++--- .../Inscribe/InscribeBundleEngineCommand.cs | 19 ++-- src/wix/WixToolset.Core.Burn/ReattachSubcommand.cs | 101 +++++++++++++++++++ src/wix/WixToolset.Sdk/tools/wix.signing.targets | 42 +++++--- .../SigningFixture.cs | 112 +++++++++++++++++++++ .../TestData/.Data/signed_bundle_engine.exe | Bin 0 -> 3015593 bytes 17 files changed, 639 insertions(+), 54 deletions(-) create mode 100644 src/wix/WixToolset.BuildTasks/DetachBundleEngineForSigning.cs create mode 100644 src/wix/WixToolset.BuildTasks/ReattachSignedBundleEngine.cs create mode 100644 src/wix/WixToolset.Core.Burn/BurnCommand.cs create mode 100644 src/wix/WixToolset.Core.Burn/BurnExtensionCommandLine.cs create mode 100644 src/wix/WixToolset.Core.Burn/BurnSubcommandBase.cs create mode 100644 src/wix/WixToolset.Core.Burn/DetachSubcommand.cs create mode 100644 src/wix/WixToolset.Core.Burn/ReattachSubcommand.cs create mode 100644 src/wix/test/WixToolsetTest.CoreIntegration/TestData/.Data/signed_bundle_engine.exe diff --git a/src/api/wix/WixToolset.Data/WarningMessages.cs b/src/api/wix/WixToolset.Data/WarningMessages.cs index a592fe48..b749bcf4 100644 --- a/src/api/wix/WixToolset.Data/WarningMessages.cs +++ b/src/api/wix/WixToolset.Data/WarningMessages.cs @@ -279,7 +279,7 @@ namespace WixToolset.Data public static Message ExternalCabsAreNotSigned(string databaseFile) { - return Message(null, Ids.ExternalCabsAreNotSigned, "The installer database '{0}' has external cabs, but at least one of them is not signed. Please ensure that all external cabs are signed, if you mean to sign them. If you don't mean to sign them, there is no need to run the insignia tool as part of your build.", databaseFile); + return Message(null, Ids.ExternalCabsAreNotSigned, "The installer database '{0}' has external cabs, but at least one of them is not signed. Please ensure that all external cabs are signed, if you mean to sign them. If you don't mean to sign them, there is no need to inscribe the MSI as part of your build.", databaseFile); } public static Message FailedToDeleteTempDir(string directory) diff --git a/src/wix/WixToolset.BuildTasks/DetachBundleEngineForSigning.cs b/src/wix/WixToolset.BuildTasks/DetachBundleEngineForSigning.cs new file mode 100644 index 00000000..5fcd1def --- /dev/null +++ b/src/wix/WixToolset.BuildTasks/DetachBundleEngineForSigning.cs @@ -0,0 +1,64 @@ +// 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. + +namespace WixToolset.BuildTasks +{ + using Microsoft.Build.Framework; + + /// + /// An MSBuild task to run WiX to detach bundle engine to be signed. + /// + public sealed partial class DetachBundleEngineForSigning : WixExeBaseTask + { + /// + /// The bundle from which to detach the bundle engine. + /// + [Required] + public ITaskItem BundleFile { get; set; } + + /// + /// Gets or sets the intermedidate folder to use. + /// + public ITaskItem IntermediateDirectory { get; set; } + + /// + /// Gets or sets the path to the output detached bundle. + /// + [Required] + public ITaskItem OutputFile { get; set; } + + /// + /// Gets or sets the output. Only set if the task does work. + /// + [Output] + public ITaskItem Output { get; set; } + + protected override void BuildCommandLine(WixCommandLineBuilder commandLineBuilder) + { + commandLineBuilder.AppendTextUnquoted("burn detach"); + + commandLineBuilder.AppendFileNameIfNotNull(this.BundleFile); + commandLineBuilder.AppendSwitchIfNotNull("-engine ", this.OutputFile); + commandLineBuilder.AppendSwitchIfNotNull("-intermediatefolder ", this.IntermediateDirectory); + + base.BuildCommandLine(commandLineBuilder); + + commandLineBuilder.AppendTextIfNotWhitespace(this.AdditionalOptions); + } + + protected override int ExecuteTool(string pathToTool, string responseFileCommands, string commandLineCommands) + { + var exitCode = base.ExecuteTool(pathToTool, responseFileCommands, commandLineCommands); + + if (exitCode == 0) // successfully did work. + { + this.Output = this.OutputFile; + } + else if (exitCode == -1000) // no work done. + { + exitCode = 0; + } + + return exitCode; + } + } +} diff --git a/src/wix/WixToolset.BuildTasks/ReattachSignedBundleEngine.cs b/src/wix/WixToolset.BuildTasks/ReattachSignedBundleEngine.cs new file mode 100644 index 00000000..c07c12b9 --- /dev/null +++ b/src/wix/WixToolset.BuildTasks/ReattachSignedBundleEngine.cs @@ -0,0 +1,71 @@ +// 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. + +namespace WixToolset.BuildTasks +{ + using Microsoft.Build.Framework; + + /// + /// An MSBuild task to run WiX to reattach a (signed) bundle engine to its bundle. + /// + public sealed partial class ReattachSignedBundleEngine : WixExeBaseTask + { + /// + /// The bundle to which to attach the bundle engine. + /// + [Required] + public ITaskItem BundleFile { get; set; } + + /// + /// The bundle engine file to reattach to the bundle. + /// + [Required] + public ITaskItem BundleEngineFile { get; set; } + + /// + /// Gets or sets the intermedidate folder to use. + /// + public ITaskItem IntermediateDirectory { get; set; } + + /// + /// Gets or sets the path to the output detached bundle. + /// + [Required] + public ITaskItem OutputFile { get; set; } + + /// + /// Gets or sets the output. Only set if the task does work. + /// + [Output] + public ITaskItem Output { get; set; } + + protected override void BuildCommandLine(WixCommandLineBuilder commandLineBuilder) + { + commandLineBuilder.AppendTextUnquoted("burn reattach"); + + commandLineBuilder.AppendFileNameIfNotNull(this.BundleFile); + commandLineBuilder.AppendSwitchIfNotNull("-engine ", this.BundleEngineFile); + commandLineBuilder.AppendSwitchIfNotNull("-out ", this.OutputFile); + commandLineBuilder.AppendSwitchIfNotNull("-intermediatefolder ", this.IntermediateDirectory); + + base.BuildCommandLine(commandLineBuilder); + + commandLineBuilder.AppendTextIfNotWhitespace(this.AdditionalOptions); + } + + protected override int ExecuteTool(string pathToTool, string responseFileCommands, string commandLineCommands) + { + var exitCode = base.ExecuteTool(pathToTool, responseFileCommands, commandLineCommands); + + if (exitCode == 0) // successfully did work. + { + this.Output = this.OutputFile; + } + else if (exitCode == -1000) // no work done. + { + exitCode = 0; + } + + return exitCode; + } + } +} diff --git a/src/wix/WixToolset.BuildTasks/ToolsetTask_InProc.cs b/src/wix/WixToolset.BuildTasks/ToolsetTask_InProc.cs index fcf4aea9..eff117da 100644 --- a/src/wix/WixToolset.BuildTasks/ToolsetTask_InProc.cs +++ b/src/wix/WixToolset.BuildTasks/ToolsetTask_InProc.cs @@ -15,7 +15,7 @@ namespace WixToolset.BuildTasks public partial class ToolsetTask { - protected sealed override int ExecuteTool(string pathToTool, string responseFileCommands, string commandLineCommands) + protected override int ExecuteTool(string pathToTool, string responseFileCommands, string commandLineCommands) { if (this.RunAsSeparateProcess) { diff --git a/src/wix/WixToolset.Core.Burn/BundleBackend.cs b/src/wix/WixToolset.Core.Burn/BundleBackend.cs index 518b77c8..b179ea50 100644 --- a/src/wix/WixToolset.Core.Burn/BundleBackend.cs +++ b/src/wix/WixToolset.Core.Burn/BundleBackend.cs @@ -47,16 +47,7 @@ namespace WixToolset.Core.Burn public bool Inscribe(IInscribeContext context) { - if (String.IsNullOrEmpty(context.SignedEngineFile)) - { - var command = new InscribeBundleCommand(context); - return command.Execute(); - } - else - { - var command = new InscribeBundleEngineCommand(context); - return command.Execute(); - } + return false; } public Intermediate Unbind(IUnbindContext context) diff --git a/src/wix/WixToolset.Core.Burn/Bundles/BurnReader.cs b/src/wix/WixToolset.Core.Burn/Bundles/BurnReader.cs index 575252b0..933afc77 100644 --- a/src/wix/WixToolset.Core.Burn/Bundles/BurnReader.cs +++ b/src/wix/WixToolset.Core.Burn/Bundles/BurnReader.cs @@ -45,11 +45,6 @@ namespace WixToolset.Core.Burn.Bundles /// public Stream Stream => this.binaryReader?.BaseStream; - internal static BurnReader Open(object inputFilePath) - { - throw new NotImplementedException(); - } - /// /// Opens a Burn reader. /// diff --git a/src/wix/WixToolset.Core.Burn/BurnCommand.cs b/src/wix/WixToolset.Core.Burn/BurnCommand.cs new file mode 100644 index 00000000..3835bf2e --- /dev/null +++ b/src/wix/WixToolset.Core.Burn/BurnCommand.cs @@ -0,0 +1,78 @@ +// 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. + +namespace WixToolset.Core.Burn +{ + using System; + using System.Threading; + using System.Threading.Tasks; + using WixToolset.Extensibility.Data; + using WixToolset.Extensibility.Services; + + /// + /// Burn specialized command. + /// + internal class BurnCommand : ICommandLineCommand + { + public BurnCommand(IServiceProvider serviceProvider) + { + this.ServiceProvider = serviceProvider; + } + + public bool ShowHelp { get; set; } + + public bool ShowLogo { get; set; } + + public bool StopParsing { get; set; } + + private IServiceProvider ServiceProvider { get; } + + private BurnSubcommandBase Subcommand { get; set; } + + public Task ExecuteAsync(CancellationToken cancellationToken) + { + if (this.ShowHelp || this.Subcommand is null) + { + DisplayHelp(); + return Task.FromResult(1); + } + + return this.Subcommand.ExecuteAsync(cancellationToken); + } + + public bool TryParseArgument(ICommandLineParser parser, string argument) + { + if (this.Subcommand is null) + { + switch (argument.ToLowerInvariant()) + { + case "detach": + this.Subcommand = new DetachSubcommand(this.ServiceProvider); + return true; + + case "reattach": + this.Subcommand = new ReattachSubcommand(this.ServiceProvider); + return true; + } + + return false; + } + + return this.Subcommand.TryParseArgument(parser, argument); + } + + private static void DisplayHelp() + { + Console.WriteLine(); + Console.WriteLine("Usage: wix burn detach|reattach bundle.exe -out engine.exe"); + Console.WriteLine(); + Console.WriteLine("Options:"); + Console.WriteLine(" -h|--help Show command line help."); + Console.WriteLine(" --nologo Suppress displaying the logo information."); + Console.WriteLine(); + Console.WriteLine("Commands:"); + Console.WriteLine(); + Console.WriteLine(" detach Detaches the burn engine from a bundle so it can be signed."); + Console.WriteLine(" reattach Reattaches a signed burn engine to a bundle."); + } + } +} diff --git a/src/wix/WixToolset.Core.Burn/BurnExtensionCommandLine.cs b/src/wix/WixToolset.Core.Burn/BurnExtensionCommandLine.cs new file mode 100644 index 00000000..66e77888 --- /dev/null +++ b/src/wix/WixToolset.Core.Burn/BurnExtensionCommandLine.cs @@ -0,0 +1,41 @@ +// 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. + +namespace WixToolset.Core.Burn +{ + using System; + using System.Collections.Generic; + using WixToolset.Extensibility; + using WixToolset.Extensibility.Data; + using WixToolset.Extensibility.Services; + + /// + /// Parses the "msi" command-line command. See WindowsInstallerCommand + /// for the bulk of the command-line processing. + /// + internal class BurnExtensionCommandLine : BaseExtensionCommandLine + { + public BurnExtensionCommandLine(IServiceProvider serviceProvider) + { + this.ServiceProvider = serviceProvider; + } + + private IServiceProvider ServiceProvider { get; } + + public override IReadOnlyCollection CommandLineSwitches => new ExtensionCommandLineSwitch[] + { + new ExtensionCommandLineSwitch { Switch = "burn", Description = "Burn specialized operations." }, + }; + + public override bool TryParseCommand(ICommandLineParser parser, string argument, out ICommandLineCommand command) + { + command = null; + + if ("burn".Equals(argument, StringComparison.OrdinalIgnoreCase)) + { + command = new BurnCommand(this.ServiceProvider); + } + + return command != null; + } + } +} diff --git a/src/wix/WixToolset.Core.Burn/BurnExtensionFactory.cs b/src/wix/WixToolset.Core.Burn/BurnExtensionFactory.cs index b34d12c1..eca94f77 100644 --- a/src/wix/WixToolset.Core.Burn/BurnExtensionFactory.cs +++ b/src/wix/WixToolset.Core.Burn/BurnExtensionFactory.cs @@ -1,4 +1,4 @@ -// 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. +// 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. namespace WixToolset.Core.Burn { @@ -7,10 +7,21 @@ namespace WixToolset.Core.Burn internal class BurnExtensionFactory : IExtensionFactory { + public BurnExtensionFactory(IServiceProvider serviceProvider) + { + this.ServiceProvider = serviceProvider; + } + + private IServiceProvider ServiceProvider { get; } + public bool TryCreateExtension(Type extensionType, out object extension) { extension = null; + if (extensionType == typeof(IExtensionCommandLine)) + { + extension = new BurnExtensionCommandLine(this.ServiceProvider); + } if (extensionType == typeof(IBackendFactory)) { extension = new BurnBackendFactory(); diff --git a/src/wix/WixToolset.Core.Burn/BurnSubcommandBase.cs b/src/wix/WixToolset.Core.Burn/BurnSubcommandBase.cs new file mode 100644 index 00000000..62d69d4a --- /dev/null +++ b/src/wix/WixToolset.Core.Burn/BurnSubcommandBase.cs @@ -0,0 +1,15 @@ +// 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. + +namespace WixToolset.Core.Burn +{ + using System.Threading; + using System.Threading.Tasks; + using WixToolset.Extensibility.Services; + + internal abstract class BurnSubcommandBase + { + public abstract bool TryParseArgument(ICommandLineParser parser, string argument); + + public abstract Task ExecuteAsync(CancellationToken cancellationToken); + } +} diff --git a/src/wix/WixToolset.Core.Burn/DetachSubcommand.cs b/src/wix/WixToolset.Core.Burn/DetachSubcommand.cs new file mode 100644 index 00000000..a1614a85 --- /dev/null +++ b/src/wix/WixToolset.Core.Burn/DetachSubcommand.cs @@ -0,0 +1,80 @@ +// 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. + +namespace WixToolset.Core.Burn +{ + using System; + using System.IO; + using System.Threading; + using System.Threading.Tasks; + using WixToolset.Core.Burn.Inscribe; + using WixToolset.Extensibility.Services; + + internal class DetachSubcommand : BurnSubcommandBase + { + public DetachSubcommand(IServiceProvider serviceProvider) + { + this.ServiceProvider = serviceProvider; + this.Messaging = serviceProvider.GetService(); + } + + private IServiceProvider ServiceProvider { get; } + + private IMessaging Messaging { get; } + + private string InputPath { get; set; } + + private string IntermediateFolder { get; set; } + + private string EngineOutputPath { get; set; } + + public override Task ExecuteAsync(CancellationToken cancellationToken) + { + if (String.IsNullOrEmpty(this.InputPath)) + { + Console.Error.WriteLine("Path to input bundle is required"); + return Task.FromResult(-1); + } + + if (String.IsNullOrEmpty(this.EngineOutputPath)) + { + Console.Error.WriteLine("Path to output the bundle engine is required"); + return Task.FromResult(-1); + } + + if (String.IsNullOrEmpty(this.IntermediateFolder)) + { + this.IntermediateFolder = Path.GetTempPath(); + } + + var command = new InscribeBundleEngineCommand(this.ServiceProvider, this.InputPath, this.EngineOutputPath, this.IntermediateFolder); + command.Execute(); + + return Task.FromResult(this.Messaging.LastErrorNumber); + } + + public override bool TryParseArgument(ICommandLineParser parser, string argument) + { + if (parser.IsSwitch(argument)) + { + var parameter = argument.Substring(1); + switch (parameter.ToLowerInvariant()) + { + case "intermediatefolder": + this.IntermediateFolder = parser.GetNextArgumentAsDirectoryOrError(argument); + return true; + + case "engine": + this.EngineOutputPath = parser.GetNextArgumentAsFilePathOrError(argument); + return true; + } + } + else if (String.IsNullOrEmpty(this.InputPath)) + { + this.InputPath = argument; + return true; + } + + return false; + } + } +} diff --git a/src/wix/WixToolset.Core.Burn/Inscribe/InscribeBundleCommand.cs b/src/wix/WixToolset.Core.Burn/Inscribe/InscribeBundleCommand.cs index f835fd3a..6e071fe7 100644 --- a/src/wix/WixToolset.Core.Burn/Inscribe/InscribeBundleCommand.cs +++ b/src/wix/WixToolset.Core.Burn/Inscribe/InscribeBundleCommand.cs @@ -2,42 +2,51 @@ namespace WixToolset.Core.Burn.Inscribe { + using System; using System.IO; using WixToolset.Core.Burn.Bundles; using WixToolset.Core.Native; - using WixToolset.Extensibility.Data; using WixToolset.Extensibility.Services; internal class InscribeBundleCommand { - public InscribeBundleCommand(IInscribeContext context) + public InscribeBundleCommand(IServiceProvider serviceProvider, string inputPath, string signedEngineFile, string outputPath, string intermediateFolder) { - this.Context = context; - - this.Messaging = context.ServiceProvider.GetService(); + this.Messaging = serviceProvider.GetService(); + this.IntermediateFolder = intermediateFolder; + this.InputFilePath = inputPath; + this.SignedEngineFile = signedEngineFile; + this.OutputFile = outputPath; } - - private IInscribeContext Context { get; } - public IMessaging Messaging { get; } + private IMessaging Messaging { get; } + + private string IntermediateFolder { get; } + + private string InputFilePath { get; } + + private string SignedEngineFile { get; } + + private string OutputFile { get; } public bool Execute() { var inscribed = false; - var tempFile = Path.Combine(this.Context.IntermediateFolder, "bundle_engine_signed.exe"); + var tempFile = Path.Combine(this.IntermediateFolder, "~bundle_engine_signed.exe"); - using (var reader = BurnReader.Open(this.Context.InputFilePath)) + using (var reader = BurnReader.Open(this.Messaging, this.InputFilePath)) { - FileSystem.CopyFile(this.Context.SignedEngineFile, tempFile, allowHardlink: false); - using (BurnWriter writer = BurnWriter.Open(this.Messaging, tempFile)) + FileSystem.CopyFile(this.SignedEngineFile, tempFile, allowHardlink: false); + + using (var writer = BurnWriter.Open(this.Messaging, tempFile)) { inscribed = writer.ReattachContainers(reader); } } - Directory.CreateDirectory(Path.GetDirectoryName(this.Context.OutputFile)); + Directory.CreateDirectory(Path.GetDirectoryName(this.OutputFile)); - FileSystem.MoveFile(tempFile, this.Context.OutputFile); + FileSystem.MoveFile(tempFile, this.OutputFile); return inscribed; } diff --git a/src/wix/WixToolset.Core.Burn/Inscribe/InscribeBundleEngineCommand.cs b/src/wix/WixToolset.Core.Burn/Inscribe/InscribeBundleEngineCommand.cs index a6789796..e607a28f 100644 --- a/src/wix/WixToolset.Core.Burn/Inscribe/InscribeBundleEngineCommand.cs +++ b/src/wix/WixToolset.Core.Burn/Inscribe/InscribeBundleEngineCommand.cs @@ -6,28 +6,31 @@ namespace WixToolset.Core.Burn.Inscribe using System.IO; using WixToolset.Core.Burn.Bundles; using WixToolset.Core.Native; - using WixToolset.Extensibility.Data; + using WixToolset.Extensibility.Services; internal class InscribeBundleEngineCommand { - public InscribeBundleEngineCommand(IInscribeContext context) + public InscribeBundleEngineCommand(IServiceProvider serviceProvider, string inputPath, string outputPath, string intermediateFolder) { - this.IntermediateFolder = context.IntermediateFolder; - this.InputFilePath = context.InputFilePath; - this.OutputFile = context.OutputFile; + this.Messaging = serviceProvider.GetService(); + this.IntermediateFolder = intermediateFolder; + this.InputFilePath = inputPath; + this.OutputFile = outputPath; } + private IMessaging Messaging { get; } + private string IntermediateFolder { get; } private string InputFilePath { get; } private string OutputFile { get; } - public bool Execute() + public void Execute() { var tempFile = Path.Combine(this.IntermediateFolder, "bundle_engine_unsigned.exe"); - using (var reader = BurnReader.Open(this.InputFilePath)) + using (var reader = BurnReader.Open(this.Messaging, this.InputFilePath)) using (var writer = File.Open(tempFile, FileMode.Create, FileAccess.Write, FileShare.Read | FileShare.Delete)) { reader.Stream.Seek(0, SeekOrigin.Begin); @@ -56,8 +59,6 @@ namespace WixToolset.Core.Burn.Inscribe Directory.CreateDirectory(Path.GetDirectoryName(this.OutputFile)); FileSystem.MoveFile(tempFile, this.OutputFile); - - return true; } } } diff --git a/src/wix/WixToolset.Core.Burn/ReattachSubcommand.cs b/src/wix/WixToolset.Core.Burn/ReattachSubcommand.cs new file mode 100644 index 00000000..ce2af2d3 --- /dev/null +++ b/src/wix/WixToolset.Core.Burn/ReattachSubcommand.cs @@ -0,0 +1,101 @@ +// 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. + +namespace WixToolset.Core.Burn +{ + using System; + using System.IO; + using System.Threading; + using System.Threading.Tasks; + using WixToolset.Core.Burn.Inscribe; + using WixToolset.Extensibility.Services; + + internal class ReattachSubcommand : BurnSubcommandBase + { + public ReattachSubcommand(IServiceProvider serviceProvider) + { + this.ServiceProvider = serviceProvider; + this.Messaging = serviceProvider.GetService(); + } + + private IServiceProvider ServiceProvider { get; } + + private IMessaging Messaging { get; } + + private string InputPath { get; set; } + + private string SignedEnginePath { get; set; } + + private string IntermediateFolder { get; set; } + + private string OutputPath { get; set; } + + public override Task ExecuteAsync(CancellationToken cancellationToken) + { + if (String.IsNullOrEmpty(this.InputPath)) + { + Console.Error.WriteLine("Path to input bundle is required"); + return Task.FromResult(-1); + } + + if (String.IsNullOrEmpty(this.SignedEnginePath)) + { + Console.Error.WriteLine("Path to detached signed bundle engine is required"); + return Task.FromResult(-1); + } + + if (String.IsNullOrEmpty(this.IntermediateFolder)) + { + this.IntermediateFolder = Path.GetTempPath(); + } + + if (String.IsNullOrEmpty(this.OutputPath)) + { + this.OutputPath = this.InputPath; + } + + var command = new InscribeBundleCommand(this.ServiceProvider, this.InputPath, this.SignedEnginePath, this.OutputPath, this.IntermediateFolder); + var didWork = command.Execute(); + + // If the detach subcommand did not encounter an error but did no work + // then return the special exit code that indicates no work was done (-1000). + var exitCode = this.Messaging.LastErrorNumber; + + if (!didWork && exitCode == 0) + { + exitCode = -1000; + } + + return Task.FromResult(exitCode); + } + + public override bool TryParseArgument(ICommandLineParser parser, string argument) + { + if (parser.IsSwitch(argument)) + { + var parameter = argument.Substring(1); + switch (parameter.ToLowerInvariant()) + { + case "engine": + this.SignedEnginePath = parser.GetNextArgumentAsFilePathOrError(argument); + return true; + + case "intermediatefolder": + this.IntermediateFolder = parser.GetNextArgumentAsDirectoryOrError(argument); + return true; + + case "o": + case "out": + this.OutputPath = parser.GetNextArgumentAsFilePathOrError(argument); + return true; + } + } + else if (String.IsNullOrEmpty(this.InputPath)) + { + this.InputPath = argument; + return true; + } + + return false; + } + } +} diff --git a/src/wix/WixToolset.Sdk/tools/wix.signing.targets b/src/wix/WixToolset.Sdk/tools/wix.signing.targets index 45556e23..cdaee4a2 100644 --- a/src/wix/WixToolset.Sdk/tools/wix.signing.targets +++ b/src/wix/WixToolset.Sdk/tools/wix.signing.targets @@ -20,6 +20,14 @@ + + + + + + + + $(NoLogo) @@ -230,22 +238,26 @@ Inputs="@(SignTargetPath)" Outputs="$(SignedFilePath)"> - + AdditionalOptions="$(InscribeAdditionalOptions)" + + RunAsSeparateProcess="$(RunWixToolsOutOfProc)" + ToolExe="$(WixToolExe)" + ToolPath="$(WixToolDir)"> - + - + @@ -274,22 +286,26 @@ Inputs="@(SignTargetPath)" Outputs="$(SignedFilePath)"> - + AdditionalOptions="$(InscribeAdditionalOptions)" + + RunAsSeparateProcess="$(RunWixToolsOutOfProc)" + ToolExe="$(WixToolExe)" + ToolPath="$(WixToolDir)"> - +