Reformat using black.

This commit is contained in:
Jelmer Vernooij 2021-02-09 23:19:40 +00:00
parent 4b1591d864
commit 8aae9c93d8
No known key found for this signature in database
GPG key ID: 579C160D4C9E23E8
7 changed files with 327 additions and 266 deletions

View file

@ -45,14 +45,12 @@ def shebang_binary(p):
class UpstreamRequirement(object): class UpstreamRequirement(object):
def __init__(self, family, name): def __init__(self, family, name):
self.family = family self.family = family
self.name = name self.name = name
class UpstreamOutput(object): class UpstreamOutput(object):
def __init__(self, family, name): def __init__(self, family, name):
self.family = family self.family = family
self.name = name self.name = name

View file

@ -18,7 +18,8 @@
import logging import logging
import os import os
import sys import sys
from . import UpstreamPackage from . import note, UpstreamPackage
from .apt import UnidentifiedError
from .buildsystem import NoBuildToolsFound, detect_buildsystems from .buildsystem import NoBuildToolsFound, detect_buildsystems
from .build import run_build from .build import run_build
from .clean import run_clean from .clean import run_clean
@ -30,7 +31,7 @@ from .resolver import (
AutoResolver, AutoResolver,
NativeResolver, NativeResolver,
MissingDependencies, MissingDependencies,
) )
from .test import run_test from .test import run_test
@ -44,18 +45,20 @@ def get_necessary_declared_requirements(resolver, requirements, stages):
def install_necessary_declared_requirements(resolver, buildsystem, stages): def install_necessary_declared_requirements(resolver, buildsystem, stages):
missing = [] missing = []
missing.extend(get_necessary_declared_requirements( missing.extend(
resolver, buildsystem.get_declared_dependencies(), get_necessary_declared_requirements(
stages)) resolver, buildsystem.get_declared_dependencies(), stages
)
)
resolver.install(missing) resolver.install(missing)
STAGE_MAP = { STAGE_MAP = {
'dist': [], "dist": [],
'install': ['build'], "install": ["build"],
'test': ['test', 'dev'], "test": ["test", "dev"],
'build': ['build'], "build": ["build"],
'clean': [] "clean": [],
} }
@ -71,13 +74,16 @@ def main():
) )
parser.add_argument("--schroot", type=str, help="schroot to run in.") parser.add_argument("--schroot", type=str, help="schroot to run in.")
parser.add_argument( parser.add_argument(
'--resolve', choices=['explain', 'apt', 'native'], "--resolve",
default='apt', choices=["explain", "apt", "native"],
help='What to do about missing dependencies') default="apt",
help="What to do about missing dependencies",
)
parser.add_argument( parser.add_argument(
'--ignore-declared-dependencies', "--ignore-declared-dependencies",
action='store_true', action="store_true",
help='Ignore declared dependencies, follow build errors only') help="Ignore declared dependencies, follow build errors only",
)
args = parser.parse_args() args = parser.parse_args()
if args.schroot: if args.schroot:
from .session.schroot import SchrootSession from .session.schroot import SchrootSession
@ -88,13 +94,13 @@ def main():
session = PlainSession() session = PlainSession()
with session: with session:
if args.resolve == 'apt': if args.resolve == "apt":
resolver = AptResolver.from_session(session) resolver = AptResolver.from_session(session)
elif args.resolve == 'explain': elif args.resolve == "explain":
resolver = ExplainResolver.from_session(session) resolver = ExplainResolver.from_session(session)
elif args.resolve == 'native': elif args.resolve == "native":
resolver = NativeResolver.from_session(session) resolver = NativeResolver.from_session(session)
elif args.resolver == 'auto': elif args.resolver == "auto":
resolver = AutoResolver.from_session(session) resolver = AutoResolver.from_session(session)
os.chdir(args.directory) os.chdir(args.directory)
try: try:
@ -103,29 +109,30 @@ def main():
stages = STAGE_MAP[args.subcommand] stages = STAGE_MAP[args.subcommand]
if stages: if stages:
for bs in bss: for bs in bss:
install_necessary_declared_requirements( install_necessary_declared_requirements(resolver, bs, stages)
resolver, bs, stages) if args.subcommand == "dist":
if args.subcommand == 'dist':
run_dist(session=session, buildsystems=bss, resolver=resolver) run_dist(session=session, buildsystems=bss, resolver=resolver)
if args.subcommand == 'build': if args.subcommand == "build":
run_build(session, buildsystems=bss, resolver=resolver) run_build(session, buildsystems=bss, resolver=resolver)
if args.subcommand == 'clean': if args.subcommand == "clean":
run_clean(session, buildsystems=bss, resolver=resolver) run_clean(session, buildsystems=bss, resolver=resolver)
if args.subcommand == 'install': if args.subcommand == "install":
run_install(session, buildsystems=bss, resolver=resolver) run_install(session, buildsystems=bss, resolver=resolver)
if args.subcommand == 'test': if args.subcommand == "test":
run_test(session, buildsystems=bss, resolver=resolver) run_test(session, buildsystems=bss, resolver=resolver)
except UnidentifiedError:
return 1
except NoBuildToolsFound: except NoBuildToolsFound:
logging.info("No build tools found.") logging.info("No build tools found.")
return 1 return 1
except MissingDependencies as e: except MissingDependencies as e:
for req in e.requirements: for req in e.requirements:
note('Missing dependency (%s:%s)' % ( note("Missing dependency (%s:%s)" % (req.family, req.name))
req.family, req.name))
for resolver in [ for resolver in [
AptResolver.from_session(session), AptResolver.from_session(session),
NativeResolver.from_session(session)]: NativeResolver.from_session(session),
note(' %s' % (resolver.explain([req]), )) ]:
note(" %s" % (resolver.explain([req]),))
return 2 return 2
return 0 return 0

View file

@ -60,25 +60,25 @@ class BuildSystem(object):
class Pear(BuildSystem): class Pear(BuildSystem):
name = 'pear' name = "pear"
def __init__(self, path): def __init__(self, path):
self.path = path self.path = path
def setup(self, resolver): def setup(self, resolver):
resolver.install([UpstreamRequirement('binary', 'pear')]) resolver.install([UpstreamRequirement("binary", "pear")])
def dist(self, session, resolver): def dist(self, session, resolver):
self.setup(resolver) self.setup(resolver)
run_with_build_fixer(session, ['pear', 'package']) run_with_build_fixer(session, ["pear", "package"])
def test(self, session, resolver): def test(self, session, resolver):
self.setup(resolver) self.setup(resolver)
run_with_build_fixer(session, ['pear', 'run-tests']) run_with_build_fixer(session, ["pear", "run-tests"])
def build(self, session, resolver): def build(self, session, resolver):
self.setup(resolver) self.setup(resolver)
run_with_build_fixer(session, ['pear', 'build']) run_with_build_fixer(session, ["pear", "build"])
def clean(self, session, resolver): def clean(self, session, resolver):
self.setup(resolver) self.setup(resolver)
@ -86,201 +86,215 @@ class Pear(BuildSystem):
def install(self, session, resolver): def install(self, session, resolver):
self.setup(resolver) self.setup(resolver)
run_with_build_fixer(session, ['pear', 'install']) run_with_build_fixer(session, ["pear", "install"])
class SetupPy(BuildSystem): class SetupPy(BuildSystem):
name = 'setup.py' name = "setup.py"
def __init__(self, path): def __init__(self, path):
from distutils.core import run_setup from distutils.core import run_setup
self.result = run_setup(os.path.abspath(path), stop_after="init") self.result = run_setup(os.path.abspath(path), stop_after="init")
def setup(self, resolver): def setup(self, resolver):
resolver.install([ resolver.install(
UpstreamRequirement('python3', 'pip'), [
UpstreamRequirement('binary', 'python3'), UpstreamRequirement("python3", "pip"),
]) UpstreamRequirement("binary", "python3"),
with open('setup.py', 'r') as f: ]
)
with open("setup.py", "r") as f:
setup_py_contents = f.read() setup_py_contents = f.read()
try: try:
with open("setup.cfg", "r") as f: with open("setup.cfg", "r") as f:
setup_cfg_contents = f.read() setup_cfg_contents = f.read()
except FileNotFoundError: except FileNotFoundError:
setup_cfg_contents = '' setup_cfg_contents = ""
if 'setuptools' in setup_py_contents: if "setuptools" in setup_py_contents:
logging.info('Reference to setuptools found, installing.') logging.info("Reference to setuptools found, installing.")
resolver.install([UpstreamRequirement('python3', 'setuptools')]) resolver.install([UpstreamRequirement("python3", "setuptools")])
if ('setuptools_scm' in setup_py_contents or if (
'setuptools_scm' in setup_cfg_contents): "setuptools_scm" in setup_py_contents
logging.info('Reference to setuptools-scm found, installing.') or "setuptools_scm" in setup_cfg_contents
resolver.install([ ):
UpstreamRequirement('python3', 'setuptools-scm'), logging.info("Reference to setuptools-scm found, installing.")
UpstreamRequirement('binary', 'git'), resolver.install(
UpstreamRequirement('binary', 'mercurial'), [
]) UpstreamRequirement("python3", "setuptools-scm"),
UpstreamRequirement("binary", "git"),
UpstreamRequirement("binary", "mercurial"),
]
)
# TODO(jelmer): Install setup_requires # TODO(jelmer): Install setup_requires
def test(self, session, resolver): def test(self, session, resolver):
self.setup(resolver) self.setup(resolver)
self._run_setup(session, resolver, ['test']) self._run_setup(session, resolver, ["test"])
def dist(self, session, resolver): def dist(self, session, resolver):
self.setup(resolver) self.setup(resolver)
self._run_setup(session, resolver, ['sdist']) self._run_setup(session, resolver, ["sdist"])
def clean(self, session, resolver): def clean(self, session, resolver):
self.setup(resolver) self.setup(resolver)
self._run_setup(session, resolver, ['clean']) self._run_setup(session, resolver, ["clean"])
def install(self, session, resolver): def install(self, session, resolver):
self.setup(resolver) self.setup(resolver)
self._run_setup(session, resolver, ['install']) self._run_setup(session, resolver, ["install"])
def _run_setup(self, session, resolver, args): def _run_setup(self, session, resolver, args):
interpreter = shebang_binary('setup.py') interpreter = shebang_binary("setup.py")
if interpreter is not None: if interpreter is not None:
if interpreter in ('python3', 'python2', 'python'): if interpreter in ("python3", "python2", "python"):
resolver.install([UpstreamRequirement('binary', interpreter)]) resolver.install([UpstreamRequirement("binary", interpreter)])
else: else:
raise ValueError('Unknown interpreter %r' % interpreter) raise ValueError("Unknown interpreter %r" % interpreter)
run_with_build_fixer( run_with_build_fixer(session, ["./setup.py"] + args)
session, ['./setup.py'] + args)
else: else:
# Just assume it's Python 3 # Just assume it's Python 3
resolver.install([UpstreamRequirement('binary', 'python3')]) resolver.install([UpstreamRequirement("binary", "python3")])
run_with_build_fixer( run_with_build_fixer(session, ["python3", "./setup.py"] + args)
session, ['python3', './setup.py'] + args)
def get_declared_dependencies(self): def get_declared_dependencies(self):
for require in self.result.get_requires(): for require in self.result.get_requires():
yield 'build', UpstreamRequirement('python3', require) yield "build", UpstreamRequirement("python3", require)
for require in self.result.install_requires: if self.result.install_requires:
yield 'install', UpstreamRequirement('python3', require) for require in self.result.install_requires:
for require in self.result.tests_require: yield "install", UpstreamRequirement("python3", require)
yield 'test', UpstreamRequirement('python3', require) if self.result.tests_require:
for require in self.result.tests_require:
yield "test", UpstreamRequirement("python3", require)
def get_declared_outputs(self): def get_declared_outputs(self):
for script in (self.result.scripts or []): for script in self.result.scripts or []:
yield UpstreamOutput('binary', os.path.basename(script)) yield UpstreamOutput("binary", os.path.basename(script))
entry_points = self.result.entry_points or {} entry_points = self.result.entry_points or {}
for script in entry_points.get('console_scripts', []): for script in entry_points.get("console_scripts", []):
yield UpstreamOutput('binary', script.split('=')[0]) yield UpstreamOutput("binary", script.split("=")[0])
for package in self.result.packages or []: for package in self.result.packages or []:
yield UpstreamOutput('python3', package) yield UpstreamOutput("python3", package)
class PyProject(BuildSystem): class PyProject(BuildSystem):
name = 'pyproject' name = "pyproject"
def __init__(self, path):
self.path = path
self.pyproject = self.load_toml()
def load_toml(self): def load_toml(self):
import toml import toml
with open("pyproject.toml", "r") as pf: with open(self.path, "r") as pf:
return toml.load(pf) return toml.load(pf)
def dist(self, session, resolver): def dist(self, session, resolver):
pyproject = self.load_toml() if "poetry" in self.pyproject.get("tool", []):
if "poetry" in pyproject.get("tool", []):
logging.info( logging.info(
'Found pyproject.toml with poetry section, ' "Found pyproject.toml with poetry section, " "assuming poetry project."
'assuming poetry project.') )
resolver.install([ resolver.install(
UpstreamRequirement('python3', 'venv'), [
UpstreamRequirement('python3', 'pip'), UpstreamRequirement("python3", "venv"),
]) UpstreamRequirement("python3", "pip"),
session.check_call(['pip3', 'install', 'poetry'], user='root') ]
session.check_call(['poetry', 'build', '-f', 'sdist']) )
session.check_call(["pip3", "install", "poetry"], user="root")
session.check_call(["poetry", "build", "-f", "sdist"])
return return
raise AssertionError("no supported section in pyproject.toml") raise AssertionError("no supported section in pyproject.toml")
class SetupCfg(BuildSystem): class SetupCfg(BuildSystem):
name = 'setup.cfg' name = "setup.cfg"
def __init__(self, path): def __init__(self, path):
self.path = path self.path = path
def setup(self, resolver): def setup(self, resolver):
resolver.install([ resolver.install(
UpstreamRequirement('python3', 'pep517'), [
UpstreamRequirement('python3', 'pip'), UpstreamRequirement("python3", "pep517"),
]) UpstreamRequirement("python3", "pip"),
]
)
def dist(self, session, resolver): def dist(self, session, resolver):
self.setup(resolver) self.setup(resolver)
session.check_call(['python3', '-m', 'pep517.build', '-s', '.']) session.check_call(["python3", "-m", "pep517.build", "-s", "."])
class Npm(BuildSystem): class Npm(BuildSystem):
name = 'npm' name = "npm"
def __init__(self, path): def __init__(self, path):
import json import json
with open(path, 'r') as f:
with open(path, "r") as f:
self.package = json.load(f) self.package = json.load(f)
def get_declared_dependencies(self): def get_declared_dependencies(self):
if 'devDependencies' in self.package: if "devDependencies" in self.package:
for name, unused_version in ( for name, unused_version in self.package["devDependencies"].items():
self.package['devDependencies'].items()):
# TODO(jelmer): Look at version # TODO(jelmer): Look at version
yield 'dev', UpstreamRequirement('npm', name) yield "dev", UpstreamRequirement("npm", name)
def setup(self, resolver): def setup(self, resolver):
resolver.install([UpstreamRequirement('binary', 'npm')]) resolver.install([UpstreamRequirement("binary", "npm")])
def dist(self, session, resolver): def dist(self, session, resolver):
self.setup(resolver) self.setup(resolver)
run_with_build_fixer(session, ['npm', 'pack']) run_with_build_fixer(session, ["npm", "pack"])
class Waf(BuildSystem): class Waf(BuildSystem):
name = 'waf' name = "waf"
def __init__(self, path): def __init__(self, path):
self.path = path self.path = path
def setup(self, resolver): def setup(self, resolver):
resolver.install([UpstreamRequirement('binary', 'python3')]) resolver.install([UpstreamRequirement("binary", "python3")])
def dist(self, session, resolver): def dist(self, session, resolver):
self.setup(resolver) self.setup(resolver)
run_with_build_fixer(session, ['./waf', 'dist']) run_with_build_fixer(session, ["./waf", "dist"])
class Gem(BuildSystem): class Gem(BuildSystem):
name = 'gem' name = "gem"
def __init__(self, path): def __init__(self, path):
self.path = path self.path = path
def setup(self, resolver): def setup(self, resolver):
resolver.install([UpstreamRequirement('binary', 'gem2deb')]) resolver.install([UpstreamRequirement("binary", "gem2deb")])
def dist(self, session, resolver): def dist(self, session, resolver):
self.setup(resolver) self.setup(resolver)
gemfiles = [entry.name for entry in session.scandir('.') gemfiles = [
if entry.name.endswith('.gem')] entry.name for entry in session.scandir(".") if entry.name.endswith(".gem")
]
if len(gemfiles) > 1: if len(gemfiles) > 1:
logging.warning('More than one gemfile. Trying the first?') logging.warning("More than one gemfile. Trying the first?")
run_with_build_fixer(session, ['gem2tgz', gemfiles[0]]) run_with_build_fixer(session, ["gem2tgz", gemfiles[0]])
class DistInkt(BuildSystem): class DistInkt(BuildSystem):
def __init__(self, path): def __init__(self, path):
self.path = path self.path = path
self.name = 'dist-zilla' self.name = "dist-zilla"
self.dist_inkt_class = None self.dist_inkt_class = None
with open('dist.ini', 'rb') as f: with open("dist.ini", "rb") as f:
for line in f: for line in f:
if not line.startswith(b";;"): if not line.startswith(b";;"):
continue continue
@ -290,102 +304,119 @@ class DistInkt(BuildSystem):
continue continue
if key.strip() == b"class" and value.strip().startswith(b"'Dist::Inkt"): if key.strip() == b"class" and value.strip().startswith(b"'Dist::Inkt"):
logging.info( logging.info(
'Found Dist::Inkt section in dist.ini, ' "Found Dist::Inkt section in dist.ini, " "assuming distinkt."
'assuming distinkt.') )
self.name = 'dist-inkt' self.name = "dist-inkt"
self.dist_inkt_class = value.decode().strip("'") self.dist_inkt_class = value.decode().strip("'")
return return
logging.info('Found dist.ini, assuming dist-zilla.') logging.info("Found dist.ini, assuming dist-zilla.")
def setup(self, resolver): def setup(self, resolver):
resolver.install([ resolver.install(
UpstreamRequirement('perl', 'Dist::Inkt'), [
]) UpstreamRequirement("perl", "Dist::Inkt"),
]
)
def dist(self, session, resolver): def dist(self, session, resolver):
self.setup(resolver) self.setup(resolver)
if self.name == 'dist-inkt': if self.name == "dist-inkt":
resolver.install([ resolver.install([UpstreamRequirement("perl-module", self.dist_inkt_class)])
UpstreamRequirement('perl-module', self.dist_inkt_class)]) run_with_build_fixer(session, ["distinkt-dist"])
run_with_build_fixer(session, ['distinkt-dist'])
else: else:
# Default to invoking Dist::Zilla # Default to invoking Dist::Zilla
resolver.install([UpstreamRequirement('perl', 'Dist::Zilla')]) resolver.install([UpstreamRequirement("perl", "Dist::Zilla")])
run_with_build_fixer(session, ['dzil', 'build', '--in', '..']) run_with_build_fixer(session, ["dzil", "build", "--in", ".."])
class Make(BuildSystem): class Make(BuildSystem):
name = 'make' name = "make"
def setup(self, session, resolver): def setup(self, session, resolver):
if session.exists('Makefile.PL') and not session.exists('Makefile'): if session.exists("Makefile.PL") and not session.exists("Makefile"):
resolver.install([UpstreamRequirement('binary', 'perl')]) resolver.install([UpstreamRequirement("binary", "perl")])
run_with_build_fixer(session, ['perl', 'Makefile.PL']) run_with_build_fixer(session, ["perl", "Makefile.PL"])
if not session.exists('Makefile') and not session.exists('configure'): if not session.exists("Makefile") and not session.exists("configure"):
if session.exists('autogen.sh'): if session.exists("autogen.sh"):
if shebang_binary('autogen.sh') is None: if shebang_binary("autogen.sh") is None:
run_with_build_fixer( run_with_build_fixer(session, ["/bin/sh", "./autogen.sh"])
session, ['/bin/sh', './autogen.sh'])
try: try:
run_with_build_fixer( run_with_build_fixer(session, ["./autogen.sh"])
session, ['./autogen.sh'])
except UnidentifiedError as e: except UnidentifiedError as e:
if ("Gnulib not yet bootstrapped; " if (
"run ./bootstrap instead.\n" in e.lines): "Gnulib not yet bootstrapped; "
"run ./bootstrap instead.\n" in e.lines
):
run_with_build_fixer(session, ["./bootstrap"]) run_with_build_fixer(session, ["./bootstrap"])
run_with_build_fixer(session, ['./autogen.sh']) run_with_build_fixer(session, ["./autogen.sh"])
else: else:
raise raise
elif (session.exists('configure.ac') or elif session.exists("configure.ac") or session.exists("configure.in"):
session.exists('configure.in')): resolver.install(
resolver.install([ [
UpstreamRequirement('binary', 'autoconf'), UpstreamRequirement("binary", "autoconf"),
UpstreamRequirement('binary', 'automake'), UpstreamRequirement("binary", "automake"),
UpstreamRequirement('binary', 'gettextize'), UpstreamRequirement("binary", "gettextize"),
UpstreamRequirement('binary', 'libtoolize'), UpstreamRequirement("binary", "libtoolize"),
]) ]
run_with_build_fixer(session, ['autoreconf', '-i']) )
run_with_build_fixer(session, ["autoreconf", "-i"])
if not session.exists('Makefile') and session.exists('configure'): if not session.exists("Makefile") and session.exists("configure"):
session.check_call(['./configure']) session.check_call(["./configure"])
def dist(self, session, resolver): def dist(self, session, resolver):
self.setup(session, resolver) self.setup(session, resolver)
resolver.install([UpstreamRequirement('binary', 'make')]) resolver.install([UpstreamRequirement("binary", "make")])
try: try:
run_with_build_fixer(session, ['make', 'dist']) run_with_build_fixer(session, ["make", "dist"])
except UnidentifiedError as e: except UnidentifiedError as e:
if "make: *** No rule to make target 'dist'. Stop.\n" in e.lines: if "make: *** No rule to make target 'dist'. Stop.\n" in e.lines:
pass pass
elif "make[1]: *** No rule to make target 'dist'. Stop.\n" in e.lines: elif "make[1]: *** No rule to make target 'dist'. Stop.\n" in e.lines:
pass pass
elif ("Reconfigure the source tree "
"(via './config' or 'perl Configure'), please.\n"
) in e.lines:
run_with_build_fixer(session, ['./config'])
run_with_build_fixer(session, ['make', 'dist'])
elif ( elif (
"Please try running 'make manifest' and then run " "Reconfigure the source tree "
"'make dist' again.\n" in e.lines): "(via './config' or 'perl Configure'), please.\n"
run_with_build_fixer(session, ['make', 'manifest']) ) in e.lines:
run_with_build_fixer(session, ['make', 'dist']) run_with_build_fixer(session, ["./config"])
run_with_build_fixer(session, ["make", "dist"])
elif (
"Please try running 'make manifest' and then run "
"'make dist' again.\n" in e.lines
):
run_with_build_fixer(session, ["make", "manifest"])
run_with_build_fixer(session, ["make", "dist"])
elif "Please run ./configure first\n" in e.lines: elif "Please run ./configure first\n" in e.lines:
run_with_build_fixer(session, ['./configure']) run_with_build_fixer(session, ["./configure"])
run_with_build_fixer(session, ['make', 'dist']) run_with_build_fixer(session, ["make", "dist"])
elif any([re.match( elif any(
r'Makefile:[0-9]+: \*\*\* Missing \'Make.inc\' ' [
r'Run \'./configure \[options\]\' and retry. Stop.\n', re.match(
line) for line in e.lines]): r"Makefile:[0-9]+: \*\*\* Missing \'Make.inc\' "
run_with_build_fixer(session, ['./configure']) r"Run \'./configure \[options\]\' and retry. Stop.\n",
run_with_build_fixer(session, ['make', 'dist']) line,
elif any([re.match( )
r'Problem opening MANIFEST: No such file or directory ' for line in e.lines
r'at .* line [0-9]+\.', line) for line in e.lines]): ]
run_with_build_fixer(session, ['make', 'manifest']) ):
run_with_build_fixer(session, ['make', 'dist']) run_with_build_fixer(session, ["./configure"])
run_with_build_fixer(session, ["make", "dist"])
elif any(
[
re.match(
r"Problem opening MANIFEST: No such file or directory "
r"at .* line [0-9]+\.",
line,
)
for line in e.lines
]
):
run_with_build_fixer(session, ["make", "manifest"])
run_with_build_fixer(session, ["make", "dist"])
else: else:
raise raise
else: else:
@ -393,46 +424,48 @@ class Make(BuildSystem):
def get_declared_dependencies(self): def get_declared_dependencies(self):
# TODO(jelmer): Split out the perl-specific stuff? # TODO(jelmer): Split out the perl-specific stuff?
if os.path.exists('META.yml'): if os.path.exists("META.yml"):
# See http://module-build.sourceforge.net/META-spec-v1.4.html for # See http://module-build.sourceforge.net/META-spec-v1.4.html for
# the specification of the format. # the specification of the format.
import ruamel.yaml import ruamel.yaml
import ruamel.yaml.reader import ruamel.yaml.reader
with open('META.yml', 'rb') as f:
with open("META.yml", "rb") as f:
try: try:
data = ruamel.yaml.load(f, ruamel.yaml.SafeLoader) data = ruamel.yaml.load(f, ruamel.yaml.SafeLoader)
except ruamel.yaml.reader.ReaderError as e: except ruamel.yaml.reader.ReaderError as e:
warnings.warn('Unable to parse META.yml: %s' % e) warnings.warn("Unable to parse META.yml: %s" % e)
return return
for require in data.get('requires', []): for require in data.get("requires", []):
yield 'build', UpstreamRequirement('perl', require) yield "build", UpstreamRequirement("perl", require)
class Cargo(BuildSystem): class Cargo(BuildSystem):
name = 'cargo' name = "cargo"
def __init__(self, path): def __init__(self, path):
from toml.decoder import load from toml.decoder import load
with open(path, 'r') as f:
with open(path, "r") as f:
self.cargo = load(f) self.cargo = load(f)
def get_declared_dependencies(self): def get_declared_dependencies(self):
if 'dependencies' in self.cargo: if "dependencies" in self.cargo:
for name, details in self.cargo['dependencies'].items(): for name, details in self.cargo["dependencies"].items():
# TODO(jelmer): Look at details['features'], details['version'] # TODO(jelmer): Look at details['features'], details['version']
yield 'build', UpstreamRequirement('cargo-crate', name) yield "build", UpstreamRequirement("cargo-crate", name)
class Golang(BuildSystem): class Golang(BuildSystem):
"""Go builds.""" """Go builds."""
name = 'golang' name = "golang"
class Maven(BuildSystem): class Maven(BuildSystem):
name = 'maven' name = "maven"
def __init__(self, path): def __init__(self, path):
self.path = path self.path = path
@ -440,83 +473,99 @@ class Maven(BuildSystem):
class Cabal(BuildSystem): class Cabal(BuildSystem):
name = 'cabal' name = "cabal"
def __init__(self, path): def __init__(self, path):
self.path = path self.path = path
def detect_buildsystems(path): def detect_buildsystems(path, trust_package=False):
"""Detect build systems.""" """Detect build systems."""
if os.path.exists(os.path.join(path, 'package.xml')): if os.path.exists(os.path.join(path, "package.xml")):
logging.info('Found package.xml, assuming pear package.') logging.info("Found package.xml, assuming pear package.")
yield Pear('package.xml') yield Pear("package.xml")
if os.path.exists(os.path.join(path, 'setup.py')): if os.path.exists(os.path.join(path, "setup.py")):
logging.info('Found setup.py, assuming python project.') logging.info("Found setup.py, assuming python project.")
yield SetupPy('setup.py') yield SetupPy("setup.py")
elif os.path.exists(os.path.join(path, 'pyproject.toml')): elif os.path.exists(os.path.join(path, "pyproject.toml")):
logging.info('Found pyproject.toml, assuming python project.') logging.info("Found pyproject.toml, assuming python project.")
yield PyProject() yield PyProject("pyproject.toml")
elif os.path.exists(os.path.join(path, 'setup.cfg')): elif os.path.exists(os.path.join(path, "setup.cfg")):
logging.info('Found setup.cfg, assuming python project.') logging.info("Found setup.cfg, assuming python project.")
yield SetupCfg('setup.cfg') yield SetupCfg("setup.cfg")
if os.path.exists(os.path.join(path, 'package.json')): if os.path.exists(os.path.join(path, "package.json")):
logging.info('Found package.json, assuming node package.') logging.info("Found package.json, assuming node package.")
yield Npm('package.json') yield Npm("package.json")
if os.path.exists(os.path.join(path, 'waf')): if os.path.exists(os.path.join(path, "waf")):
logging.info('Found waf, assuming waf package.') logging.info("Found waf, assuming waf package.")
yield Waf('waf') yield Waf("waf")
if os.path.exists(os.path.join(path, 'Cargo.toml')): if os.path.exists(os.path.join(path, "Cargo.toml")):
logging.info('Found Cargo.toml, assuming rust cargo package.') logging.info("Found Cargo.toml, assuming rust cargo package.")
yield Cargo('Cargo.toml') yield Cargo("Cargo.toml")
if os.path.exists(os.path.join(path, 'pom.xml')): if os.path.exists(os.path.join(path, "pom.xml")):
logging.info('Found pom.xml, assuming maven package.') logging.info("Found pom.xml, assuming maven package.")
yield Maven('pom.xml') yield Maven("pom.xml")
if (os.path.exists(os.path.join(path, 'dist.ini')) and if os.path.exists(os.path.join(path, "dist.ini")) and not os.path.exists(
not os.path.exists(os.path.join(path, 'Makefile.PL'))): os.path.join(path, "Makefile.PL")
yield DistInkt('dist.ini') ):
yield DistInkt("dist.ini")
gemfiles = [ gemfiles = [entry.name for entry in os.scandir(path) if entry.name.endswith(".gem")]
entry.name for entry in os.scandir(path)
if entry.name.endswith('.gem')]
if gemfiles: if gemfiles:
yield Gem(gemfiles[0]) yield Gem(gemfiles[0])
if any([os.path.exists(os.path.join(path, p)) for p in [ if any(
'Makefile', 'Makefile.PL', 'autogen.sh', 'configure.ac', [
'configure.in']]): os.path.exists(os.path.join(path, p))
for p in [
"Makefile",
"Makefile.PL",
"autogen.sh",
"configure.ac",
"configure.in",
]
]
):
yield Make() yield Make()
cabal_filenames = [ cabal_filenames = [
entry.name for entry in os.scandir(path) entry.name for entry in os.scandir(path) if entry.name.endswith(".cabal")
if entry.name.endswith('.cabal')] ]
if cabal_filenames: if cabal_filenames:
if len(cabal_filenames) == 1: if len(cabal_filenames) == 1:
yield Cabal(cabal_filenames[0]) yield Cabal(cabal_filenames[0])
else: else:
warnings.warn( warnings.warn(
'More than one cabal filename, ignoring all: %r' % "More than one cabal filename, ignoring all: %r" % cabal_filenames
cabal_filenames) )
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
with open('.travis.yml', 'rb') as f:
with open(".travis.yml", "rb") as f:
try: try:
data = ruamel.yaml.load(f, ruamel.yaml.SafeLoader) data = ruamel.yaml.load(f, ruamel.yaml.SafeLoader)
except ruamel.yaml.reader.ReaderError as e: except ruamel.yaml.reader.ReaderError as e:
warnings.warn('Unable to parse .travis.yml: %s' % (e, )) warnings.warn("Unable to parse .travis.yml: %s" % (e,))
else: else:
language = data.get('language') language = data.get("language")
if language == 'go': if language == "go":
yield Golang() yield Golang()
for entry in os.scandir(path): for entry in os.scandir(path):
if entry.name.endswith('.go'): if entry.name.endswith(".go"):
yield Golang() yield Golang()
break break
def get_buildsystem(path, trust_package=False):
for buildsystem in detect_buildsystems(path, trust_package=trust_package):
return buildsystem
raise NoBuildToolsFound()

View file

@ -35,13 +35,14 @@ from debmutate.changelog import get_maintainer, format_datetime
from breezy import osutils from breezy import osutils
from breezy.mutabletree import MutableTree from breezy.mutabletree import MutableTree
from breezy.plugins.debian.builder import BuildFailedError from breezy.plugins.debian.util import BuildFailedError
from buildlog_consultant.sbuild import ( from buildlog_consultant.sbuild import (
worker_failure_from_sbuild_log, worker_failure_from_sbuild_log,
SbuildFailure, SbuildFailure,
) )
DEFAULT_BUILDER = "sbuild --no-clean-source" DEFAULT_BUILDER = "sbuild --no-clean-source"

View file

@ -30,7 +30,7 @@ from debian.deb822 import (
Deb822, Deb822,
PkgRelation, PkgRelation,
Release, Release,
) )
from debian.changelog import Version from debian.changelog import Version
from breezy.commit import PointlessCommit from breezy.commit import PointlessCommit
@ -113,6 +113,7 @@ from buildlog_consultant.sbuild import (
SbuildFailure, SbuildFailure,
) )
DEFAULT_MAX_ITERATIONS = 10 DEFAULT_MAX_ITERATIONS = 10
@ -124,18 +125,21 @@ class CircularDependency(Exception):
class DependencyContext(object): class DependencyContext(object):
def __init__(
def __init__(self, tree: MutableTree, self,
subpath: str = '', committer: Optional[str] = None, tree: MutableTree,
update_changelog: bool = True): subpath: str = "",
committer: Optional[str] = None,
update_changelog: bool = True,
):
self.tree = tree self.tree = tree
self.subpath = subpath self.subpath = subpath
self.committer = committer self.committer = committer
self.update_changelog = update_changelog self.update_changelog = update_changelog
def add_dependency( def add_dependency(
self, package: str, self, package: str, minimum_version: Optional[Version] = None
minimum_version: Optional[Version] = None) -> bool: ) -> bool:
raise NotImplementedError(self.add_dependency) raise NotImplementedError(self.add_dependency)
@ -273,9 +277,13 @@ def add_test_dependency(
) )
def commit_debian_changes(tree: MutableTree, subpath: str, def commit_debian_changes(
summary: str, committer: Optional[str] = None, tree: MutableTree,
update_changelog: bool = True) -> bool: subpath: str,
summary: str,
committer: Optional[str] = None,
update_changelog: bool = True,
) -> bool:
with tree.lock_write(): with tree.lock_write():
try: try:
if update_changelog: if update_changelog:

View file

@ -115,12 +115,16 @@ class DistCatcher(object):
def create_dist_schroot( def create_dist_schroot(
tree: Tree, target_dir: str, tree: Tree,
chroot: str, packaging_tree: Optional[Tree] = None, target_dir: str,
include_controldir: bool = True, chroot: str,
subdir: Optional[str] = None) -> str: packaging_tree: Optional[Tree] = None,
include_controldir: bool = True,
subdir: Optional[str] = None,
) -> str:
from .buildsystem import detect_buildsystems from .buildsystem import detect_buildsystems
from .resolver import AptResolver from .resolver import AptResolver
if subdir is None: if subdir is None:
subdir = "package" subdir = "package"
with SchrootSession(chroot) as session: with SchrootSession(chroot) as session:

View file

@ -17,13 +17,11 @@
class MissingDependencies(Exception): class MissingDependencies(Exception):
def __init__(self, reqs): def __init__(self, reqs):
self.requirements = reqs self.requirements = reqs
class Resolver(object): class Resolver(object):
def install(self, requirements): def install(self, requirements):
raise NotImplementedError(self.install) raise NotImplementedError(self.install)
@ -32,21 +30,20 @@ class Resolver(object):
class AptResolver(Resolver): class AptResolver(Resolver):
def __init__(self, apt): def __init__(self, apt):
self.apt = apt self.apt = apt
@classmethod @classmethod
def from_session(cls, session): def from_session(cls, session):
from .apt import AptManager from .apt import AptManager
return cls(AptManager(session)) return cls(AptManager(session))
def install(self, requirements): def install(self, requirements):
missing = [] missing = []
for req in requirements: for req in requirements:
pps = list(self._possible_paths(req)) pps = list(self._possible_paths(req))
if (not pps or if not pps or not any(self.apt.session.exists(p) for p in pps):
not any(self.apt.session.exists(p) for p in pps)):
missing.append(req) missing.append(req)
if missing: if missing:
self.apt.install(list(self.resolve(missing))) self.apt.install(list(self.resolve(missing)))
@ -55,22 +52,21 @@ class AptResolver(Resolver):
raise NotImplementedError(self.explain) raise NotImplementedError(self.explain)
def _possible_paths(self, req): def _possible_paths(self, req):
if req.family == 'binary': if req.family == "binary":
yield '/usr/bin/%s' % req.name yield "/usr/bin/%s" % req.name
else: else:
return return
def resolve(self, requirements): def resolve(self, requirements):
for req in requirements: for req in requirements:
if req.family == 'python3': if req.family == "python3":
yield 'python3-%s' % req.name yield "python3-%s" % req.name
else: else:
list(self._possible_paths(req)) list(self._possible_paths(req))
raise NotImplementedError raise NotImplementedError
class NativeResolver(Resolver): class NativeResolver(Resolver):
def __init__(self, session): def __init__(self, session):
self.session = session self.session = session
@ -86,7 +82,6 @@ class NativeResolver(Resolver):
class ExplainResolver(Resolver): class ExplainResolver(Resolver):
def __init__(self, session): def __init__(self, session):
self.session = session self.session = session
@ -99,8 +94,7 @@ class ExplainResolver(Resolver):
class AutoResolver(Resolver): class AutoResolver(Resolver):
"""Automatically find out the most appropriate way to instal dependencies. """Automatically find out the most appropriate way to instal dependencies."""
"""
def __init__(self, session): def __init__(self, session):
self.session = session self.session = session