diff options
Diffstat (limited to 'nixpkgs/pkgs/development/interpreters/python/catch_conflicts/catch_conflicts.py')
-rw-r--r-- | nixpkgs/pkgs/development/interpreters/python/catch_conflicts/catch_conflicts.py | 73 |
1 files changed, 61 insertions, 12 deletions
diff --git a/nixpkgs/pkgs/development/interpreters/python/catch_conflicts/catch_conflicts.py b/nixpkgs/pkgs/development/interpreters/python/catch_conflicts/catch_conflicts.py index d5c99e64751c..d4219192790b 100644 --- a/nixpkgs/pkgs/development/interpreters/python/catch_conflicts/catch_conflicts.py +++ b/nixpkgs/pkgs/development/interpreters/python/catch_conflicts/catch_conflicts.py @@ -2,28 +2,77 @@ from importlib.metadata import PathDistribution from pathlib import Path import collections import sys +import os +from typing import Dict, List, Tuple +do_abort: bool = False +packages: Dict[str, Dict[str, List[Dict[str, List[str]]]]] = collections.defaultdict(list) +out_path: Path = Path(os.getenv("out")) +version: Tuple[int, int] = sys.version_info +site_packages_path: str = f'lib/python{version[0]}.{version[1]}/site-packages' -do_abort = False -packages = collections.defaultdict(list) +def get_name(dist: PathDistribution) -> str: + return dist.metadata['name'].lower().replace('-', '_') -for path in sys.path: - for dist_info in Path(path).glob("*.dist-info"): - dist = PathDistribution(dist_info) +# pretty print a package +def describe_package(dist: PathDistribution) -> str: + return f"{get_name(dist)} {dist.version} ({dist._path})" - packages[dist._normalized_name].append( - f"{dist._normalized_name} {dist.version} ({dist._path})" - ) +# pretty print a list of parents (dependency chain) +def describe_parents(parents: List[str]) -> str: + if not parents: + return "" + return \ + f" dependency chain:\n " \ + + str(f"\n ...depending on: ".join(parents)) -for name, duplicates in packages.items(): - if len(duplicates) > 1: + +# inserts an entry into 'packages' +def add_entry(name: str, version: str, store_path: str, parents: List[str]) -> None: + if name not in packages: + packages[name] = {} + if store_path not in packages[name]: + packages[name][store_path] = [] + packages[name][store_path].append(dict( + version=version, + parents=parents, + )) + + +# transitively discover python dependencies and store them in 'packages' +def find_packages(store_path: Path, site_packages_path: str, parents: List[str]) -> None: + site_packages: Path = (store_path / site_packages_path) + propagated_build_inputs: Path = (store_path / "nix-support/propagated-build-inputs") + + # add the current package to the list + if site_packages.exists(): + for dist_info in site_packages.glob("*.dist-info"): + dist: PathDistribution = PathDistribution(dist_info) + add_entry(get_name(dist), dist.version, store_path, parents) + + # recursively add dependencies + if propagated_build_inputs.exists(): + with open(propagated_build_inputs, "r") as f: + build_inputs: List[str] = f.read().strip().split(" ") + for build_input in build_inputs: + find_packages(Path(build_input), site_packages_path, parents + [build_input]) + + +find_packages(out_path, site_packages_path, [f"this derivation: {out_path}"]) + +# print all duplicates +for name, store_paths in packages.items(): + if len(store_paths) > 1: do_abort = True print("Found duplicated packages in closure for dependency '{}': ".format(name)) - for duplicate in duplicates: - print(f"\t{duplicate}") + for store_path, candidates in store_paths.items(): + for candidate in candidates: + print(f" {name} {candidate['version']} ({store_path})") + print(describe_parents(candidate['parents'])) +# fail if duplicates were found if do_abort: print("") print( |