Merge lp:~cjwatson/launchpad-buildd/complex-build-deps into lp:launchpad-buildd

Proposed by Colin Watson on 2015-07-23
Status: Merged
Merged at revision: 165
Proposed branch: lp:~cjwatson/launchpad-buildd/complex-build-deps
Merge into: lp:launchpad-buildd
Diff against target: 167 lines (+101/-6)
3 files modified
debian/changelog (+2/-0)
lpbuildd/binarypackage.py (+57/-6)
lpbuildd/tests/test_binarypackage.py (+42/-0)
To merge this branch: bzr merge lp:~cjwatson/launchpad-buildd/complex-build-deps
Reviewer Review Type Date Requested Status
William Grant code 2015-07-23 Approve on 2015-07-24
Review via email: mp+265650@code.launchpad.net

Commit Message

Handle architecture restrictions, architecture qualifications, and restriction formulas (build profiles) in build-dependencies.

Description of the Change

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.

To post a comment you must log in.
William Grant (wgrant) :
review: Approve (code)
166. By Colin Watson on 2015-07-28

Sync comment with reality.

167. By Colin Watson on 2015-07-28

Adjust variable names.

168. By Colin Watson on 2015-07-28

Clarify comment about !other-architecture restrictions.

Colin Watson (cjwatson) :

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'debian/changelog'
2--- debian/changelog 2015-07-16 13:03:35 +0000
3+++ debian/changelog 2015-07-28 13:58:14 +0000
4@@ -5,6 +5,8 @@
5 build-dependencies are uninstallable.
6 * If there is a mix of definite and dubious dep-wait output, then analyse
7 the situation rather than trusting just the definite information.
8+ * Handle architecture restrictions, architecture qualifications, and
9+ restriction formulas (build profiles) in build-dependencies.
10
11 -- Colin Watson <cjwatson@ubuntu.com> Thu, 16 Jul 2015 14:00:16 +0100
12
13
14=== modified file 'lpbuildd/binarypackage.py'
15--- lpbuildd/binarypackage.py 2015-07-16 13:03:35 +0000
16+++ lpbuildd/binarypackage.py 2015-07-28 13:58:14 +0000
17@@ -6,6 +6,7 @@
18 from collections import defaultdict
19 import os
20 import re
21+import subprocess
22 import traceback
23
24 import apt_pkg
25@@ -61,6 +62,25 @@
26 }
27
28
29+class DpkgArchitectureCache:
30+ """Cache the results of asking questions of dpkg-architecture."""
31+
32+ def __init__(self):
33+ self._matches = {}
34+
35+ def match(self, arch, wildcard):
36+ if (arch, wildcard) not in self._matches:
37+ command = ["dpkg-architecture", "-i%s" % wildcard]
38+ env = dict(os.environ)
39+ env["DEB_HOST_ARCH"] = arch
40+ ret = (subprocess.call(command, env=env) == 0)
41+ self._matches[(arch, wildcard)] = ret
42+ return self._matches[(arch, wildcard)]
43+
44+
45+dpkg_architecture = DpkgArchitectureCache()
46+
47+
48 class BinaryPackageBuildState(DebianBuildState):
49 SBUILD = "SBUILD"
50
51@@ -180,18 +200,42 @@
52 def relationMatches(self, dep, available):
53 """Return True iff a dependency matches an available package.
54
55- :param dep: A dictionary with at least a "name" key, perhaps also a
56- "version" key, and optionally other keys, of the kind returned
57- in a list of lists by
58+ :param dep: A dictionary with at least a "name" key, perhaps also
59+ "version", "arch", and "restrictions" keys, and optionally other
60+ keys, of the kind returned in a list of lists by
61 `debian.deb822.PkgRelation.parse_relations`.
62 :param available: A dictionary mapping package names to a list of
63 the available versions of each package.
64 """
65+ dep_arch = dep.get("arch")
66+ if dep_arch is not None:
67+ arch_match = False
68+ for enabled, arch_wildcard in dep_arch:
69+ if dpkg_architecture.match(self.arch_tag, arch_wildcard):
70+ arch_match = enabled
71+ break
72+ elif not enabled:
73+ # Any !other-architecture restriction implies that this
74+ # architecture is allowed, unless it's specifically
75+ # excluded by some other restriction.
76+ arch_match = True
77+ if not arch_match:
78+ # This dependency "matches" in the sense that it's ignored
79+ # on this architecture.
80+ return True
81+ dep_restrictions = dep.get("restrictions")
82+ if dep_restrictions is not None:
83+ if all(
84+ any(restriction.enabled for restriction in restrlist)
85+ for restrlist in dep_restrictions):
86+ # This dependency "matches" in the sense that it's ignored
87+ # when no build profiles are enabled.
88+ return True
89 if dep["name"] not in available:
90 return False
91- if dep.get("version") is None:
92+ dep_version = dep.get("version")
93+ if dep_version is None:
94 return True
95- dep_version = dep.get("version")
96 operator_map = {
97 "<<": (lambda a, b: a < b),
98 "<=": (lambda a, b: a <= b),
99@@ -230,7 +274,14 @@
100 unsat_deps = []
101 for or_dep in deps:
102 if not any(self.relationMatches(dep, avail) for dep in or_dep):
103- unsat_deps.append(or_dep)
104+ stripped_or_dep = []
105+ for simple_dep in or_dep:
106+ stripped_simple_dep = dict(simple_dep)
107+ stripped_simple_dep["arch"] = None
108+ stripped_simple_dep["archqual"] = None
109+ stripped_simple_dep["restrictions"] = None
110+ stripped_or_dep.append(stripped_simple_dep)
111+ unsat_deps.append(stripped_or_dep)
112 if unsat_deps:
113 return PkgRelation.str(unsat_deps)
114 except Exception:
115
116=== modified file 'lpbuildd/tests/test_binarypackage.py'
117--- lpbuildd/tests/test_binarypackage.py 2015-07-16 13:03:35 +0000
118+++ lpbuildd/tests/test_binarypackage.py 2015-07-28 13:58:14 +0000
119@@ -426,6 +426,48 @@
120 "debhelper (>= 9~), foo (>= 1), bar (<< 1) | bar (>= 2)"),
121 {"debhelper": set(["9"]), "bar": set(["1", "1.5"])}))
122
123+ def test_analyseDepWait_strips_arch_restrictions(self):
124+ # analyseDepWait removes architecture restrictions (e.g. "[amd64]")
125+ # from the unsatisfied build-dependencies it returns, and only
126+ # returns those relevant to the current architecture.
127+ self.buildmanager.initiate(
128+ {'foo_1.dsc': ''}, 'chroot.tar.gz',
129+ {'distribution': 'ubuntu', 'suite': 'warty',
130+ 'ogrecomponent': 'main', 'arch_tag': 'i386'})
131+ self.assertEqual(
132+ "foo (>= 1)",
133+ self.buildmanager.analyseDepWait(
134+ PkgRelation.parse_relations(
135+ "foo (>= 1) [any-i386], bar (>= 1) [amd64]"),
136+ {}))
137+
138+ def test_analyseDepWait_strips_arch_qualifications(self):
139+ # analyseDepWait removes architecture qualifications (e.g. ":any")
140+ # from the unsatisfied build-dependencies it returns.
141+ self.buildmanager.initiate(
142+ {'foo_1.dsc': ''}, 'chroot.tar.gz',
143+ {'distribution': 'ubuntu', 'suite': 'warty',
144+ 'ogrecomponent': 'main', 'arch_tag': 'i386'})
145+ self.assertEqual(
146+ "foo",
147+ self.buildmanager.analyseDepWait(
148+ PkgRelation.parse_relations("foo:any, bar:any"),
149+ {"bar": set(["1"])}))
150+
151+ def test_analyseDepWait_strips_restrictions(self):
152+ # analyseDepWait removes restrictions (e.g. "<stage1>") from the
153+ # unsatisfied build-dependencies it returns, and only returns those
154+ # that evaluate to true when no build profiles are active.
155+ self.buildmanager.initiate(
156+ {'foo_1.dsc': ''}, 'chroot.tar.gz',
157+ {'distribution': 'ubuntu', 'suite': 'warty',
158+ 'ogrecomponent': 'main', 'arch_tag': 'i386'})
159+ self.assertEqual(
160+ "foo",
161+ self.buildmanager.analyseDepWait(
162+ PkgRelation.parse_relations("foo <!nocheck>, bar <stage1>"),
163+ {}))
164+
165 def startDepFail(self, error, dscname=''):
166 self.startBuild(dscname=dscname)
167 write_file(

Subscribers

People subscribed via source and target branches

to all changes: