python/catch_conflicts: scan $out, not sys.path

This changes the non-legacy version of pythonCatchConflictsHook
to recursively scan the output of the target derivation  as well
as its propagatedBuildInputs for duplicate dependencies.

Previously, we did scan sys.path but did prove problematic as it
produced false positives i.e. when build-time dependencies of
hooks - such as setuptools in pythonCatchConflictsHook itself -
where mistakenly flagged as duplicates; even though the are
not included in the outputs of the target dervation.

As all python runtime-dependencies are currently passed via
propagatedBuildInputs in nixpkgs, scanning that plus
site-packages seems sufficient to catch all conflicts that
matter at runtime and less likely to produce false positives.

The legacyHook in catch_conflicts_py2.py needs to be migrated
as well, if it's still needed.
This commit is contained in:
phaer 2024-01-26 18:24:26 +01:00 committed by DavHau
parent b8ec2cc99b
commit 2651ddc7b0

View File

@ -2,21 +2,35 @@ from importlib.metadata import PathDistribution
from pathlib import Path
import collections
import sys
import os
do_abort = False
packages = collections.defaultdict(list)
out_path = Path(os.getenv("out"))
version = sys.version_info
site_packages_path = f'lib/python{version[0]}.{version[1]}/site-packages'
for path in sys.path:
for dist_info in Path(path).glob("*.dist-info"):
dist = PathDistribution(dist_info)
def find_packages(store_path, site_packages_path):
site_packages = (store_path / site_packages_path)
propagated_build_inputs = (store_path / "nix-support/propagated-build-inputs")
if site_packages.exists():
for dist_info in site_packages.glob("*.dist-info"):
dist = PathDistribution(dist_info)
packages[dist._normalized_name].append(
f"{dist._normalized_name} {dist.version} ({dist._path})"
)
packages[dist._normalized_name].append(
f"{dist._normalized_name} {dist.version} ({dist._path})"
)
if propagated_build_inputs.exists():
with open(propagated_build_inputs, "r") as f:
build_inputs = f.read().strip().split(" ")
for build_input in build_inputs:
find_packages(Path(build_input), site_packages_path)
find_packages(out_path, site_packages_path)
for name, duplicates in packages.items():
if len(duplicates) > 1:
do_abort = True