/// <summary> /// Expand (recursively) set of active targets to include targets which reference any /// of the active targets with BeforeTarget or AfterTarget. /// </summary> /// <param name="projectInstance">An MSBuild Project instance to use for context.</param> /// <param name="activeTargets"> /// Set of active targets. Will be modified in place to add targets that reference this /// graph with BeforeTarget or AfterTarget. /// </param> public static void AddBeforeAndAfterTargets(this ProjectInstance projectInstance, Dictionary <string, ProjectTargetInstance> activeTargets) { var newTargetsToConsider = true; while (newTargetsToConsider) { newTargetsToConsider = false; foreach (KeyValuePair <string, ProjectTargetInstance> pair in projectInstance.Targets) { string targetName = pair.Key; ProjectTargetInstance targetInstance = pair.Value; // If the target is not already in our list of active targets ... if (!activeTargets.ContainsKey(targetName)) { IEnumerable <string> hookedTargets = projectInstance.EvaluateValue(targetInstance.AfterTargets) .Concat(projectInstance.EvaluateValue(targetInstance.BeforeTargets)); foreach (string hookedTarget in hookedTargets) { // ... and it hooks a running target with BeforeTargets/AfterTargets ... if (activeTargets.ContainsKey(hookedTarget)) { // ... then add it to the list of running targets ... projectInstance.AddToActiveTargets(targetName, activeTargets); // ... and make a note to run again, since activeTargets has changed. newTargetsToConsider = true; } } } } } }
/// <summary> /// Given a target name, gets set of targets that are to be executed, /// for the provided target name and all targets that those depend on. /// </summary> /// <param name="projectInstance">An MSBuild Project instance to use for context.</param> /// <param name="evaluatedTargetName">Evaluated target name that we should analyze.</param> /// <param name="activeTargets">Collection into which targets should be added.</param> public static void AddToActiveTargets( this ProjectInstance projectInstance, string evaluatedTargetName, Dictionary <string, ProjectTargetInstance> activeTargets) { // Avoid circular dependencies if (activeTargets.ContainsKey(evaluatedTargetName)) { return; } // The Project or its includes might not actually include the target name. if (projectInstance.Targets.TryGetValue(evaluatedTargetName, out ProjectTargetInstance target)) { activeTargets.Add(evaluatedTargetName, target); // Parse all parent targets that current target depends on. var dependsOnTargets = projectInstance.EvaluateValue(target.DependsOnTargets); foreach (string dependsOnTarget in dependsOnTargets) { AddToActiveTargets(projectInstance, dependsOnTarget, activeTargets); } } }