Bug 1431297 - Allow to use aptitude instead of apt-get to install build dependencies. r=dustin
authorMike Hommey <mh+mozilla@glandium.org>
Thu, 18 Jan 2018 14:33:57 +0900
changeset 454234 4e81b24af0cc476131e1922ee06cf1f9b419f73b
parent 454233 5ac7a06102e294523f15e80f91813fc07ff7059b
child 454235 c647e9f13846de9f6f89d4b8bf89414bdab43ce3
push id1648
push usermtabara@mozilla.com
push dateThu, 01 Mar 2018 12:45:47 +0000
treeherdermozilla-release@cbb9688c2eeb [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdustin
bugs1431297
milestone59.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1431297 - Allow to use aptitude instead of apt-get to install build dependencies. r=dustin In some cases, apt-get can't figure out how to install build dependencies, and aptitude, with hints, is necessary instead. But aptitude also doesn't necessarily work in some cases (e.g. it picks the wrong automake version to build valgrind, although that's a problem in valgrind's build dependencies). All in all, it's still better to use apt-get for all the simple cases.
taskcluster/taskgraph/transforms/job/debian_package.py
--- a/taskcluster/taskgraph/transforms/job/debian_package.py
+++ b/taskcluster/taskgraph/transforms/job/debian_package.py
@@ -45,16 +45,22 @@ run_schema = Schema({
     # Patch to apply to the extracted source.
     Optional('patch'): basestring,
 
     # Command to run before dpkg-buildpackage.
     Optional('pre-build-command'): basestring,
 
     # List of package tasks to get build dependencies from.
     Optional('packages'): [basestring],
+
+    # What resolver to use to install build dependencies. The default
+    # (apt-get) is good in most cases, but in subtle cases involving
+    # a *-backports archive, its solver might not be able to find a
+    # solution that satisfies the build dependencies.
+    Optional('resolver'): Any('apt-get', 'aptitude'),
 })
 
 
 @run_job_using("docker-worker", "debian-package", schema=run_schema)
 def docker_worker_debian_package(config, job, taskdesc):
     run = job['run']
 
     name = taskdesc['label'].replace('{}-'.format(config.kind), '', 1)
@@ -83,16 +89,34 @@ def docker_worker_debian_package(config,
     else:
         raise RuntimeError('Unreachable')
     src_url = src['url']
     src_file = os.path.basename(src_url)
     src_sha256 = src['sha256']
     package = package_re.match(src_file).group(0)
     unpack = unpack.format(src_file=src_file, package=package)
 
+    base_deps = [
+        'apt-utils',
+        'build-essential',
+        'devscripts',
+        'fakeroot',
+    ]
+
+    resolver = run.get('resolver', 'apt-get')
+    if resolver == 'apt-get':
+        resolver = 'apt-get -yyq --no-install-recommends'
+    elif resolver == 'aptitude':
+        resolver = ('aptitude -y --without-recommends -o '
+                    'Aptitude::ProblemResolver::Hints::KeepBuildDeps='
+                    '"reject {}-build-deps :UNINST"').format(package)
+        base_deps.append('aptitude')
+    else:
+        raise RuntimeError('Unreachable')
+
     adjust = ''
     if 'patch' in run:
         # We can't depend on docker images, so we don't have robustcheckout or
         # or run-task to get a checkout. So for this one file we'd need
         # from a checkout, download it.
         env['PATCH_URL'] = '{head_repo}/raw-file/{head_rev}/build/debian-packages/{patch}'.format(
             head_repo=config.params['head_repository'],
             head_rev=config.params['head_rev'],
@@ -134,27 +158,27 @@ def docker_worker_debian_package(config,
         'apt-get install -yyq apt-transport-https ca-certificates && '
         'for task in $PACKAGES; do '
         '  echo "deb [trusted=yes] https://queue.taskcluster.net/v1/task'
         '/$task/runs/0/artifacts/public/build/ debian/" '
         '>> /etc/apt/sources.list; '
         'done && '
         # Install the base utilities required to build debian packages.
         'apt-get update -o Acquire::Check-Valid-Until=false -q && '
-        'apt-get install -yyq fakeroot build-essential devscripts apt-utils && '
+        'apt-get install -yyq {base_deps} && '
         'cd /tmp && '
         # Get, validate and extract the package source.
         'dget -d -u {src_url} && '
         'echo "{src_sha256}  {src_file}" | sha256sum -c && '
         '{unpack} && '
         'cd {package} && '
         # Optionally apply patch and/or pre-build command.
         '{adjust}'
         # Install the necessary build dependencies.
-        'mk-build-deps -i -r debian/control -t "apt-get -yyq --no-install-recommends" && '
+        'mk-build-deps -i -r debian/control -t \'{resolver}\' && '
         # Build the package
         'DEB_BUILD_OPTIONS="parallel=$(nproc) nocheck" dpkg-buildpackage && '
         # Copy the artifacts
         'mkdir -p {artifacts}/debian && '
         'dcmd cp ../{package}_*.changes {artifacts}/debian/ && '
         'cd {artifacts} && '
         # Make the artifacts directory usable as an APT repository.
         'apt-ftparchive sources debian | gzip -c9 > debian/Sources.gz && '
@@ -166,16 +190,18 @@ def docker_worker_debian_package(config,
             snapshot=run['snapshot'],
             dist=run['dist'],
             src_url=src_url,
             src_file=src_file,
             src_sha256=src_sha256,
             unpack=unpack,
             adjust=adjust,
             artifacts='/tmp/artifacts',
+            base_deps=' '.join(base_deps),
+            resolver=resolver,
         )
     ]
 
     # Use the command generated above as the base for the index hash.
     # We rely on it not varying depending on the head_repository or head_rev.
     data = list(worker['command'])
     if 'patch' in run:
         data.append(hash_path(os.path.join(GECKO, 'build', 'debian-packages', run['patch'])))