More refactoring.
This commit is contained in:
parent
ea32f33f90
commit
52e119022b
10 changed files with 135 additions and 66 deletions
|
@ -67,8 +67,8 @@ STAGE_MAP = {
|
||||||
|
|
||||||
|
|
||||||
def determine_fixers(session, resolver):
|
def determine_fixers(session, resolver):
|
||||||
from .buildlog import RequirementFixer
|
from .buildlog import InstallFixer
|
||||||
return [RequirementFixer(resolver)]
|
return [InstallFixer(resolver)]
|
||||||
|
|
||||||
|
|
||||||
def main(): # noqa: C901
|
def main(): # noqa: C901
|
||||||
|
|
|
@ -81,6 +81,7 @@ from .requirements import (
|
||||||
PythonModuleRequirement,
|
PythonModuleRequirement,
|
||||||
PythonPackageRequirement,
|
PythonPackageRequirement,
|
||||||
)
|
)
|
||||||
|
from .resolver import UnsatisfiedRequirements
|
||||||
|
|
||||||
|
|
||||||
def problem_to_upstream_requirement(problem): # noqa: C901
|
def problem_to_upstream_requirement(problem): # noqa: C901
|
||||||
|
@ -166,7 +167,7 @@ def problem_to_upstream_requirement(problem): # noqa: C901
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
class RequirementFixer(BuildFixer):
|
class InstallFixer(BuildFixer):
|
||||||
def __init__(self, resolver):
|
def __init__(self, resolver):
|
||||||
self.resolver = resolver
|
self.resolver = resolver
|
||||||
|
|
||||||
|
@ -188,11 +189,8 @@ class RequirementFixer(BuildFixer):
|
||||||
if not isinstance(reqs, list):
|
if not isinstance(reqs, list):
|
||||||
reqs = [reqs]
|
reqs = [reqs]
|
||||||
|
|
||||||
changed = False
|
try:
|
||||||
for req in reqs:
|
self.resolver.install(reqs)
|
||||||
package = self.resolver.resolve(req)
|
except UnsatisfiedRequirements:
|
||||||
if package is None:
|
return False
|
||||||
return False
|
return True
|
||||||
if context.add_dependency(package):
|
|
||||||
changed = True
|
|
||||||
return changed
|
|
||||||
|
|
|
@ -457,7 +457,7 @@ class Make(BuildSystem):
|
||||||
run_with_build_fixers(session, ["autoreconf", "-i"], fixers)
|
run_with_build_fixers(session, ["autoreconf", "-i"], fixers)
|
||||||
|
|
||||||
if not makefile_exists() and session.exists("configure"):
|
if not makefile_exists() and session.exists("configure"):
|
||||||
session.check_call(["./configure"])
|
run_with_build_fixers(session, ["./configure"], fixers)
|
||||||
|
|
||||||
def build(self, session, resolver, fixers):
|
def build(self, session, resolver, fixers):
|
||||||
self.setup(session, resolver, fixers)
|
self.setup(session, resolver, fixers)
|
||||||
|
@ -553,9 +553,14 @@ class Cargo(BuildSystem):
|
||||||
|
|
||||||
name = "cargo"
|
name = "cargo"
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return "%s(%r)" % (type(self).__name__, self.path)
|
||||||
|
|
||||||
def __init__(self, path):
|
def __init__(self, path):
|
||||||
from toml.decoder import load
|
from toml.decoder import load
|
||||||
|
|
||||||
|
self.path = path
|
||||||
|
|
||||||
with open(path, "r") as f:
|
with open(path, "r") as f:
|
||||||
self.cargo = load(f)
|
self.cargo = load(f)
|
||||||
|
|
||||||
|
@ -568,12 +573,30 @@ class Cargo(BuildSystem):
|
||||||
def test(self, session, resolver, fixers):
|
def test(self, session, resolver, fixers):
|
||||||
run_with_build_fixers(session, ["cargo", "test"], fixers)
|
run_with_build_fixers(session, ["cargo", "test"], fixers)
|
||||||
|
|
||||||
|
def clean(self, session, resolver, fixers):
|
||||||
|
run_with_build_fixers(session, ["cargo", "clean"], fixers)
|
||||||
|
|
||||||
|
def build(self, session, resolver, fixers):
|
||||||
|
run_with_build_fixers(session, ["cargo", "build"], fixers)
|
||||||
|
|
||||||
|
|
||||||
class Golang(BuildSystem):
|
class Golang(BuildSystem):
|
||||||
"""Go builds."""
|
"""Go builds."""
|
||||||
|
|
||||||
name = "golang"
|
name = "golang"
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return "%s()" % (type(self).__name__)
|
||||||
|
|
||||||
|
def test(self, session, resolver, fixers):
|
||||||
|
session.check_call(["go", "test"])
|
||||||
|
|
||||||
|
def build(self, session, resolver, fixers):
|
||||||
|
session.check_call(["go", "build"])
|
||||||
|
|
||||||
|
def clean(self, session, resolver, fixers):
|
||||||
|
session.check_call(["go", "clean"])
|
||||||
|
|
||||||
|
|
||||||
class Maven(BuildSystem):
|
class Maven(BuildSystem):
|
||||||
|
|
||||||
|
@ -664,6 +687,7 @@ def detect_buildsystems(path, trust_package=False): # noqa: C901
|
||||||
"GNUmakefile",
|
"GNUmakefile",
|
||||||
"makefile",
|
"makefile",
|
||||||
"Makefile.PL",
|
"Makefile.PL",
|
||||||
|
"CMakeLists.txt",
|
||||||
"autogen.sh",
|
"autogen.sh",
|
||||||
"configure.ac",
|
"configure.ac",
|
||||||
"configure.in",
|
"configure.in",
|
||||||
|
@ -672,6 +696,7 @@ def detect_buildsystems(path, trust_package=False): # noqa: C901
|
||||||
):
|
):
|
||||||
yield Make()
|
yield Make()
|
||||||
|
|
||||||
|
seen_golang = False
|
||||||
if os.path.exists(os.path.join(path, ".travis.yml")):
|
if os.path.exists(os.path.join(path, ".travis.yml")):
|
||||||
import ruamel.yaml.reader
|
import ruamel.yaml.reader
|
||||||
|
|
||||||
|
@ -684,11 +709,13 @@ def detect_buildsystems(path, trust_package=False): # noqa: C901
|
||||||
language = data.get("language")
|
language = data.get("language")
|
||||||
if language == "go":
|
if language == "go":
|
||||||
yield Golang()
|
yield Golang()
|
||||||
|
seen_golang = True
|
||||||
|
|
||||||
for entry in os.scandir(path):
|
if not seen_golang:
|
||||||
if entry.name.endswith(".go"):
|
for entry in os.scandir(path):
|
||||||
yield Golang()
|
if entry.name.endswith(".go"):
|
||||||
break
|
yield Golang()
|
||||||
|
break
|
||||||
|
|
||||||
|
|
||||||
def get_buildsystem(path, trust_package=False):
|
def get_buildsystem(path, trust_package=False):
|
||||||
|
|
|
@ -79,8 +79,8 @@ from buildlog_consultant.sbuild import (
|
||||||
SbuildFailure,
|
SbuildFailure,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
from ..buildlog import problem_to_upstream_requirement
|
||||||
from ..fix_build import BuildFixer, resolve_error, DependencyContext
|
from ..fix_build import BuildFixer, resolve_error, DependencyContext
|
||||||
from ..buildlog import RequirementFixer
|
|
||||||
from ..resolver.apt import (
|
from ..resolver.apt import (
|
||||||
AptRequirement,
|
AptRequirement,
|
||||||
get_package_for_python_module,
|
get_package_for_python_module,
|
||||||
|
@ -98,7 +98,66 @@ class CircularDependency(Exception):
|
||||||
self.package = package
|
self.package = package
|
||||||
|
|
||||||
|
|
||||||
|
class PackageDependencyFixer(BuildFixer):
|
||||||
|
|
||||||
|
def __init__(self, apt_resolver):
|
||||||
|
self.apt_resolver = apt_resolver
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return "%s(%r)" % (type(self).__name__, self.apt_resolver)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return "upstream requirement fixer(%s)" % self.apt_resolver
|
||||||
|
|
||||||
|
def can_fix(self, error):
|
||||||
|
req = problem_to_upstream_requirement(error)
|
||||||
|
return req is not None
|
||||||
|
|
||||||
|
def fix(self, error, context):
|
||||||
|
reqs = problem_to_upstream_requirement(error)
|
||||||
|
if reqs is None:
|
||||||
|
return False
|
||||||
|
|
||||||
|
if not isinstance(reqs, list):
|
||||||
|
reqs = [reqs]
|
||||||
|
|
||||||
|
changed = False
|
||||||
|
for req in reqs:
|
||||||
|
package = self.apt_resolver.resolve(req)
|
||||||
|
if package is None:
|
||||||
|
return False
|
||||||
|
if context.phase[0] == "autopkgtest":
|
||||||
|
return add_test_dependency(
|
||||||
|
context.tree,
|
||||||
|
context.phase[1],
|
||||||
|
package,
|
||||||
|
committer=context.committer,
|
||||||
|
subpath=context.subpath,
|
||||||
|
update_changelog=context.update_changelog,
|
||||||
|
)
|
||||||
|
elif context.phase[0] == "build":
|
||||||
|
return add_build_dependency(
|
||||||
|
context.tree,
|
||||||
|
package,
|
||||||
|
committer=context.committer,
|
||||||
|
subpath=context.subpath,
|
||||||
|
update_changelog=context.update_changelog,
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
logging.warning('Unknown phase %r', context.phase)
|
||||||
|
return False
|
||||||
|
return changed
|
||||||
|
|
||||||
|
|
||||||
class BuildDependencyContext(DependencyContext):
|
class BuildDependencyContext(DependencyContext):
|
||||||
|
def __init__(
|
||||||
|
self, phase, tree, apt, subpath="", committer=None, update_changelog=True
|
||||||
|
):
|
||||||
|
self.phase = phase
|
||||||
|
super(BuildDependencyContext, self).__init__(
|
||||||
|
tree, apt, subpath, committer, update_changelog
|
||||||
|
)
|
||||||
|
|
||||||
def add_dependency(self, requirement: AptRequirement):
|
def add_dependency(self, requirement: AptRequirement):
|
||||||
return add_build_dependency(
|
return add_build_dependency(
|
||||||
self.tree,
|
self.tree,
|
||||||
|
@ -111,9 +170,9 @@ class BuildDependencyContext(DependencyContext):
|
||||||
|
|
||||||
class AutopkgtestDependencyContext(DependencyContext):
|
class AutopkgtestDependencyContext(DependencyContext):
|
||||||
def __init__(
|
def __init__(
|
||||||
self, testname, tree, apt, subpath="", committer=None, update_changelog=True
|
self, phase, tree, apt, subpath="", committer=None, update_changelog=True
|
||||||
):
|
):
|
||||||
self.testname = testname
|
self.phase = phase
|
||||||
super(AutopkgtestDependencyContext, self).__init__(
|
super(AutopkgtestDependencyContext, self).__init__(
|
||||||
tree, apt, subpath, committer, update_changelog
|
tree, apt, subpath, committer, update_changelog
|
||||||
)
|
)
|
||||||
|
@ -498,13 +557,12 @@ def versioned_package_fixers(session):
|
||||||
|
|
||||||
def apt_fixers(apt) -> List[BuildFixer]:
|
def apt_fixers(apt) -> List[BuildFixer]:
|
||||||
from ..resolver.apt import AptResolver
|
from ..resolver.apt import AptResolver
|
||||||
|
|
||||||
resolver = AptResolver(apt)
|
resolver = AptResolver(apt)
|
||||||
return [
|
return [
|
||||||
SimpleBuildFixer(MissingPythonModule, fix_missing_python_module),
|
SimpleBuildFixer(MissingPythonModule, fix_missing_python_module),
|
||||||
SimpleBuildFixer(MissingPythonDistribution, fix_missing_python_distribution),
|
SimpleBuildFixer(MissingPythonDistribution, fix_missing_python_distribution),
|
||||||
SimpleBuildFixer(AptFetchFailure, retry_apt_failure),
|
SimpleBuildFixer(AptFetchFailure, retry_apt_failure),
|
||||||
RequirementFixer(resolver),
|
PackageDependencyFixer(resolver),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
@ -553,6 +611,7 @@ def build_incrementally(
|
||||||
reset_tree(local_tree, local_tree.basis_tree(), subpath=subpath)
|
reset_tree(local_tree, local_tree.basis_tree(), subpath=subpath)
|
||||||
if e.phase[0] == "build":
|
if e.phase[0] == "build":
|
||||||
context = BuildDependencyContext(
|
context = BuildDependencyContext(
|
||||||
|
e.phase,
|
||||||
local_tree,
|
local_tree,
|
||||||
apt,
|
apt,
|
||||||
subpath=subpath,
|
subpath=subpath,
|
||||||
|
@ -561,7 +620,7 @@ def build_incrementally(
|
||||||
)
|
)
|
||||||
elif e.phase[0] == "autopkgtest":
|
elif e.phase[0] == "autopkgtest":
|
||||||
context = AutopkgtestDependencyContext(
|
context = AutopkgtestDependencyContext(
|
||||||
e.phase[1],
|
e.phase,
|
||||||
local_tree,
|
local_tree,
|
||||||
apt,
|
apt,
|
||||||
subpath=subpath,
|
subpath=subpath,
|
||||||
|
|
|
@ -133,7 +133,7 @@ def create_dist_schroot(
|
||||||
) -> str:
|
) -> str:
|
||||||
from .buildsystem import detect_buildsystems
|
from .buildsystem import detect_buildsystems
|
||||||
from .resolver.apt import AptResolver
|
from .resolver.apt import AptResolver
|
||||||
from .buildlog import RequirementFixer
|
from .buildlog import InstallFixer
|
||||||
|
|
||||||
if subdir is None:
|
if subdir is None:
|
||||||
subdir = "package"
|
subdir = "package"
|
||||||
|
@ -159,7 +159,7 @@ def create_dist_schroot(
|
||||||
|
|
||||||
buildsystems = list(detect_buildsystems(export_directory))
|
buildsystems = list(detect_buildsystems(export_directory))
|
||||||
resolver = AptResolver.from_session(session)
|
resolver = AptResolver.from_session(session)
|
||||||
fixers = [RequirementFixer(resolver)]
|
fixers = [InstallFixer(resolver)]
|
||||||
|
|
||||||
with DistCatcher(export_directory) as dc:
|
with DistCatcher(export_directory) as dc:
|
||||||
oldcwd = os.getcwd()
|
oldcwd = os.getcwd()
|
||||||
|
|
|
@ -58,23 +58,10 @@ class DependencyContext(object):
|
||||||
self.committer = committer
|
self.committer = committer
|
||||||
self.update_changelog = update_changelog
|
self.update_changelog = update_changelog
|
||||||
|
|
||||||
def add_dependency(
|
def add_dependency(self, package) -> bool:
|
||||||
self, package: str, minimum_version=None
|
|
||||||
) -> bool:
|
|
||||||
raise NotImplementedError(self.add_dependency)
|
raise NotImplementedError(self.add_dependency)
|
||||||
|
|
||||||
|
|
||||||
class SchrootDependencyContext(DependencyContext):
|
|
||||||
def __init__(self, session):
|
|
||||||
self.session = session
|
|
||||||
self.apt = AptManager(session)
|
|
||||||
|
|
||||||
def add_dependency(self, package, minimum_version=None):
|
|
||||||
# TODO(jelmer): Handle minimum_version
|
|
||||||
self.apt.install([package])
|
|
||||||
return True
|
|
||||||
|
|
||||||
|
|
||||||
def run_with_build_fixers(session: Session, args: List[str], fixers: List[BuildFixer]):
|
def run_with_build_fixers(session: Session, args: List[str], fixers: List[BuildFixer]):
|
||||||
logging.info("Running %r", args)
|
logging.info("Running %r", args)
|
||||||
fixed_errors = []
|
fixed_errors = []
|
||||||
|
@ -99,7 +86,7 @@ def run_with_build_fixers(session: Session, args: List[str], fixers: List[BuildF
|
||||||
raise DetailedFailure(retcode, args, error)
|
raise DetailedFailure(retcode, args, error)
|
||||||
if not resolve_error(
|
if not resolve_error(
|
||||||
error,
|
error,
|
||||||
SchrootDependencyContext(session),
|
None,
|
||||||
fixers=fixers,
|
fixers=fixers,
|
||||||
):
|
):
|
||||||
logging.warning("Failed to find resolution for error %r. Giving up.", error)
|
logging.warning("Failed to find resolution for error %r. Giving up.", error)
|
||||||
|
|
|
@ -98,6 +98,15 @@ class CargoCrateRequirement(Requirement):
|
||||||
super(CargoCrateRequirement, self).__init__("cargo-crate")
|
super(CargoCrateRequirement, self).__init__("cargo-crate")
|
||||||
self.crate = crate
|
self.crate = crate
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return "%s(%r)" % (
|
||||||
|
type(self).__name__,
|
||||||
|
self.crate,
|
||||||
|
)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return "cargo crate: %s" % self.crate
|
||||||
|
|
||||||
|
|
||||||
class PkgConfigRequirement(Requirement):
|
class PkgConfigRequirement(Requirement):
|
||||||
|
|
||||||
|
|
|
@ -42,6 +42,9 @@ class CPANResolver(Resolver):
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return "cpan"
|
return "cpan"
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return "%s(%r)" % (type(self).__name__, self.session)
|
||||||
|
|
||||||
def install(self, requirements):
|
def install(self, requirements):
|
||||||
from ..requirements import PerlModuleRequirement
|
from ..requirements import PerlModuleRequirement
|
||||||
|
|
||||||
|
@ -70,6 +73,9 @@ class HackageResolver(Resolver):
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return "hackage"
|
return "hackage"
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return "%s(%r)" % (type(self).__name__, self.session)
|
||||||
|
|
||||||
def install(self, requirements):
|
def install(self, requirements):
|
||||||
from ..requirements import HaskellPackageRequirement
|
from ..requirements import HaskellPackageRequirement
|
||||||
|
|
||||||
|
@ -88,31 +94,6 @@ class HackageResolver(Resolver):
|
||||||
raise NotImplementedError(self.explain)
|
raise NotImplementedError(self.explain)
|
||||||
|
|
||||||
|
|
||||||
class CargoResolver(Resolver):
|
|
||||||
def __init__(self, session):
|
|
||||||
self.session = session
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return "cargo"
|
|
||||||
|
|
||||||
def install(self, requirements):
|
|
||||||
from ..requirements import CargoCrateRequirement
|
|
||||||
|
|
||||||
missing = []
|
|
||||||
for requirement in requirements:
|
|
||||||
if not isinstance(requirement, CargoCrateRequirement):
|
|
||||||
missing.append(requirement)
|
|
||||||
continue
|
|
||||||
self.session.check_call(
|
|
||||||
["cargo", "install", requirement.crate], user="root"
|
|
||||||
)
|
|
||||||
if missing:
|
|
||||||
raise UnsatisfiedRequirements(missing)
|
|
||||||
|
|
||||||
def explain(self, requirements):
|
|
||||||
raise NotImplementedError(self.explain)
|
|
||||||
|
|
||||||
|
|
||||||
class PypiResolver(Resolver):
|
class PypiResolver(Resolver):
|
||||||
def __init__(self, session):
|
def __init__(self, session):
|
||||||
self.session = session
|
self.session = session
|
||||||
|
@ -120,6 +101,9 @@ class PypiResolver(Resolver):
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return "pypi"
|
return "pypi"
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return "%s(%r)" % (type(self).__name__, self.session)
|
||||||
|
|
||||||
def install(self, requirements):
|
def install(self, requirements):
|
||||||
from ..requirements import PythonPackageRequirement
|
from ..requirements import PythonPackageRequirement
|
||||||
|
|
||||||
|
@ -148,6 +132,9 @@ class NpmResolver(Resolver):
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return "npm"
|
return "npm"
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return "%s(%r)" % (type(self).__name__, self.session)
|
||||||
|
|
||||||
def install(self, requirements):
|
def install(self, requirements):
|
||||||
from ..requirements import NodePackageRequirement
|
from ..requirements import NodePackageRequirement
|
||||||
|
|
||||||
|
@ -195,7 +182,6 @@ def native_resolvers(session):
|
||||||
CPANResolver(session),
|
CPANResolver(session),
|
||||||
PypiResolver(session),
|
PypiResolver(session),
|
||||||
NpmResolver(session),
|
NpmResolver(session),
|
||||||
CargoResolver(session),
|
|
||||||
HackageResolver(session),
|
HackageResolver(session),
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
@ -227,7 +213,6 @@ def auto_resolver(session):
|
||||||
CPANResolver(session),
|
CPANResolver(session),
|
||||||
PypiResolver(session),
|
PypiResolver(session),
|
||||||
NpmResolver(session),
|
NpmResolver(session),
|
||||||
CargoResolver(session),
|
|
||||||
HackageResolver(session),
|
HackageResolver(session),
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
|
@ -27,6 +27,9 @@ class PlainSession(Session):
|
||||||
|
|
||||||
location = "/"
|
location = "/"
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return "%s()" % (type(self).__name__, )
|
||||||
|
|
||||||
def create_home(self):
|
def create_home(self):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
|
@ -98,6 +98,7 @@ blah (0.1) UNRELEASED; urgency=medium
|
||||||
apt = AptManager(session)
|
apt = AptManager(session)
|
||||||
apt._searchers = [DummyAptSearcher(self._apt_files)]
|
apt._searchers = [DummyAptSearcher(self._apt_files)]
|
||||||
context = BuildDependencyContext(
|
context = BuildDependencyContext(
|
||||||
|
("build", ),
|
||||||
self.tree,
|
self.tree,
|
||||||
apt,
|
apt,
|
||||||
subpath="",
|
subpath="",
|
||||||
|
|
Loading…
Add table
Reference in a new issue