diff --git a/src/python/jw/pkg/App.py b/src/python/jw/pkg/App.py index 1e1a5d3b..c12bbaba 100644 --- a/src/python/jw/pkg/App.py +++ b/src/python/jw/pkg/App.py @@ -258,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: