mach-nix/mach_nix/resolver/resolvelib_resolver.py

95 lines
3.9 KiB
Python
Raw Normal View History

2020-04-22 09:28:58 +00:00
from typing import Iterable, List
import resolvelib
2020-08-08 09:59:55 +00:00
from mach_nix.data.nixpkgs import NixpkgsIndex
2020-10-25 18:09:37 +00:00
from mach_nix.data.providers import DependencyProviderBase, Candidate
from mach_nix.deptree import remove_circles_and_print
from mach_nix.requirements import Requirement, filter_versions
2020-04-22 09:28:58 +00:00
from mach_nix.resolver import Resolver, ResolvedPkg
# Implement logic so the resolver understands the requirement format.
class Provider(resolvelib.providers.AbstractProvider):
2020-08-08 09:59:55 +00:00
def __init__(self, nixpkgs: NixpkgsIndex, deps_db: DependencyProviderBase):
2020-04-22 09:28:58 +00:00
self.nixpkgs = nixpkgs
2020-10-25 18:09:37 +00:00
self.provider = deps_db
2020-04-22 09:28:58 +00:00
def get_extras_for(self, dependency):
2020-11-17 11:29:44 +00:00
# return selected extras
return tuple(sorted(dependency.selected_extras))
2020-04-22 09:28:58 +00:00
def get_base_requirement(self, candidate):
return Requirement("{}=={}".format(candidate.name, candidate.ver))
2022-02-09 19:55:25 +00:00
def identify(self, requirement_or_candidate):
return requirement_or_candidate.name
2020-04-22 09:28:58 +00:00
2022-02-09 20:09:18 +00:00
def get_preference(
self, identifier, resolutions, candidates, information, backtrack_causes
):
# This logic could be improved, for example to prefer the cause of backtracking.
# See https://github.com/pypa/pip/blob/main/src/pip/_internal/resolution/resolvelib/provider.py
# for the implementation in pip.
return sum(1 for _ in candidates[identifier])
2020-04-22 09:28:58 +00:00
2022-02-09 19:55:25 +00:00
def find_matches(self, identifier, requirements, incompatibilities):
return [
candidate
for candidate in self.provider.find_matches(list(requirements[identifier]))
if candidate not in incompatibilities.get(identifier, ())
]
2020-04-22 09:28:58 +00:00
2020-10-25 18:09:37 +00:00
def is_satisfied_by(self, requirement, candidate: Candidate):
res = bool(len(list(filter_versions([candidate.ver], requirement))))
2020-10-25 18:09:37 +00:00
return res
2020-04-22 09:28:58 +00:00
def get_dependencies(self, candidate):
2020-10-25 18:09:37 +00:00
install_requires, setup_requires = self.provider.get_pkg_reqs(candidate)
if install_requires is None:
install_requires = []
if setup_requires is None:
setup_requires = []
2020-04-22 09:28:58 +00:00
deps = install_requires + setup_requires
return deps
class ResolvelibResolver(Resolver):
2020-08-08 09:59:55 +00:00
def __init__(self, nixpkgs: NixpkgsIndex, deps_provider: DependencyProviderBase):
2020-04-22 09:28:58 +00:00
self.nixpkgs = nixpkgs
self.deps_provider = deps_provider
2020-04-22 09:28:58 +00:00
def resolve(self, reqs: Iterable[Requirement]) -> List[ResolvedPkg]:
2020-04-22 09:28:58 +00:00
reporter = resolvelib.BaseReporter()
result = resolvelib.Resolver(Provider(self.nixpkgs, self.deps_provider), reporter).resolve(reqs, max_rounds=1000)
2020-04-22 09:28:58 +00:00
nix_py_pkgs = []
for name in result.graph._forwards.keys():
2020-11-20 17:38:51 +00:00
if name is None or name.startswith('-'):
2020-04-22 09:28:58 +00:00
continue
candidate = result.mapping[name]
ver = candidate.ver
install_requires, setup_requires = self.deps_provider.get_pkg_reqs(candidate)
build_inputs, prop_build_inputs = None, None
if install_requires is not None:
prop_build_inputs = list(filter(
lambda name: not name.startswith('-'),
list({req.key for req in install_requires})))
if setup_requires is not None:
build_inputs = list(filter(
lambda name: not name.startswith('-'),
list({req.key for req in setup_requires})))
2020-04-22 09:28:58 +00:00
is_root = name in result.graph._forwards[None]
nix_py_pkgs.append(ResolvedPkg(
name=name,
ver=ver,
raw_version=candidate.raw_version,
2020-04-22 09:28:58 +00:00
build_inputs=build_inputs,
prop_build_inputs=prop_build_inputs,
is_root=is_root,
provider_info=candidate.provider_info,
2020-11-17 11:29:44 +00:00
extras_selected=list(result.mapping[name].selected_extras),
build=candidate.build
2020-04-22 09:28:58 +00:00
))
remove_circles_and_print(nix_py_pkgs, self.nixpkgs)
2020-04-22 09:28:58 +00:00
return nix_py_pkgs