Add hackage repository support.

This commit is contained in:
Jelmer Vernooij 2021-02-27 17:23:51 +00:00
parent a963db22be
commit 27a02686d6
5 changed files with 122 additions and 59 deletions

View file

@ -38,11 +38,17 @@ def get_necessary_declared_requirements(resolver, requirements, stages):
def install_necessary_declared_requirements(resolver, buildsystem, stages):
missing = []
missing.extend(
get_necessary_declared_requirements(
resolver, buildsystem.get_declared_dependencies(), stages
try:
declared_reqs = buildsystem.get_declared_dependencies()
except NotImplementedError:
logging.warning(
'Unable to determine declared dependencies from %s', buildsystem)
else:
missing.extend(
get_necessary_declared_requirements(
resolver, declared_reqs, stages
)
)
)
resolver.install(missing)

View file

@ -124,11 +124,10 @@ def problem_to_upstream_requirement(problem):
elif isinstance(problem, MissingJavaClass):
return JavaClassRequirement(problem.classname)
elif isinstance(problem, MissingHaskellDependencies):
# TODO(jelmer): Create multiple HaskellPackageRequirement objects?
return HaskellPackageRequirement(problem.package)
return [HaskellPackageRequirement(dep) for dep in problem.deps]
elif isinstance(problem, MissingMavenArtifacts):
# TODO(jelmer): Create multiple MavenArtifactRequirement objects?
return MavenArtifactRequirement(problem.artifacts)
return [MavenArtifactRequirement(artifact)
for artifact in problem.artifacts]
elif isinstance(problem, MissingCSharpCompiler):
return BinaryRequirement('msc')
elif isinstance(problem, GnomeCommonMissing):
@ -179,16 +178,29 @@ class UpstreamRequirementFixer(BuildFixer):
def __init__(self, resolver):
self.resolver = resolver
def __repr__(self):
return "%s(%r)" % (type(self).__name__, self.resolver)
def __str__(self):
return "upstream requirement fixer(%s)" % self.resolver
def can_fix(self, error):
req = problem_to_upstream_requirement(error)
return req is not None
def fix(self, error, context):
req = problem_to_upstream_requirement(error)
if req is None:
reqs = problem_to_upstream_requirement(error)
if reqs is None:
return False
package = self.resolver.resolve(req)
if package is None:
return False
return context.add_dependency(package)
if not isinstance(reqs, list):
reqs = [reqs]
changed = False
for req in reqs:
package = self.resolver.resolve(reqs)
if package is None:
return False
if context.add_dependency(package):
changed = True
return changed

View file

@ -51,6 +51,9 @@ class BuildSystem(object):
name: str
def __str__(self):
return self.name
def dist(self, session, resolver, fixers):
raise NotImplementedError(self.dist)
@ -125,13 +128,13 @@ class SetupPy(BuildSystem):
except FileNotFoundError:
setup_cfg_contents = ""
if "setuptools" in setup_py_contents:
logging.info("Reference to setuptools found, installing.")
logging.debug("Reference to setuptools found, installing.")
resolver.install([PythonPackageRequirement("setuptools")])
if (
"setuptools_scm" in setup_py_contents
or "setuptools_scm" in setup_cfg_contents
):
logging.info("Reference to setuptools-scm found, installing.")
logging.debug("Reference to setuptools-scm found, installing.")
resolver.install(
[
PythonPackageRequirement("setuptools-scm"),
@ -215,8 +218,9 @@ class PyProject(BuildSystem):
def dist(self, session, resolver, fixers):
if "poetry" in self.pyproject.get("tool", []):
logging.info(
"Found pyproject.toml with poetry section, " "assuming poetry project."
logging.debug(
"Found pyproject.toml with poetry section, "
"assuming poetry project."
)
resolver.install(
[
@ -279,13 +283,17 @@ class Waf(BuildSystem):
def __init__(self, path):
self.path = path
def setup(self, resolver):
def setup(self, session, resolver, fixers):
resolver.install([BinaryRequirement("python3")])
def dist(self, session, resolver, fixers):
self.setup(resolver)
self.setup(session, resolver, fixers)
run_with_build_fixers(session, ["./waf", "dist"], fixers)
def test(self, session, resolver, fixers):
self.setup(session, resolver, fixers)
run_with_build_fixers(session, ["./waf", "test"], fixers)
class Gem(BuildSystem):
@ -321,13 +329,14 @@ class DistInkt(BuildSystem):
except ValueError:
continue
if key.strip() == b"class" and value.strip().startswith(b"'Dist::Inkt"):
logging.info(
"Found Dist::Inkt section in dist.ini, " "assuming distinkt."
logging.debug(
"Found Dist::Inkt section in dist.ini, "
"assuming distinkt."
)
self.name = "dist-inkt"
self.dist_inkt_class = value.decode().strip("'")
return
logging.info("Found dist.ini, assuming dist-zilla.")
logging.debug("Found dist.ini, assuming dist-zilla.")
def setup(self, resolver):
resolver.install(
@ -397,15 +406,19 @@ class Make(BuildSystem):
session.check_call(["./configure"])
def build(self, session, resolver, fixers):
self.setup(session, resolver)
self.setup(session, resolver, fixers)
run_with_build_fixers(session, ["make", "all"], fixers)
def test(self, session, resolver, fixers):
self.setup(session, resolver, fixers)
run_with_build_fixers(session, ["make", "check"], fixers)
def install(self, session, resolver, fixers, install_target):
self.setup(session, resolver)
self.setup(session, resolver, fixers)
run_with_build_fixers(session, ["make", "install"], fixers)
def dist(self, session, resolver, fixers):
self.setup(session, resolver)
self.setup(session, resolver, fixers)
try:
run_with_build_fixers(session, ["make", "dist"], fixers)
except UnidentifiedError as e:
@ -491,6 +504,9 @@ class Cargo(BuildSystem):
# TODO(jelmer): Look at details['features'], details['version']
yield "build", CargoCrateRequirement(name)
def test(self, session, resolver, fixers):
run_with_build_fixers(session, ["cargo", "test"], fixers)
class Golang(BuildSystem):
"""Go builds."""
@ -513,37 +529,59 @@ class Cabal(BuildSystem):
def __init__(self, path):
self.path = path
def __repr__(self):
return "%s(%r)" % (type(self).__name__, self.path)
def _run(self, session, args, fixers):
try:
run_with_build_fixers(
session, ["runhaskell", "Setup.hs"] + args, fixers)
except UnidentifiedError as e:
if "Run the 'configure' command first.\n" in e.lines:
run_with_build_fixers(
session, ["runhaskell", "Setup.hs", "configure"], fixers)
run_with_build_fixers(
session, ["runhaskell", "Setup.hs"] + args, fixers)
else:
raise
def test(self, session, resolver, fixers):
self._run(session, ["test"], fixers)
def detect_buildsystems(path, trust_package=False): # noqa: C901
"""Detect build systems."""
if os.path.exists(os.path.join(path, "package.xml")):
logging.info("Found package.xml, assuming pear package.")
logging.debug("Found package.xml, assuming pear package.")
yield Pear("package.xml")
if os.path.exists(os.path.join(path, "setup.py")):
logging.info("Found setup.py, assuming python project.")
logging.debug("Found setup.py, assuming python project.")
yield SetupPy("setup.py")
elif os.path.exists(os.path.join(path, "pyproject.toml")):
logging.info("Found pyproject.toml, assuming python project.")
logging.debug("Found pyproject.toml, assuming python project.")
yield PyProject("pyproject.toml")
elif os.path.exists(os.path.join(path, "setup.cfg")):
logging.info("Found setup.cfg, assuming python project.")
logging.debug("Found setup.cfg, assuming python project.")
yield SetupCfg("setup.cfg")
if os.path.exists(os.path.join(path, "package.json")):
logging.info("Found package.json, assuming node package.")
logging.debug("Found package.json, assuming node package.")
yield Npm("package.json")
if os.path.exists(os.path.join(path, "waf")):
logging.info("Found waf, assuming waf package.")
logging.debug("Found waf, assuming waf package.")
yield Waf("waf")
if os.path.exists(os.path.join(path, "Cargo.toml")):
logging.info("Found Cargo.toml, assuming rust cargo package.")
logging.debug("Found Cargo.toml, assuming rust cargo package.")
yield Cargo("Cargo.toml")
if os.path.exists(os.path.join(path, 'Setup.hs')):
logging.debug("Found Setup.hs, assuming haskell package.")
yield Cabal('Setup.hs')
if os.path.exists(os.path.join(path, "pom.xml")):
logging.info("Found pom.xml, assuming maven package.")
logging.debug("Found pom.xml, assuming maven package.")
yield Maven("pom.xml")
if os.path.exists(os.path.join(path, "dist.ini")) and not os.path.exists(
@ -569,17 +607,6 @@ def detect_buildsystems(path, trust_package=False): # noqa: C901
):
yield Make()
cabal_filenames = [
entry.name for entry in os.scandir(path) if entry.name.endswith(".cabal")
]
if cabal_filenames:
if len(cabal_filenames) == 1:
yield Cabal(cabal_filenames[0])
else:
warnings.warn(
"More than one cabal filename, ignoring all: %r" % cabal_filenames
)
if os.path.exists(os.path.join(path, ".travis.yml")):
import ruamel.yaml.reader

View file

@ -120,7 +120,7 @@ def resolve_error(error, context, fixers):
logging.warning("No fixer found for %r", error)
return False
for fixer in relevant_fixers:
logging.info("Attempting to use fixer %r to address %r", fixer, error)
logging.info("Attempting to use fixer %s to address %r", fixer, error)
made_changes = fixer.fix(error, context)
if made_changes:
return True

View file

@ -60,8 +60,30 @@ class CPANResolver(Resolver):
def explain(self, requirements):
raise NotImplementedError(self.explain)
def met(self, requirement):
raise NotImplementedError(self.met)
class HackageResolver(Resolver):
def __init__(self, session):
self.session = session
def __str__(self):
return "hackage"
def install(self, requirements):
from ..requirements import HaskellPackageRequirement
missing = []
for requirement in requirements:
if not isinstance(requirement, HaskellPackageRequirement):
missing.append(requirement)
continue
self.session.check_call(
["cabal", "install", requirement.package],
user="root")
if missing:
raise UnsatisfiedRequirements(missing)
def explain(self, requirements):
raise NotImplementedError(self.explain)
class CargoResolver(Resolver):
@ -88,9 +110,6 @@ class CargoResolver(Resolver):
def explain(self, requirements):
raise NotImplementedError(self.explain)
def met(self, requirement):
raise NotImplementedError(self.met)
class PypiResolver(Resolver):
@ -114,9 +133,6 @@ class PypiResolver(Resolver):
def explain(self, requirements):
raise NotImplementedError(self.explain)
def met(self, requirement):
raise NotImplementedError(self.met)
NPM_COMMAND_PACKAGES = {
"del-cli": "del-cli",
@ -150,14 +166,14 @@ class NpmResolver(Resolver):
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 __repr__(self):
return "%s(%r)" % (type(self).__name__, self.subs)
def __str__(self):
return "[" + ", ".join(map(str, self.subs)) + "]"
@ -176,7 +192,8 @@ def native_resolvers(session):
CPANResolver(session),
PypiResolver(session),
NpmResolver(session),
CargoResolver(session)])
CargoResolver(session),
HackageResolver(session)])
class ExplainResolver(Resolver):
@ -203,5 +220,6 @@ def auto_resolver(session):
CPANResolver(session),
PypiResolver(session),
NpmResolver(session),
CargoResolver(session)])
CargoResolver(session),
HackageResolver(session)])
return StackedResolver(resolvers)