diff --git a/fablib/plan.py b/fablib/plan.py index 96f0218..0a32d81 100644 --- a/fablib/plan.py +++ b/fablib/plan.py @@ -352,7 +352,7 @@ def dctrls(self) -> dict[Dependency, deb822.Deb822]: return dctrls - def resolve(self) -> tuple[Iterable[str], Iterable[str]]: + def resolve(self, bootstrap_provided: set[str] | None = None) -> tuple[Iterable[str], Iterable[str]]: """resolve plan dependencies recursively -> return spec""" logger.debug("resolve") @@ -364,7 +364,7 @@ def resolve(self) -> tuple[Iterable[str], Iterable[str]]: resolved: set[Dependency] = set() missing: set[Dependency] = set() - provided: set[str] = set() + provided: set[str] = set(bootstrap_provided or set()) def reformat2dep(pkg: str) -> str: if "=" not in pkg: @@ -402,8 +402,10 @@ def reformat2dep(pkg: str) -> str: ) provided |= self._get_provided(pkg_control) + missing |= packages.missing unresolved = new_deps - resolved - all_missing = set(map(str, (missing | packages.missing))) - provided + + all_missing = set(map(str, missing)) - provided if all_missing: @@ -417,9 +419,7 @@ def get_origins(dep: Dependency) -> Generator[str, None, None]: except KeyError: depname = None - brokendeps = [] - for dep in missing: - brokendeps.append(dep.name) + brokendeps = [dep.name for dep in missing if str(dep) in all_missing] logger.debug( f"could not find these packages in pool: {brokendeps!r}" diff --git a/fablib/resolve.py b/fablib/resolve.py index fd61175..09ea3c4 100644 --- a/fablib/resolve.py +++ b/fablib/resolve.py @@ -7,6 +7,8 @@ from .plan import PackageOrigins, Plan +import re + logger = logging.getLogger("fab.resolve") @@ -23,6 +25,25 @@ def iter_packages(root: str) -> Generator[str, None, None]: control += line +def iter_provided(root: str) -> Generator[str, None, None]: + """Yield virtual package names provided by installed bootstrap packages.""" + control = "" + with open(join(root, "var/lib/dpkg/status")) as fob: + for line in fob: + if not line.strip(): + deb = Deb822(control.splitlines()) + if deb["Status"] == "install ok installed": + provides = deb.get("Provides", "") + if provides: + for p in re.split(r"\s*,\s*", provides.strip()): + name = p.split()[0].strip() + if name: + yield name + control = "" + else: + control += line + + def annotate_spec( repo_spec: Iterable[str], pool_spec: Iterable[str], @@ -54,8 +75,10 @@ def resolve_plan( plans: list[str], ) -> None: plan = Plan(pool_path=pool_path) + bootstrap_provided: set[str] = set() if bootstrap_path: bootstrap_packages = set(iter_packages(bootstrap_path)) + bootstrap_provided = set(iter_provided(bootstrap_path)) plan |= bootstrap_packages for package in bootstrap_packages: @@ -72,7 +95,7 @@ def resolve_plan( plan.add(plan_path) plan.packageorigins.add(plan_path, "_") - spec, unresolved = plan.resolve() + spec, unresolved = plan.resolve(bootstrap_provided=bootstrap_provided) logger.debug("unresolved" + "\n".join(unresolved)) spec = annotate_spec(unresolved, spec, plan.packageorigins) logger.debug(spec)