def _topological_sort(self, phase_info_by_phase): dependees_by_phase = OrderedDict() def add_dependee(phase, dependee=None): dependees = dependees_by_phase.get(phase) if dependees is None: dependees = set() dependees_by_phase[phase] = dependees if dependee: dependees.add(dependee) for phase, phase_info in phase_info_by_phase.items(): add_dependee(phase) for dependency in phase_info.phase_dependencies: add_dependee(dependency, phase) satisfied = set() while dependees_by_phase: count = len(dependees_by_phase) for phase, dependees in dependees_by_phase.items(): unsatisfied = len(dependees - satisfied) if unsatisfied == 0: satisfied.add(phase) dependees_by_phase.pop(phase) yield phase_info_by_phase[phase] break if len(dependees_by_phase) == count: for dependees in dependees_by_phase.values(): dependees.difference_update(satisfied) # TODO(John Sirois): Do a better job here and actually collect and print cycle paths # between Goals/Tasks. The developer can most directly address that data. raise self.PhaseCycleError('Cycle detected in phase dependencies:\n\t{0}' .format('\n\t'.join('{0} <- {1}'.format(phase, list(dependees)) for phase, dependees in dependees_by_phase.items())))
def _topological_sort(self, goal_info_by_goal): dependees_by_goal = OrderedDict() def add_dependee(goal, dependee=None): dependees = dependees_by_goal.get(goal) if dependees is None: dependees = set() dependees_by_goal[goal] = dependees if dependee: dependees.add(dependee) for goal, goal_info in goal_info_by_goal.items(): add_dependee(goal) for dependency in goal_info.goal_dependencies: add_dependee(dependency, goal) satisfied = set() while dependees_by_goal: count = len(dependees_by_goal) for goal, dependees in dependees_by_goal.items(): unsatisfied = len(dependees - satisfied) if unsatisfied == 0: satisfied.add(goal) dependees_by_goal.pop(goal) yield goal_info_by_goal[goal] break if len(dependees_by_goal) == count: for dependees in dependees_by_goal.values(): dependees.difference_update(satisfied) # TODO(John Sirois): Do a better job here and actually collect and print cycle paths # between Goals/Tasks. The developer can most directly address that data. raise self.GoalCycleError('Cycle detected in goal dependencies:\n\t{0}' .format('\n\t'.join('{0} <- {1}'.format(goal, list(dependees)) for goal, dependees in dependees_by_goal.items())))