@joebigelow / wix-1 / commits / dfcd6728

Introduce PatchFilterMap to remove Row.SectionId

A Row's SectionId is not set correctly in most scenarios. It was only really needed for the old section-based patch filtering. As section-base patch filtering was replaced in favor of the more logical filter generation, Row.SectionId was archaic and mostly outdated/wrong data.

Rob Mensching committed Sep 27, 2022 at 15:03 UTC dfcd6728a9d56ac37a5daa8cbedabbf10c333773
14 files changed +426 -368
src/api/wix/WixToolset.Data/WindowsInstaller/Row.cs
-31
@@ -52,17 +52,6 @@ namespace WixToolset.Data.WindowsInstaller
52 /// <value>The row transform operation.</value>
53 public RowOperation Operation { get; set; }
54
55 - /// <summary>
56 - /// Gets or sets wether the row is a duplicate of another row thus redundant.
57 - /// </summary>
58 - public bool Redundant { get; set; }
59 -
60 - /// <summary>
61 - /// Gets or sets the SectionId property on the row.
62 - /// </summary>
63 - /// <value>The SectionId property on the row.</value>
64 - public string SectionId { get; set; }
65 -
55 /// <summary>
56 /// Gets the source file and line number for the row.
57 /// </summary>
@@ -276,8 +265,6 @@ namespace WixToolset.Data.WindowsInstaller
265
266 bool empty = reader.IsEmptyElement;
267 RowOperation operation = RowOperation.None;
279 - bool redundant = false;
280 - string sectionId = null;
268 SourceLineNumber sourceLineNumbers = null;
269
270 while (reader.MoveToNextAttribute())
@@ -287,12 +274,6 @@ namespace WixToolset.Data.WindowsInstaller
274 case "op":
275 operation = (RowOperation)Enum.Parse(typeof(RowOperation), reader.Value, true);
276 break;
290 - case "redundant":
291 - redundant = reader.Value.Equals("yes");
292 - break;
293 - case "sectionId":
294 - sectionId = reader.Value;
295 - break;
277 case "sourceLineNumber":
278 sourceLineNumbers = SourceLineNumber.CreateFromEncoded(reader.Value);
279 break;
@@ -301,8 +282,6 @@ namespace WixToolset.Data.WindowsInstaller
282
283 var row = table.CreateRow(sourceLineNumbers);
284 row.Operation = operation;
304 - row.Redundant = redundant;
305 - row.SectionId = sectionId;
285
286 // loop through all the fields in a row
287 if (!empty)
@@ -364,16 +343,6 @@ namespace WixToolset.Data.WindowsInstaller
343 writer.WriteAttributeString("op", this.Operation.ToString().ToLowerInvariant());
344 }
345
367 - if (this.Redundant)
368 - {
369 - writer.WriteAttributeString("redundant", "yes");
370 - }
371 -
372 - if (null != this.SectionId)
373 - {
374 - writer.WriteAttributeString("sectionId", this.SectionId);
375 - }
376 -
346 if (null != this.SourceLineNumbers)
347 {
348 writer.WriteAttributeString("sourceLineNumber", this.SourceLineNumbers.GetEncoded());
src/api/wix/WixToolset.Data/WindowsInstaller/Xsd/objects.xsd
-2
@@ -96,8 +96,6 @@
96 </xs:restriction>
97 </xs:simpleType>
98 </xs:attribute>
99 - <xs:attribute name="redundant" type="YesNoType" />
100 - <xs:attribute name="sectionId" type="xs:string" />
99 <xs:attribute name="sourceLineNumber" type="xs:string" />
100 </xs:complexType>
101 </xs:element>
src/api/wix/WixToolset.Extensibility/BaseWindowsInstallerBackendBinderExtension.cs
+7
@@ -62,6 +62,13 @@ namespace WixToolset.Extensibility
62 {
63 }
64
65 + /// <summary>
66 + /// See <see cref="IWindowsInstallerBackendBinderExtension.FinalizePatchFilterIds(WindowsInstallerData, IDictionary{Row, string}, string)"/>
67 + /// </summary>
68 + public virtual void FinalizePatchFilterIds(WindowsInstallerData data, IDictionary<Row, string> rowToFilterId, string filterIdPrefix)
69 + {
70 + }
71 +
72 /// <summary>
73 /// See <see cref="IWindowsInstallerBackendBinderExtension.PreBackendBind(IBindContext)"/>
74 /// </summary>
src/api/wix/WixToolset.Extensibility/IWindowsInstallerBackendBinderExtension.cs
+8
@@ -29,6 +29,14 @@ namespace WixToolset.Extensibility
29 /// <param name="section">The finalized intermediate section.</param>
30 void SymbolsFinalized(IntermediateSection section);
31
32 + /// <summary>
33 + /// Extension can process the filter ids applied to rows when processing patches.
34 + /// </summary>
35 + /// <param name="data">The <c>WindowsInstallerData</c> with rows to apply filters to.</param>
36 + /// <param name="rowToFilterId">The mapping that applies a filter id to a row.</param>
37 + /// <param name="filterIdPrefix">The prefix to use applying additional filters to rows.</param>
38 + void FinalizePatchFilterIds(WindowsInstallerData data, IDictionary<Row, string> rowToFilterId, string filterIdPrefix);
39 +
40 /// <summary>
41 /// Finds an existing cabinet that contains the provided files.
42 /// </summary>
src/wix/WixToolset.Core.WindowsInstaller/Bind/CreateIdtFileCommand.cs
-5
@@ -71,11 +71,6 @@ namespace WixToolset.Core.WindowsInstaller.Bind
71
72 foreach (Row row in table.Rows)
73 {
74 - if (row.Redundant)
75 - {
76 - continue;
77 - }
78 -
74 string rowString = this.RowToIdtDefinition(row, keepAddedColumns);
75 byte[] rowBytes;
76
src/wix/WixToolset.Core.WindowsInstaller/Bind/CreatePatchTransformsCommand.cs
+15 -4
@@ -16,13 +16,14 @@ namespace WixToolset.Core.WindowsInstaller.Bind
16
17 internal class CreatePatchTransformsCommand
18 {
19 - public CreatePatchTransformsCommand(IMessaging messaging, IBackendHelper backendHelper, IPathResolver pathResolver, IFileResolver fileResolver, IReadOnlyCollection<IResolverExtension> resolverExtensions, Intermediate intermediate, string intermediateFolder, IReadOnlyCollection<IBindPath> bindPaths)
19 + public CreatePatchTransformsCommand(IMessaging messaging, IBackendHelper backendHelper, 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.PathResolver = pathResolver;
24 this.FileResolver = fileResolver;
25 this.ResolverExtensions = resolverExtensions;
26 + this.BackendExtensions = backendExtensions;
27 this.Intermediate = intermediate;
28 this.IntermediateFolder = intermediateFolder;
29 this.BindPaths = bindPaths;
@@ -38,16 +39,21 @@ namespace WixToolset.Core.WindowsInstaller.Bind
39
40 private IReadOnlyCollection<IResolverExtension> ResolverExtensions { get; }
41
42 + private IReadOnlyCollection<IWindowsInstallerBackendBinderExtension> BackendExtensions { get; }
43 +
44 private Intermediate Intermediate { get; }
45
46 private string IntermediateFolder { get; }
47
48 private IReadOnlyCollection<IBindPath> BindPaths { get; }
49
50 + public PatchFilterMap PatchFilterMap { get; private set; }
51 +
52 public IEnumerable<PatchTransform> PatchTransforms { get; private set; }
53
54 public IEnumerable<PatchTransform> Execute()
55 {
56 + var patchFilterMap = new PatchFilterMap();
57 var patchTransforms = new List<PatchTransform>();
58
59 var symbols = this.Intermediate.Sections.SelectMany(s => s.Symbols);
@@ -63,19 +69,24 @@ namespace WixToolset.Core.WindowsInstaller.Bind
69
70 if (patchRefSymbols.Count > 0)
71 {
66 - var targetCommand = new GenerateSectionIdsCommand(targetData);
72 + var targetCommand = new GeneratePatchFilterIdsCommand(this.BackendExtensions, targetData, "target:");
73 targetCommand.Execute();
74
69 - var updatedCommand = new GenerateSectionIdsCommand(updatedData);
75 + patchFilterMap.AddTargetRowFilterIds(targetCommand.RowToFilterId);
76 +
77 + var updatedCommand = new GeneratePatchFilterIdsCommand(this.BackendExtensions, updatedData, "updated:");
78 updatedCommand.Execute();
79 +
80 + patchFilterMap.AddUpdatedRowFilterIds(updatedCommand.RowToFilterId);
81 }
82
73 - var command = new GenerateTransformCommand(this.Messaging, targetData, updatedData, preserveUnchangedRows: true, showPedanticMessages: false);
83 + var command = new GenerateTransformCommand(this.Messaging, targetData, updatedData, patchFilterMap, preserveUnchangedRows: true, showPedanticMessages: false);
84 var transform = command.Execute();
85
86 patchTransforms.Add(new PatchTransform(symbol.Id.Id, transform));
87 }
88
89 + this.PatchFilterMap = patchFilterMap;
90 this.PatchTransforms = patchTransforms;
91
92 return this.PatchTransforms;
src/wix/WixToolset.Core.WindowsInstaller/Bind/GeneratePatchFilterIdsCommand.cs new
+233
@@ -0,0 +1,233 @@
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.Globalization;
8 + using WixToolset.Data.WindowsInstaller;
9 + using WixToolset.Extensibility;
10 +
11 + /// <summary>
12 + /// Creates section ids on rows which form logical groupings of resources.
13 + /// </summary>
14 + internal class GeneratePatchFilterIdsCommand
15 + {
16 + public GeneratePatchFilterIdsCommand(IReadOnlyCollection<IWindowsInstallerBackendBinderExtension> backendExtensions, WindowsInstallerData data, string filterIdPrefix)
17 + {
18 + this.BackendExtensions = backendExtensions;
19 + this.Data = data;
20 + this.FilterIdPrefix = filterIdPrefix;
21 + }
22 +
23 + private IReadOnlyCollection<IWindowsInstallerBackendBinderExtension> BackendExtensions { get; }
24 +
25 + private WindowsInstallerData Data { get; }
26 +
27 + private string FilterIdPrefix { get; }
28 +
29 + public IDictionary<Row, string> RowToFilterId { get; private set; }
30 +
31 + public void Execute()
32 + {
33 + this.RowToFilterId = new Dictionary<Row, string>();
34 +
35 + var output = this.Data;
36 +
37 + // First assign and index section ids for the tables that are in their own sections.
38 + this.AssignFilterIdsToTable(output.Tables["Binary"], 0);
39 + var componentSectionIdIndex = this.AssignFilterIdsToTable(output.Tables["Component"], 0);
40 + var customActionSectionIdIndex = this.AssignFilterIdsToTable(output.Tables["CustomAction"], 0);
41 + this.AssignFilterIdsToTable(output.Tables["Directory"], 0);
42 + var featureSectionIdIndex = this.AssignFilterIdsToTable(output.Tables["Feature"], 0);
43 + this.AssignFilterIdsToTable(output.Tables["Icon"], 0);
44 + var digitalCertificateSectionIdIndex = this.AssignFilterIdsToTable(output.Tables["MsiDigitalCertificate"], 0);
45 + this.AssignFilterIdsToTable(output.Tables["Property"], 0);
46 +
47 + // Now handle all the tables that rely on the first set of indexes but also produce their own indexes. Order matters here.
48 + var fileFilterIdIndex = this.ConnectTableToSectionAndIndex(output.Tables["File"], componentSectionIdIndex, 1, 0);
49 + var appIdFilterIdIndex = this.ConnectTableToSectionAndIndex(output.Tables["Class"], componentSectionIdIndex, 2, 5);
50 + var odbcDataSourceFilterIdIndex = this.ConnectTableToSectionAndIndex(output.Tables["ODBCDataSource"], componentSectionIdIndex, 1, 0);
51 + var odbcDriverSectionIdIndex = this.ConnectTableToSectionAndIndex(output.Tables["ODBCDriver"], componentSectionIdIndex, 1, 0);
52 + var registrySectionIdIndex = this.ConnectTableToSectionAndIndex(output.Tables["Registry"], componentSectionIdIndex, 5, 0);
53 + var serviceInstallSectionIdIndex = this.ConnectTableToSectionAndIndex(output.Tables["ServiceInstall"], componentSectionIdIndex, 11, 0);
54 +
55 + // Now handle all the tables which only rely on previous indexes and order does not matter.
56 + foreach (var table in output.Tables)
57 + {
58 + switch (table.Name)
59 + {
60 + case "MsiFileHash":
61 + this.ConnectTableToFilterId(table, fileFilterIdIndex, 0);
62 + break;
63 + case "MsiAssembly":
64 + case "MsiAssemblyName":
65 + this.ConnectTableToFilterId(table, componentSectionIdIndex, 0);
66 + break;
67 + case "MsiPackageCertificate":
68 + case "MsiPatchCertificate":
69 + this.ConnectTableToFilterId(table, digitalCertificateSectionIdIndex, 1);
70 + break;
71 + case "CreateFolder":
72 + case "FeatureComponents":
73 + case "MoveFile":
74 + case "ReserveCost":
75 + case "ODBCTranslator":
76 + this.ConnectTableToFilterId(table, componentSectionIdIndex, 1);
77 + break;
78 + case "TypeLib":
79 + this.ConnectTableToFilterId(table, componentSectionIdIndex, 2);
80 + break;
81 + case "Shortcut":
82 + case "Environment":
83 + this.ConnectTableToFilterId(table, componentSectionIdIndex, 3);
84 + break;
85 + case "RemoveRegistry":
86 + this.ConnectTableToFilterId(table, componentSectionIdIndex, 4);
87 + break;
88 + case "ServiceControl":
89 + this.ConnectTableToFilterId(table, componentSectionIdIndex, 5);
90 + break;
91 + case "IniFile":
92 + case "RemoveIniFile":
93 + this.ConnectTableToFilterId(table, componentSectionIdIndex, 7);
94 + break;
95 + case "AppId":
96 + this.ConnectTableToFilterId(table, appIdFilterIdIndex, 0);
97 + break;
98 + case "Condition":
99 + this.ConnectTableToFilterId(table, featureSectionIdIndex, 0);
100 + break;
101 + case "ODBCSourceAttribute":
102 + this.ConnectTableToFilterId(table, odbcDataSourceFilterIdIndex, 0);
103 + break;
104 + case "ODBCAttribute":
105 + this.ConnectTableToFilterId(table, odbcDriverSectionIdIndex, 0);
106 + break;
107 + case "AdminExecuteSequence":
108 + case "AdminUISequence":
109 + case "AdvtExecuteSequence":
110 + case "AdvtUISequence":
111 + case "InstallExecuteSequence":
112 + case "InstallUISequence":
113 + this.ConnectTableToFilterId(table, customActionSectionIdIndex, 0);
114 + break;
115 + case "LockPermissions":
116 + case "MsiLockPermissions":
117 + foreach (var row in table.Rows)
118 + {
119 + var lockObject = row.FieldAsString(0);
120 + var tableName = row.FieldAsString(1);
121 +
122 + var filterId = String.Empty;
123 + switch (tableName)
124 + {
125 + case "File":
126 + filterId = fileFilterIdIndex[lockObject];
127 + break;
128 + case "Registry":
129 + filterId = registrySectionIdIndex[lockObject];
130 + break;
131 + case "ServiceInstall":
132 + filterId = serviceInstallSectionIdIndex[lockObject];
133 + break;
134 + }
135 +
136 + if (!String.IsNullOrEmpty(filterId))
137 + {
138 + this.RowToFilterId.Add(row, filterId);
139 + }
140 + }
141 + break;
142 + }
143 + }
144 +
145 + // Now pass the data to each backend extension to allow them to analyze the data and determine their proper filter ids.
146 + foreach (var extension in this.BackendExtensions)
147 + {
148 + extension.FinalizePatchFilterIds(this.Data, this.RowToFilterId, this.FilterIdPrefix);
149 + }
150 + }
151 +
152 + private Dictionary<string, string> AssignFilterIdsToTable(Table table, int rowPrimaryKeyIndex)
153 + {
154 + var primaryKeyToFilterId = new Dictionary<string, string>();
155 +
156 + if (null != table)
157 + {
158 + foreach (var row in table.Rows)
159 + {
160 + var filterId = this.GetNewFilterId(row);
161 +
162 + this.RowToFilterId.Add(row, filterId);
163 +
164 + primaryKeyToFilterId.Add(row.FieldAsString(rowPrimaryKeyIndex), filterId);
165 + }
166 + }
167 +
168 + return primaryKeyToFilterId;
169 + }
170 +
171 + /// <summary>
172 + /// Connects a table's rows to an already sectioned table.
173 + /// </summary>
174 + /// <param name="table">The table containing rows that need to be connected to sections.</param>
175 + /// <param name="filterIdByPrimaryKey">A hashtable containing keys to map table to its section.</param>
176 + /// <param name="rowIndex">The index of the column which is used as the foreign key in to the sectionIdIndex.</param>
177 + private void ConnectTableToFilterId(Table table, Dictionary<string, string> filterIdByPrimaryKey, int rowIndex)
178 + {
179 + if (null != table)
180 + {
181 + foreach (var row in table.Rows)
182 + {
183 + if (filterIdByPrimaryKey.TryGetValue(row.FieldAsString(rowIndex), out var filterId))
184 + {
185 + this.RowToFilterId.Add(row, filterId);
186 + }
187 + }
188 + }
189 + }
190 +
191 + /// <summary>
192 + /// Connects a table's rows to a table with filter ids already assigned and produces an index for other tables to connect to it.
193 + /// </summary>
194 + /// <param name="table">The table containing rows that need to be connected to sections.</param>
195 + /// <param name="filterIdsByPrimaryKey">A dictionary containing keys to map table to its section.</param>
196 + /// <param name="rowIndex">The index of the column which is used as the foreign key in to the sectionIdIndex.</param>
197 + /// <param name="rowPrimaryKeyIndex">The index of the column which is used by other tables to reference this table.</param>
198 + /// <returns>A dictionary containing the tables key for each row paired with its assigned section id.</returns>
199 + private Dictionary<string, string> ConnectTableToSectionAndIndex(Table table, Dictionary<string, string> filterIdsByPrimaryKey, int rowIndex, int rowPrimaryKeyIndex)
200 + {
201 + var newPrimaryKeyToSectionId = new Dictionary<string, string>();
202 +
203 + if (null != table)
204 + {
205 + foreach (var row in table.Rows)
206 + {
207 + var foreignKey = row.FieldAsString(rowIndex);
208 +
209 + if (!filterIdsByPrimaryKey.TryGetValue(foreignKey, out var filterId))
210 + {
211 + continue;
212 + }
213 +
214 + this.RowToFilterId.Add(row, filterId);
215 +
216 + var primaryKey = row.FieldAsString(rowPrimaryKeyIndex);
217 +
218 + if (!String.IsNullOrEmpty(primaryKey) && filterIdsByPrimaryKey.ContainsKey(primaryKey))
219 + {
220 + newPrimaryKeyToSectionId.Add(primaryKey, filterId);
221 + }
222 + }
223 + }
224 +
225 + return newPrimaryKeyToSectionId;
226 + }
227 +
228 + private string GetNewFilterId(Row row)
229 + {
230 + return this.FilterIdPrefix + row.Number.ToString(CultureInfo.InvariantCulture);
231 + }
232 + }
233 +}
src/wix/WixToolset.Core.WindowsInstaller/Bind/GenerateSectionIdsCommand.cs deleted
-225
@@ -1,225 +0,0 @@
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.Globalization;
8 - using WixToolset.Data.WindowsInstaller;
9 -
10 - /// <summary>
11 - /// Creates section ids on rows which form logical groupings of resources.
12 - /// </summary>
13 - internal class GenerateSectionIdsCommand
14 - {
15 - private int sectionCount;
16 -
17 - public GenerateSectionIdsCommand(WindowsInstallerData data)
18 - {
19 - this.Data = data;
20 - }
21 -
22 - private WindowsInstallerData Data { get; }
23 -
24 - public void Execute()
25 - {
26 - var output = this.Data;
27 -
28 - this.sectionCount = 0;
29 -
30 - // First assign and index section ids for the tables that are in their own sections.
31 - this.AssignSectionIdsToTable(output.Tables["Binary"], 0);
32 - var componentSectionIdIndex = this.AssignSectionIdsToTable(output.Tables["Component"], 0);
33 - var customActionSectionIdIndex = this.AssignSectionIdsToTable(output.Tables["CustomAction"], 0);
34 - this.AssignSectionIdsToTable(output.Tables["Directory"], 0);
35 - var featureSectionIdIndex = this.AssignSectionIdsToTable(output.Tables["Feature"], 0);
36 - this.AssignSectionIdsToTable(output.Tables["Icon"], 0);
37 - var digitalCertificateSectionIdIndex = this.AssignSectionIdsToTable(output.Tables["MsiDigitalCertificate"], 0);
38 - this.AssignSectionIdsToTable(output.Tables["Property"], 0);
39 -
40 - // Now handle all the tables that rely on the first set of indexes but also produce their own indexes. Order matters here.
41 - var fileSectionIdIndex = ConnectTableToSectionAndIndex(output.Tables["File"], componentSectionIdIndex, 1, 0);
42 - var appIdSectionIdIndex = ConnectTableToSectionAndIndex(output.Tables["Class"], componentSectionIdIndex, 2, 5);
43 - var odbcDataSourceSectionIdIndex = ConnectTableToSectionAndIndex(output.Tables["ODBCDataSource"], componentSectionIdIndex, 1, 0);
44 - var odbcDriverSectionIdIndex = ConnectTableToSectionAndIndex(output.Tables["ODBCDriver"], componentSectionIdIndex, 1, 0);
45 - var registrySectionIdIndex = ConnectTableToSectionAndIndex(output.Tables["Registry"], componentSectionIdIndex, 5, 0);
46 - var serviceInstallSectionIdIndex = ConnectTableToSectionAndIndex(output.Tables["ServiceInstall"], componentSectionIdIndex, 11, 0);
47 -
48 - // Now handle all the tables which only rely on previous indexes and order does not matter.
49 - foreach (var table in output.Tables)
50 - {
51 - switch (table.Name)
52 - {
53 - case "MsiFileHash":
54 - ConnectTableToSection(table, fileSectionIdIndex, 0);
55 - break;
56 - case "MsiAssembly":
57 - case "MsiAssemblyName":
58 - ConnectTableToSection(table, componentSectionIdIndex, 0);
59 - break;
60 - case "MsiPackageCertificate":
61 - case "MsiPatchCertificate":
62 - ConnectTableToSection(table, digitalCertificateSectionIdIndex, 1);
63 - break;
64 - case "CreateFolder":
65 - case "FeatureComponents":
66 - case "MoveFile":
67 - case "ReserveCost":
68 - case "ODBCTranslator":
69 - ConnectTableToSection(table, componentSectionIdIndex, 1);
70 - break;
71 - case "TypeLib":
72 - ConnectTableToSection(table, componentSectionIdIndex, 2);
73 - break;
74 - case "Shortcut":
75 - case "Environment":
76 - ConnectTableToSection(table, componentSectionIdIndex, 3);
77 - break;
78 - case "RemoveRegistry":
79 - ConnectTableToSection(table, componentSectionIdIndex, 4);
80 - break;
81 - case "ServiceControl":
82 - ConnectTableToSection(table, componentSectionIdIndex, 5);
83 - break;
84 - case "IniFile":
85 - case "RemoveIniFile":
86 - ConnectTableToSection(table, componentSectionIdIndex, 7);
87 - break;
88 - case "AppId":
89 - ConnectTableToSection(table, appIdSectionIdIndex, 0);
90 - break;
91 - case "Condition":
92 - ConnectTableToSection(table, featureSectionIdIndex, 0);
93 - break;
94 - case "ODBCSourceAttribute":
95 - ConnectTableToSection(table, odbcDataSourceSectionIdIndex, 0);
96 - break;
97 - case "ODBCAttribute":
98 - ConnectTableToSection(table, odbcDriverSectionIdIndex, 0);
99 - break;
100 - case "AdminExecuteSequence":
101 - case "AdminUISequence":
102 - case "AdvtExecuteSequence":
103 - case "AdvtUISequence":
104 - case "InstallExecuteSequence":
105 - case "InstallUISequence":
106 - ConnectTableToSection(table, customActionSectionIdIndex, 0);
107 - break;
108 - case "LockPermissions":
109 - case "MsiLockPermissions":
110 - foreach (var row in table.Rows)
111 - {
112 - var lockObject = row.FieldAsString(0);
113 - var tableName = row.FieldAsString(1);
114 - switch (tableName)
115 - {
116 - case "File":
117 - row.SectionId = fileSectionIdIndex[lockObject];
118 - break;
119 - case "Registry":
120 - row.SectionId = registrySectionIdIndex[lockObject];
121 - break;
122 - case "ServiceInstall":
123 - row.SectionId = serviceInstallSectionIdIndex[lockObject];
124 - break;
125 - }
126 - }
127 - break;
128 - }
129 - }
130 -
131 - // Now pass the output to each unbinder extension to allow them to analyze the output and determine their proper section ids.
132 - //foreach (IUnbinderExtension extension in this.unbinderExtensions)
133 - //{
134 - // extension.GenerateSectionIds(output);
135 - //}
136 - }
137 -
138 - /// <summary>
139 - /// Creates new section ids on all the rows in a table.
140 - /// </summary>
141 - /// <param name="table">The table to add sections to.</param>
142 - /// <param name="rowPrimaryKeyIndex">The index of the column which is used by other tables to reference this table.</param>
143 - /// <returns>A dictionary containing the tables key for each row paired with its assigned section id.</returns>
144 - private Dictionary<string, string> AssignSectionIdsToTable(Table table, int rowPrimaryKeyIndex)
145 - {
146 - var primaryKeyToSectionId = new Dictionary<string, string>();
147 -
148 - if (null != table)
149 - {
150 - foreach (var row in table.Rows)
151 - {
152 - row.SectionId = this.GetNewSectionId();
153 -
154 - primaryKeyToSectionId.Add(row.FieldAsString(rowPrimaryKeyIndex), row.SectionId);
155 - }
156 - }
157 -
158 - return primaryKeyToSectionId;
159 - }
160 -
161 - /// <summary>
162 - /// Connects a table's rows to an already sectioned table.
163 - /// </summary>
164 - /// <param name="table">The table containing rows that need to be connected to sections.</param>
165 - /// <param name="sectionIdIndex">A hashtable containing keys to map table to its section.</param>
166 - /// <param name="rowIndex">The index of the column which is used as the foreign key in to the sectionIdIndex.</param>
167 - private static void ConnectTableToSection(Table table, Dictionary<string, string> sectionIdIndex, int rowIndex)
168 - {
169 - if (null != table)
170 - {
171 - foreach (var row in table.Rows)
172 - {
173 - if (sectionIdIndex.TryGetValue(row.FieldAsString(rowIndex), out var sectionId))
174 - {
175 - row.SectionId = sectionId;
176 - }
177 - }
178 - }
179 - }
180 -
181 - /// <summary>
182 - /// Connects a table's rows to an already sectioned table and produces an index for other tables to connect to it.
183 - /// </summary>
184 - /// <param name="table">The table containing rows that need to be connected to sections.</param>
185 - /// <param name="sectionIdIndex">A dictionary containing keys to map table to its section.</param>
186 - /// <param name="rowIndex">The index of the column which is used as the foreign key in to the sectionIdIndex.</param>
187 - /// <param name="rowPrimaryKeyIndex">The index of the column which is used by other tables to reference this table.</param>
188 - /// <returns>A dictionary containing the tables key for each row paired with its assigned section id.</returns>
189 - private static Dictionary<string, string> ConnectTableToSectionAndIndex(Table table, Dictionary<string, string> sectionIdIndex, int rowIndex, int rowPrimaryKeyIndex)
190 - {
191 - var newPrimaryKeyToSectionId = new Dictionary<string, string>();
192 -
193 - if (null != table)
194 - {
195 - foreach (var row in table.Rows)
196 - {
197 - var foreignKey = row.FieldAsString(rowIndex);
198 -
199 - if (!sectionIdIndex.TryGetValue(foreignKey, out var sectionId))
200 - {
201 - continue;
202 - }
203 -
204 - row.SectionId = sectionId;
205 -
206 - var primaryKey = row.FieldAsString(rowPrimaryKeyIndex);
207 -
208 - if (!String.IsNullOrEmpty(primaryKey) && sectionIdIndex.ContainsKey(primaryKey))
209 - {
210 - newPrimaryKeyToSectionId.Add(primaryKey, row.SectionId);
211 - }
212 - }
213 - }
214 -
215 - return newPrimaryKeyToSectionId;
216 - }
217 -
218 - private string GetNewSectionId()
219 - {
220 - this.sectionCount++;
221 -
222 - return "wix.section." + this.sectionCount.ToString(CultureInfo.InvariantCulture);
223 - }
224 - }
225 -}
src/wix/WixToolset.Core.WindowsInstaller/Bind/GenerateTransformCommand.cs
+10 -8
@@ -6,6 +6,7 @@ namespace WixToolset.Core.WindowsInstaller
6 using System.Collections.Generic;
7 using System.Globalization;
8 using WixToolset.Core.Native.Msi;
9 + using WixToolset.Core.WindowsInstaller.Bind;
10 using WixToolset.Data;
11 using WixToolset.Data.Symbols;
12 using WixToolset.Data.WindowsInstaller;
@@ -16,18 +17,18 @@ namespace WixToolset.Core.WindowsInstaller
17 /// </summary>
18 internal class GenerateTransformCommand
19 {
19 - private const char SectionDelimiter = '/';
20 private readonly IMessaging messaging;
21 private SummaryInformationStreams transformSummaryInfo;
22
23 /// <summary>
24 /// Instantiates a new Differ class.
25 /// </summary>
26 - public GenerateTransformCommand(IMessaging messaging, WindowsInstallerData targetOutput, WindowsInstallerData updatedOutput, bool preserveUnchangedRows, bool showPedanticMessages)
26 + public GenerateTransformCommand(IMessaging messaging, WindowsInstallerData targetOutput, WindowsInstallerData updatedOutput, PatchFilterMap patchFilterMap, bool preserveUnchangedRows, bool showPedanticMessages)
27 {
28 this.messaging = messaging;
29 this.TargetOutput = targetOutput;
30 this.UpdatedOutput = updatedOutput;
31 + this.PatchFilterMap = patchFilterMap;
32 this.PreserveUnchangedRows = preserveUnchangedRows;
33 this.ShowPedanticMessages = showPedanticMessages;
34 }
@@ -36,6 +37,8 @@ namespace WixToolset.Core.WindowsInstaller
37
38 private WindowsInstallerData UpdatedOutput { get; }
39
40 + public PatchFilterMap PatchFilterMap { get; }
41 +
42 private TransformFlags ValidationFlags { get; }
43
44 private bool ShowPedanticMessages { get; }
@@ -112,7 +115,6 @@ namespace WixToolset.Core.WindowsInstaller
115 foreach (var updatedRow in updatedTable.Rows)
116 {
117 updatedRow.Operation = RowOperation.Add;
115 - updatedRow.SectionId = SectionDelimiter + updatedRow.SectionId;
118 addedTable.Rows.Add(updatedRow);
119 }
120 }
@@ -177,7 +179,6 @@ namespace WixToolset.Core.WindowsInstaller
179 else if (null == updatedRow)
180 {
181 targetRow.Operation = RowOperation.Delete;
180 - targetRow.SectionId += SectionDelimiter;
182
183 comparedRow = targetRow;
184 keepRow = true;
@@ -189,9 +190,10 @@ namespace WixToolset.Core.WindowsInstaller
190 if (!this.SuppressKeepingSpecialRows && "_SummaryInformation" == targetTable.Name)
191 {
192 // Include only summary information rows that are allowed in a transform.
192 - if (Enum.IsDefined(typeof(SummaryInformation.Transform), (int)updatedRow[0]))
193 + if (Enum.IsDefined(typeof(SummaryInformation.Transform), updatedRow.FieldAsInteger(0)))
194 {
194 - updatedRow.SectionId = targetRow.SectionId + SectionDelimiter + updatedRow.SectionId;
195 + this.PatchFilterMap.AddTargetRowFilterToUpdatedRowFilter(targetRow, updatedRow);
196 +
197 comparedRow = updatedRow;
198 keepRow = true;
199 }
@@ -273,8 +275,9 @@ namespace WixToolset.Core.WindowsInstaller
275
276 if (keepRow)
277 {
278 + this.PatchFilterMap.AddTargetRowFilterToUpdatedRowFilter(targetRow, updatedRow);
279 +
280 comparedRow = updatedRow;
277 - comparedRow.SectionId = targetRow.SectionId + SectionDelimiter + updatedRow.SectionId;
281 }
282 }
283 }
@@ -340,7 +343,6 @@ namespace WixToolset.Core.WindowsInstaller
343 var updatedRow = updatedPrimaryKeyEntry.Value;
344
345 updatedRow.Operation = RowOperation.Add;
343 - updatedRow.SectionId = SectionDelimiter + updatedRow.SectionId;
346 rows.Add(updatedRow);
347 }
348 }
src/wix/WixToolset.Core.WindowsInstaller/Bind/PatchFilterMap.cs new
+80
@@ -0,0 +1,80 @@
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 WixToolset.Data.WindowsInstaller;
8 +
9 + internal class PatchFilterMap
10 + {
11 + private readonly Dictionary<Row, PatchFilter> filterMap = new Dictionary<Row, PatchFilter>();
12 +
13 + public void AddTargetRowFilterIds(IEnumerable<KeyValuePair<Row, string>> rowFilterIds)
14 + {
15 + foreach (var kvp in rowFilterIds)
16 + {
17 + this.filterMap.Add(kvp.Key, new PatchFilter(kvp.Key, kvp.Value, null));
18 + }
19 + }
20 +
21 + public void AddUpdatedRowFilterIds(IEnumerable<KeyValuePair<Row, string>> rowFilterIds)
22 + {
23 + foreach (var kvp in rowFilterIds)
24 + {
25 + this.filterMap.Add(kvp.Key, new PatchFilter(kvp.Key, null, kvp.Value));
26 + }
27 + }
28 +
29 + public void AddTargetRowFilterToUpdatedRowFilter(Row targetRow, Row updatedRow)
30 + {
31 + if (this.filterMap.TryGetValue(targetRow, out var targetPatchFilter) && !String.IsNullOrEmpty(targetPatchFilter.TargetFilterId))
32 + {
33 + // If the updated row didn't have a patch filter, it gets one now because the target patch has
34 + // a target filter id to add.
35 + if (!this.filterMap.TryGetValue(updatedRow, out var updatedPatchFilter))
36 + {
37 + updatedPatchFilter = new PatchFilter(updatedRow, null, null);
38 + this.filterMap.Add(updatedRow, updatedPatchFilter);
39 + }
40 +
41 + updatedPatchFilter.SetTargetFilterId(targetPatchFilter);
42 + }
43 + }
44 +
45 + internal bool ContainsPatchFilterForRow(Row row)
46 + {
47 + return this.filterMap.ContainsKey(row);
48 + }
49 +
50 + internal bool TryGetPatchFiltersForRow(Row row, out string targetFilterId, out string updatedFilterId)
51 + {
52 + this.filterMap.TryGetValue(row, out var patchFilter);
53 +
54 + targetFilterId = patchFilter?.TargetFilterId;
55 + updatedFilterId = patchFilter?.UpdatedFilterId;
56 + return patchFilter != null;
57 + }
58 +
59 + private class PatchFilter
60 + {
61 + public PatchFilter(Row row, string targetFilterId, string updatedFilterId)
62 + {
63 + this.Row = row;
64 + this.TargetFilterId = targetFilterId;
65 + this.UpdatedFilterId = updatedFilterId;
66 + }
67 +
68 + public Row Row { get; }
69 +
70 + public string TargetFilterId { get; private set; }
71 +
72 + public string UpdatedFilterId { get; }
73 +
74 + public void SetTargetFilterId(PatchFilter targetPatchFilter)
75 + {
76 + this.TargetFilterId = targetPatchFilter.TargetFilterId;
77 + }
78 + }
79 + }
80 +}
src/wix/WixToolset.Core.WindowsInstaller/Bind/ReduceTransformCommand.cs
+63 -79
@@ -11,18 +11,19 @@ namespace WixToolset.Core.WindowsInstaller.Bind
11
12 internal class ReduceTransformCommand
13 {
14 - private const char SectionDelimiter = '/';
15 -
16 - public ReduceTransformCommand(Intermediate intermediate, IEnumerable<PatchTransform> patchTransforms)
14 + public ReduceTransformCommand(Intermediate intermediate, IEnumerable<PatchTransform> patchTransforms, PatchFilterMap patchFilterMap)
15 {
16 this.Intermediate = intermediate;
17 this.PatchTransforms = patchTransforms;
18 + this.PatchFilterMap = patchFilterMap;
19 }
20
21 private Intermediate Intermediate { get; }
22
23 private IEnumerable<PatchTransform> PatchTransforms { get; }
24
25 + private PatchFilterMap PatchFilterMap { get; }
26 +
27 public void Execute()
28 {
29 var symbols = this.Intermediate.Sections.SelectMany(s => s.Symbols).ToList();
@@ -51,8 +52,8 @@ namespace WixToolset.Core.WindowsInstaller.Bind
52 private bool ReduceTransform(WindowsInstallerData transform, IEnumerable<WixPatchRefSymbol> patchRefSymbols)
53 {
54 // identify sections to keep
54 - var oldSections = new Dictionary<string, Row>();
55 - var newSections = new Dictionary<string, Row>();
55 + var targetFilterIdsToKeep = new Dictionary<string, Row>();
56 + var updatedFilterIdsToKeep = new Dictionary<string, Row>();
57 var tableKeyRows = new Dictionary<string, Dictionary<string, Row>>();
58 var sequenceList = new List<Table>();
59 var componentFeatureAddsIndex = new Dictionary<string, List<string>>();
@@ -72,10 +73,10 @@ namespace WixToolset.Core.WindowsInstaller.Bind
73 foreach (var patchRefSymbol in patchRefSymbols)
74 {
75 var tableName = patchRefSymbol.Table;
75 - var key = patchRefSymbol.PrimaryKeys;
76 + var primaryKey = patchRefSymbol.PrimaryKeys;
77
78 // Short circuit filtering if all changes should be included.
78 - if ("*" == tableName && "*" == key)
79 + if ("*" == tableName && "*" == primaryKey)
80 {
81 RemoveProductCodeFromTransform(transform);
82 return true;
@@ -88,22 +89,24 @@ namespace WixToolset.Core.WindowsInstaller.Bind
89 }
90
91 // Index the table.
91 - if (!tableKeyRows.TryGetValue(tableName, out var keyRows))
92 + if (!tableKeyRows.TryGetValue(tableName, out var rowsByPrimaryKey))
93 {
93 - keyRows = table.Rows.ToDictionary(r => r.GetPrimaryKey());
94 - tableKeyRows.Add(tableName, keyRows);
94 + rowsByPrimaryKey = table.Rows.ToDictionary(r => r.GetPrimaryKey());
95 + tableKeyRows.Add(tableName, rowsByPrimaryKey);
96 }
97
97 - if (!keyRows.TryGetValue(key, out var row))
98 + if (!rowsByPrimaryKey.TryGetValue(primaryKey, out var row))
99 {
100 // Row not found.
101 continue;
102 }
103
104 // Differ.sectionDelimiter
104 - var sections = row.SectionId.Split(SectionDelimiter);
105 - oldSections[sections[0]] = row;
106 - newSections[sections[1]] = row;
105 + if (this.PatchFilterMap.TryGetPatchFiltersForRow(row, out var targetFilterId, out var updatedFilterId))
106 + {
107 + targetFilterIdsToKeep[targetFilterId] = row;
108 + updatedFilterIdsToKeep[updatedFilterId] = row;
109 + }
110 }
111
112 // throw away sections not referenced
@@ -221,49 +224,34 @@ namespace WixToolset.Core.WindowsInstaller.Bind
224 }
225 }
226
224 - if (null == row.SectionId)
227 + if (this.IsInPatchFamily(row, targetFilterIdsToKeep, updatedFilterIdsToKeep))
228 {
226 - table.Rows.RemoveAt(i);
227 - i--;
228 - }
229 - else
230 - {
231 - var sections = row.SectionId.Split(SectionDelimiter);
232 - // ignore the row without section id.
233 - if (0 == sections[0].Length && 0 == sections[1].Length)
229 + if ("Component" == table.Name)
230 {
235 - table.Rows.RemoveAt(i);
236 - i--;
231 + keptComponents.Add(row.FieldAsString(0), row);
232 }
238 - else if (IsInPatchFamily(sections[0], sections[1], oldSections, newSections))
239 - {
240 - if ("Component" == table.Name)
241 - {
242 - keptComponents.Add(row.FieldAsString(0), row);
243 - }
233
245 - if ("Directory" == table.Name)
246 - {
247 - keptDirectories.Add(row.FieldAsString(0), row);
248 - }
249 -
250 - if ("Feature" == table.Name)
251 - {
252 - keptFeatures.Add(row.FieldAsString(0), row);
253 - }
254 -
255 - keptRows++;
234 + if ("Directory" == table.Name)
235 + {
236 + keptDirectories.Add(row.FieldAsString(0), row);
237 }
257 - else
238 +
239 + if ("Feature" == table.Name)
240 {
259 - table.Rows.RemoveAt(i);
260 - i--;
241 + keptFeatures.Add(row.FieldAsString(0), row);
242 }
243 +
244 + keptRows++;
245 + }
246 + else
247 + {
248 + table.Rows.RemoveAt(i);
249 + i--;
250 }
251 }
252 }
253
266 - keptRows += ReduceTransformSequenceTable(sequenceList, oldSections, newSections, customActionTable);
254 + keptRows += ReduceTransformSequenceTable(sequenceList, targetFilterIdsToKeep, updatedFilterIdsToKeep, customActionTable);
255
256 if (null != directoryTable)
257 {
@@ -345,7 +333,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
333 }
334 }
335
348 - keptRows += ReduceTransformSequenceTable(sequenceList, oldSections, newSections, customActionTable);
336 + keptRows += ReduceTransformSequenceTable(sequenceList, targetFilterIdsToKeep, updatedFilterIdsToKeep, customActionTable);
337
338 // Delete tables that are empty.
339 var tablesToDelete = transform.Tables.Where(t => t.Rows.Count == 0).Select(t => t.Name).ToList();
@@ -358,6 +346,25 @@ namespace WixToolset.Core.WindowsInstaller.Bind
346 return keptRows > 0;
347 }
348
349 + private bool IsInPatchFamily(Row row, Dictionary<string, Row> oldSections, Dictionary<string, Row> newSections)
350 + {
351 + var result = false;
352 +
353 + if (this.PatchFilterMap.TryGetPatchFiltersForRow(row, out var targetFilterId, out var updatedFilterId))
354 + {
355 + if ((String.IsNullOrEmpty(targetFilterId) && newSections.ContainsKey(updatedFilterId)) || (String.IsNullOrEmpty(updatedFilterId) && oldSections.ContainsKey(targetFilterId)))
356 + {
357 + result = true;
358 + }
359 + else if (!String.IsNullOrEmpty(targetFilterId) && !String.IsNullOrEmpty(updatedFilterId) && (oldSections.ContainsKey(targetFilterId) || newSections.ContainsKey(updatedFilterId)))
360 + {
361 + result = true;
362 + }
363 + }
364 +
365 + return result;
366 + }
367 +
368 /// <summary>
369 /// Check if the section is in a PatchFamily.
370 /// </summary>
@@ -415,7 +422,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
422 /// <param name="newSections">Hashtable contains section id should be kept in the target wixout.</param>
423 /// <param name="customAction">Hashtable contains all the rows in the CustomAction table.</param>
424 /// <returns>Number of rows left</returns>
418 - private static int ReduceTransformSequenceTable(List<Table> sequenceList, Dictionary<string, Row> oldSections, Dictionary<string, Row> newSections, Dictionary<string, Row> customAction)
425 + private int ReduceTransformSequenceTable(List<Table> sequenceList, Dictionary<string, Row> oldSections, Dictionary<string, Row> newSections, Dictionary<string, Row> customAction)
426 {
427 var keptRows = 0;
428
@@ -424,19 +431,11 @@ namespace WixToolset.Core.WindowsInstaller.Bind
431 for (var i = 0; i < currentTable.Rows.Count; i++)
432 {
433 var row = currentTable.Rows[i];
427 - var actionName = row.Fields[0].Data.ToString();
428 - var sections = row.SectionId.Split(SectionDelimiter);
429 - var isSectionIdEmpty = (sections[0].Length == 0 && sections[1].Length == 0);
434 + var actionName = row.FieldAsString(0);
435
436 if (row.Operation == RowOperation.None)
437 {
433 - // Ignore the rows without section id.
434 - if (isSectionIdEmpty)
435 - {
436 - currentTable.Rows.RemoveAt(i);
437 - i--;
438 - }
439 - else if (IsInPatchFamily(sections[0], sections[1], oldSections, newSections))
438 + if (this.IsInPatchFamily(row, oldSections, newSections))
439 {
440 keptRows++;
441 }
@@ -457,12 +456,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
456 }
457 else if (!sequenceChanged && conditionChanged)
458 {
460 - if (isSectionIdEmpty)
461 - {
462 - currentTable.Rows.RemoveAt(i);
463 - i--;
464 - }
465 - else if (IsInPatchFamily(sections[0], sections[1], oldSections, newSections))
459 + if (this.IsInPatchFamily(row, oldSections, newSections))
460 {
461 keptRows++;
462 }
@@ -474,12 +468,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
468 }
469 else if (sequenceChanged && conditionChanged)
470 {
477 - if (isSectionIdEmpty)
478 - {
479 - row.Fields[1].Modified = false;
480 - keptRows++;
481 - }
482 - else if (IsInPatchFamily(sections[0], sections[1], oldSections, newSections))
471 + if (this.IsInPatchFamily(row, oldSections, newSections))
472 {
473 keptRows++;
474 }
@@ -492,13 +481,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
481 }
482 else if (row.Operation == RowOperation.Delete)
483 {
495 - if (isSectionIdEmpty)
496 - {
497 - // it is a stardard action which is added by wix, we should keep this action.
498 - row.Operation = RowOperation.None;
499 - keptRows++;
500 - }
501 - else if (IsInPatchFamily(sections[0], sections[1], oldSections, newSections))
484 + if (this.IsInPatchFamily(row, oldSections, newSections))
485 {
486 keptRows++;
487 }
@@ -519,11 +502,12 @@ namespace WixToolset.Core.WindowsInstaller.Bind
502 }
503 else if (row.Operation == RowOperation.Add)
504 {
522 - if (isSectionIdEmpty)
505 + // Keep unfiltered added rows.
506 + if (!this.PatchFilterMap.ContainsPatchFilterForRow(row))
507 {
508 keptRows++;
509 }
526 - else if (IsInPatchFamily(sections[0], sections[1], oldSections, newSections))
510 + else if (this.IsInPatchFamily(row, oldSections, newSections))
511 {
512 keptRows++;
513 }
src/wix/WixToolset.Core.WindowsInstaller/Differ.cs
+2 -7
@@ -17,7 +17,6 @@ namespace WixToolset.Core.WindowsInstaller
17 /// </summary>
18 public sealed class Differ
19 {
20 - private const char SectionDelimiter = '/';
20 private readonly IMessaging messaging;
21 private SummaryInformationStreams transformSummaryInfo;
22
@@ -111,7 +110,6 @@ namespace WixToolset.Core.WindowsInstaller
110 foreach (var updatedRow in updatedTable.Rows)
111 {
112 updatedRow.Operation = RowOperation.Add;
114 - updatedRow.SectionId = SectionDelimiter + updatedRow.SectionId;
113 addedTable.Rows.Add(updatedRow);
114 }
115 }
@@ -200,7 +198,6 @@ namespace WixToolset.Core.WindowsInstaller
198 else if (null == updatedRow)
199 {
200 operation = targetRow.Operation = RowOperation.Delete;
203 - targetRow.SectionId += SectionDelimiter;
201 comparedRow = targetRow;
202 keepRow = true;
203 }
@@ -211,9 +208,8 @@ namespace WixToolset.Core.WindowsInstaller
208 if (!this.SuppressKeepingSpecialRows && "_SummaryInformation" == targetTable.Name)
209 {
210 // ignore rows that shouldn't be in a transform
214 - if (Enum.IsDefined(typeof(SummaryInformation.Transform), (int)updatedRow[0]))
211 + if (Enum.IsDefined(typeof(SummaryInformation.Transform), updatedRow.FieldAsInteger(0)))
212 {
216 - updatedRow.SectionId = targetRow.SectionId + SectionDelimiter + updatedRow.SectionId;
213 comparedRow = updatedRow;
214 keepRow = true;
215 operation = RowOperation.Modify;
@@ -297,7 +293,7 @@ namespace WixToolset.Core.WindowsInstaller
293 if (keepRow)
294 {
295 comparedRow = updatedRow;
300 - comparedRow.SectionId = targetRow.SectionId + SectionDelimiter + updatedRow.SectionId;
296 + //comparedRow.SectionId = targetRow.SectionId + SectionDelimiter + updatedRow.SectionId;
297 }
298 }
299 }
@@ -361,7 +357,6 @@ namespace WixToolset.Core.WindowsInstaller
357 var updatedRow = (Row)updatedPrimaryKeyEntry.Value;
358
359 updatedRow.Operation = RowOperation.Add;
364 - updatedRow.SectionId = SectionDelimiter + updatedRow.SectionId;
360 rows.Add(updatedRow);
361 }
362 }
src/wix/WixToolset.Core.WindowsInstaller/ExtensibilityServices/WindowsInstallerBackendHelper.cs
+1 -4
@@ -141,10 +141,7 @@ namespace WixToolset.Core.WindowsInstaller.ExtensibilityServices
141 {
142 var table = data.EnsureTable(tableDefinition);
143
144 - var row = table.CreateRow(symbol.SourceLineNumbers);
145 - row.SectionId = section.Id;
146 -
147 - return row;
144 + return table.CreateRow(symbol.SourceLineNumbers);
145 }
146
147 public bool TryAddSymbolToMatchingTableDefinitions(IntermediateSection section, IntermediateSymbol symbol, WindowsInstallerData data, TableDefinitionCollection tableDefinitions)
src/wix/WixToolset.Core.WindowsInstaller/MspBackend.cs
+7 -3
@@ -34,14 +34,18 @@ namespace WixToolset.Core.WindowsInstaller
34
35 // Create transforms named in patch transforms.
36 IEnumerable<PatchTransform> patchTransforms;
37 + PatchFilterMap patchFilterMap;
38 {
38 - var command = new CreatePatchTransformsCommand(messaging, backendHelper, pathResolver, fileResolver, resolveExtensions, context.IntermediateRepresentation, context.IntermediateFolder, context.BindPaths);
39 - patchTransforms = command.Execute();
39 + var command = new CreatePatchTransformsCommand(messaging, backendHelper, pathResolver, fileResolver, resolveExtensions, backendExtensions, context.IntermediateRepresentation, context.IntermediateFolder, context.BindPaths);
40 + command.Execute();
41 +
42 + patchTransforms = command.PatchTransforms;
43 + patchFilterMap = command.PatchFilterMap;
44 }
45
46 // Reduce transforms.
47 {
44 - var command = new ReduceTransformCommand(context.IntermediateRepresentation, patchTransforms);
48 + var command = new ReduceTransformCommand(context.IntermediateRepresentation, patchTransforms, patchFilterMap);
49 command.Execute();
50 }
51