aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/WixToolset.Core.WindowsInstaller/Bind/SequenceActionsCommand.cs262
1 files changed, 135 insertions, 127 deletions
diff --git a/src/WixToolset.Core.WindowsInstaller/Bind/SequenceActionsCommand.cs b/src/WixToolset.Core.WindowsInstaller/Bind/SequenceActionsCommand.cs
index 97602afa..0d6e15d5 100644
--- a/src/WixToolset.Core.WindowsInstaller/Bind/SequenceActionsCommand.cs
+++ b/src/WixToolset.Core.WindowsInstaller/Bind/SequenceActionsCommand.cs
@@ -31,150 +31,142 @@ namespace WixToolset.Core.WindowsInstaller.Bind
31 public IMessaging Messaging { private get; set; } 31 public IMessaging Messaging { private get; set; }
32 32
33 /// <summary> 33 /// <summary>
34 /// Set sequence numbers for all the actions and create rows in the output object. 34 /// Set sequence numbers for all the actions and create tuples in the output object.
35 /// </summary> 35 /// </summary>
36 public void Execute() 36 public void Execute()
37 { 37 {
38 var overridableActionRows = new Dictionary<string, WixActionTuple>(); 38 var requiredActionTuples = new Dictionary<string, WixActionTuple>();
39 var requiredActionRows = new Dictionary<string, WixActionTuple>();
40 39
41 // Get the standard actions required based on tuples in the section. 40 // Get the standard actions required based on tuples in the section.
42 var requiredActionIds = this.GetRequiredActionIds(); 41 var overridableActionTuples = this.GetRequiredStandardActions();
43
44 foreach (var actionId in requiredActionIds)
45 {
46 var standardAction = this.StandardActionsById[actionId];
47 42
48 overridableActionRows.Add(standardAction.Id.Id, standardAction); 43 // Index all the action tuples and look for collisions.
49 } 44 foreach (var actionTuple in this.Section.Tuples.OfType<WixActionTuple>())
50
51 // Index all the action rows and look for collisions.
52 foreach (var actionRow in this.Section.Tuples.OfType<WixActionTuple>())
53 { 45 {
54 if (actionRow.Overridable) // overridable action 46 if (actionTuple.Overridable) // overridable action
55 { 47 {
56 if (overridableActionRows.TryGetValue(actionRow.Id.Id, out var collidingActionRow)) 48 if (overridableActionTuples.TryGetValue(actionTuple.Id.Id, out var collidingActionTuple))
57 { 49 {
58 this.Messaging.Write(ErrorMessages.OverridableActionCollision(actionRow.SourceLineNumbers, actionRow.SequenceTable.ToString(), actionRow.Action)); 50 this.Messaging.Write(ErrorMessages.OverridableActionCollision(actionTuple.SourceLineNumbers, actionTuple.SequenceTable.ToString(), actionTuple.Action));
59 if (null != collidingActionRow.SourceLineNumbers) 51 if (null != collidingActionTuple.SourceLineNumbers)
60 { 52 {
61 this.Messaging.Write(ErrorMessages.OverridableActionCollision2(collidingActionRow.SourceLineNumbers)); 53 this.Messaging.Write(ErrorMessages.OverridableActionCollision2(collidingActionTuple.SourceLineNumbers));
62 } 54 }
63 } 55 }
64 else 56 else
65 { 57 {
66 overridableActionRows.Add(actionRow.Id.Id, actionRow); 58 overridableActionTuples.Add(actionTuple.Id.Id, actionTuple);
67 } 59 }
68 } 60 }
69 else // unsequenced or sequenced action. 61 else // unsequenced or sequenced action.
70 { 62 {
71 // Unsequenced action (allowed for certain standard actions). 63 // Unsequenced action (allowed for certain standard actions).
72 if (null == actionRow.Before && null == actionRow.After && 0 == actionRow.Sequence) 64 if (null == actionTuple.Before && null == actionTuple.After && !actionTuple.Sequence.HasValue)
73 { 65 {
74 if (this.StandardActionsById.TryGetValue(actionRow.Id.Id, out var standardAction)) 66 if (this.StandardActionsById.TryGetValue(actionTuple.Id.Id, out var standardAction))
75 { 67 {
76 // Populate the sequence from the standard action 68 // Populate the sequence from the standard action
77 actionRow.Sequence = standardAction.Sequence; 69 actionTuple.Sequence = standardAction.Sequence;
78 } 70 }
79 else // not a supported unscheduled action. 71 else // not a supported unscheduled action.
80 { 72 {
81 throw new InvalidOperationException("Found an ActionRow with no Sequence, Before, or After column set."); 73 throw new InvalidOperationException("Found an action with no Sequence, Before, or After column set.");
82 } 74 }
83 } 75 }
84 76
85 if (requiredActionRows.TryGetValue(actionRow.Id.Id, out var collidingActionRow)) 77 if (requiredActionTuples.TryGetValue(actionTuple.Id.Id, out var collidingActionTuple))
86 { 78 {
87 this.Messaging.Write(ErrorMessages.ActionCollision(actionRow.SourceLineNumbers, actionRow.SequenceTable.ToString(), actionRow.Action)); 79 this.Messaging.Write(ErrorMessages.ActionCollision(actionTuple.SourceLineNumbers, actionTuple.SequenceTable.ToString(), actionTuple.Action));
88 if (null != collidingActionRow.SourceLineNumbers) 80 if (null != collidingActionTuple.SourceLineNumbers)
89 { 81 {
90 this.Messaging.Write(ErrorMessages.ActionCollision2(collidingActionRow.SourceLineNumbers)); 82 this.Messaging.Write(ErrorMessages.ActionCollision2(collidingActionTuple.SourceLineNumbers));
91 } 83 }
92 } 84 }
93 else 85 else
94 { 86 {
95 requiredActionRows.Add(actionRow.Id.Id, actionRow); 87 requiredActionTuples.Add(actionTuple.Id.Id, actionTuple);
96 } 88 }
97 } 89 }
98 } 90 }
99 91
100 // Add the overridable action rows that are not overridden to the required action rows. 92 // Add the overridable action tuples that are not overridden to the required action tuples.
101 foreach (var actionRow in overridableActionRows.Values) 93 foreach (var actionTuple in overridableActionTuples.Values)
102 { 94 {
103 if (!requiredActionRows.ContainsKey(actionRow.Id.Id)) 95 if (!requiredActionTuples.ContainsKey(actionTuple.Id.Id))
104 { 96 {
105 requiredActionRows.Add(actionRow.Id.Id, actionRow); 97 requiredActionTuples.Add(actionTuple.Id.Id, actionTuple);
106 } 98 }
107 } 99 }
108 100
109 // Suppress the required actions that are overridable. 101 // Suppress the required actions that are overridable.
110 foreach (var suppressActionRow in this.Section.Tuples.OfType<WixSuppressActionTuple>()) 102 foreach (var suppressActionTuple in this.Section.Tuples.OfType<WixSuppressActionTuple>())
111 { 103 {
112 var key = suppressActionRow.Id.Id; 104 var key = suppressActionTuple.Id.Id;
113 105
114 // If there is an overridable row to suppress; suppress it. There is no warning if there 106 // If there is an overridable tuple to suppress; suppress it. There is no warning if there
115 // is no action to suppress because the action may be suppressed from a merge module in 107 // is no action to suppress because the action may be suppressed from a merge module in
116 // the binder. 108 // the binder.
117 if (requiredActionRows.TryGetValue(key, out var requiredActionRow)) 109 if (requiredActionTuples.TryGetValue(key, out var requiredActionTuple))
118 { 110 {
119 if (requiredActionRow.Overridable) 111 if (requiredActionTuple.Overridable)
120 { 112 {
121 this.Messaging.Write(WarningMessages.SuppressAction(suppressActionRow.SourceLineNumbers, suppressActionRow.Action, suppressActionRow.SequenceTable.ToString())); 113 this.Messaging.Write(WarningMessages.SuppressAction(suppressActionTuple.SourceLineNumbers, suppressActionTuple.Action, suppressActionTuple.SequenceTable.ToString()));
122 if (null != requiredActionRow.SourceLineNumbers) 114 if (null != requiredActionTuple.SourceLineNumbers)
123 { 115 {
124 this.Messaging.Write(WarningMessages.SuppressAction2(requiredActionRow.SourceLineNumbers)); 116 this.Messaging.Write(WarningMessages.SuppressAction2(requiredActionTuple.SourceLineNumbers));
125 } 117 }
126 118
127 requiredActionRows.Remove(key); 119 requiredActionTuples.Remove(key);
128 } 120 }
129 else // suppressing a non-overridable action row 121 else // suppressing a non-overridable action tuple
130 { 122 {
131 this.Messaging.Write(ErrorMessages.SuppressNonoverridableAction(suppressActionRow.SourceLineNumbers, suppressActionRow.SequenceTable.ToString(), suppressActionRow.Action)); 123 this.Messaging.Write(ErrorMessages.SuppressNonoverridableAction(suppressActionTuple.SourceLineNumbers, suppressActionTuple.SequenceTable.ToString(), suppressActionTuple.Action));
132 if (null != requiredActionRow.SourceLineNumbers) 124 if (null != requiredActionTuple.SourceLineNumbers)
133 { 125 {
134 this.Messaging.Write(ErrorMessages.SuppressNonoverridableAction2(requiredActionRow.SourceLineNumbers)); 126 this.Messaging.Write(ErrorMessages.SuppressNonoverridableAction2(requiredActionTuple.SourceLineNumbers));
135 } 127 }
136 } 128 }
137 } 129 }
138 } 130 }
139 131
140 // Build up dependency trees of the relatively scheduled actions. 132 // Build up dependency trees of the relatively scheduled actions.
141 // Use ToList() to create a copy of the required action rows so that new tuples can 133 // Use ToList() to create a copy of the required action tuples so that new tuples can
142 // be added while enumerating. 134 // be added while enumerating.
143 foreach (var actionRow in requiredActionRows.Values.ToList()) 135 foreach (var actionTuple in requiredActionTuples.Values.ToList())
144 { 136 {
145 if (0 == actionRow.Sequence) 137 if (!actionTuple.Sequence.HasValue)
146 { 138 {
147 // check for standard actions that don't have a sequence number in a merge module 139 // check for standard actions that don't have a sequence number in a merge module
148 if (SectionType.Module == this.Section.Type && WindowsInstallerStandard.IsStandardAction(actionRow.Action)) 140 if (SectionType.Module == this.Section.Type && WindowsInstallerStandard.IsStandardAction(actionTuple.Action))
149 { 141 {
150 this.Messaging.Write(ErrorMessages.StandardActionRelativelyScheduledInModule(actionRow.SourceLineNumbers, actionRow.SequenceTable.ToString(), actionRow.Action)); 142 this.Messaging.Write(ErrorMessages.StandardActionRelativelyScheduledInModule(actionTuple.SourceLineNumbers, actionTuple.SequenceTable.ToString(), actionTuple.Action));
151 } 143 }
152 144
153 this.SequenceActionRow(actionRow, requiredActionRows); 145 this.SequenceActionTuple(actionTuple, requiredActionTuples);
154 } 146 }
155 else if (SectionType.Module == this.Section.Type && 0 < actionRow.Sequence && !WindowsInstallerStandard.IsStandardAction(actionRow.Action)) // check for custom actions and dialogs that have a sequence number 147 else if (SectionType.Module == this.Section.Type && 0 < actionTuple.Sequence && !WindowsInstallerStandard.IsStandardAction(actionTuple.Action)) // check for custom actions and dialogs that have a sequence number
156 { 148 {
157 this.Messaging.Write(ErrorMessages.CustomActionSequencedInModule(actionRow.SourceLineNumbers, actionRow.SequenceTable.ToString(), actionRow.Action)); 149 this.Messaging.Write(ErrorMessages.CustomActionSequencedInModule(actionTuple.SourceLineNumbers, actionTuple.SequenceTable.ToString(), actionTuple.Action));
158 } 150 }
159 } 151 }
160 152
161 // Look for standard actions with sequence restrictions that aren't necessarily scheduled based 153 // Look for standard actions with sequence restrictions that aren't necessarily scheduled based
162 // on the presence of a particular table. 154 // on the presence of a particular table.
163 if (requiredActionRows.ContainsKey("InstallExecuteSequence/DuplicateFiles") && !requiredActionRows.ContainsKey("InstallExecuteSequence/InstallFiles")) 155 if (requiredActionTuples.ContainsKey("InstallExecuteSequence/DuplicateFiles") && !requiredActionTuples.ContainsKey("InstallExecuteSequence/InstallFiles"))
164 { 156 {
165 var standardAction = this.StandardActionsById["InstallExecuteSequence/InstallFiles"]; 157 var standardAction = this.StandardActionsById["InstallExecuteSequence/InstallFiles"];
166 requiredActionRows.Add(standardAction.Id.Id, standardAction); 158 requiredActionTuples.Add(standardAction.Id.Id, standardAction);
167 } 159 }
168 160
169 // Schedule actions. 161 // Schedule actions.
170 List<WixActionTuple> scheduledActionRows; 162 List<WixActionTuple> scheduledActionTuples;
171 if (SectionType.Module == this.Section.Type) 163 if (SectionType.Module == this.Section.Type)
172 { 164 {
173 scheduledActionRows = requiredActionRows.Values.ToList(); 165 scheduledActionTuples = requiredActionTuples.Values.ToList();
174 } 166 }
175 else 167 else
176 { 168 {
177 scheduledActionRows = this.ScheduleActions(requiredActionRows); 169 scheduledActionTuples = this.ScheduleActions(requiredActionTuples);
178 } 170 }
179 171
180 // Remove all existing WixActionTuples from the section then add the 172 // Remove all existing WixActionTuples from the section then add the
@@ -195,146 +187,162 @@ namespace WixToolset.Core.WindowsInstaller.Bind
195 this.Section.Tuples.RemoveAt(removeIndex); 187 this.Section.Tuples.RemoveAt(removeIndex);
196 } 188 }
197 189
198 foreach (var action in scheduledActionRows) 190 foreach (var action in scheduledActionTuples)
199 { 191 {
200 this.Section.Tuples.Add(action); 192 this.Section.Tuples.Add(action);
201 } 193 }
202 } 194 }
203 195
204 private List<WixActionTuple> ScheduleActions(Dictionary<string, WixActionTuple> requiredActionRows) 196 private Dictionary<string, WixActionTuple> GetRequiredStandardActions()
197 {
198 var overridableActionTuples = new Dictionary<string, WixActionTuple>();
199
200 var requiredActionIds = this.GetRequiredActionIds();
201
202 foreach (var actionId in requiredActionIds)
203 {
204 var standardAction = this.StandardActionsById[actionId];
205
206 overridableActionTuples.Add(standardAction.Id.Id, standardAction);
207 }
208
209 return overridableActionTuples;
210 }
211
212 private List<WixActionTuple> ScheduleActions(Dictionary<string, WixActionTuple> requiredActionTuples)
205 { 213 {
206 var scheduledActionRows = new List<WixActionTuple>(); 214 var scheduledActionTuples = new List<WixActionTuple>();
207 215
208 // Process each sequence table individually. 216 // Process each sequence table individually.
209 foreach (SequenceTable sequenceTable in Enum.GetValues(typeof(SequenceTable))) 217 foreach (SequenceTable sequenceTable in Enum.GetValues(typeof(SequenceTable)))
210 { 218 {
211 // Create a collection of just the action rows in this sequence 219 // Create a collection of just the action tuples in this sequence
212 var sequenceActionRows = requiredActionRows.Values.Where(a => a.SequenceTable == sequenceTable).ToList(); 220 var sequenceActionTuples = requiredActionTuples.Values.Where(a => a.SequenceTable == sequenceTable).ToList();
213 221
214 // Schedule the absolutely scheduled actions (by sorting them by their sequence numbers). 222 // Schedule the absolutely scheduled actions (by sorting them by their sequence numbers).
215 var absoluteActionRows = new List<WixActionTuple>(); 223 var absoluteActionTuples = new List<WixActionTuple>();
216 foreach (var actionRow in sequenceActionRows) 224 foreach (var actionTuple in sequenceActionTuples)
217 { 225 {
218 if (0 != actionRow.Sequence) 226 if (actionTuple.Sequence.HasValue)
219 { 227 {
220 // Look for sequence number collisions 228 // Look for sequence number collisions
221 foreach (var sequenceScheduledActionRow in absoluteActionRows) 229 foreach (var sequenceScheduledActionTuple in absoluteActionTuples)
222 { 230 {
223 if (sequenceScheduledActionRow.Sequence == actionRow.Sequence) 231 if (sequenceScheduledActionTuple.Sequence == actionTuple.Sequence)
224 { 232 {
225 this.Messaging.Write(WarningMessages.ActionSequenceCollision(actionRow.SourceLineNumbers, actionRow.SequenceTable.ToString(), actionRow.Action, sequenceScheduledActionRow.Action, actionRow.Sequence ?? 0)); 233 this.Messaging.Write(WarningMessages.ActionSequenceCollision(actionTuple.SourceLineNumbers, actionTuple.SequenceTable.ToString(), actionTuple.Action, sequenceScheduledActionTuple.Action, actionTuple.Sequence ?? 0));
226 if (null != sequenceScheduledActionRow.SourceLineNumbers) 234 if (null != sequenceScheduledActionTuple.SourceLineNumbers)
227 { 235 {
228 this.Messaging.Write(WarningMessages.ActionSequenceCollision2(sequenceScheduledActionRow.SourceLineNumbers)); 236 this.Messaging.Write(WarningMessages.ActionSequenceCollision2(sequenceScheduledActionTuple.SourceLineNumbers));
229 } 237 }
230 } 238 }
231 } 239 }
232 240
233 absoluteActionRows.Add(actionRow); 241 absoluteActionTuples.Add(actionTuple);
234 } 242 }
235 } 243 }
236 244
237 absoluteActionRows.Sort((x, y) => (x.Sequence ?? 0).CompareTo(y.Sequence ?? 0)); 245 absoluteActionTuples.Sort((x, y) => (x.Sequence ?? 0).CompareTo(y.Sequence ?? 0));
238 246
239 // Schedule the relatively scheduled actions (by resolving the dependency trees). 247 // Schedule the relatively scheduled actions (by resolving the dependency trees).
240 var previousUsedSequence = 0; 248 var previousUsedSequence = 0;
241 var relativeActionRows = new List<WixActionTuple>(); 249 var relativeActionTuples = new List<WixActionTuple>();
242 for (int j = 0; j < absoluteActionRows.Count; j++) 250 for (int j = 0; j < absoluteActionTuples.Count; j++)
243 { 251 {
244 var absoluteActionRow = absoluteActionRows[j]; 252 var absoluteActionTuple = absoluteActionTuples[j];
245 253
246 // Get all the relatively scheduled action rows occuring before and after this absolutely scheduled action row. 254 // Get all the relatively scheduled action tuples occuring before and after this absolutely scheduled action tuple.
247 var relativeActions = this.GetAllRelativeActionsForSequenceType(sequenceTable, absoluteActionRow); 255 var relativeActions = this.GetAllRelativeActionsForSequenceType(sequenceTable, absoluteActionTuple);
248 256
249 // Check for relatively scheduled actions occuring before/after a special action 257 // Check for relatively scheduled actions occuring before/after a special action
250 // (those actions with a negative sequence number). 258 // (those actions with a negative sequence number).
251 if (absoluteActionRow.Sequence < 0 && (relativeActions.PreviousActions.Any() || relativeActions.NextActions.Any())) 259 if (absoluteActionTuple.Sequence < 0 && (relativeActions.PreviousActions.Any() || relativeActions.NextActions.Any()))
252 { 260 {
253 // Create errors for all the before actions. 261 // Create errors for all the before actions.
254 foreach (var actionRow in relativeActions.PreviousActions) 262 foreach (var actionTuple in relativeActions.PreviousActions)
255 { 263 {
256 this.Messaging.Write(ErrorMessages.ActionScheduledRelativeToTerminationAction(actionRow.SourceLineNumbers, actionRow.SequenceTable.ToString(), actionRow.Action, absoluteActionRow.Action)); 264 this.Messaging.Write(ErrorMessages.ActionScheduledRelativeToTerminationAction(actionTuple.SourceLineNumbers, actionTuple.SequenceTable.ToString(), actionTuple.Action, absoluteActionTuple.Action));
257 } 265 }
258 266
259 // Create errors for all the after actions. 267 // Create errors for all the after actions.
260 foreach (var actionRow in relativeActions.NextActions) 268 foreach (var actionTuple in relativeActions.NextActions)
261 { 269 {
262 this.Messaging.Write(ErrorMessages.ActionScheduledRelativeToTerminationAction(actionRow.SourceLineNumbers, actionRow.SequenceTable.ToString(), actionRow.Action, absoluteActionRow.Action)); 270 this.Messaging.Write(ErrorMessages.ActionScheduledRelativeToTerminationAction(actionTuple.SourceLineNumbers, actionTuple.SequenceTable.ToString(), actionTuple.Action, absoluteActionTuple.Action));
263 } 271 }
264 272
265 // If there is source line information for the absolutely scheduled action display it 273 // If there is source line information for the absolutely scheduled action display it
266 if (absoluteActionRow.SourceLineNumbers != null) 274 if (absoluteActionTuple.SourceLineNumbers != null)
267 { 275 {
268 this.Messaging.Write(ErrorMessages.ActionScheduledRelativeToTerminationAction2(absoluteActionRow.SourceLineNumbers)); 276 this.Messaging.Write(ErrorMessages.ActionScheduledRelativeToTerminationAction2(absoluteActionTuple.SourceLineNumbers));
269 } 277 }
270 278
271 continue; 279 continue;
272 } 280 }
273 281
274 // Schedule the action rows before this one. 282 // Schedule the action tuples before this one.
275 var unusedSequence = absoluteActionRow.Sequence - 1; 283 var unusedSequence = absoluteActionTuple.Sequence - 1;
276 for (var i = relativeActions.PreviousActions.Count - 1; i >= 0; i--) 284 for (var i = relativeActions.PreviousActions.Count - 1; i >= 0; i--)
277 { 285 {
278 var relativeActionRow = relativeActions.PreviousActions[i]; 286 var relativeActionTuple = relativeActions.PreviousActions[i];
279 287
280 // look for collisions 288 // look for collisions
281 if (unusedSequence == previousUsedSequence) 289 if (unusedSequence == previousUsedSequence)
282 { 290 {
283 this.Messaging.Write(ErrorMessages.NoUniqueActionSequenceNumber(relativeActionRow.SourceLineNumbers, relativeActionRow.SequenceTable.ToString(), relativeActionRow.Action, absoluteActionRow.Action)); 291 this.Messaging.Write(ErrorMessages.NoUniqueActionSequenceNumber(relativeActionTuple.SourceLineNumbers, relativeActionTuple.SequenceTable.ToString(), relativeActionTuple.Action, absoluteActionTuple.Action));
284 if (absoluteActionRow.SourceLineNumbers != null) 292 if (absoluteActionTuple.SourceLineNumbers != null)
285 { 293 {
286 this.Messaging.Write(ErrorMessages.NoUniqueActionSequenceNumber2(absoluteActionRow.SourceLineNumbers)); 294 this.Messaging.Write(ErrorMessages.NoUniqueActionSequenceNumber2(absoluteActionTuple.SourceLineNumbers));
287 } 295 }
288 296
289 unusedSequence++; 297 unusedSequence++;
290 } 298 }
291 299
292 relativeActionRow.Sequence = unusedSequence; 300 relativeActionTuple.Sequence = unusedSequence;
293 relativeActionRows.Add(relativeActionRow); 301 relativeActionTuples.Add(relativeActionTuple);
294 302
295 unusedSequence--; 303 unusedSequence--;
296 } 304 }
297 305
298 // Determine the next used action sequence number. 306 // Determine the next used action sequence number.
299 var nextUsedSequence = Int16.MaxValue + 1; 307 var nextUsedSequence = Int16.MaxValue + 1;
300 if (absoluteActionRows.Count > j + 1) 308 if (absoluteActionTuples.Count > j + 1)
301 { 309 {
302 nextUsedSequence = absoluteActionRows[j + 1].Sequence ?? 0; 310 nextUsedSequence = absoluteActionTuples[j + 1].Sequence ?? 0;
303 } 311 }
304 312
305 // Schedule the action rows after this one. 313 // Schedule the action tuples after this one.
306 unusedSequence = absoluteActionRow.Sequence + 1; 314 unusedSequence = absoluteActionTuple.Sequence + 1;
307 for (var i = 0; i < relativeActions.NextActions.Count; i++) 315 for (var i = 0; i < relativeActions.NextActions.Count; i++)
308 { 316 {
309 var relativeActionRow = relativeActions.NextActions[i]; 317 var relativeActionTuple = relativeActions.NextActions[i];
310 318
311 if (unusedSequence == nextUsedSequence) 319 if (unusedSequence == nextUsedSequence)
312 { 320 {
313 this.Messaging.Write(ErrorMessages.NoUniqueActionSequenceNumber(relativeActionRow.SourceLineNumbers, relativeActionRow.SequenceTable.ToString(), relativeActionRow.Action, absoluteActionRow.Action)); 321 this.Messaging.Write(ErrorMessages.NoUniqueActionSequenceNumber(relativeActionTuple.SourceLineNumbers, relativeActionTuple.SequenceTable.ToString(), relativeActionTuple.Action, absoluteActionTuple.Action));
314 if (absoluteActionRow.SourceLineNumbers != null) 322 if (absoluteActionTuple.SourceLineNumbers != null)
315 { 323 {
316 this.Messaging.Write(ErrorMessages.NoUniqueActionSequenceNumber2(absoluteActionRow.SourceLineNumbers)); 324 this.Messaging.Write(ErrorMessages.NoUniqueActionSequenceNumber2(absoluteActionTuple.SourceLineNumbers));
317 } 325 }
318 326
319 unusedSequence--; 327 unusedSequence--;
320 } 328 }
321 329
322 relativeActionRow.Sequence = unusedSequence; 330 relativeActionTuple.Sequence = unusedSequence;
323 relativeActionRows.Add(relativeActionRow); 331 relativeActionTuples.Add(relativeActionTuple);
324 332
325 unusedSequence++; 333 unusedSequence++;
326 } 334 }
327 335
328 // keep track of this sequence number as the previous used sequence number for the next iteration 336 // keep track of this sequence number as the previous used sequence number for the next iteration
329 previousUsedSequence = absoluteActionRow.Sequence ?? 0; 337 previousUsedSequence = absoluteActionTuple.Sequence ?? 0;
330 } 338 }
331 339
332 // add the absolutely and relatively scheduled actions to the list of scheduled actions 340 // add the absolutely and relatively scheduled actions to the list of scheduled actions
333 scheduledActionRows.AddRange(absoluteActionRows); 341 scheduledActionTuples.AddRange(absoluteActionTuples);
334 scheduledActionRows.AddRange(relativeActionRows); 342 scheduledActionTuples.AddRange(relativeActionTuples);
335 } 343 }
336 344
337 return scheduledActionRows; 345 return scheduledActionTuples;
338 } 346 }
339 347
340 private IEnumerable<string> GetRequiredActionIds() 348 private IEnumerable<string> GetRequiredActionIds()
@@ -568,51 +576,51 @@ namespace WixToolset.Core.WindowsInstaller.Bind
568 /// <summary> 576 /// <summary>
569 /// Sequence an action before or after a standard action. 577 /// Sequence an action before or after a standard action.
570 /// </summary> 578 /// </summary>
571 /// <param name="actionRow">The action row to be sequenced.</param> 579 /// <param name="actionTuple">The action tuple to be sequenced.</param>
572 /// <param name="requiredActionRows">Collection of actions which must be included.</param> 580 /// <param name="requiredActionTuples">Collection of actions which must be included.</param>
573 private void SequenceActionRow(WixActionTuple actionRow, Dictionary<string, WixActionTuple> requiredActionRows) 581 private void SequenceActionTuple(WixActionTuple actionTuple, Dictionary<string, WixActionTuple> requiredActionTuples)
574 { 582 {
575 var after = false; 583 var after = false;
576 584
577 if (actionRow.After != null) 585 if (actionTuple.After != null)
578 { 586 {
579 after = true; 587 after = true;
580 } 588 }
581 else if (actionRow.Before == null) 589 else if (actionTuple.Before == null)
582 { 590 {
583 throw new InvalidOperationException("Found an ActionRow with no Sequence, Before, or After column set."); 591 throw new InvalidOperationException("Found an action with no Sequence, Before, or After column set.");
584 } 592 }
585 593
586 var parentActionName = (after ? actionRow.After : actionRow.Before); 594 var parentActionName = (after ? actionTuple.After : actionTuple.Before);
587 var parentActionKey = actionRow.SequenceTable.ToString() + "/" + parentActionName; 595 var parentActionKey = actionTuple.SequenceTable.ToString() + "/" + parentActionName;
588 596
589 if (!requiredActionRows.TryGetValue(parentActionKey, out var parentActionRow)) 597 if (!requiredActionTuples.TryGetValue(parentActionKey, out var parentActionTuple))
590 { 598 {
591 // If the missing parent action is a standard action (with a suggested sequence number), add it. 599 // If the missing parent action is a standard action (with a suggested sequence number), add it.
592 if (this.StandardActionsById.TryGetValue(parentActionKey, out parentActionRow)) 600 if (this.StandardActionsById.TryGetValue(parentActionKey, out parentActionTuple))
593 { 601 {
594 // Create a clone to avoid modifying the static copy of the object. 602 // Create a clone to avoid modifying the static copy of the object.
595 // TODO: consider this: parentActionRow = parentActionRow.Clone(); 603 // TODO: consider this: parentActionTuple = parentActionTuple.Clone();
596 604
597 requiredActionRows.Add(parentActionRow.Id.Id, parentActionRow); 605 requiredActionTuples.Add(parentActionTuple.Id.Id, parentActionTuple);
598 } 606 }
599 else 607 else
600 { 608 {
601 throw new InvalidOperationException(String.Format(CultureInfo.CurrentUICulture, "Found an ActionRow with a non-existent {0} action: {1}.", (after ? "After" : "Before"), parentActionName)); 609 throw new InvalidOperationException(String.Format(CultureInfo.CurrentUICulture, "Found an action with a non-existent {0} action: {1}.", (after ? "After" : "Before"), parentActionName));
602 } 610 }
603 } 611 }
604 else if (actionRow == parentActionRow || this.ContainsChildActionRow(actionRow, parentActionRow)) // cycle detected 612 else if (actionTuple == parentActionTuple || this.ContainsChildActionTuple(actionTuple, parentActionTuple)) // cycle detected
605 { 613 {
606 throw new WixException(ErrorMessages.ActionCircularDependency(actionRow.SourceLineNumbers, actionRow.SequenceTable.ToString(), actionRow.Action, parentActionRow.Action)); 614 throw new WixException(ErrorMessages.ActionCircularDependency(actionTuple.SourceLineNumbers, actionTuple.SequenceTable.ToString(), actionTuple.Action, parentActionTuple.Action));
607 } 615 }
608 616
609 // Add this action to the appropriate list of dependent action rows. 617 // Add this action to the appropriate list of dependent action tuples.
610 var relativeActions = this.GetRelativeActions(parentActionRow); 618 var relativeActions = this.GetRelativeActions(parentActionTuple);
611 var relatedRows = (after ? relativeActions.NextActions : relativeActions.PreviousActions); 619 var relatedTuples = (after ? relativeActions.NextActions : relativeActions.PreviousActions);
612 relatedRows.Add(actionRow); 620 relatedTuples.Add(actionTuple);
613 } 621 }
614 622
615 private bool ContainsChildActionRow(WixActionTuple childTuple, WixActionTuple parentTuple) 623 private bool ContainsChildActionTuple(WixActionTuple childTuple, WixActionTuple parentTuple)
616 { 624 {
617 var result = false; 625 var result = false;
618 626