private RelativeActions GetRelativeActions(WixActionSymbol action) { if (!this.RelativeActionsForActions.TryGetValue(action.Id.Id, out var relativeActions)) { relativeActions = new RelativeActions(); this.RelativeActionsForActions.Add(action.Id.Id, relativeActions); } return(relativeActions); }
private bool ContainsChildActionSymbol(WixActionSymbol childSymbol, WixActionSymbol parentSymbol) { var result = false; if (this.RelativeActionsForActions.TryGetValue(childSymbol.Id.Id, out var relativeActions)) { result = relativeActions.NextActions.Any(a => a.SequenceTable == parentSymbol.SequenceTable && a.Id.Id == parentSymbol.Id.Id) || relativeActions.PreviousActions.Any(a => a.SequenceTable == parentSymbol.SequenceTable && a.Id.Id == parentSymbol.Id.Id); } return(result); }
/// <summary> /// Get the action symbol that is the parent of the given action symbol. /// </summary> /// <param name="actionSymbol">The given action symbol.</param> /// <param name="requiredActionSymbols">Collection of actions which must be included.</param> /// <returns>Null if there is no parent. Used for loop termination.</returns> private WixActionSymbol GetParentActionSymbol(WixActionSymbol actionSymbol, Dictionary <string, WixActionSymbol> requiredActionSymbols) { if (null == actionSymbol.Before && null == actionSymbol.After) { return(null); } var parentActionKey = actionSymbol.SequenceTable.ToString() + "/" + (actionSymbol.After ?? actionSymbol.Before); if (!requiredActionSymbols.TryGetValue(parentActionKey, out var parentActionSymbol)) { WindowsInstallerStandard.TryGetStandardAction(parentActionKey, out parentActionSymbol); } return(parentActionSymbol); }
/// <summary> /// Sequence an action before or after a standard action. /// </summary> /// <param name="actionSymbol">The action symbol to be sequenced.</param> /// <param name="requiredActionSymbols">Collection of actions which must be included.</param> private void SequenceActionSymbol(WixActionSymbol actionSymbol, Dictionary <string, WixActionSymbol> requiredActionSymbols) { var after = false; if (actionSymbol.After != null) { after = true; } else if (actionSymbol.Before == null) { throw new InvalidOperationException("Found an action with no Sequence, Before, or After column set."); } var parentActionName = (after ? actionSymbol.After : actionSymbol.Before); var parentActionKey = actionSymbol.SequenceTable.ToString() + "/" + parentActionName; if (!requiredActionSymbols.TryGetValue(parentActionKey, out var parentActionSymbol)) { // If the missing parent action is a standard action (with a suggested sequence number), add it. if (WindowsInstallerStandard.TryGetStandardAction(parentActionKey, out parentActionSymbol)) { // Create a clone to avoid modifying the static copy of the object. // TODO: consider this: parentActionSymbol = parentActionSymbol.Clone(); requiredActionSymbols.Add(parentActionSymbol.Id.Id, parentActionSymbol); } else { throw new InvalidOperationException(String.Format(CultureInfo.CurrentUICulture, "Found an action with a non-existent {0} action: {1}.", (after ? "After" : "Before"), parentActionName)); } } else if (actionSymbol == parentActionSymbol || this.ContainsChildActionSymbol(actionSymbol, parentActionSymbol)) // cycle detected { throw new WixException(ErrorMessages.ActionCircularDependency(actionSymbol.SourceLineNumbers, actionSymbol.SequenceTable.ToString(), actionSymbol.Action, parentActionSymbol.Action)); } // Add this action to the appropriate list of dependent action symbols. var relativeActions = this.GetRelativeActions(parentActionSymbol); var relatedSymbols = (after ? relativeActions.NextActions : relativeActions.PreviousActions); relatedSymbols.Add(actionSymbol); }
/// <summary> /// Sequence an action before or after a standard action. /// </summary> /// <param name="actionSymbol">The action symbol to be sequenced.</param> /// <param name="requiredActionSymbols">Collection of actions which must be included.</param> /// <param name="firstReference">A dictionary used for detecting cyclic references among action symbols.</param> private void SequenceActionSymbol(WixActionSymbol actionSymbol, Dictionary <string, WixActionSymbol> requiredActionSymbols, Dictionary <WixActionSymbol, WixActionSymbol> firstReference) { var after = false; if (actionSymbol.After != null) { after = true; } else if (actionSymbol.Before == null) { throw new WixException($"Found action '{actionSymbol.Id.Id}' at {actionSymbol.SourceLineNumbers}' with no Sequence, Before, or After column set. The compiler should have prevented this."); } var parentActionName = (after ? actionSymbol.After : actionSymbol.Before); var parentActionKey = actionSymbol.SequenceTable.ToString() + "/" + parentActionName; if (!requiredActionSymbols.TryGetValue(parentActionKey, out var parentActionSymbol)) { // If the missing parent action is a standard action (with a suggested sequence number), add it. if (WindowsInstallerStandard.TryGetStandardAction(parentActionKey, out parentActionSymbol)) { // Create a clone to avoid modifying the static copy of the object. // TODO: consider this: parentActionSymbol = parentActionSymbol.Clone(); requiredActionSymbols.Add(parentActionSymbol.Id.Id, parentActionSymbol); } else { throw new WixException($"Found action {actionSymbol.Id.Id} with a non-existent {(after ? "After" : "Before")} action '{parentActionName}'. The linker should have prevented this."); } } this.CheckForCircularActionReference(actionSymbol, requiredActionSymbols, firstReference); // Add this action to the appropriate list of dependent action symbols. var relativeActions = this.GetRelativeActions(parentActionSymbol); var relatedSymbols = (after ? relativeActions.NextActions : relativeActions.PreviousActions); relatedSymbols.Add(actionSymbol); }
/// <summary> /// Check the specified action symbol to see if it leads to a cycle. /// </summary> /// <para> Use the provided dictionary to note the initial action symbol that first led to each action /// symbol. Any action symbol encountered that has already been encountered starting from a different /// initial action symbol inherits the loop characteristics of that initial action symbol, and thus is /// also not part of a cycle. However, any action symbol encountered that has already been encountered /// starting from the same initial action symbol is an indication that the current action symbol is /// part of a cycle. /// </para> /// <param name="actionSymbol">The action symbol to be checked.</param> /// <param name="requiredActionSymbols">Collection of actions which must be included.</param> /// <param name="firstReference">The first encountered action symbol that led to each action symbol.</param> private void CheckForCircularActionReference(WixActionSymbol actionSymbol, Dictionary <string, WixActionSymbol> requiredActionSymbols, Dictionary <WixActionSymbol, WixActionSymbol> firstReference) { WixActionSymbol currentActionSymbol = null; var parentActionSymbol = actionSymbol; do { var previousActionSymbol = currentActionSymbol ?? parentActionSymbol; currentActionSymbol = parentActionSymbol; if (!firstReference.TryGetValue(currentActionSymbol, out var existingInitialActionSymbol)) { firstReference[currentActionSymbol] = actionSymbol; } else if (existingInitialActionSymbol == actionSymbol) { throw new WixException(ErrorMessages.ActionCircularDependency(currentActionSymbol.SourceLineNumbers, currentActionSymbol.SequenceTable.ToString(), currentActionSymbol.Action, previousActionSymbol.Action)); } parentActionSymbol = this.GetParentActionSymbol(currentActionSymbol, requiredActionSymbols); } while (null != parentActionSymbol); }
private RelativeActions GetAllRelativeActionsForSequenceType(SequenceTable sequenceType, WixActionSymbol action) { var relativeActions = new RelativeActions(); if (this.RelativeActionsForActions.TryGetValue(action.Id.Id, out var actionRelatives)) { this.RecurseRelativeActionsForSequenceType(sequenceType, actionRelatives.PreviousActions, relativeActions.PreviousActions); this.RecurseRelativeActionsForSequenceType(sequenceType, actionRelatives.NextActions, relativeActions.NextActions); } return(relativeActions); }
/// <summary> /// Try to get standard action by sequence and action name. /// </summary> public static bool TryGetStandardAction(string sequenceName, string actioname, out WixActionSymbol standardAction) => standardActionsById.TryGetValue(String.Concat(sequenceName, "/", actioname), out standardAction);
/// <summary> /// Try to get standard action by id. /// </summary> public static bool TryGetStandardAction(string id, out WixActionSymbol standardAction) => standardActionsById.TryGetValue(id, out standardAction);