Skip to content

Commit 0d6987d

Browse files
committed
feat: topologically sort generated modules based on dependencies
1 parent ea92dc2 commit 0d6987d

File tree

1 file changed

+43
-3
lines changed

1 file changed

+43
-3
lines changed

pip/flatpak-pip-generator.py

Lines changed: 43 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,11 @@
3535
'Requirements module is not installed. Run "pip install requirements-parser"'
3636
)
3737

38+
try:
39+
import graphlib
40+
except ImportError:
41+
sys.exit("This script requires Python 3.9 or higher for graphlib support.")
42+
3843
parser = argparse.ArgumentParser()
3944
parser.add_argument("packages", nargs="*")
4045
parser.add_argument(
@@ -425,9 +430,10 @@ def get_flatpak_runtime_scope(runtime: str) -> str:
425430
if not output_filename.endswith(suffix):
426431
output_filename += suffix
427432

428-
modules: list[dict[str, str | list[str] | list[dict[str, Any]]]] = []
429-
vcs_modules: list[dict[str, str | list[str] | list[dict[str, Any]]]] = []
430-
sources = {}
433+
modules: list[dict[str, Any]] = []
434+
vcs_modules: list[dict[str, Any]] = []
435+
sources: dict[str, Any] = {}
436+
dependency_graph: dict[str, set[str]] = {}
431437

432438
unresolved_dependencies_errors = []
433439

@@ -558,6 +564,10 @@ def get_flatpak_runtime_scope(runtime: str) -> str:
558564
]
559565

560566
fprint("Generating dependencies")
567+
568+
# Build dependency graph
569+
modules_map: dict[str, dict[str, Any]] = {}
570+
561571
for package in packages:
562572
if package.name is None:
563573
print(
@@ -625,8 +635,18 @@ def get_flatpak_runtime_scope(runtime: str) -> str:
625635

626636
is_vcs = bool(package.vcs)
627637
package_sources = []
638+
639+
# Add to dependency graph
640+
package_name_key = package.name.casefold()
641+
dependency_graph[package_name_key] = set()
642+
628643
for dependency in dependencies:
629644
casefolded = dependency.casefold()
645+
646+
# Add dependency to graph (ignore self-dependencies)
647+
if casefolded != package_name_key:
648+
dependency_graph[package_name_key].add(casefolded)
649+
630650
if casefolded in sources and sources[casefolded].get("pypi") is True:
631651
source = sources[casefolded]
632652
elif dependency in sources and sources[dependency].get("pypi") is False:
@@ -684,6 +704,26 @@ def get_flatpak_runtime_scope(runtime: str) -> str:
684704
if package.vcs:
685705
vcs_modules.append(module)
686706
else:
707+
# Store module for sorting later
708+
modules_map[package_name_key] = module
709+
710+
# Topological Sort
711+
ts = graphlib.TopologicalSorter(dependency_graph)
712+
try:
713+
sorted_nodes = list(ts.static_order())
714+
except graphlib.CycleError as cycle_error:
715+
print(f"Dependency cycle detected: {cycle_error}. Falling back to input order.")
716+
sorted_nodes = list(modules_map.keys())
717+
718+
# Reconstruct modules list based on sorted order
719+
# Only include modules that were actually processed (present in modules_map)
720+
for node in sorted_nodes:
721+
if node in modules_map:
722+
modules.append(modules_map[node])
723+
724+
# Add any modules that might have been missed
725+
for name, module in modules_map.items():
726+
if module not in modules:
687727
modules.append(module)
688728

689729
modules = vcs_modules + modules

0 commit comments

Comments
 (0)