Don't invoke apt unless we have to.
This commit is contained in:
parent
8133a5fa68
commit
db616ee3b0
4 changed files with 60 additions and 33 deletions
|
@ -19,6 +19,8 @@
|
||||||
|
|
||||||
from typing import List
|
from typing import List
|
||||||
|
|
||||||
|
import apt_pkg
|
||||||
|
import os
|
||||||
from buildlog_consultant.sbuild import (
|
from buildlog_consultant.sbuild import (
|
||||||
find_apt_get_failure,
|
find_apt_get_failure,
|
||||||
)
|
)
|
||||||
|
@ -53,9 +55,29 @@ def run_apt(session: Session, args: List[str]) -> None:
|
||||||
raise UnidentifiedError(retcode, args, lines)
|
raise UnidentifiedError(retcode, args, lines)
|
||||||
|
|
||||||
|
|
||||||
def install(session: Session, packages: List[str]) -> None:
|
class AptResolver(object):
|
||||||
run_apt(session, ['install'] + packages)
|
|
||||||
|
|
||||||
|
session: Session
|
||||||
|
|
||||||
def satisfy(session: Session, deps: List[str]) -> None:
|
def __init__(self, session):
|
||||||
run_apt(session, ['satisfy'] + deps)
|
self.session = session
|
||||||
|
|
||||||
|
def missing(self, packages):
|
||||||
|
root = getattr(self.session, 'location', '/')
|
||||||
|
status_path = os.path.join(root, 'var/lib/dpkg/status')
|
||||||
|
missing = set(packages)
|
||||||
|
with apt_pkg.TagFile(status_path) as tagf:
|
||||||
|
while tagf and missing:
|
||||||
|
tagf.step()
|
||||||
|
if tagf.section['Package'] in missing:
|
||||||
|
if tagf.section['Status'] == 'install ok installed':
|
||||||
|
missing.remove(tagf.section['Package'])
|
||||||
|
return list(missing)
|
||||||
|
|
||||||
|
def install(self, packages: List[str]) -> None:
|
||||||
|
packages = self.missing(packages)
|
||||||
|
if packages:
|
||||||
|
run_apt(self.session, ['install'] + packages)
|
||||||
|
|
||||||
|
def satisfy(self, deps: List[str]) -> None:
|
||||||
|
run_apt(self.session, ['satisfy'] + deps)
|
||||||
|
|
|
@ -33,7 +33,8 @@ from breezy.workingtree import WorkingTree
|
||||||
|
|
||||||
from breezy.plugins.debian.repack_tarball import get_filetype
|
from breezy.plugins.debian.repack_tarball import get_filetype
|
||||||
|
|
||||||
from . import apt, DetailedFailure, shebang_binary
|
from . import DetailedFailure, shebang_binary
|
||||||
|
from .apt import AptResolver, UnidentifiedError
|
||||||
from .buildsystem import detect_buildsystems, NoBuildToolsFound
|
from .buildsystem import detect_buildsystems, NoBuildToolsFound
|
||||||
from .session import run_with_tee, Session
|
from .session import run_with_tee, Session
|
||||||
from .session.schroot import SchrootSession
|
from .session.schroot import SchrootSession
|
||||||
|
@ -72,17 +73,19 @@ def satisfy_build_deps(session: Session, tree):
|
||||||
deps = [
|
deps = [
|
||||||
dep.strip().strip(',')
|
dep.strip().strip(',')
|
||||||
for dep in deps]
|
for dep in deps]
|
||||||
apt.satisfy(session, deps)
|
apt = AptResolver(session)
|
||||||
|
apt.satisfy(deps)
|
||||||
|
|
||||||
|
|
||||||
class SchrootDependencyContext(DependencyContext):
|
class SchrootDependencyContext(DependencyContext):
|
||||||
|
|
||||||
def __init__(self, session):
|
def __init__(self, session):
|
||||||
self.session = session
|
self.session = session
|
||||||
|
self.apt = AptResolver(session)
|
||||||
|
|
||||||
def add_dependency(self, package, minimum_version=None):
|
def add_dependency(self, package, minimum_version=None):
|
||||||
# TODO(jelmer): Handle minimum_version
|
# TODO(jelmer): Handle minimum_version
|
||||||
apt.install(self.session, [package])
|
self.apt.install([package])
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
@ -127,9 +130,9 @@ def run_with_build_fixer(session: Session, args: List[str]):
|
||||||
if error is None:
|
if error is None:
|
||||||
logging.warning('Build failed with unidentified error. Giving up.')
|
logging.warning('Build failed with unidentified error. Giving up.')
|
||||||
if line is not None:
|
if line is not None:
|
||||||
raise apt.UnidentifiedError(
|
raise UnidentifiedError(
|
||||||
retcode, args, lines, secondary=(offset, line))
|
retcode, args, lines, secondary=(offset, line))
|
||||||
raise apt.UnidentifiedError(retcode, args, lines)
|
raise UnidentifiedError(retcode, args, lines)
|
||||||
|
|
||||||
logging.info('Identified error: %r', error)
|
logging.info('Identified error: %r', error)
|
||||||
if error in fixed_errors:
|
if error in fixed_errors:
|
||||||
|
@ -148,7 +151,8 @@ def run_with_build_fixer(session: Session, args: List[str]):
|
||||||
|
|
||||||
|
|
||||||
def run_dist(session):
|
def run_dist(session):
|
||||||
apt.install(session, ['git'])
|
apt = AptResolver(session)
|
||||||
|
apt.install(['git'])
|
||||||
|
|
||||||
# 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
|
||||||
|
@ -159,7 +163,7 @@ def run_dist(session):
|
||||||
return
|
return
|
||||||
|
|
||||||
if os.path.exists('package.xml'):
|
if os.path.exists('package.xml'):
|
||||||
apt.install(session, ['php-pear', 'php-horde-core'])
|
apt.install(['php-pear', 'php-horde-core'])
|
||||||
logging.info('Found package.xml, assuming pear package.')
|
logging.info('Found package.xml, assuming pear package.')
|
||||||
session.check_call(['pear', 'package'])
|
session.check_call(['pear', 'package'])
|
||||||
return
|
return
|
||||||
|
@ -172,14 +176,14 @@ def run_dist(session):
|
||||||
logging.info(
|
logging.info(
|
||||||
'Found pyproject.toml with poetry section, '
|
'Found pyproject.toml with poetry section, '
|
||||||
'assuming poetry project.')
|
'assuming poetry project.')
|
||||||
apt.install(session, ['python3-venv', 'python3-pip'])
|
apt.install(['python3-venv', 'python3-pip'])
|
||||||
session.check_call(['pip3', 'install', 'poetry'], user='root')
|
session.check_call(['pip3', 'install', 'poetry'], user='root')
|
||||||
session.check_call(['poetry', 'build', '-f', 'sdist'])
|
session.check_call(['poetry', 'build', '-f', 'sdist'])
|
||||||
return
|
return
|
||||||
|
|
||||||
if os.path.exists('setup.py'):
|
if os.path.exists('setup.py'):
|
||||||
logging.info('Found setup.py, assuming python project.')
|
logging.info('Found setup.py, assuming python project.')
|
||||||
apt.install(session, ['python3', 'python3-pip'])
|
apt.install(['python3', 'python3-pip'])
|
||||||
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:
|
||||||
|
@ -189,41 +193,40 @@ def run_dist(session):
|
||||||
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.')
|
||||||
apt.install(session, ['python3-setuptools'])
|
apt.install(['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.')
|
||||||
apt.install(
|
apt.install(['python3-setuptools-scm', 'git', 'mercurial'])
|
||||||
session, ['python3-setuptools-scm', 'git', 'mercurial'])
|
|
||||||
|
|
||||||
# TODO(jelmer): Install setup_requires
|
# TODO(jelmer): Install setup_requires
|
||||||
|
|
||||||
interpreter = shebang_binary('setup.py')
|
interpreter = shebang_binary('setup.py')
|
||||||
if interpreter is not None:
|
if interpreter is not None:
|
||||||
if interpreter == 'python3':
|
if interpreter == 'python3':
|
||||||
apt.install(session, ['python3'])
|
apt.install(['python3'])
|
||||||
elif interpreter == 'python2':
|
elif interpreter == 'python2':
|
||||||
apt.install(session, ['python2'])
|
apt.install(['python2'])
|
||||||
elif interpreter == 'python':
|
elif interpreter == 'python':
|
||||||
apt.install(session, ['python'])
|
apt.install(['python'])
|
||||||
else:
|
else:
|
||||||
raise ValueError('Unknown interpreter %r' % interpreter)
|
raise ValueError('Unknown interpreter %r' % interpreter)
|
||||||
apt.install(session, ['python2', 'python3'])
|
apt.install(['python2', 'python3'])
|
||||||
run_with_build_fixer(session, ['./setup.py', 'sdist'])
|
run_with_build_fixer(session, ['./setup.py', 'sdist'])
|
||||||
else:
|
else:
|
||||||
# Just assume it's Python 3
|
# Just assume it's Python 3
|
||||||
apt.install(session, ['python3'])
|
apt.install(['python3'])
|
||||||
run_with_build_fixer(session, ['python3', './setup.py', 'sdist'])
|
run_with_build_fixer(session, ['python3', './setup.py', 'sdist'])
|
||||||
return
|
return
|
||||||
|
|
||||||
if os.path.exists('setup.cfg'):
|
if os.path.exists('setup.cfg'):
|
||||||
logging.info('Found setup.cfg, assuming python project.')
|
logging.info('Found setup.cfg, assuming python project.')
|
||||||
apt.install(session, ['python3-pep517', 'python3-pip'])
|
apt.install(['python3-pep517', 'python3-pip'])
|
||||||
session.check_call(['python3', '-m', 'pep517.build', '-s', '.'])
|
session.check_call(['python3', '-m', 'pep517.build', '-s', '.'])
|
||||||
return
|
return
|
||||||
|
|
||||||
if os.path.exists('dist.ini') and not os.path.exists('Makefile.PL'):
|
if os.path.exists('dist.ini') and not os.path.exists('Makefile.PL'):
|
||||||
apt.install(session, ['libdist-inkt-perl'])
|
apt.install(['libdist-inkt-perl'])
|
||||||
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';;'):
|
||||||
|
@ -245,30 +248,30 @@ def run_dist(session):
|
||||||
return
|
return
|
||||||
# Default to invoking Dist::Zilla
|
# Default to invoking Dist::Zilla
|
||||||
logging.info('Found dist.ini, assuming dist-zilla.')
|
logging.info('Found dist.ini, assuming dist-zilla.')
|
||||||
apt.install(session, ['libdist-zilla-perl'])
|
apt.install(['libdist-zilla-perl'])
|
||||||
run_with_build_fixer(session, ['dzil', 'build', '--in', '..'])
|
run_with_build_fixer(session, ['dzil', 'build', '--in', '..'])
|
||||||
return
|
return
|
||||||
|
|
||||||
if os.path.exists('package.json'):
|
if os.path.exists('package.json'):
|
||||||
apt.install(session, ['npm'])
|
apt.install(['npm'])
|
||||||
run_with_build_fixer(session, ['npm', 'pack'])
|
run_with_build_fixer(session, ['npm', 'pack'])
|
||||||
return
|
return
|
||||||
|
|
||||||
gemfiles = [name for name in os.listdir('.') if name.endswith('.gem')]
|
gemfiles = [name for name in os.listdir('.') if name.endswith('.gem')]
|
||||||
if gemfiles:
|
if gemfiles:
|
||||||
apt.install(session, ['gem2deb'])
|
apt.install(['gem2deb'])
|
||||||
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]])
|
||||||
return
|
return
|
||||||
|
|
||||||
if os.path.exists('waf'):
|
if os.path.exists('waf'):
|
||||||
apt.install(session, ['python3'])
|
apt.install(['python3'])
|
||||||
run_with_build_fixer(session, ['./waf', 'dist'])
|
run_with_build_fixer(session, ['./waf', 'dist'])
|
||||||
return
|
return
|
||||||
|
|
||||||
if os.path.exists('Makefile.PL') and not os.path.exists('Makefile'):
|
if os.path.exists('Makefile.PL') and not os.path.exists('Makefile'):
|
||||||
apt.install(session, ['perl'])
|
apt.install(['perl'])
|
||||||
run_with_build_fixer(session, ['perl', 'Makefile.PL'])
|
run_with_build_fixer(session, ['perl', 'Makefile.PL'])
|
||||||
|
|
||||||
if not os.path.exists('Makefile') and not os.path.exists('configure'):
|
if not os.path.exists('Makefile') and not os.path.exists('configure'):
|
||||||
|
@ -277,7 +280,7 @@ def run_dist(session):
|
||||||
run_with_build_fixer(session, ['/bin/sh', './autogen.sh'])
|
run_with_build_fixer(session, ['/bin/sh', './autogen.sh'])
|
||||||
try:
|
try:
|
||||||
run_with_build_fixer(session, ['./autogen.sh'])
|
run_with_build_fixer(session, ['./autogen.sh'])
|
||||||
except apt.UnidentifiedError as e:
|
except UnidentifiedError as e:
|
||||||
if ("Gnulib not yet bootstrapped; "
|
if ("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, ["./bootstrap"])
|
||||||
|
@ -286,7 +289,7 @@ def run_dist(session):
|
||||||
raise
|
raise
|
||||||
|
|
||||||
elif os.path.exists('configure.ac') or os.path.exists('configure.in'):
|
elif os.path.exists('configure.ac') or os.path.exists('configure.in'):
|
||||||
apt.install(session, [
|
apt.install([
|
||||||
'autoconf', 'automake', 'gettext', 'libtool', 'gnu-standards'])
|
'autoconf', 'automake', 'gettext', 'libtool', 'gnu-standards'])
|
||||||
run_with_build_fixer(session, ['autoreconf', '-i'])
|
run_with_build_fixer(session, ['autoreconf', '-i'])
|
||||||
|
|
||||||
|
@ -294,10 +297,10 @@ def run_dist(session):
|
||||||
session.check_call(['./configure'])
|
session.check_call(['./configure'])
|
||||||
|
|
||||||
if os.path.exists('Makefile'):
|
if os.path.exists('Makefile'):
|
||||||
apt.install(session, ['make'])
|
apt.install(['make'])
|
||||||
try:
|
try:
|
||||||
run_with_build_fixer(session, ['make', 'dist'])
|
run_with_build_fixer(session, ['make', 'dist'])
|
||||||
except apt.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"
|
elif ("make[1]: *** No rule to make target 'dist'. Stop.\n"
|
||||||
|
|
|
@ -34,7 +34,7 @@ class Session(object):
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def location(self) -> str:
|
def location(self) -> str:
|
||||||
raise NotImplementedError(self.location)
|
raise NotImplementedError
|
||||||
|
|
||||||
def check_call(
|
def check_call(
|
||||||
self,
|
self,
|
||||||
|
|
|
@ -24,6 +24,8 @@ import subprocess
|
||||||
class PlainSession(Session):
|
class PlainSession(Session):
|
||||||
"""Session ignoring user."""
|
"""Session ignoring user."""
|
||||||
|
|
||||||
|
location = '/'
|
||||||
|
|
||||||
def create_home(self):
|
def create_home(self):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue