main
cs 156 lines 6.46 KB
Raw
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
4 {
5 using System;
6 using System.Collections.Generic;
7 using System.IO;
8 using System.Linq;
9 using WixToolset.Core.WindowsInstaller.Unbind;
10 using WixToolset.Data;
11 using WixToolset.Data.Symbols;
12 using WixToolset.Data.WindowsInstaller;
13 using WixToolset.Extensibility;
14 using WixToolset.Extensibility.Data;
15 using WixToolset.Extensibility.Services;
16
17 internal class CreatePatchTransformsCommand
18 {
19 public CreatePatchTransformsCommand(IMessaging messaging, IBackendHelper backendHelper, IFileSystem fileSystem, IPathResolver pathResolver, IFileResolver fileResolver, IReadOnlyCollection<IResolverExtension> resolverExtensions, IReadOnlyCollection<IWindowsInstallerBackendBinderExtension> backendExtensions, Intermediate intermediate, string intermediateFolder, IReadOnlyCollection<IBindPath> bindPaths)
20 {
21 this.Messaging = messaging;
22 this.BackendHelper = backendHelper;
23 this.FileSystem = fileSystem;
24 this.PathResolver = pathResolver;
25 this.FileResolver = fileResolver;
26 this.ResolverExtensions = resolverExtensions;
27 this.BackendExtensions = backendExtensions;
28 this.Intermediate = intermediate;
29 this.IntermediateFolder = intermediateFolder;
30 this.BindPaths = bindPaths;
31 }
32
33 private IMessaging Messaging { get; }
34
35 private IBackendHelper BackendHelper { get; }
36
37 private IFileSystem FileSystem { get; }
38
39 private IPathResolver PathResolver { get; }
40
41 private IFileResolver FileResolver { get; }
42
43 private IReadOnlyCollection<IResolverExtension> ResolverExtensions { get; }
44
45 private IReadOnlyCollection<IWindowsInstallerBackendBinderExtension> BackendExtensions { get; }
46
47 private Intermediate Intermediate { get; }
48
49 private string IntermediateFolder { get; }
50
51 private IReadOnlyCollection<IBindPath> BindPaths { get; }
52
53 public PatchFilterMap PatchFilterMap { get; private set; }
54
55 public IEnumerable<PatchTransform> PatchTransforms { get; private set; }
56
57 public IEnumerable<PatchTransform> Execute()
58 {
59 var patchFilterMap = new PatchFilterMap();
60 var patchTransforms = new List<PatchTransform>();
61
62 var symbols = this.Intermediate.Sections.SelectMany(s => s.Symbols);
63
64 var patchBaselineSymbols = symbols.OfType<WixPatchBaselineSymbol>();
65
66 var patchRefSymbols = symbols.OfType<WixPatchRefSymbol>().ToList();
67
68 foreach (var symbol in patchBaselineSymbols)
69 {
70 var targetData = this.GetWindowsInstallerData(symbol.BaselineFile.Path, BindStage.Target);
71 var updatedData = this.GetWindowsInstallerData(symbol.UpdateFile.Path, BindStage.Updated);
72
73 if (patchRefSymbols.Count > 0)
74 {
75 var targetCommand = new GeneratePatchFilterIdsCommand(this.BackendExtensions, targetData, "target:");
76 targetCommand.Execute();
77
78 patchFilterMap.AddTargetRowFilterIds(targetCommand.RowToFilterId);
79
80 var updatedCommand = new GeneratePatchFilterIdsCommand(this.BackendExtensions, updatedData, "updated:");
81 updatedCommand.Execute();
82
83 patchFilterMap.AddUpdatedRowFilterIds(updatedCommand.RowToFilterId);
84 }
85
86 var command = new GenerateTransformCommand(this.Messaging, targetData, updatedData, patchFilterMap, preserveUnchangedRows: true, showPedanticMessages: false);
87 var transform = command.Execute();
88
89 patchTransforms.Add(new PatchTransform(symbol.Id.Id, transform));
90 }
91
92 this.PatchFilterMap = patchFilterMap;
93 this.PatchTransforms = patchTransforms;
94
95 return this.PatchTransforms;
96 }
97
98 private WindowsInstallerData GetWindowsInstallerData(string path, BindStage stage)
99 {
100 if (DataLoader.TryLoadWindowsInstallerData(path, true, out var data))
101 {
102 // Re-resolve file paths only when loading from .wixpdb.
103 this.ReResolveWindowsInstallerData(data, stage);
104 }
105 else
106 {
107 var stageFolder = $"_{stage.ToString().ToLowerInvariant()}_msi";
108 var exportBasePath = Path.Combine(this.IntermediateFolder, stageFolder);
109 var extractFilesFolder = Path.Combine(exportBasePath, "File");
110
111 var command = new UnbindDatabaseCommand(this.Messaging, this.BackendHelper, this.FileSystem, this.PathResolver, path, null, OutputType.Package, exportBasePath, extractFilesFolder, this.IntermediateFolder, enableDemodularization: false, skipSummaryInfo: false);
112 data = command.Execute();
113 }
114
115 return data;
116 }
117
118 private void ReResolveWindowsInstallerData(WindowsInstallerData data, BindStage stage)
119 {
120 var bindPaths = this.BindPaths.Where(b => b.Stage == stage).ToList();
121
122 if (bindPaths.Count == 0)
123 {
124 return;
125 }
126
127 foreach (var table in data.Tables)
128 {
129 foreach (var row in table.Rows)
130 {
131 foreach (var field in row.Fields.Where(f => f.Column.Type == ColumnType.Object))
132 {
133 if (field.PreviousData != null)
134 {
135 try
136 {
137 var originalPath = field.AsString();
138
139 var resolvedPath = this.FileResolver.ResolveFile(field.PreviousData, this.ResolverExtensions, bindPaths, stage, row.SourceLineNumbers, null);
140
141 if (!String.Equals(originalPath, resolvedPath, StringComparison.OrdinalIgnoreCase))
142 {
143 field.Data = resolvedPath;
144 }
145 }
146 catch (WixException e)
147 {
148 this.Messaging.Write(e.Error);
149 }
150 }
151 }
152 }
153 }
154 }
155 }
156 }