More fixes.
This commit is contained in:
parent
aa2a3e47fa
commit
6b30479b97
9 changed files with 499 additions and 320 deletions
|
@ -34,20 +34,109 @@ class Resolver(object):
|
|||
raise NotImplementedError(self.met)
|
||||
|
||||
|
||||
class NativeResolver(Resolver):
|
||||
class CPANResolver(object):
|
||||
|
||||
def __init__(self, session):
|
||||
self.session = session
|
||||
|
||||
@classmethod
|
||||
def from_session(cls, session):
|
||||
return cls(session)
|
||||
|
||||
def install(self, requirements):
|
||||
raise NotImplementedError(self.install)
|
||||
from ..requirements import PerlModuleRequirement
|
||||
missing = []
|
||||
for requirement in requirements:
|
||||
if not isinstance(requirement, PerlModuleRequirement):
|
||||
missing.append(requirement)
|
||||
continue
|
||||
# TODO(jelmer): Specify -T to skip tests?
|
||||
self.session.check_call(
|
||||
["cpan", "-i", requirement.module],
|
||||
user="root", env={"PERL_MM_USE_DEFAULT": "1"}
|
||||
)
|
||||
if missing:
|
||||
raise MissingDependencies(missing)
|
||||
|
||||
def explain(self, requirements):
|
||||
raise NotImplementedError(self.explain)
|
||||
|
||||
def met(self, requirement):
|
||||
raise NotImplementedError(self.met)
|
||||
|
||||
|
||||
class PypiResolver(object):
|
||||
|
||||
def __init__(self, session):
|
||||
self.session = session
|
||||
|
||||
def install(self, requirements):
|
||||
from ..requirements import PythonPackageRequirement
|
||||
missing = []
|
||||
for requirement in requirements:
|
||||
if not isinstance(requirement, PythonPackageRequirement):
|
||||
missing.append(requirement)
|
||||
continue
|
||||
self.session.check_call(["pip", "install", requirement.package])
|
||||
if missing:
|
||||
raise MissingDependencies(missing)
|
||||
|
||||
def explain(self, requirements):
|
||||
raise NotImplementedError(self.explain)
|
||||
|
||||
def met(self, requirement):
|
||||
raise NotImplementedError(self.met)
|
||||
|
||||
|
||||
NPM_COMMAND_PACKAGES = {
|
||||
"del-cli": "del-cli",
|
||||
}
|
||||
|
||||
|
||||
class NpmResolver(object):
|
||||
|
||||
def __init__(self, session):
|
||||
self.session = session
|
||||
|
||||
def install(self, requirements):
|
||||
from ..requirements import NodePackageRequirement
|
||||
missing = []
|
||||
for requirement in requirements:
|
||||
if not isinstance(requirement, NodePackageRequirement):
|
||||
missing.append(requirement)
|
||||
continue
|
||||
try:
|
||||
package = NPM_COMMAND_PACKAGES[requirement.command]
|
||||
except KeyError:
|
||||
missing.append(requirement)
|
||||
continue
|
||||
self.session.check_call(["npm", "-g", "install", package])
|
||||
if missing:
|
||||
raise MissingDependencies(missing)
|
||||
|
||||
def explain(self, requirements):
|
||||
raise NotImplementedError(self.explain)
|
||||
|
||||
def met(self, requirement):
|
||||
raise NotImplementedError(self.met)
|
||||
|
||||
|
||||
class StackedResolver(Resolver):
|
||||
def __init__(self, subs):
|
||||
self.subs = subs
|
||||
|
||||
def install(self, requirements):
|
||||
for sub in self.subs:
|
||||
try:
|
||||
sub.install(requirements)
|
||||
except MissingDependencies as e:
|
||||
requirements = e.requirements
|
||||
else:
|
||||
return
|
||||
|
||||
|
||||
def native_resolvers(session):
|
||||
return StackedResolver([
|
||||
CPANResolver(session),
|
||||
PypiResolver(session),
|
||||
NpmResolver(session)])
|
||||
|
||||
|
||||
class ExplainResolver(Resolver):
|
||||
def __init__(self, session):
|
||||
|
|
|
@ -21,7 +21,7 @@ import posixpath
|
|||
|
||||
from ..debian.apt import AptManager
|
||||
|
||||
from . import Resolver
|
||||
from . import Resolver, MissingDependencies
|
||||
from ..requirements import (
|
||||
BinaryRequirement,
|
||||
CHeaderRequirement,
|
||||
|
@ -57,24 +57,35 @@ class NoAptPackage(Exception):
|
|||
"""No apt package."""
|
||||
|
||||
|
||||
class AptRequirement(object):
|
||||
|
||||
def __init__(self, package, minimum_version=None):
|
||||
self.package = package
|
||||
self.minimum_version = minimum_version
|
||||
|
||||
|
||||
def get_package_for_python_package(apt_mgr, package, python_version, minimum_version=None):
|
||||
if python_version == "pypy":
|
||||
return apt_mgr.get_package_for_paths(
|
||||
pkg_name = apt_mgr.get_package_for_paths(
|
||||
["/usr/lib/pypy/dist-packages/%s-.*.egg-info/PKG-INFO" % package],
|
||||
regex=True)
|
||||
elif python_version == "cpython2":
|
||||
return apt_mgr.get_package_for_paths(
|
||||
pkg_name = apt_mgr.get_package_for_paths(
|
||||
["/usr/lib/python2\\.[0-9]/dist-packages/%s-.*.egg-info/PKG-INFO" % package],
|
||||
regex=True)
|
||||
elif python_version == "cpython3":
|
||||
return apt_mgr.get_package_for_paths(
|
||||
pkg_name = apt_mgr.get_package_for_paths(
|
||||
["/usr/lib/python3/dist-packages/%s-.*.egg-info/PKG-INFO" % package],
|
||||
regex=True)
|
||||
else:
|
||||
raise NotImplementedError
|
||||
# TODO(jelmer): Dealing with epoch, etc?
|
||||
if pkg_name is not None:
|
||||
return AptRequirement(pkg_name, minimum_version)
|
||||
return None
|
||||
|
||||
|
||||
def get_package_for_python_module(apt_mgr, module, python_version):
|
||||
def get_package_for_python_module(apt_mgr, module, python_version, minimum_version):
|
||||
if python_version == "python3":
|
||||
paths = [
|
||||
posixpath.join(
|
||||
|
@ -127,7 +138,10 @@ def get_package_for_python_module(apt_mgr, module, python_version):
|
|||
]
|
||||
else:
|
||||
raise AssertionError("unknown python version %r" % python_version)
|
||||
return apt_mgr.get_package_for_paths(paths, regex=True)
|
||||
pkg_name = apt_mgr.get_package_for_paths(paths, regex=True)
|
||||
if pkg_name is not None:
|
||||
return AptRequirement(pkg_name, minimum_version=minimum_version)
|
||||
return None
|
||||
|
||||
|
||||
def resolve_binary_req(apt_mgr, req):
|
||||
|
@ -138,7 +152,10 @@ def resolve_binary_req(apt_mgr, req):
|
|||
posixpath.join(dirname, req.binary_name)
|
||||
for dirname in ["/usr/bin", "/bin"]
|
||||
]
|
||||
return apt_mgr.get_package_for_paths(paths)
|
||||
pkg_name = apt_mgr.get_package_for_paths(paths)
|
||||
if pkg_name is not None:
|
||||
return AptRequirement(pkg_name)
|
||||
return None
|
||||
|
||||
|
||||
def resolve_pkg_config_req(apt_mgr, req):
|
||||
|
@ -151,11 +168,16 @@ def resolve_pkg_config_req(apt_mgr, req):
|
|||
[posixpath.join("/usr/lib", ".*", "pkgconfig", req.module + ".pc")],
|
||||
regex=True,
|
||||
minimum_version=req.minimum_version)
|
||||
return package
|
||||
if package is not None:
|
||||
return AptRequirement(package)
|
||||
return None
|
||||
|
||||
|
||||
def resolve_path_req(apt_mgr, req):
|
||||
return apt_mgr.get_package_for_paths([req.path])
|
||||
package = apt_mgr.get_package_for_paths([req.path])
|
||||
if package is not None:
|
||||
return AptRequirement(package)
|
||||
return None
|
||||
|
||||
|
||||
def resolve_c_header_req(apt_mgr, req):
|
||||
|
@ -166,17 +188,25 @@ def resolve_c_header_req(apt_mgr, req):
|
|||
package = apt_mgr.get_package_for_paths(
|
||||
[posixpath.join("/usr/include", ".*", req.header)], regex=True
|
||||
)
|
||||
return package
|
||||
if package is None:
|
||||
return None
|
||||
return AptRequirement(package)
|
||||
|
||||
|
||||
def resolve_js_runtime_req(apt_mgr, req):
|
||||
return apt_mgr.get_package_for_paths(
|
||||
package = apt_mgr.get_package_for_paths(
|
||||
["/usr/bin/node", "/usr/bin/duk"], regex=False)
|
||||
if package is not None:
|
||||
return AptRequirement(package)
|
||||
return None
|
||||
|
||||
|
||||
def resolve_vala_package_req(apt_mgr, req):
|
||||
path = "/usr/share/vala-[0-9.]+/vapi/%s.vapi" % req.package
|
||||
return apt_mgr.get_package_for_paths([path], regex=True)
|
||||
package = apt_mgr.get_package_for_paths([path], regex=True)
|
||||
if package is not None:
|
||||
return AptRequirement(package)
|
||||
return None
|
||||
|
||||
|
||||
def resolve_ruby_gem_req(apt_mgr, req):
|
||||
|
@ -186,30 +216,45 @@ def resolve_ruby_gem_req(apt_mgr, req):
|
|||
"specifications/%s-.*\\.gemspec" % req.gem
|
||||
)
|
||||
]
|
||||
return apt_mgr.get_package_for_paths(
|
||||
paths, regex=True, minimum_version=req.minimum_version)
|
||||
package = apt_mgr.get_package_for_paths(
|
||||
paths, regex=True)
|
||||
if package is not None:
|
||||
return AptRequirement(package, minimum_version=req.minimum_version)
|
||||
return None
|
||||
|
||||
|
||||
def resolve_go_package_req(apt_mgr, req):
|
||||
return apt_mgr.get_package_for_paths(
|
||||
package = apt_mgr.get_package_for_paths(
|
||||
[posixpath.join("/usr/share/gocode/src", req.package, ".*")],
|
||||
regex=True
|
||||
)
|
||||
if package is not None:
|
||||
return AptRequirement(package)
|
||||
return None
|
||||
|
||||
|
||||
def resolve_dh_addon_req(apt_mgr, req):
|
||||
paths = [posixpath.join("/usr/share/perl5", req.path)]
|
||||
return apt_mgr.get_package_for_paths(paths)
|
||||
package = apt_mgr.get_package_for_paths(paths)
|
||||
if package is not None:
|
||||
return AptRequirement(package)
|
||||
return None
|
||||
|
||||
|
||||
def resolve_php_class_req(apt_mgr, req):
|
||||
path = "/usr/share/php/%s.php" % req.php_class.replace("\\", "/")
|
||||
return apt_mgr.get_package_for_paths([path])
|
||||
package = apt_mgr.get_package_for_paths([path])
|
||||
if package is not None:
|
||||
return AptRequirement(package)
|
||||
return None
|
||||
|
||||
|
||||
def resolve_r_package_req(apt_mgr, req):
|
||||
paths = [posixpath.join("/usr/lib/R/site-library/.*/R/%s$" % req.package)]
|
||||
return apt_mgr.get_package_for_paths(paths, regex=True)
|
||||
package = apt_mgr.get_package_for_paths(paths, regex=True)
|
||||
if package is not None:
|
||||
return AptRequirement(package)
|
||||
return None
|
||||
|
||||
|
||||
def resolve_node_package_req(apt_mgr, req):
|
||||
|
@ -218,7 +263,10 @@ def resolve_node_package_req(apt_mgr, req):
|
|||
"/usr/lib/nodejs/%s/package.json" % req.package,
|
||||
"/usr/share/nodejs/%s/package.json" % req.package,
|
||||
]
|
||||
return apt_mgr.get_package_for_paths(paths, regex=True)
|
||||
pkg_name = apt_mgr.get_package_for_paths(paths, regex=True)
|
||||
if pkg_name is not None:
|
||||
return AptRequirement(pkg_name)
|
||||
return None
|
||||
|
||||
|
||||
def resolve_library_req(apt_mgr, req):
|
||||
|
@ -228,21 +276,27 @@ def resolve_library_req(apt_mgr, req):
|
|||
posixpath.join("/usr/lib/lib%s.a$" % req.library),
|
||||
posixpath.join("/usr/lib/.*/lib%s.a$" % req.library),
|
||||
]
|
||||
return apt_mgr.get_package_for_paths(paths, regex=True)
|
||||
pkg_name = apt_mgr.get_package_for_paths(paths, regex=True)
|
||||
if pkg_name is not None:
|
||||
return AptRequirement(pkg_name)
|
||||
return None
|
||||
|
||||
|
||||
def resolve_ruby_file_req(apt_mgr, req):
|
||||
paths = [posixpath.join("/usr/lib/ruby/vendor_ruby/%s.rb" % req.filename)]
|
||||
package = apt_mgr.get_package_for_paths(paths)
|
||||
if package is not None:
|
||||
return package
|
||||
return AptRequirement(package)
|
||||
paths = [
|
||||
posixpath.join(
|
||||
r"/usr/share/rubygems-integration/all/gems/([^/]+)/"
|
||||
"lib/%s.rb" % req.filename
|
||||
)
|
||||
]
|
||||
return apt_mgr.get_package_for_paths(paths, regex=True)
|
||||
pkg_name = apt_mgr.get_package_for_paths(paths, regex=True)
|
||||
if pkg_name is not None:
|
||||
return AptRequirement(pkg_name)
|
||||
return None
|
||||
|
||||
|
||||
def resolve_xml_entity_req(apt_mgr, req):
|
||||
|
@ -258,7 +312,10 @@ def resolve_xml_entity_req(apt_mgr, req):
|
|||
else:
|
||||
return None
|
||||
|
||||
return apt_mgr.get_package_for_paths([search_path], regex=False)
|
||||
pkg_name = apt_mgr.get_package_for_paths([search_path], regex=False)
|
||||
if pkg_name is not None:
|
||||
return AptRequirement(pkg_name)
|
||||
return None
|
||||
|
||||
|
||||
def resolve_sprockets_file_req(apt_mgr, req):
|
||||
|
@ -267,7 +324,10 @@ def resolve_sprockets_file_req(apt_mgr, req):
|
|||
else:
|
||||
logging.warning("unable to handle content type %s", req.content_type)
|
||||
return None
|
||||
return apt_mgr.get_package_for_paths([path], regex=True)
|
||||
pkg_name = apt_mgr.get_package_for_paths([path], regex=True)
|
||||
if pkg_name is not None:
|
||||
return AptRequirement(pkg_name)
|
||||
return None
|
||||
|
||||
|
||||
def resolve_java_class_req(apt_mgr, req):
|
||||
|
@ -285,12 +345,15 @@ def resolve_java_class_req(apt_mgr, req):
|
|||
if package is None:
|
||||
logging.warning("no package for files in %r", classpath)
|
||||
return None
|
||||
return package
|
||||
return AptRequirement(package)
|
||||
|
||||
|
||||
def resolve_haskell_package_req(apt_mgr, req):
|
||||
path = "/var/lib/ghc/package.conf.d/%s-.*.conf" % req.deps[0][0]
|
||||
return apt_mgr.get_package_for_paths([path], regex=True)
|
||||
pkg_name = apt_mgr.get_package_for_paths([path], regex=True)
|
||||
if pkg_name is not None:
|
||||
return AptRequirement(pkg_name)
|
||||
return None
|
||||
|
||||
|
||||
def resolve_maven_artifact_req(apt_mgr, req):
|
||||
|
@ -319,16 +382,22 @@ def resolve_maven_artifact_req(apt_mgr, req):
|
|||
"%s-%s.%s" % (artifact_id, version, kind),
|
||||
)
|
||||
]
|
||||
return apt_mgr.get_package_for_paths(paths, regex=regex)
|
||||
pkg_name = apt_mgr.get_package_for_paths(paths, regex=regex)
|
||||
if pkg_name is not None:
|
||||
return AptRequirement(pkg_name)
|
||||
return None
|
||||
|
||||
|
||||
def resolve_gnome_common_req(apt_mgr, req):
|
||||
return 'gnome-common'
|
||||
return AptRequirement('gnome-common')
|
||||
|
||||
|
||||
def resolve_jdk_file_req(apt_mgr, req):
|
||||
path = req.jdk_path + ".*/" + req.filename
|
||||
return apt_mgr.get_package_for_paths([path], regex=True)
|
||||
pkg_name = apt_mgr.get_package_for_paths([path], regex=True)
|
||||
if pkg_name is not None:
|
||||
return AptRequirement(pkg_name)
|
||||
return None
|
||||
|
||||
|
||||
def resolve_perl_module_req(apt_mgr, req):
|
||||
|
@ -344,11 +413,17 @@ def resolve_perl_module_req(apt_mgr, req):
|
|||
paths = [req.filename]
|
||||
else:
|
||||
paths = [posixpath.join(inc, req.filename) for inc in req.inc]
|
||||
return apt_mgr.get_package_for_paths(paths, regex=False)
|
||||
pkg_name = apt_mgr.get_package_for_paths(paths, regex=False)
|
||||
if pkg_name is not None:
|
||||
return AptRequirement(pkg_name)
|
||||
return None
|
||||
|
||||
|
||||
def resolve_perl_file_req(apt_mgr, req):
|
||||
return apt_mgr.get_package_for_paths([req.filename], regex=False)
|
||||
pkg_name = apt_mgr.get_package_for_paths([req.filename], regex=False)
|
||||
if pkg_name is not None:
|
||||
return AptRequirement(pkg_name)
|
||||
return None
|
||||
|
||||
|
||||
def _find_aclocal_fun(macro):
|
||||
|
@ -370,7 +445,10 @@ def resolve_autoconf_macro_req(apt_mgr, req):
|
|||
except KeyError:
|
||||
logging.info("No local m4 file found defining %s", req.macro)
|
||||
return None
|
||||
return apt_mgr.get_package_for_paths([path])
|
||||
pkg_name = apt_mgr.get_package_for_paths([path])
|
||||
if pkg_name is not None:
|
||||
return AptRequirement(pkg_name)
|
||||
return None
|
||||
|
||||
|
||||
def resolve_python_module_req(apt_mgr, req):
|
||||
|
@ -421,14 +499,7 @@ APT_REQUIREMENT_RESOLVERS = [
|
|||
]
|
||||
|
||||
|
||||
class AptRequirement(object):
|
||||
|
||||
def __init__(self, package, minimum_version=None):
|
||||
self.package = package
|
||||
self.minimum_version = minimum_version
|
||||
|
||||
|
||||
def resolve_requirement_apt(apt_mgr, req: UpstreamRequirement):
|
||||
def resolve_requirement_apt(apt_mgr, req: UpstreamRequirement) -> AptRequirement:
|
||||
for rr_class, rr_fn in APT_REQUIREMENT_RESOLVERS:
|
||||
if isinstance(req, rr_class):
|
||||
deb_req = rr_fn(apt_mgr, req)
|
||||
|
@ -456,7 +527,17 @@ class AptResolver(Resolver):
|
|||
except NotImplementedError:
|
||||
missing.append(req)
|
||||
if missing:
|
||||
self.apt.install([self.resolve(m) for m in missing])
|
||||
still_missing = []
|
||||
apt_requirements = []
|
||||
for m in missing:
|
||||
try:
|
||||
apt_requirements.append(self.resolve(m))
|
||||
except NoAptPackage:
|
||||
still_missing.append(m)
|
||||
self.apt.install(
|
||||
[req.package for req in apt_requirements])
|
||||
if still_missing:
|
||||
raise MissingDependencies(still_missing)
|
||||
|
||||
def explain(self, requirements):
|
||||
raise NotImplementedError(self.explain)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue