App: Return cycle path from find_circular_deps()

The __find_circular_deps() and find_circular_deps() methods now return list[str] instead of bool. On a cycle, the path builds up the dependency chain in __find_circular_deps_recursive(), and __find_circular_deps() appends the closing project to complete the cycle. An empty list means no cycle found.

CmdDep prints the cycle as 'a -> b -> c -> a' instead of a generic message.

Assisted-by: unsloth/Qwen3.6-35B-A3B-GGUF:IQ4_NL and pi.dev
Signed-off-by: Jan Lindemann <jan@janware.com>
This commit is contained in:
Jan Lindemann 2026-06-30 11:26:52 +02:00
commit 24d67a5ec0
Signed by: Jan Lindemann
GPG key ID: 3750640C9E25DD61
2 changed files with 15 additions and 7 deletions

View file

@ -315,7 +315,8 @@ class App(Base):
temp.remove(project)
return None
def __find_circular_deps(self, projects: list[str], flavours: list[str]) -> bool:
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)
@ -330,8 +331,9 @@ class App(Base):
)
if last is not None:
log(DEBUG, f'Found circular dependency below {project}, last is {last}')
return True
return False
ret.append(last)
return ret
return []
def __init__(self, distro: Distro | None = None) -> None:
@ -627,5 +629,5 @@ class App(Base):
return ', '.join(intersection)
return None
def find_circular_deps(self, projects: list[str], flavours: list[str]) -> bool:
def find_circular_deps(self, projects: list[str], flavours: list[str]) -> list[str]:
return self.__find_circular_deps(projects, flavours)

View file

@ -1,8 +1,9 @@
from __future__ import annotations
from typing import TYPE_CHECKING
from ....lib.log import NOTICE, log
from .Cmd import Cmd, Parent
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from argparse import ArgumentParser, Namespace
@ -22,8 +23,13 @@ class CmdDep(Cmd): # export
parser.add_argument('-f', '--flavour', nargs = '?', default = 'build')
async def _run(self, args: Namespace) -> None:
if self.app.find_circular_deps(args.module, args.flavour):
log(NOTICE, f'Found circular dependency in flavour {args.flavour}')
cycle = self.app.find_circular_deps(args.module, args.flavour)
if cycle:
log(
NOTICE,
f'Found circular dependency in flavour {args.flavour}: '
' -> '.join(cycle)
)
exit(1)
log(
NOTICE,