@joebigelow / wix-1 / commits / 4d30dccc

Implement "wix burn extract"

In v3, bundles were extracted by "decompiling" even though the process did not actually result in decompiled source code. In v4, the backends and provide specialized commands so have "extract" join "detach" and "reattach" subcommands on the "burn" command. Completes 6314

Rob Mensching committed Mar 10, 2022 at 14:27 UTC 4d30dccc66470fb4311b602adee60bf00ae8e64f
4 files changed +104 -26
src/wix/WixToolset.Core.Burn/BundleBackend.cs
-17
@@ -3,9 +3,6 @@
3 namespace WixToolset.Core.Burn
4 {
5 using System;
6 - using System.IO;
7 - using WixToolset.Core.Burn.Bundles;
8 - using WixToolset.Data;
6 using WixToolset.Extensibility;
7 using WixToolset.Extensibility.Data;
8 using WixToolset.Extensibility.Services;
@@ -43,19 +40,5 @@ namespace WixToolset.Core.Burn
40 {
41 throw new NotImplementedException();
42 }
46 -
47 - public Intermediate Unbind(IUnbindContext context)
48 - {
49 - var uxExtractPath = Path.Combine(context.ExportBasePath, "UX");
50 - var messaging = context.ServiceProvider.GetService<IMessaging>();
51 -
52 - using (var reader = BurnReader.Open(messaging, context.InputFilePath))
53 - {
54 - reader.ExtractUXContainer(uxExtractPath, context.IntermediateFolder);
55 - reader.ExtractAttachedContainers(context.ExportBasePath, context.IntermediateFolder);
56 - }
57 -
58 - return null;
59 - }
43 }
44 }
src/wix/WixToolset.Core.Burn/CommandLine/BurnCommand.cs
+4
@@ -49,6 +49,10 @@ namespace WixToolset.Core.Burn.CommandLine
49 this.Subcommand = new DetachSubcommand(this.ServiceProvider);
50 return true;
51
52 + case "extract":
53 + this.Subcommand = new ExtractSubcommand(this.ServiceProvider);
54 + return true;
55 +
56 case "reattach":
57 this.Subcommand = new ReattachSubcommand(this.ServiceProvider);
58 return true;
src/wix/WixToolset.Core.Burn/CommandLine/ExtractSubcommand.cs new
+86
@@ -0,0 +1,86 @@
1 +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2 +
3 +namespace WixToolset.Core.Burn.CommandLine
4 +{
5 + using System;
6 + using System.IO;
7 + using System.Threading;
8 + using System.Threading.Tasks;
9 + using WixToolset.Core.Burn.Bundles;
10 + using WixToolset.Core.Burn.Inscribe;
11 + using WixToolset.Extensibility.Services;
12 +
13 + internal class ExtractSubcommand : BurnSubcommandBase
14 + {
15 + public ExtractSubcommand(IServiceProvider serviceProvider)
16 + {
17 + this.ServiceProvider = serviceProvider;
18 + this.Messaging = serviceProvider.GetService<IMessaging>();
19 + }
20 +
21 + private IServiceProvider ServiceProvider { get; }
22 +
23 + private IMessaging Messaging { get; }
24 +
25 + private string InputPath { get; set; }
26 +
27 + private string IntermediateFolder { get; set; }
28 +
29 + private string ExtractPath { get; set; }
30 +
31 + public override Task<int> ExecuteAsync(CancellationToken cancellationToken)
32 + {
33 + if (String.IsNullOrEmpty(this.InputPath))
34 + {
35 + Console.Error.WriteLine("Path to input bundle is required");
36 + return Task.FromResult(-1);
37 + }
38 +
39 + if (String.IsNullOrEmpty(this.ExtractPath))
40 + {
41 + Console.Error.WriteLine("Path to output the extracted bundle is required");
42 + return Task.FromResult(-1);
43 + }
44 +
45 + if (String.IsNullOrEmpty(this.IntermediateFolder))
46 + {
47 + this.IntermediateFolder = Path.GetTempPath();
48 + }
49 +
50 + var uxExtractPath = Path.Combine(this.ExtractPath, "BA");
51 +
52 + using (var reader = BurnReader.Open(this.Messaging, this.InputPath))
53 + {
54 + reader.ExtractUXContainer(uxExtractPath, this.IntermediateFolder);
55 + reader.ExtractAttachedContainers(this.ExtractPath, this.IntermediateFolder);
56 + }
57 +
58 + return Task.FromResult(this.Messaging.LastErrorNumber);
59 + }
60 +
61 + public override bool TryParseArgument(ICommandLineParser parser, string argument)
62 + {
63 + if (parser.IsSwitch(argument))
64 + {
65 + var parameter = argument.Substring(1);
66 + switch (parameter.ToLowerInvariant())
67 + {
68 + case "intermediatefolder":
69 + this.IntermediateFolder = parser.GetNextArgumentAsDirectoryOrError(argument);
70 + return true;
71 +
72 + case "o":
73 + this.ExtractPath = parser.GetNextArgumentAsDirectoryOrError(argument);
74 + return true;
75 + }
76 + }
77 + else if (String.IsNullOrEmpty(this.InputPath))
78 + {
79 + this.InputPath = argument;
80 + return true;
81 + }
82 +
83 + return false;
84 + }
85 + }
86 +}
src/wix/test/WixToolsetTest.CoreIntegration/BundleExtractionFixture.cs
+14 -9
@@ -5,10 +5,8 @@ namespace WixToolsetTest.CoreIntegration
5 using System.IO;
6 using System.Linq;
7 using WixBuildTools.TestSupport;
8 - using WixToolset.Core;
8 using WixToolset.Core.TestPackage;
9 using WixToolset.Data;
11 - using WixToolset.Extensibility.Services;
10 using Xunit;
11
12 public class BundleExtractionFixture
@@ -23,13 +21,10 @@ namespace WixToolsetTest.CoreIntegration
21 var baseFolder = fs.GetFolder();
22 var intermediateFolder = Path.Combine(baseFolder, "obj");
23 var exePath = Path.Combine(baseFolder, @"bin\test.exe");
26 - var pdbPath = Path.Combine(baseFolder, @"bin\test.wixpdb");
24 var extractFolderPath = Path.Combine(baseFolder, "extract");
28 - var baFolderPath = Path.Combine(extractFolderPath, "UX");
25 + var baFolderPath = Path.Combine(extractFolderPath, "BA");
26 var attachedContainerFolderPath = Path.Combine(extractFolderPath, "WixAttachedContainer");
27
31 - // TODO: use WixRunner.Execute(string[]) to always go through the command line.
32 - var serviceProvider = WixToolsetServiceProviderFactory.CreateServiceProvider();
28 var result = WixRunner.Execute(new[]
29 {
30 "build",
@@ -40,14 +35,24 @@ namespace WixToolsetTest.CoreIntegration
35 "-bindpath", Path.Combine(folder, ".Data"),
36 "-intermediateFolder", intermediateFolder,
37 "-o", exePath,
43 - }, serviceProvider, out var messages).Result;
38 + });
39
45 - WixRunnerResult.AssertSuccess(result, messages);
46 - Assert.Empty(messages.Where(m => m.Level == MessageLevel.Warning));
40 + result.AssertSuccess();
41 + Assert.Empty(result.Messages.Where(m => m.Level == MessageLevel.Warning));
42
43 Assert.True(File.Exists(exePath));
44
45 + result = WixRunner.Execute(new[]
46 + {
47 + "burn", "extract",
48 + exePath,
49 + "-o", extractFolderPath
50 + });
51 +
52 + result.AssertSuccess();
53
54 + Assert.True(File.Exists(Path.Combine(baFolderPath, "manifest.xml")));
55 + Assert.False(Directory.Exists(attachedContainerFolderPath));
56 }
57 }
58 }