diff --git a/src/python/jw/pkg/App.py b/src/python/jw/pkg/App.py index 7abc3040..c12bbaba 100644 --- a/src/python/jw/pkg/App.py +++ b/src/python/jw/pkg/App.py @@ -232,18 +232,17 @@ class App(Base): for project in projects: if project in graph: continue - for section in sections: - deps = self.get_project_refs( - [project], - ['pkg.requires.jw'], - sections, - scope = Scope.One, - add_self = False, - names_only = True, - ) - graph[project] = set(deps) - for dep in deps: - self.__read_dep_graph([dep], sections, graph) + deps = self.get_project_refs( + [project], + ['pkg.requires.jw'], + sections, + scope = Scope.One, + add_self = False, + names_only = True, + ) + graph[project] = set(deps) + for dep in deps: + self.__read_dep_graph([dep], sections, graph) def __flip_dep_graph(self, graph: Graph) -> Graph: ret: Graph = {} @@ -259,45 +258,43 @@ class App(Base): project: str, graph: Graph, unvisited: list[str], - temp: set[str], - path: list[str], - ) -> str | None: - if project in temp: + stack: list[str], + ) -> list[str] | None: + if project in stack: log(DEBUG, 'found circular dependency at project', project) - return project + idx = stack.index(project) + return stack[idx:] + [project] if project not in unvisited: return None - temp.add(project) + stack.append(project) if project in graph: for dep in graph[project]: - last = self.__find_circular_deps_recursive( - dep, graph, unvisited, temp, path + cycle = self.__find_circular_deps_recursive( + dep, graph, unvisited, stack ) - if last is not None: - path.insert(0, dep) - return last + if cycle is not None: + return cycle unvisited.remove(project) - temp.remove(project) + stack.pop() return None def __find_circular_deps(self, projects: list[str], flavours: list[str]) -> list[str]: graph: Graph = {} - ret: list[str] = [] self.__read_dep_graph(projects, flavours, graph) unvisited = list(graph.keys()) - temp: set[str] = set() flipped = self.__flip_dep_graph(graph) while unvisited: project = unvisited[0] log(DEBUG, 'Checking circular dependency of', project) - last = self.__find_circular_deps_recursive( - project, flipped, unvisited, temp, ret - ) - if last is not None: - log(DEBUG, f'Found circular dependency below {project}, last is {last}') - ret.append(last) - return ret + cycle = self.__find_circular_deps_recursive(project, flipped, unvisited, []) + if cycle is not None: + # An edge a -> b in the flipped graph means that b + # depends on a, so reverse to report the cycle in the + # original direction + cycle = list(reversed(cycle)) + log(DEBUG, f'Found circular dependency: {" -> ".join(cycle)}') + return cycle return [] def __init__(self, distro: Distro | None = None) -> None: