Skip to content

Commit e99fc34

Browse files
committed
[wip] another work, integrate SLOTs
Signed-off-by: Arthur Zamarin <[email protected]>
1 parent db2ce25 commit e99fc34

File tree

1 file changed

+45
-32
lines changed

1 file changed

+45
-32
lines changed

src/pkgcheck/checks/visibility.py

Lines changed: 45 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
from collections import defaultdict
2+
from itertools import groupby
23
from operator import attrgetter
34

45
from pkgcore.ebuild.atom import atom, transitive_use_atom
@@ -487,52 +488,64 @@ def __init__(self, options, **kwargs):
487488
self.repo = self.options.target_repo
488489
self.no_cycle = set()
489490

490-
def _verify_dfs(self, key: str, path: list[str], visited: set[str]):
491-
if key in path:
492-
path.append(key)
493-
return path
494-
assert key in self.visited_packages
491+
def find_cycle(self, start_key: str):
492+
path: list[str] = []
493+
visited: set[str] = set()
495494

496-
visited.add(key)
497-
path.append(key)
498-
for dep in self.visited_packages[key] - self.no_cycle:
499-
if cycle := self._verify_dfs(dep, path, visited):
500-
return cycle
501-
path.pop()
502-
self.no_cycle.add(key)
503-
return []
495+
def dfs(node):
496+
visited.add(node)
497+
path.append(node)
504498

505-
def _collect_deps_graph(self, pkgset):
506-
key = pkgset[0].key
499+
for neighbor in sorted(self.visited_packages[node] - self.no_cycle):
500+
if neighbor not in visited:
501+
if result := dfs(neighbor):
502+
return result
503+
elif neighbor in path and neighbor == start_key:
504+
# Found a cycle that ends at the start node
505+
idx = path.index(start_key)
506+
return path[idx:] + [start_key]
507507

508-
if key in self.visited_packages:
509-
return
508+
path.pop()
509+
self.no_cycle.add(node)
510+
return None
511+
512+
return dfs(start_key)
510513

514+
def _collect_deps_graph(self, key: str, pkgset):
511515
pkg_deps = {
512-
pkg: {dep.key for dep in pkg.rdepend if isinstance(dep, atom) and not dep.blocks}
516+
pkg: {
517+
f"{dep.key}:{dep.slot}" if dep.slot is not None else dep.key
518+
for dep in pkg.rdepend
519+
if isinstance(dep, atom) and not dep.blocks
520+
}
513521
for pkg in pkgset
514522
}
523+
524+
if key in self.visited_packages:
525+
return pkg_deps
526+
515527
self.visited_packages[key] = all_deps = frozenset().union(*pkg_deps.values())
516528
if missing := all_deps - self.visited_packages.keys():
517529
for missing_key in missing:
518530
try:
519-
self._collect_deps_graph(self.repo.match(atom(missing_key)))
520-
except IndexError:
531+
self._collect_deps_graph(missing_key, self.repo.match(atom(missing_key)))
532+
except IndexError: # NonexistentDeps, invalid dep
521533
self.visited_packages[missing_key] = frozenset()
522534
return pkg_deps
523535

524-
def feed(self, pkgset):
525-
key = pkgset[0].key
536+
def _collect_graph_variants(self, pkgset):
537+
self._collect_deps_graph(key := pkgset[0].key, pkgset)
538+
yield key, pkgset
526539

527-
if key in self.visited_packages:
528-
pkg_deps = {
529-
pkg: {dep.key for dep in pkg.rdepend if isinstance(dep, atom) and not dep.blocks}
530-
for pkg in pkgset
531-
}
532-
else:
533-
pkg_deps = self._collect_deps_graph(pkgset)
540+
def key_func(x):
541+
return f"{x.key}:{x.slot}"
542+
543+
for key, pkgs in groupby(sorted(pkgset, key=key_func), key_func):
544+
self._collect_deps_graph(key, pkgs)
545+
yield key, pkgs
534546

535-
for pkg in pkgset:
536-
for dep in pkg_deps[pkg]:
537-
if (cycle := self._verify_dfs(dep, [key], set())) and cycle[-1] == key:
547+
def feed(self, pkgset):
548+
for key, pkg_deps in self._collect_graph_variants(pkgset):
549+
if (cycle := self.find_cycle(key)) and cycle[-1] == key:
550+
for pkg in pkg_deps:
538551
yield RdependCycle(cycle, pkg=pkg)

0 commit comments

Comments
 (0)