More work on factoring out resolver.
This commit is contained in:
parent
713a624b00
commit
fa222a6ae4
8 changed files with 399 additions and 226 deletions
|
@ -42,3 +42,17 @@ def shebang_binary(p):
|
||||||
if args[0] in (b"/usr/bin/env", b"env"):
|
if args[0] in (b"/usr/bin/env", b"env"):
|
||||||
return os.path.basename(args[1].decode()).strip()
|
return os.path.basename(args[1].decode()).strip()
|
||||||
return os.path.basename(args[0].decode()).strip()
|
return os.path.basename(args[0].decode()).strip()
|
||||||
|
|
||||||
|
|
||||||
|
class UpstreamRequirement(object):
|
||||||
|
|
||||||
|
def __init__(self, family, name):
|
||||||
|
self.family = family
|
||||||
|
self.name = name
|
||||||
|
|
||||||
|
|
||||||
|
class UpstreamOutput(object):
|
||||||
|
|
||||||
|
def __init__(self, family, name):
|
||||||
|
self.family = family
|
||||||
|
self.name = name
|
||||||
|
|
|
@ -34,14 +34,31 @@ from .resolver import (
|
||||||
from .test import run_test
|
from .test import run_test
|
||||||
|
|
||||||
|
|
||||||
def install_declared_requirements(resolver, requirements, subcommand):
|
def get_necessary_declared_requirements(resolver, requirements, stages):
|
||||||
missing = []
|
missing = []
|
||||||
for req in requirements:
|
for stage, req in requirements:
|
||||||
# TODO(jelmer): Look at stage
|
if stage in stages:
|
||||||
missing.append(UpstreamPackage(req.package.family, req.package.name))
|
missing.append(req)
|
||||||
|
return missing
|
||||||
|
|
||||||
|
|
||||||
|
def install_necessary_declared_requirements(resolver, buildsystem, stages):
|
||||||
|
missing = []
|
||||||
|
missing.extend(get_necessary_declared_requirements(
|
||||||
|
resolver, buildsystem.get_declared_dependencies(),
|
||||||
|
stages))
|
||||||
resolver.install(missing)
|
resolver.install(missing)
|
||||||
|
|
||||||
|
|
||||||
|
STAGE_MAP = {
|
||||||
|
'dist': [],
|
||||||
|
'install': ['build'],
|
||||||
|
'test': ['test', 'dev'],
|
||||||
|
'build': ['build'],
|
||||||
|
'clean': []
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
import argparse
|
import argparse
|
||||||
|
|
||||||
|
@ -81,26 +98,23 @@ def main():
|
||||||
resolver = AutoResolver.from_session(session)
|
resolver = AutoResolver.from_session(session)
|
||||||
os.chdir(args.directory)
|
os.chdir(args.directory)
|
||||||
try:
|
try:
|
||||||
|
bss = list(detect_buildsystems(args.directory))
|
||||||
if not args.ignore_declared_dependencies:
|
if not args.ignore_declared_dependencies:
|
||||||
from upstream_ontologist.guess import get_upstream_info
|
stages = STAGE_MAP[args.subcommand]
|
||||||
buildsystem, requirements, metadata = get_upstream_info(
|
if stages:
|
||||||
path=args.directory,
|
for bs in bss:
|
||||||
trust_package=True,
|
install_necessary_declared_requirements(
|
||||||
net_access=True,
|
resolver, bs, stages)
|
||||||
consult_external_directory=True,
|
|
||||||
check=True)
|
|
||||||
install_declared_requirements(
|
|
||||||
resolver, requirements, args.subcommand)
|
|
||||||
if args.subcommand == 'dist':
|
if args.subcommand == 'dist':
|
||||||
run_dist(session=session, resolver=resolver)
|
run_dist(session=session, buildsystems=bss, resolver=resolver)
|
||||||
if args.subcommand == 'build':
|
if args.subcommand == 'build':
|
||||||
run_build(session, resolver=resolver)
|
run_build(session, buildsystems=bss, resolver=resolver)
|
||||||
if args.subcommand == 'clean':
|
if args.subcommand == 'clean':
|
||||||
run_clean(session, resolver=resolver)
|
run_clean(session, buildsystems=bss, resolver=resolver)
|
||||||
if args.subcommand == 'install':
|
if args.subcommand == 'install':
|
||||||
run_install(session, resolver=resolver)
|
run_install(session, buildsystems=bss, resolver=resolver)
|
||||||
if args.subcommand == 'test':
|
if args.subcommand == 'test':
|
||||||
run_test(session, resolver=resolver)
|
run_test(session, buildsystems=bss, resolver=resolver)
|
||||||
except NoBuildToolsFound:
|
except NoBuildToolsFound:
|
||||||
logging.info("No build tools found.")
|
logging.info("No build tools found.")
|
||||||
return 1
|
return 1
|
||||||
|
|
|
@ -15,16 +15,16 @@
|
||||||
# along with this program; if not, write to the Free Software
|
# along with this program; if not, write to the Free Software
|
||||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
|
||||||
from .buildsystem import detect_buildsystems, NoBuildToolsFound
|
from .buildsystem import NoBuildToolsFound
|
||||||
|
|
||||||
|
|
||||||
def run_build(session, resolver):
|
def run_build(session, buildsystems, resolver):
|
||||||
# Some things want to write to the user's home directory,
|
# Some things want to write to the user's home directory,
|
||||||
# e.g. pip caches in ~/.cache
|
# e.g. pip caches in ~/.cache
|
||||||
session.create_home()
|
session.create_home()
|
||||||
|
|
||||||
for buildsystem in detect_buildsystems(session):
|
for buildsystem in buildsystems:
|
||||||
buildsystem.build(resolver)
|
buildsystem.build(session, resolver)
|
||||||
return
|
return
|
||||||
|
|
||||||
raise NoBuildToolsFound()
|
raise NoBuildToolsFound()
|
||||||
|
|
|
@ -18,9 +18,11 @@
|
||||||
|
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
|
import os
|
||||||
import re
|
import re
|
||||||
|
import warnings
|
||||||
|
|
||||||
from . import shebang_binary, UpstreamPackage
|
from . import shebang_binary, UpstreamRequirement, UpstreamOutput
|
||||||
from .apt import UnidentifiedError
|
from .apt import UnidentifiedError
|
||||||
from .fix_build import run_with_build_fixer
|
from .fix_build import run_with_build_fixer
|
||||||
|
|
||||||
|
@ -32,57 +34,73 @@ class NoBuildToolsFound(Exception):
|
||||||
class BuildSystem(object):
|
class BuildSystem(object):
|
||||||
"""A particular buildsystem."""
|
"""A particular buildsystem."""
|
||||||
|
|
||||||
def __init__(self, session):
|
name: str
|
||||||
self.session = session
|
|
||||||
|
|
||||||
def dist(self, resolver):
|
def dist(self, session, resolver):
|
||||||
raise NotImplementedError(self.dist)
|
raise NotImplementedError(self.dist)
|
||||||
|
|
||||||
def test(self, resolver):
|
def test(self, session, resolver):
|
||||||
raise NotImplementedError(self.test)
|
raise NotImplementedError(self.test)
|
||||||
|
|
||||||
def build(self, resolver):
|
def build(self, session, resolver):
|
||||||
raise NotImplementedError(self.build)
|
raise NotImplementedError(self.build)
|
||||||
|
|
||||||
def clean(self, resolver):
|
def clean(self, session, resolver):
|
||||||
raise NotImplementedError(self.clean)
|
raise NotImplementedError(self.clean)
|
||||||
|
|
||||||
def install(self, resolver):
|
def install(self, session, resolver):
|
||||||
raise NotImplementedError(self.install)
|
raise NotImplementedError(self.install)
|
||||||
|
|
||||||
|
def get_declared_dependencies(self):
|
||||||
|
raise NotImplementedError(self.get_declared_dependencies)
|
||||||
|
|
||||||
|
def get_declared_outputs(self):
|
||||||
|
raise NotImplementedError(self.get_declared_outputs)
|
||||||
|
|
||||||
|
|
||||||
class Pear(BuildSystem):
|
class Pear(BuildSystem):
|
||||||
|
|
||||||
|
name = 'pear'
|
||||||
|
|
||||||
|
def __init__(self, path):
|
||||||
|
self.path = path
|
||||||
|
|
||||||
def setup(self, resolver):
|
def setup(self, resolver):
|
||||||
resolver.install([UpstreamPackage('binary', 'pear')])
|
resolver.install([UpstreamRequirement('binary', 'pear')])
|
||||||
|
|
||||||
def dist(self, resolver):
|
def dist(self, session, resolver):
|
||||||
self.setup(resolver)
|
self.setup(resolver)
|
||||||
run_with_build_fixer(self.session, ['pear', 'package'])
|
run_with_build_fixer(session, ['pear', 'package'])
|
||||||
|
|
||||||
def test(self, resolver):
|
def test(self, session, resolver):
|
||||||
self.setup()
|
|
||||||
run_with_build_fixer(self.session, ["pear", "run-tests"])
|
|
||||||
|
|
||||||
def build(self, resolver):
|
|
||||||
self.setup(resolver)
|
self.setup(resolver)
|
||||||
run_with_build_fixer(self.session, ['pear', 'build'])
|
run_with_build_fixer(session, ['pear', 'run-tests'])
|
||||||
|
|
||||||
def clean(self, resolver):
|
def build(self, session, resolver):
|
||||||
|
self.setup(resolver)
|
||||||
|
run_with_build_fixer(session, ['pear', 'build'])
|
||||||
|
|
||||||
|
def clean(self, session, resolver):
|
||||||
self.setup(resolver)
|
self.setup(resolver)
|
||||||
# TODO
|
# TODO
|
||||||
|
|
||||||
def install(self, resolver):
|
def install(self, session, resolver):
|
||||||
self.setup(resolver)
|
self.setup(resolver)
|
||||||
run_with_build_fixer(self.session, ['pear', 'install'])
|
run_with_build_fixer(session, ['pear', 'install'])
|
||||||
|
|
||||||
|
|
||||||
class SetupPy(BuildSystem):
|
class SetupPy(BuildSystem):
|
||||||
|
|
||||||
|
name = 'setup.py'
|
||||||
|
|
||||||
|
def __init__(self, path):
|
||||||
|
from distutils.core import run_setup
|
||||||
|
self.result = run_setup(os.path.abspath(path), stop_after="init")
|
||||||
|
|
||||||
def setup(self, resolver):
|
def setup(self, resolver):
|
||||||
resolver.install([
|
resolver.install([
|
||||||
UpstreamPackage('python3', 'pip'),
|
UpstreamRequirement('python3', 'pip'),
|
||||||
UpstreamPackage('binary', 'python3'),
|
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()
|
||||||
|
@ -93,129 +111,175 @@ class SetupPy(BuildSystem):
|
||||||
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([UpstreamPackage('python3', 'setuptools')])
|
resolver.install([UpstreamRequirement('python3', 'setuptools')])
|
||||||
if ('setuptools_scm' in setup_py_contents or
|
if ('setuptools_scm' in setup_py_contents or
|
||||||
'setuptools_scm' in setup_cfg_contents):
|
'setuptools_scm' in setup_cfg_contents):
|
||||||
logging.info('Reference to setuptools-scm found, installing.')
|
logging.info('Reference to setuptools-scm found, installing.')
|
||||||
resolver.install([
|
resolver.install([
|
||||||
UpstreamPackage('python3', 'setuptools-scm'),
|
UpstreamRequirement('python3', 'setuptools-scm'),
|
||||||
UpstreamPackage('binary', 'git'),
|
UpstreamRequirement('binary', 'git'),
|
||||||
UpstreamPackage('binary', 'mercurial'),
|
UpstreamRequirement('binary', 'mercurial'),
|
||||||
])
|
])
|
||||||
|
|
||||||
# TODO(jelmer): Install setup_requires
|
# TODO(jelmer): Install setup_requires
|
||||||
|
|
||||||
def test(self, resolver):
|
def test(self, session, resolver):
|
||||||
self.setup(resolver)
|
self.setup(resolver)
|
||||||
self._run_setup(resolver, ['test'])
|
self._run_setup(session, resolver, ['test'])
|
||||||
|
|
||||||
def dist(self, resolver):
|
def dist(self, session, resolver):
|
||||||
self.setup(resolver)
|
self.setup(resolver)
|
||||||
self._run_setup(resolver, ['sdist'])
|
self._run_setup(session, resolver, ['sdist'])
|
||||||
|
|
||||||
def clean(self, resolver):
|
def clean(self, session, resolver):
|
||||||
self.setup(resolver)
|
self.setup(resolver)
|
||||||
self._run_setup(resolver, ['clean'])
|
self._run_setup(session, resolver, ['clean'])
|
||||||
|
|
||||||
def install(self, resolver):
|
def install(self, session, resolver):
|
||||||
self.setup(resolver)
|
self.setup(resolver)
|
||||||
self._run_setup(resolver, ['install'])
|
self._run_setup(session, resolver, ['install'])
|
||||||
|
|
||||||
def _run_setup(self, 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([UpstreamPackage('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(
|
||||||
self.session, ['./setup.py'] + args)
|
session, ['./setup.py'] + args)
|
||||||
else:
|
else:
|
||||||
# Just assume it's Python 3
|
# Just assume it's Python 3
|
||||||
resolver.install([UpstreamPackage('binary', 'python3')])
|
resolver.install([UpstreamRequirement('binary', 'python3')])
|
||||||
run_with_build_fixer(
|
run_with_build_fixer(
|
||||||
self.session, ['python3', './setup.py'] + args)
|
session, ['python3', './setup.py'] + args)
|
||||||
|
|
||||||
|
def get_declared_dependencies(self):
|
||||||
|
for require in self.result.get_requires():
|
||||||
|
yield 'build', UpstreamRequirement('python3', require)
|
||||||
|
for require in self.result.install_requires:
|
||||||
|
yield 'install', UpstreamRequirement('python3', require)
|
||||||
|
for require in self.result.tests_require:
|
||||||
|
yield 'test', UpstreamRequirement('python3', require)
|
||||||
|
|
||||||
|
def get_declared_outputs(self):
|
||||||
|
for script in (self.result.scripts or []):
|
||||||
|
yield UpstreamOutput('binary', os.path.basename(script))
|
||||||
|
entry_points = self.result.entry_points or {}
|
||||||
|
for script in entry_points.get('console_scripts', []):
|
||||||
|
yield UpstreamOutput('binary', script.split('=')[0])
|
||||||
|
for package in self.result.packages or []:
|
||||||
|
yield UpstreamOutput('python3', package)
|
||||||
|
|
||||||
|
|
||||||
class PyProject(BuildSystem):
|
class PyProject(BuildSystem):
|
||||||
|
|
||||||
|
name = 'pyproject'
|
||||||
|
|
||||||
def load_toml(self):
|
def load_toml(self):
|
||||||
import toml
|
import toml
|
||||||
|
|
||||||
with open("pyproject.toml", "r") as pf:
|
with open("pyproject.toml", "r") as pf:
|
||||||
return toml.load(pf)
|
return toml.load(pf)
|
||||||
|
|
||||||
def dist(self, resolver):
|
def dist(self, session, resolver):
|
||||||
pyproject = self.load_toml()
|
pyproject = self.load_toml()
|
||||||
if "poetry" in 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([
|
||||||
UpstreamPackage('python3', 'venv'),
|
UpstreamRequirement('python3', 'venv'),
|
||||||
UpstreamPackage('python3', 'pip'),
|
UpstreamRequirement('python3', 'pip'),
|
||||||
])
|
])
|
||||||
self.session.check_call(['pip3', 'install', 'poetry'], user='root')
|
session.check_call(['pip3', 'install', 'poetry'], user='root')
|
||||||
self.session.check_call(['poetry', 'build', '-f', 'sdist'])
|
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'
|
||||||
|
|
||||||
|
def __init__(self, path):
|
||||||
|
self.path = path
|
||||||
|
|
||||||
def setup(self, resolver):
|
def setup(self, resolver):
|
||||||
resolver.install([
|
resolver.install([
|
||||||
UpstreamPackage('python3', 'pep517'),
|
UpstreamRequirement('python3', 'pep517'),
|
||||||
UpstreamPackage('python3', 'pip'),
|
UpstreamRequirement('python3', 'pip'),
|
||||||
])
|
])
|
||||||
|
|
||||||
def dist(self, resolver):
|
def dist(self, session, resolver):
|
||||||
self.setup(resolver)
|
self.setup(resolver)
|
||||||
self.session.check_call(['python3', '-m', 'pep517.build', '-s', '.'])
|
session.check_call(['python3', '-m', 'pep517.build', '-s', '.'])
|
||||||
|
|
||||||
|
|
||||||
class NpmPackage(BuildSystem):
|
class Npm(BuildSystem):
|
||||||
|
|
||||||
|
name = 'npm'
|
||||||
|
|
||||||
|
def __init__(self, path):
|
||||||
|
import json
|
||||||
|
with open(path, 'r') as f:
|
||||||
|
self.package = json.load(f)
|
||||||
|
|
||||||
|
def get_declared_dependencies(self):
|
||||||
|
if 'devDependencies' in self.package:
|
||||||
|
for name, unused_version in (
|
||||||
|
self.package['devDependencies'].items()):
|
||||||
|
# TODO(jelmer): Look at version
|
||||||
|
yield 'dev', UpstreamRequirement('npm', name)
|
||||||
|
|
||||||
def setup(self, resolver):
|
def setup(self, resolver):
|
||||||
resolver.install([UpstreamPackage('binary', 'npm')])
|
resolver.install([UpstreamRequirement('binary', 'npm')])
|
||||||
|
|
||||||
def dist(self, resolver):
|
def dist(self, session, resolver):
|
||||||
self.setup(resolver)
|
self.setup(resolver)
|
||||||
run_with_build_fixer(self.session, ['npm', 'pack'])
|
run_with_build_fixer(session, ['npm', 'pack'])
|
||||||
|
|
||||||
|
|
||||||
class Waf(BuildSystem):
|
class Waf(BuildSystem):
|
||||||
|
|
||||||
def setup(self, resolver):
|
name = 'waf'
|
||||||
resolver.install([UpstreamPackage('binary', 'python3')])
|
|
||||||
|
|
||||||
def dist(self, resolver):
|
def __init__(self, path):
|
||||||
|
self.path = path
|
||||||
|
|
||||||
|
def setup(self, resolver):
|
||||||
|
resolver.install([UpstreamRequirement('binary', 'python3')])
|
||||||
|
|
||||||
|
def dist(self, session, resolver):
|
||||||
self.setup(resolver)
|
self.setup(resolver)
|
||||||
run_with_build_fixer(self.session, ['./waf', 'dist'])
|
run_with_build_fixer(session, ['./waf', 'dist'])
|
||||||
|
|
||||||
|
|
||||||
class Gem(BuildSystem):
|
class Gem(BuildSystem):
|
||||||
|
|
||||||
def setup(self, resolver):
|
name = 'gem'
|
||||||
resolver.install([UpstreamPackage('binary', 'gem2deb')])
|
|
||||||
|
|
||||||
def dist(self, resolver):
|
def __init__(self, path):
|
||||||
|
self.path = path
|
||||||
|
|
||||||
|
def setup(self, resolver):
|
||||||
|
resolver.install([UpstreamRequirement('binary', 'gem2deb')])
|
||||||
|
|
||||||
|
def dist(self, session, resolver):
|
||||||
self.setup(resolver)
|
self.setup(resolver)
|
||||||
gemfiles = [entry.name for entry in self.session.scandir('.')
|
gemfiles = [entry.name for entry in session.scandir('.')
|
||||||
if entry.name.endswith('.gem')]
|
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(self.session, ["gem2tgz", gemfiles[0]])
|
run_with_build_fixer(session, ['gem2tgz', gemfiles[0]])
|
||||||
|
|
||||||
|
|
||||||
class DistInkt(BuildSystem):
|
class DistInkt(BuildSystem):
|
||||||
|
|
||||||
def setup(self, resolver):
|
def __init__(self, path):
|
||||||
resolver.install([
|
self.path = path
|
||||||
UpstreamPackage('perl', 'Dist::Inkt'),
|
self.name = 'dist-zilla'
|
||||||
])
|
self.dist_inkt_class = None
|
||||||
|
|
||||||
def dist(self, resolver):
|
|
||||||
self.setup(resolver)
|
|
||||||
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";;"):
|
||||||
|
@ -226,155 +290,234 @@ 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, " "assuming distinkt."
|
'Found Dist::Inkt section in dist.ini, '
|
||||||
)
|
'assuming distinkt.')
|
||||||
# TODO(jelmer): install via apt if possible
|
self.name = 'dist-inkt'
|
||||||
self.session.check_call(
|
self.dist_inkt_class = value.decode().strip("'")
|
||||||
["cpan", "install", value.decode().strip("'")], user="root"
|
|
||||||
)
|
|
||||||
run_with_build_fixer(self.session, ["distinkt-dist"])
|
|
||||||
return
|
return
|
||||||
# Default to invoking Dist::Zilla
|
|
||||||
logging.info('Found dist.ini, assuming dist-zilla.')
|
logging.info('Found dist.ini, assuming dist-zilla.')
|
||||||
resolver.install([UpstreamPackage('perl', 'Dist::Zilla')])
|
|
||||||
run_with_build_fixer(self.session, ['dzil', 'build', '--in', '..'])
|
def setup(self, resolver):
|
||||||
|
resolver.install([
|
||||||
|
UpstreamRequirement('perl', 'Dist::Inkt'),
|
||||||
|
])
|
||||||
|
|
||||||
|
def dist(self, session, resolver):
|
||||||
|
self.setup(resolver)
|
||||||
|
if self.name == 'dist-inkt':
|
||||||
|
resolver.install([
|
||||||
|
UpstreamRequirement('perl-module', self.dist_inkt_class)])
|
||||||
|
run_with_build_fixer(session, ['distinkt-dist'])
|
||||||
|
else:
|
||||||
|
# Default to invoking Dist::Zilla
|
||||||
|
resolver.install([UpstreamRequirement('perl', 'Dist::Zilla')])
|
||||||
|
run_with_build_fixer(session, ['dzil', 'build', '--in', '..'])
|
||||||
|
|
||||||
|
|
||||||
class Make(BuildSystem):
|
class Make(BuildSystem):
|
||||||
|
|
||||||
def setup(self, resolver):
|
name = 'make'
|
||||||
if self.session.exists('Makefile.PL') and not self.session.exists('Makefile'):
|
|
||||||
resolver.install([UpstreamPackage('binary', 'perl')])
|
|
||||||
run_with_build_fixer(self.session, ['perl', 'Makefile.PL'])
|
|
||||||
|
|
||||||
if not self.session.exists('Makefile') and not self.session.exists('configure'):
|
def setup(self, session, resolver):
|
||||||
if self.session.exists('autogen.sh'):
|
if session.exists('Makefile.PL') and not session.exists('Makefile'):
|
||||||
|
resolver.install([UpstreamRequirement('binary', 'perl')])
|
||||||
|
run_with_build_fixer(session, ['perl', 'Makefile.PL'])
|
||||||
|
|
||||||
|
if not session.exists('Makefile') and not session.exists('configure'):
|
||||||
|
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(
|
||||||
self.session, ['/bin/sh', './autogen.sh'])
|
session, ['/bin/sh', './autogen.sh'])
|
||||||
try:
|
try:
|
||||||
run_with_build_fixer(self.session, ["./autogen.sh"])
|
run_with_build_fixer(
|
||||||
|
session, ['./autogen.sh'])
|
||||||
except UnidentifiedError as e:
|
except UnidentifiedError as e:
|
||||||
if (
|
if ("Gnulib not yet bootstrapped; "
|
||||||
"Gnulib not yet bootstrapped; "
|
"run ./bootstrap instead.\n" in e.lines):
|
||||||
"run ./bootstrap instead.\n" in e.lines
|
run_with_build_fixer(session, ["./bootstrap"])
|
||||||
):
|
run_with_build_fixer(session, ['./autogen.sh'])
|
||||||
run_with_build_fixer(self.session, ["./bootstrap"])
|
|
||||||
run_with_build_fixer(self.session, ["./autogen.sh"])
|
|
||||||
else:
|
else:
|
||||||
raise
|
raise
|
||||||
|
|
||||||
elif self.session.exists("configure.ac") or self.session.exists(
|
elif (session.exists('configure.ac') or
|
||||||
"configure.in"
|
session.exists('configure.in')):
|
||||||
):
|
resolver.install([
|
||||||
apt.install(
|
UpstreamRequirement('binary', 'autoconf'),
|
||||||
["autoconf", "automake", "gettext", "libtool", "gnu-standards"]
|
UpstreamRequirement('binary', 'automake'),
|
||||||
)
|
UpstreamRequirement('binary', 'gettextize'),
|
||||||
run_with_build_fixer(self.session, ["autoreconf", "-i"])
|
UpstreamRequirement('binary', 'libtoolize'),
|
||||||
|
])
|
||||||
|
run_with_build_fixer(session, ['autoreconf', '-i'])
|
||||||
|
|
||||||
if not self.session.exists("Makefile") and self.session.exists("configure"):
|
if not session.exists('Makefile') and session.exists('configure'):
|
||||||
self.session.check_call(["./configure"])
|
session.check_call(['./configure'])
|
||||||
|
|
||||||
def dist(self, resolver):
|
def dist(self, session, resolver):
|
||||||
self.setup(resolver)
|
self.setup(session, resolver)
|
||||||
resolver.install([UpstreamPackage('binary', 'make')])
|
resolver.install([UpstreamRequirement('binary', 'make')])
|
||||||
try:
|
try:
|
||||||
run_with_build_fixer(self.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 (
|
elif ("Reconfigure the source tree "
|
||||||
"Reconfigure the source tree "
|
|
||||||
"(via './config' or 'perl Configure'), please.\n"
|
"(via './config' or 'perl Configure'), please.\n"
|
||||||
) in e.lines:
|
) in e.lines:
|
||||||
run_with_build_fixer(self.session, ["./config"])
|
run_with_build_fixer(session, ['./config'])
|
||||||
run_with_build_fixer(self.session, ["make", "dist"])
|
run_with_build_fixer(session, ['make', 'dist'])
|
||||||
elif (
|
elif (
|
||||||
"Please try running 'make manifest' and then run "
|
"Please try running 'make manifest' and then run "
|
||||||
"'make dist' again.\n" in e.lines
|
"'make dist' again.\n" in e.lines):
|
||||||
):
|
run_with_build_fixer(session, ['make', 'manifest'])
|
||||||
run_with_build_fixer(self.session, ["make", "manifest"])
|
run_with_build_fixer(session, ['make', 'dist'])
|
||||||
run_with_build_fixer(self.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(self.session, ["./configure"])
|
run_with_build_fixer(session, ['./configure'])
|
||||||
run_with_build_fixer(self.session, ["make", "dist"])
|
run_with_build_fixer(session, ['make', 'dist'])
|
||||||
elif any(
|
elif any([re.match(
|
||||||
[
|
r'Makefile:[0-9]+: \*\*\* Missing \'Make.inc\' '
|
||||||
re.match(
|
r'Run \'./configure \[options\]\' and retry. Stop.\n',
|
||||||
r"Makefile:[0-9]+: \*\*\* Missing \'Make.inc\' "
|
line) for line in e.lines]):
|
||||||
r"Run \'./configure \[options\]\' and retry. Stop.\n",
|
run_with_build_fixer(session, ['./configure'])
|
||||||
line,
|
run_with_build_fixer(session, ['make', 'dist'])
|
||||||
)
|
elif any([re.match(
|
||||||
for line in e.lines
|
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(self.session, ["./configure"])
|
run_with_build_fixer(session, ['make', 'dist'])
|
||||||
run_with_build_fixer(self.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(self.session, ["make", "manifest"])
|
|
||||||
run_with_build_fixer(self.session, ["make", "dist"])
|
|
||||||
else:
|
else:
|
||||||
raise
|
raise
|
||||||
else:
|
else:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
def get_declared_dependencies(self):
|
||||||
|
# TODO(jelmer): Split out the perl-specific stuff?
|
||||||
|
if os.path.exists('META.yml'):
|
||||||
|
# See http://module-build.sourceforge.net/META-spec-v1.4.html for
|
||||||
|
# the specification of the format.
|
||||||
|
import ruamel.yaml
|
||||||
|
import ruamel.yaml.reader
|
||||||
|
with open('META.yml', 'rb') as f:
|
||||||
|
try:
|
||||||
|
data = ruamel.yaml.load(f, ruamel.yaml.SafeLoader)
|
||||||
|
except ruamel.yaml.reader.ReaderError as e:
|
||||||
|
warnings.warn('Unable to parse META.yml: %s' % e)
|
||||||
|
return
|
||||||
|
for require in data.get('requires', []):
|
||||||
|
yield 'build', UpstreamRequirement('perl', require)
|
||||||
|
|
||||||
def detect_buildsystems(session):
|
|
||||||
|
class Cargo(BuildSystem):
|
||||||
|
|
||||||
|
name = 'cargo'
|
||||||
|
|
||||||
|
def __init__(self, path):
|
||||||
|
from toml.decoder import load, TomlDecodeError
|
||||||
|
with open(path, 'r') as f:
|
||||||
|
self.cargo = load(f)
|
||||||
|
|
||||||
|
def get_declared_dependencies(self):
|
||||||
|
if 'dependencies' in self.cargo:
|
||||||
|
for name, details in self.cargo['dependencies'].items():
|
||||||
|
# TODO(jelmer): Look at details['features'], details['version']
|
||||||
|
yield 'build', UpstreamRequirement('cargo-crate', name)
|
||||||
|
|
||||||
|
|
||||||
|
class Golang(BuildSystem):
|
||||||
|
"""Go builds."""
|
||||||
|
|
||||||
|
name = 'golang'
|
||||||
|
|
||||||
|
|
||||||
|
class Maven(BuildSystem):
|
||||||
|
|
||||||
|
name = 'maven'
|
||||||
|
|
||||||
|
def __init__(self, path):
|
||||||
|
self.path = path
|
||||||
|
|
||||||
|
|
||||||
|
class Cabal(BuildSystem):
|
||||||
|
|
||||||
|
name = 'cabal'
|
||||||
|
|
||||||
|
def __init__(self, path):
|
||||||
|
self.path = path
|
||||||
|
|
||||||
|
|
||||||
|
def detect_buildsystems(path):
|
||||||
"""Detect build systems."""
|
"""Detect build systems."""
|
||||||
if session.exists("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(session)
|
yield Pear('package.xml')
|
||||||
|
|
||||||
if session.exists("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(session)
|
yield SetupPy('setup.py')
|
||||||
|
elif os.path.exists(os.path.join(path, 'pyproject.toml')):
|
||||||
|
logging.info('Found pyproject.toml, assuming python project.')
|
||||||
|
yield PyProject()
|
||||||
|
elif os.path.exists(os.path.join(path, 'setup.cfg')):
|
||||||
|
logging.info('Found setup.cfg, assuming python project.')
|
||||||
|
yield SetupCfg('setup.cfg')
|
||||||
|
|
||||||
if session.exists("pyproject.toml"):
|
if os.path.exists(os.path.join(path, 'package.json')):
|
||||||
logging.info("Found pyproject.toml, assuming python project.")
|
logging.info('Found package.json, assuming node package.')
|
||||||
yield PyProject(session)
|
yield Npm('package.json')
|
||||||
|
|
||||||
if session.exists("setup.cfg"):
|
if os.path.exists(os.path.join(path, 'waf')):
|
||||||
logging.info("Found setup.cfg, assuming python project.")
|
logging.info('Found waf, assuming waf package.')
|
||||||
yield SetupCfg(session)
|
yield Waf('waf')
|
||||||
|
|
||||||
if session.exists("package.json"):
|
if os.path.exists(os.path.join(path, 'Cargo.toml')):
|
||||||
logging.info("Found package.json, assuming node package.")
|
logging.info('Found Cargo.toml, assuming rust cargo package.')
|
||||||
yield NpmPackage(session)
|
yield Cargo('Cargo.toml')
|
||||||
|
|
||||||
if session.exists("waf"):
|
if os.path.exists(os.path.join(path, 'pom.xml')):
|
||||||
logging.info("Found waf, assuming waf package.")
|
logging.info('Found pom.xml, assuming maven package.')
|
||||||
yield Waf(session)
|
yield Maven('pom.xml')
|
||||||
|
|
||||||
|
if (os.path.exists(os.path.join(path, 'dist.ini')) and
|
||||||
|
not os.path.exists(os.path.join(path, 'Makefile.PL'))):
|
||||||
|
yield DistInkt('dist.ini')
|
||||||
|
|
||||||
gemfiles = [
|
gemfiles = [
|
||||||
entry.name for entry in session.scandir(".") if entry.name.endswith(".gem")
|
entry.name for entry in os.scandir(path)
|
||||||
]
|
if entry.name.endswith('.gem')]
|
||||||
if gemfiles:
|
if gemfiles:
|
||||||
yield Gem(session)
|
yield Gem(gemfiles[0])
|
||||||
|
|
||||||
if session.exists("dist.ini") and not session.exists("Makefile.PL"):
|
if any([os.path.exists(os.path.join(path, p)) for p in [
|
||||||
yield DistInkt(session)
|
'Makefile', 'Makefile.PL', 'autogen.sh', 'configure.ac',
|
||||||
|
'configure.in']]):
|
||||||
|
yield Make()
|
||||||
|
|
||||||
if any(
|
cabal_filenames = [
|
||||||
[
|
entry.name for entry in os.scandir(path)
|
||||||
session.exists(p)
|
if entry.name.endswith('.cabal')]
|
||||||
for p in [
|
if cabal_filenames:
|
||||||
"Makefile",
|
if len(cabal_filenames) == 1:
|
||||||
"Makefile.PL",
|
yield Cabal(cabal_filenames[0])
|
||||||
"autogen.sh",
|
else:
|
||||||
"configure.ac",
|
warnings.warn(
|
||||||
"configure.in",
|
'More than one cabal filename, ignoring all: %r' %
|
||||||
]
|
cabal_filenames)
|
||||||
]
|
|
||||||
):
|
if os.path.exists(os.path.join(path, '.travis.yml')):
|
||||||
yield Make(session)
|
import yaml
|
||||||
|
import ruamel.yaml.reader
|
||||||
|
with open('.travis.yml', 'rb') as f:
|
||||||
|
try:
|
||||||
|
data = ruamel.yaml.load(f, ruamel.yaml.SafeLoader)
|
||||||
|
except ruamel.yaml.reader.ReaderError as e:
|
||||||
|
warnings.warn('Unable to parse .travis.yml: %s' % (e, ))
|
||||||
|
else:
|
||||||
|
language = data.get('language')
|
||||||
|
if language == 'go':
|
||||||
|
yield Golang()
|
||||||
|
|
||||||
|
for entry in os.scandir(path):
|
||||||
|
if entry.name.endswith('.go'):
|
||||||
|
yield Golang()
|
||||||
|
break
|
||||||
|
|
|
@ -15,16 +15,16 @@
|
||||||
# along with this program; if not, write to the Free Software
|
# along with this program; if not, write to the Free Software
|
||||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
|
||||||
from .buildsystem import detect_buildsystems, NoBuildToolsFound
|
from .buildsystem import NoBuildToolsFound
|
||||||
|
|
||||||
|
|
||||||
def run_clean(session, resolver):
|
def run_clean(session, buildsystems, resolver):
|
||||||
# Some things want to write to the user's home directory,
|
# Some things want to write to the user's home directory,
|
||||||
# e.g. pip caches in ~/.cache
|
# e.g. pip caches in ~/.cache
|
||||||
session.create_home()
|
session.create_home()
|
||||||
|
|
||||||
for buildsystem in detect_buildsystems(session):
|
for buildsystem in buildsystems:
|
||||||
buildsystem.clean(resolver)
|
buildsystem.clean(session, resolver)
|
||||||
return
|
return
|
||||||
|
|
||||||
raise NoBuildToolsFound()
|
raise NoBuildToolsFound()
|
||||||
|
|
|
@ -34,7 +34,7 @@ from buildlog_consultant.common import (
|
||||||
|
|
||||||
|
|
||||||
from . import DetailedFailure
|
from . import DetailedFailure
|
||||||
from .buildsystem import detect_buildsystems, NoBuildToolsFound
|
from .buildsystem import NoBuildToolsFound
|
||||||
from .session.schroot import SchrootSession
|
from .session.schroot import SchrootSession
|
||||||
from .vcs import dupe_vcs_tree, export_vcs_tree
|
from .vcs import dupe_vcs_tree, export_vcs_tree
|
||||||
|
|
||||||
|
@ -62,13 +62,13 @@ class DistNoTarball(Exception):
|
||||||
"""Dist operation did not create a tarball."""
|
"""Dist operation did not create a tarball."""
|
||||||
|
|
||||||
|
|
||||||
def run_dist(session, resolver):
|
def run_dist(session, buildsystems, resolver):
|
||||||
# Some things want to write to the user's home directory,
|
# Some things want to write to the user's home directory,
|
||||||
# e.g. pip caches in ~/.cache
|
# e.g. pip caches in ~/.cache
|
||||||
session.create_home()
|
session.create_home()
|
||||||
|
|
||||||
for buildsystem in detect_buildsystems(session):
|
for buildsystem in buildsystems:
|
||||||
buildsystem.dist(resolver)
|
buildsystem.dist(session, resolver)
|
||||||
return
|
return
|
||||||
|
|
||||||
raise NoBuildToolsFound()
|
raise NoBuildToolsFound()
|
||||||
|
@ -115,13 +115,12 @@ class DistCatcher(object):
|
||||||
|
|
||||||
|
|
||||||
def create_dist_schroot(
|
def create_dist_schroot(
|
||||||
tree: Tree,
|
tree: Tree, target_dir: str,
|
||||||
target_dir: str,
|
chroot: str, packaging_tree: Optional[Tree] = None,
|
||||||
chroot: str,
|
|
||||||
packaging_tree: Optional[Tree] = None,
|
|
||||||
include_controldir: bool = True,
|
include_controldir: bool = True,
|
||||||
subdir: Optional[str] = None,
|
subdir: Optional[str] = None) -> str:
|
||||||
) -> str:
|
from .buildsystem import detect_buildsystems
|
||||||
|
from .apt import AptResolver
|
||||||
if subdir is None:
|
if subdir is None:
|
||||||
subdir = "package"
|
subdir = "package"
|
||||||
with SchrootSession(chroot) as session:
|
with SchrootSession(chroot) as session:
|
||||||
|
@ -144,12 +143,15 @@ def create_dist_schroot(
|
||||||
else:
|
else:
|
||||||
dupe_vcs_tree(tree, export_directory)
|
dupe_vcs_tree(tree, export_directory)
|
||||||
|
|
||||||
|
buildsystems = list(detect_buildsystems(export_directory))
|
||||||
|
resolver = AptResolver.from_session(session)
|
||||||
|
|
||||||
with DistCatcher(export_directory) as dc:
|
with DistCatcher(export_directory) as dc:
|
||||||
oldcwd = os.getcwd()
|
oldcwd = os.getcwd()
|
||||||
os.chdir(export_directory)
|
os.chdir(export_directory)
|
||||||
try:
|
try:
|
||||||
session.chdir(os.path.join(reldir, subdir))
|
session.chdir(os.path.join(reldir, subdir))
|
||||||
run_dist(session)
|
run_dist(session, buildsystems, resolver)
|
||||||
finally:
|
finally:
|
||||||
os.chdir(oldcwd)
|
os.chdir(oldcwd)
|
||||||
|
|
||||||
|
|
|
@ -15,16 +15,16 @@
|
||||||
# along with this program; if not, write to the Free Software
|
# along with this program; if not, write to the Free Software
|
||||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
|
||||||
from .buildsystem import detect_buildsystems, NoBuildToolsFound
|
from .buildsystem import NoBuildToolsFound
|
||||||
|
|
||||||
|
|
||||||
def run_install(session, resolver):
|
def run_install(session, buildsystems, resolver):
|
||||||
# Some things want to write to the user's home directory,
|
# Some things want to write to the user's home directory,
|
||||||
# e.g. pip caches in ~/.cache
|
# e.g. pip caches in ~/.cache
|
||||||
session.create_home()
|
session.create_home()
|
||||||
|
|
||||||
for buildsystem in detect_buildsystems(session):
|
for buildsystem in buildsystems:
|
||||||
buildsystem.install(resolver)
|
buildsystem.install(session, resolver)
|
||||||
return
|
return
|
||||||
|
|
||||||
raise NoBuildToolsFound()
|
raise NoBuildToolsFound()
|
||||||
|
|
|
@ -15,16 +15,16 @@
|
||||||
# along with this program; if not, write to the Free Software
|
# along with this program; if not, write to the Free Software
|
||||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
|
||||||
from .buildsystem import detect_buildsystems, NoBuildToolsFound
|
from .buildsystem import NoBuildToolsFound
|
||||||
|
|
||||||
|
|
||||||
def run_test(session, resolver):
|
def run_test(session, buildsystems, resolver):
|
||||||
# Some things want to write to the user's home directory,
|
# Some things want to write to the user's home directory,
|
||||||
# e.g. pip caches in ~/.cache
|
# e.g. pip caches in ~/.cache
|
||||||
session.create_home()
|
session.create_home()
|
||||||
|
|
||||||
for buildsystem in detect_buildsystems(session):
|
for buildsystem in buildsystems:
|
||||||
buildsystem.test(resolver)
|
buildsystem.test(session, resolver)
|
||||||
return
|
return
|
||||||
|
|
||||||
raise NoBuildToolsFound()
|
raise NoBuildToolsFound()
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue