Better support for user-local.

This commit is contained in:
Jelmer Vernooij 2021-03-22 14:14:15 +00:00
parent a0283a2e4e
commit 7b794a987f
No known key found for this signature in database
GPG key ID: 579C160D4C9E23E8
3 changed files with 70 additions and 23 deletions

View file

@ -147,7 +147,7 @@ def main(): # noqa: C901
if args.resolve == "apt": if args.resolve == "apt":
resolver = AptResolver.from_session(session) resolver = AptResolver.from_session(session)
elif args.resolve == "native": elif args.resolve == "native":
resolver = native_resolvers(session) resolver = native_resolvers(session, user_local=args.user)
elif args.resolve == "auto": elif args.resolve == "auto":
resolver = auto_resolver(session, explain=args.explain) resolver = auto_resolver(session, explain=args.explain)
logging.info("Using requirement resolver: %s", resolver) logging.info("Using requirement resolver: %s", resolver)

View file

@ -280,6 +280,8 @@ def get_package_for_paths(
logging.warning( logging.warning(
"More than 1 packages found that contain %r: %r", path, candidates "More than 1 packages found that contain %r: %r", path, candidates
) )
# TODO(jelmer): Pick package based on what appears most commonly in
# build-depends{-indep,-arch}
try: try:
from .udd import UDD from .udd import UDD
except ModuleNotFoundError: except ModuleNotFoundError:

View file

@ -39,8 +39,9 @@ class Resolver(object):
class CPANResolver(Resolver): class CPANResolver(Resolver):
def __init__(self, session): def __init__(self, session, user_local=False):
self.session = session self.session = session
self.user_local = user_local
def __str__(self): def __str__(self):
return "cpan" return "cpan"
@ -62,6 +63,15 @@ class CPANResolver(Resolver):
def install(self, requirements): def install(self, requirements):
from ..requirements import PerlModuleRequirement from ..requirements import PerlModuleRequirement
env = {
"PERL_MM_USE_DEFAULT": "1",
"PERL_MM_OPT": "",
"PERL_MB_OPT": "",
}
if not self.user_local:
user = "root"
missing = [] missing = []
for requirement in requirements: for requirement in requirements:
if not isinstance(requirement, PerlModuleRequirement): if not isinstance(requirement, PerlModuleRequirement):
@ -70,16 +80,18 @@ class CPANResolver(Resolver):
# TODO(jelmer): Specify -T to skip tests? # TODO(jelmer): Specify -T to skip tests?
self.session.check_call( self.session.check_call(
["cpan", "-i", requirement.module], ["cpan", "-i", requirement.module],
env={"PERL_MM_USE_DEFAULT": "1"}, env=env,
user=user,
) )
if missing: if missing:
raise UnsatisfiedRequirements(missing) raise UnsatisfiedRequirements(missing)
class RResolver(Resolver): class RResolver(Resolver):
def __init__(self, session, repos): def __init__(self, session, repos, user_local=False):
self.session = session self.session = session
self.repos = repos self.repos = repos
self.user_local = user_local
def __str__(self): def __str__(self):
return "cran" return "cran"
@ -88,6 +100,7 @@ class RResolver(Resolver):
return "%s(%r, %r)" % (type(self).__name__, self.session, self.repos) return "%s(%r, %r)" % (type(self).__name__, self.session, self.repos)
def _cmd(self, req): def _cmd(self, req):
# TODO(jelmer: Handle self.user_local
return ["R", "-e", "install.packages('%s', repos=%r)" % (req.package, self.repos)] return ["R", "-e", "install.packages('%s', repos=%r)" % (req.package, self.repos)]
def explain(self, requirements): def explain(self, requirements):
@ -104,32 +117,38 @@ class RResolver(Resolver):
def install(self, requirements): def install(self, requirements):
from ..requirements import RPackageRequirement from ..requirements import RPackageRequirement
if self.user_local:
user = None
else:
user = "root"
missing = [] missing = []
for requirement in requirements: for requirement in requirements:
if not isinstance(requirement, RPackageRequirement): if not isinstance(requirement, RPackageRequirement):
missing.append(requirement) missing.append(requirement)
continue continue
self.session.check_call(self._cmd(requirement)) self.session.check_call(self._cmd(requirement), user=user)
if missing: if missing:
raise UnsatisfiedRequirements(missing) raise UnsatisfiedRequirements(missing)
class CRANResolver(RResolver): class CRANResolver(RResolver):
def __init__(self, session): def __init__(self, session, user_local=False):
super(CRANResolver, self).__init__(session, 'http://cran.r-project.org') super(CRANResolver, self).__init__(session, 'http://cran.r-project.org', user_local=user_local)
class BioconductorResolver(RResolver): class BioconductorResolver(RResolver):
def __init__(self, session): def __init__(self, session):
super(BioconductorResolver, self).__init__( super(BioconductorResolver, self).__init__(
session, 'https://hedgehog.fhcrc.org/bioconductor') session, 'https://hedgehog.fhcrc.org/bioconductor', user_local=user_local)
class HackageResolver(Resolver): class HackageResolver(Resolver):
def __init__(self, session): def __init__(self, session, user_local=False):
self.session = session self.session = session
self.user_local = user_local
def __str__(self): def __str__(self):
return "hackage" return "hackage"
@ -137,17 +156,26 @@ class HackageResolver(Resolver):
def __repr__(self): def __repr__(self):
return "%s(%r)" % (type(self).__name__, self.session) return "%s(%r)" % (type(self).__name__, self.session)
def _cmd(self, reqs):
extra_args = []
if self.user_local:
extra_args.append('--user')
return ["cabal", "install"] + extra_args + [req.package for req in reqs]
def install(self, requirements): def install(self, requirements):
from ..requirements import HaskellPackageRequirement from ..requirements import HaskellPackageRequirement
if self.user_local:
user = None
else:
user = "root"
missing = [] missing = []
for requirement in requirements: for requirement in requirements:
if not isinstance(requirement, HaskellPackageRequirement): if not isinstance(requirement, HaskellPackageRequirement):
missing.append(requirement) missing.append(requirement)
continue continue
self.session.check_call( self.session.check_call(self._cmd([requirement]), user=user)
["cabal", "install", requirement.package]
)
if missing: if missing:
raise UnsatisfiedRequirements(missing) raise UnsatisfiedRequirements(missing)
@ -160,13 +188,13 @@ class HackageResolver(Resolver):
continue continue
haskellreqs.append(requirement) haskellreqs.append(requirement)
if haskellreqs: if haskellreqs:
yield (["cabal", "install"] + [req.package for req in haskellreqs], yield (self._cmd(haskellreqs), haskellreqs)
haskellreqs)
class PypiResolver(Resolver): class PypiResolver(Resolver):
def __init__(self, session): def __init__(self, session, user_local=False):
self.session = session self.session = session
self.user_local = user_local
def __str__(self): def __str__(self):
return "pypi" return "pypi"
@ -174,9 +202,20 @@ class PypiResolver(Resolver):
def __repr__(self): def __repr__(self):
return "%s(%r)" % (type(self).__name__, self.session) return "%s(%r)" % (type(self).__name__, self.session)
def _cmd(self, reqs):
extra_args = []
if self.user_local:
extra_args.append('--user')
return ["pip", "install"] + extra_args + [req.package for req in reqs]
def install(self, requirements): def install(self, requirements):
from ..requirements import PythonPackageRequirement from ..requirements import PythonPackageRequirement
if self.user_local:
user = None
else:
user = "root"
missing = [] missing = []
for requirement in requirements: for requirement in requirements:
if not isinstance(requirement, PythonPackageRequirement): if not isinstance(requirement, PythonPackageRequirement):
@ -184,7 +223,7 @@ class PypiResolver(Resolver):
continue continue
try: try:
self.session.check_call( self.session.check_call(
["pip", "install", requirement.package]) self._cmd([requirement]), user=user)
except subprocess.CalledProcessError: except subprocess.CalledProcessError:
missing.append(requirement) missing.append(requirement)
if missing: if missing:
@ -199,14 +238,14 @@ class PypiResolver(Resolver):
continue continue
pyreqs.append(requirement) pyreqs.append(requirement)
if pyreqs: if pyreqs:
yield (["pip", "install"] + [req.package for req in pyreqs], yield (self._cmd(pyreqs), pyreqs)
pyreqs)
class GoResolver(Resolver): class GoResolver(Resolver):
def __init__(self, session): def __init__(self, session, user_local):
self.session = session self.session = session
# TODO(jelmer): Handle user_local=False
def __str__(self): def __str__(self):
return "go" return "go"
@ -245,8 +284,10 @@ NPM_COMMAND_PACKAGES = {
class NpmResolver(Resolver): class NpmResolver(Resolver):
def __init__(self, session): def __init__(self, session, user_local=False):
self.session = session self.session = session
self.user_local = user_local
# TODO(jelmer): Handle user_local
def __str__(self): def __str__(self):
return "npm" return "npm"
@ -324,8 +365,8 @@ NATIVE_RESOLVER_CLS = [
] ]
def native_resolvers(session): def native_resolvers(session, user_local):
return StackedResolver([kls(session) for kls in NATIVE_RESOLVER_CLS]) return StackedResolver([kls(session, user_local) for kls in NATIVE_RESOLVER_CLS])
def auto_resolver(session, explain=False): def auto_resolver(session, explain=False):
@ -339,6 +380,10 @@ def auto_resolver(session, explain=False):
# TODO(jelmer): Check VIRTUAL_ENV, and prioritize PypiResolver if # TODO(jelmer): Check VIRTUAL_ENV, and prioritize PypiResolver if
# present? # present?
if isinstance(session, SchrootSession) or user == "root" or explain: if isinstance(session, SchrootSession) or user == "root" or explain:
user_local = False
else:
user_local = True
if not user_local:
resolvers.append(AptResolver.from_session(session)) resolvers.append(AptResolver.from_session(session))
resolvers.extend([kls(session) for kls in NATIVE_RESOLVER_CLS]) resolvers.extend([kls(session, user_local) for kls in NATIVE_RESOLVER_CLS])
return StackedResolver(resolvers) return StackedResolver(resolvers)