launchpad-reviewers team mailing list archive
-
launchpad-reviewers team
-
Mailing list archive
-
Message #19054
[Merge] lp:~cjwatson/launchpad-buildd/complex-build-deps into lp:launchpad-buildd
Colin Watson has proposed merging lp:~cjwatson/launchpad-buildd/complex-build-deps into lp:launchpad-buildd.
Commit message:
Handle architecture restrictions, architecture qualifications, and restriction formulas (build profiles) in build-dependencies.
Requested reviews:
Launchpad code reviewers (launchpad-reviewers)
For more details, see:
https://code.launchpad.net/~cjwatson/launchpad-buildd/complex-build-deps/+merge/265650
Handle architecture restrictions, architecture qualifications, and restriction formulas (build profiles) in build-dependencies, since now that we're doing our own build-dependency analysis we have to worry about this. Architecture qualifications and restriction formulas require a newer version of python-debian, which is in https://launchpad.net/~cjwatson/+archive/ubuntu/launchpad/+packages.
--
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~cjwatson/launchpad-buildd/complex-build-deps into lp:launchpad-buildd.
=== modified file 'debian/changelog'
--- debian/changelog 2015-07-16 13:03:35 +0000
+++ debian/changelog 2015-07-23 12:27:10 +0000
@@ -5,6 +5,8 @@
build-dependencies are uninstallable.
* If there is a mix of definite and dubious dep-wait output, then analyse
the situation rather than trusting just the definite information.
+ * Handle architecture restrictions, architecture qualifications, and
+ restriction formulas (build profiles) in build-dependencies.
-- Colin Watson <cjwatson@xxxxxxxxxx> Thu, 16 Jul 2015 14:00:16 +0100
=== modified file 'lpbuildd/binarypackage.py'
--- lpbuildd/binarypackage.py 2015-07-16 13:03:35 +0000
+++ lpbuildd/binarypackage.py 2015-07-23 12:27:10 +0000
@@ -6,6 +6,7 @@
from collections import defaultdict
import os
import re
+import subprocess
import traceback
import apt_pkg
@@ -61,6 +62,25 @@
}
+class DpkgArchitectureCache:
+ """Cache the results of asking questions of dpkg-architecture."""
+
+ def __init__(self):
+ self._matches = {}
+
+ def match(self, arch, wildcard):
+ if (arch, wildcard) not in self._matches:
+ command = ["dpkg-architecture", "-i%s" % wildcard]
+ env = dict(os.environ)
+ env["DEB_HOST_ARCH"] = arch
+ ret = (subprocess.call(command, env=env) == 0)
+ self._matches[(arch, wildcard)] = ret
+ return self._matches[(arch, wildcard)]
+
+
+dpkg_architecture = DpkgArchitectureCache()
+
+
class BinaryPackageBuildState(DebianBuildState):
SBUILD = "SBUILD"
@@ -180,18 +200,42 @@
def relationMatches(self, dep, available):
"""Return True iff a dependency matches an available package.
- :param dep: A dictionary with at least a "name" key, perhaps also a
- "version" key, and optionally other keys, of the kind returned
- in a list of lists by
+ :param dep: A dictionary with at least a "name" key, perhaps also
+ "version" and "arch" keys, and optionally other keys, of the
+ kind returned in a list of lists by
`debian.deb822.PkgRelation.parse_relations`.
:param available: A dictionary mapping package names to a list of
the available versions of each package.
"""
+ dep_arch = dep.get("arch")
+ if dep_arch is not None:
+ seen_arch = False
+ for polarity, arch_wildcard in dep_arch:
+ if dpkg_architecture.match(self.arch_tag, arch_wildcard):
+ seen_arch = polarity
+ break
+ elif not polarity:
+ # Any !other-architecture restriction implies that this
+ # architecture is allowed, unless it's specifically
+ # excluded later.
+ seen_arch = True
+ if not seen_arch:
+ # This dependency "matches" in the sense that it's ignored
+ # on this architecture.
+ return True
+ dep_restrictions = dep.get("restrictions")
+ if dep_restrictions is not None:
+ if all(
+ any(restriction.enabled for restriction in restrlist)
+ for restrlist in dep_restrictions):
+ # This dependency "matches" in the sense that it's ignored
+ # when no build profiles are enabled.
+ return True
if dep["name"] not in available:
return False
- if dep.get("version") is None:
+ dep_version = dep.get("version")
+ if dep_version is None:
return True
- dep_version = dep.get("version")
operator_map = {
"<<": (lambda a, b: a < b),
"<=": (lambda a, b: a <= b),
@@ -230,7 +274,14 @@
unsat_deps = []
for or_dep in deps:
if not any(self.relationMatches(dep, avail) for dep in or_dep):
- unsat_deps.append(or_dep)
+ stripped_or_dep = []
+ for simple_dep in or_dep:
+ stripped_simple_dep = dict(simple_dep)
+ stripped_simple_dep["arch"] = None
+ stripped_simple_dep["archqual"] = None
+ stripped_simple_dep["restrictions"] = None
+ stripped_or_dep.append(stripped_simple_dep)
+ unsat_deps.append(stripped_or_dep)
if unsat_deps:
return PkgRelation.str(unsat_deps)
except Exception:
=== modified file 'lpbuildd/tests/test_binarypackage.py'
--- lpbuildd/tests/test_binarypackage.py 2015-07-16 13:03:35 +0000
+++ lpbuildd/tests/test_binarypackage.py 2015-07-23 12:27:10 +0000
@@ -426,6 +426,48 @@
"debhelper (>= 9~), foo (>= 1), bar (<< 1) | bar (>= 2)"),
{"debhelper": set(["9"]), "bar": set(["1", "1.5"])}))
+ def test_analyseDepWait_strips_arch_restrictions(self):
+ # analyseDepWait removes architecture restrictions (e.g. "[amd64]")
+ # from the unsatisfied build-dependencies it returns, and only
+ # returns those relevant to the current architecture.
+ self.buildmanager.initiate(
+ {'foo_1.dsc': ''}, 'chroot.tar.gz',
+ {'distribution': 'ubuntu', 'suite': 'warty',
+ 'ogrecomponent': 'main', 'arch_tag': 'i386'})
+ self.assertEqual(
+ "foo (>= 1)",
+ self.buildmanager.analyseDepWait(
+ PkgRelation.parse_relations(
+ "foo (>= 1) [any-i386], bar (>= 1) [amd64]"),
+ {}))
+
+ def test_analyseDepWait_strips_arch_qualifications(self):
+ # analyseDepWait removes architecture qualifications (e.g. ":any")
+ # from the unsatisfied build-dependencies it returns.
+ self.buildmanager.initiate(
+ {'foo_1.dsc': ''}, 'chroot.tar.gz',
+ {'distribution': 'ubuntu', 'suite': 'warty',
+ 'ogrecomponent': 'main', 'arch_tag': 'i386'})
+ self.assertEqual(
+ "foo",
+ self.buildmanager.analyseDepWait(
+ PkgRelation.parse_relations("foo:any, bar:any"),
+ {"bar": set(["1"])}))
+
+ def test_analyseDepWait_strips_restrictions(self):
+ # analyseDepWait removes restrictions (e.g. "<stage1>") from the
+ # unsatisfied build-dependencies it returns, and only returns those
+ # that evaluate to true when no build profiles are active.
+ self.buildmanager.initiate(
+ {'foo_1.dsc': ''}, 'chroot.tar.gz',
+ {'distribution': 'ubuntu', 'suite': 'warty',
+ 'ogrecomponent': 'main', 'arch_tag': 'i386'})
+ self.assertEqual(
+ "foo",
+ self.buildmanager.analyseDepWait(
+ PkgRelation.parse_relations("foo <!nocheck>, bar <stage1>"),
+ {}))
+
def startDepFail(self, error, dscname=''):
self.startBuild(dscname=dscname)
write_file(
Follow ups