main
cs 119 lines 4.99 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.Burn.Bundles
4 {
5 using System;
6 using System.Collections.Generic;
7 using System.Linq;
8 using WixToolset.Data;
9 using WixToolset.Data.Symbols;
10 using WixToolset.Extensibility.Services;
11
12 internal class AutomaticallySlipstreamPatchesCommand
13 {
14 public AutomaticallySlipstreamPatchesCommand(IMessaging messaging, IntermediateSection section, PackageFacades packageFacades)
15 {
16 this.Messaging = messaging;
17 this.Section = section;
18 this.PackageFacades = packageFacades;
19 }
20
21 private IMessaging Messaging { get; }
22
23 private IntermediateSection Section { get; }
24
25 private PackageFacades PackageFacades { get; }
26
27 public void Execute()
28 {
29 var msiPackages = new List<WixBundleMsiPackageSymbol>();
30 var targetsProductCode = new Dictionary<string, List<WixBundlePatchTargetCodeSymbol>>();
31 var targetsUpgradeCode = new Dictionary<string, List<WixBundlePatchTargetCodeSymbol>>();
32
33 foreach (var facade in this.PackageFacades.Values)
34 {
35 // Keep track of all MSI packages.
36 if (facade.SpecificPackageSymbol is WixBundleMsiPackageSymbol msiPackage)
37 {
38 msiPackages.Add(msiPackage);
39 }
40 else if (facade.SpecificPackageSymbol is WixBundleMspPackageSymbol mspPackage && mspPackage.Slipstream)
41 {
42 var patchTargetCodeSymbols = this.Section.Symbols
43 .OfType<WixBundlePatchTargetCodeSymbol>()
44 .Where(r => r.PackagePayloadRef == facade.PackageSymbol.PayloadRef);
45
46 // Index target ProductCodes and UpgradeCodes for slipstreamed MSPs.
47 foreach (var symbol in patchTargetCodeSymbols)
48 {
49 if (symbol.Type == WixBundlePatchTargetCodeType.ProductCode)
50 {
51 if (!targetsProductCode.TryGetValue(symbol.TargetCode, out var symbols))
52 {
53 symbols = new List<WixBundlePatchTargetCodeSymbol>();
54 targetsProductCode.Add(symbol.TargetCode, symbols);
55 }
56
57 symbols.Add(symbol);
58 }
59 else if (symbol.Type == WixBundlePatchTargetCodeType.UpgradeCode)
60 {
61 if (!targetsUpgradeCode.TryGetValue(symbol.TargetCode, out var symbols))
62 {
63 symbols = new List<WixBundlePatchTargetCodeSymbol>();
64 targetsUpgradeCode.Add(symbol.TargetCode, symbols);
65 }
66
67 symbols.Add(symbol);
68 }
69 }
70 }
71 }
72
73 var slipstreamMspIds = new HashSet<string>();
74
75 // Loop through the MSI and slipstream patches targeting it.
76 foreach (var msi in msiPackages)
77 {
78 if (targetsProductCode.TryGetValue(msi.ProductCode, out var symbols))
79 {
80 foreach (var symbol in symbols)
81 {
82 this.TryAddSlipstreamSymbol(slipstreamMspIds, msi, symbol);
83 }
84 }
85
86 if (!String.IsNullOrEmpty(msi.UpgradeCode) && targetsUpgradeCode.TryGetValue(msi.UpgradeCode, out symbols))
87 {
88 foreach (var symbol in symbols)
89 {
90 this.TryAddSlipstreamSymbol(slipstreamMspIds, msi, symbol);
91 }
92 }
93 }
94 }
95
96 private void TryAddSlipstreamSymbol(HashSet<string> slipstreamMspIds, WixBundleMsiPackageSymbol msiPackage, WixBundlePatchTargetCodeSymbol patchTargetCode)
97 {
98 if (!this.PackageFacades.TryGetFacadesByPackagePayloadId(patchTargetCode.PackagePayloadRef, out var packageFacades))
99 {
100 this.Messaging.Write(ErrorMessages.IdentifierNotFound("Package.PayloadRef", patchTargetCode.PackagePayloadRef));
101 return;
102 }
103
104 foreach (var packageFacade in packageFacades)
105 {
106 var id = new Identifier(AccessModifier.Section, msiPackage.Id.Id, packageFacade.PackageId);
107
108 if (slipstreamMspIds.Add(id.Id))
109 {
110 this.Section.AddSymbol(new WixBundleSlipstreamMspSymbol(patchTargetCode.SourceLineNumbers)
111 {
112 TargetPackageRef = msiPackage.Id.Id,
113 MspPackageRef = packageFacade.PackageId,
114 });
115 }
116 }
117 }
118 }
119 }