Merge ~ubuntu-release/autopkgtest/+git/development:cross-arch-testing into ~ubuntu-release/autopkgtest/+git/development:master
- Git
- lp:~ubuntu-release/autopkgtest/+git/development
- cross-arch-testing
- Merge into master
Proposed by
Steve Langasek
Status: | Merged |
---|---|
Merge reported by: | Brian Murray |
Merged at revision: | c4fc7003a2447e07d4e44083757dfe3458b26e2e |
Proposed branch: | ~ubuntu-release/autopkgtest/+git/development:cross-arch-testing |
Merge into: | ~ubuntu-release/autopkgtest/+git/development:master |
Diff against target: |
533 lines (+247/-69) 8 files modified
.gitlab-ci.yml (+2/-2) debian/control (+26/-24) debian/tests/control (+6/-9) lib/adt_testbed.py (+119/-2) lib/autopkgtest_args.py (+5/-0) lib/testdesc.py (+28/-10) runner/autopkgtest (+55/-22) runner/autopkgtest.1 (+6/-0) |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Julian Andres Klode (community) | Approve | ||
Iain Lane | Pending | ||
Review via email: mp+376169@code.launchpad.net |
Commit message
Description of the change
A first pass at implementing a -a $arch argument to autopkgtest to support cross-arch testing
To post a comment you must log in.
- c4fc700... by Steve Langasek
-
coding style
Revision history for this message
Julian Andres Klode (juliank) wrote : | # |
Revision history for this message
Steve Langasek (vorlon) : | # |
Revision history for this message
Julian Andres Klode (juliank) : | # |
Revision history for this message
Julian Andres Klode (juliank) : | # |
Revision history for this message
Julian Andres Klode (juliank) wrote : | # |
The code seems to do the right thing when testing it, but see the previous note about the missing = in the man page.
review:
Approve
Revision history for this message
Brian Murray (brian-murray) wrote : | # |
All the commit ids in this merge proposal exist in the master branch of autopkgtest so I'm setting this to merged.
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml |
2 | index f28fa86..b9e1492 100644 |
3 | --- a/.gitlab-ci.yml |
4 | +++ b/.gitlab-ci.yml |
5 | @@ -17,9 +17,9 @@ tests-sid: |
6 | - apt-get install -y apt-utils autodep8 build-essential debhelper libdpkg-perl procps python3 python3-debian |
7 | - tests/autopkgtest NullRunner NullRunnerRoot ChrootRunner |
8 | |
9 | -tests-stretch: |
10 | +tests-stable: |
11 | stage: test |
12 | - image: debian:stretch |
13 | + image: debian:stable |
14 | script: |
15 | - apt-get update |
16 | - apt-get install -y apt-utils autodep8 build-essential debhelper libdpkg-perl procps python3 python3-debian |
17 | diff --git a/debian/control b/debian/control |
18 | index 6b347f0..c37b4ee 100644 |
19 | --- a/debian/control |
20 | +++ b/debian/control |
21 | @@ -1,39 +1,41 @@ |
22 | Source: autopkgtest |
23 | Maintainer: Debian CI team <team+ci@tracker.debian.org> |
24 | -Uploaders: Ian Jackson <ijackson@chiark.greenend.org.uk>, Martin Pitt <mpitt@debian.org>, Antonio Terceiro <terceiro@debian.org>, Paul Gevers <elbrus@debian.org> |
25 | +Uploaders: Ian Jackson <ijackson@chiark.greenend.org.uk>, |
26 | + Martin Pitt <mpitt@debian.org>, |
27 | + Antonio Terceiro <terceiro@debian.org>, |
28 | + Paul Gevers <elbrus@debian.org> |
29 | Section: devel |
30 | Priority: optional |
31 | Standards-Version: 4.4.0 |
32 | Build-Depends: debhelper (>= 9), |
33 | - python3 (>= 3.1), |
34 | - python3-mock, |
35 | - python3-debian, |
36 | - python3-docutils, |
37 | - pyflakes3 | pyflakes, |
38 | - procps, |
39 | - pycodestyle | pep8, |
40 | + procps, |
41 | + pycodestyle | pep8, |
42 | + pyflakes3 | pyflakes, |
43 | + python3 (>= 3.1), |
44 | + python3-debian, |
45 | + python3-docutils, |
46 | + python3-mock |
47 | Vcs-Git: https://salsa.debian.org/ci-team/autopkgtest.git |
48 | Vcs-Browser: https://salsa.debian.org/ci-team/autopkgtest |
49 | |
50 | Package: autopkgtest |
51 | Architecture: all |
52 | -Depends: python3, |
53 | - python3-debian, |
54 | - apt-utils, |
55 | - libdpkg-perl, |
56 | - procps, |
57 | - ${misc:Depends} |
58 | +Depends: apt-utils, |
59 | + libdpkg-perl, |
60 | + procps, |
61 | + python3, |
62 | + python3-debian, |
63 | + ${misc:Depends} |
64 | Recommends: autodep8 |
65 | -Suggests: |
66 | - lxc, |
67 | - lxd, |
68 | - ovmf, |
69 | - qemu-efi-aarch64, |
70 | - qemu-efi-arm, |
71 | - qemu-system, |
72 | - qemu-utils, |
73 | - schroot, |
74 | - vmdb2, |
75 | +Suggests: lxc, |
76 | + lxd, |
77 | + ovmf, |
78 | + qemu-efi-aarch64, |
79 | + qemu-efi-arm, |
80 | + qemu-system, |
81 | + qemu-utils, |
82 | + schroot, |
83 | + vmdb2 |
84 | Breaks: debci (<< 1.7~) |
85 | Description: automatic as-installed testing for Debian packages |
86 | autopkgtest runs tests on binary packages. The tests are run on the |
87 | diff --git a/debian/tests/control b/debian/tests/control |
88 | index a59b3ef..26f4a18 100644 |
89 | --- a/debian/tests/control |
90 | +++ b/debian/tests/control |
91 | @@ -1,8 +1,5 @@ |
92 | Tests: autopkgtest |
93 | -Depends: autopkgtest, |
94 | - autodep8, |
95 | - build-essential, |
96 | - debhelper (>= 7) |
97 | +Depends: autodep8, autopkgtest, build-essential, debhelper (>= 7) |
98 | Restrictions: needs-root |
99 | Tests-Directory: tests |
100 | |
101 | @@ -15,9 +12,9 @@ Depends: autopkgtest |
102 | |
103 | Tests: lxd |
104 | Depends: autopkgtest, |
105 | - lxd, |
106 | - build-essential, |
107 | - debhelper (>= 7), |
108 | - fakeroot, |
109 | - iptables |
110 | + build-essential, |
111 | + debhelper (>= 7), |
112 | + fakeroot, |
113 | + iptables, |
114 | + lxd |
115 | Restrictions: isolation-machine, needs-root, allow-stderr |
116 | diff --git a/lib/adt_testbed.py b/lib/adt_testbed.py |
117 | index 4fe8874..ff1a0ff 100644 |
118 | --- a/lib/adt_testbed.py |
119 | +++ b/lib/adt_testbed.py |
120 | @@ -395,7 +395,8 @@ class Testbed: |
121 | self._opened(pl) |
122 | self.modified = False |
123 | |
124 | - def install_deps(self, deps_new, recommends, shell_on_failure=False, synth_deps=[]): |
125 | + def install_deps(self, deps_new, recommends, shell_on_failure=False, |
126 | + synth_deps=[], cross_arch=None): |
127 | '''Install dependencies into testbed''' |
128 | adtlog.debug('install_deps: deps_new=%s, recommends=%s' % (deps_new, recommends)) |
129 | |
130 | @@ -403,7 +404,24 @@ class Testbed: |
131 | self.recommends_installed = recommends |
132 | if not deps_new: |
133 | return |
134 | - self.satisfy_dependencies_string(', '.join(deps_new), 'install-deps', recommends, shell_on_failure=shell_on_failure, synth_deps=synth_deps) |
135 | + if cross_arch: |
136 | + # mock up a .dsc with our dependencies string as our build-deps |
137 | + dsc = TempPath(self, 'autopkgtest-satdep.dsc') |
138 | + with open(dsc.host, 'w', encoding='UTF-8') as f_dsc: |
139 | + f_dsc.write("Source: autopkgtest-satdep\n" |
140 | + "Binary: autopkgtest-satdep\n" |
141 | + "Architecture: any all\n" |
142 | + "Build-Depends: " + ', '.join(deps_new) + "\n") |
143 | + dsc.copydown() |
144 | + |
145 | + # feed the result to apt-get build-dep |
146 | + self.satisfy_build_deps(dsc.tb, cross_arch, |
147 | + recommends, shell_on_failure) |
148 | + # Now handle the synthetic deps as well |
149 | + self.install_apt('', recommends, shell_on_failure, synth_deps) |
150 | + |
151 | + else: |
152 | + self.satisfy_dependencies_string(', '.join(deps_new), 'install-deps', recommends, shell_on_failure=shell_on_failure, synth_deps=synth_deps) |
153 | |
154 | def needs_reset(self): |
155 | # show what caused a reset |
156 | @@ -1021,6 +1039,105 @@ fi |
157 | if self.execute(['sh', adtlog.verbosity >= 2 and '-exc' or '-ec', script], kind='install')[0] != 0: |
158 | self.bomb('Failed to update click AppArmor rules') |
159 | |
160 | + def _run_apt_build_dep(self, what, prefix, recommends, ignorerc=False): |
161 | + '''actually run apt-get build-dep''' |
162 | + |
163 | + # capture status-fd to stderr |
164 | + (rc, _, serr) = self.execute(['/bin/sh', '-ec', '%s apt-get build-dep ' |
165 | + '--assume-yes %s ' |
166 | + '-o APT::Status-Fd=3 ' |
167 | + '-o APT::Install-Recommends=%s ' |
168 | + '-o Dpkg::Options::=--force-confnew ' |
169 | + '-o Debug::pkgProblemResolver=true 3>&2 2>&1' % |
170 | + (prefix, what, recommends)], |
171 | + kind='install', stderr=subprocess.PIPE) |
172 | + if not ignorerc and rc != 0: |
173 | + adtlog.debug('apt-get build-dep %s failed; status-fd:\n%s' % (what, serr)) |
174 | + # check if apt failed during package download, which might be a |
175 | + # transient error, so retry |
176 | + if 'dlstatus:' in serr and 'pmstatus:' not in serr: |
177 | + raise adtlog.AptDownloadError |
178 | + else: |
179 | + raise adtlog.AptPermanentError |
180 | + |
181 | + def satisfy_build_deps(self, source_pkg, architecture=None, |
182 | + recommends=False, shell_on_failure=False): |
183 | + '''Install build-dependencies into testbed with apt-get build-dep |
184 | + |
185 | + This requires root privileges and a writable file system. |
186 | + ''' |
187 | + # check if we can use apt-get |
188 | + can_apt_get = False |
189 | + if 'root-on-testbed' in self.caps: |
190 | + rc = self.execute(['test', '-w', '/var/lib/dpkg/status'])[0] |
191 | + if rc == 0: |
192 | + can_apt_get = True |
193 | + adtlog.debug('can use apt-get on testbed: %s' % can_apt_get) |
194 | + |
195 | + if not can_apt_get: |
196 | + self.bomb('no root on testbed, unsupported when specifying target architecture') |
197 | + |
198 | + what = source_pkg |
199 | + if architecture: |
200 | + what += ' -a ' + architecture |
201 | + # install the build-dependencies for the specified source (which can |
202 | + # be a source package name, or a path); our apt pinning is not |
203 | + # very clever wrt. resolving transitional dependencies in the pocket, |
204 | + # so we might need to retry without pinning |
205 | + download_fail_retries = 3 |
206 | + while True: |
207 | + rc = 0 |
208 | + try: |
209 | + self._run_apt_build_dep(what, ' '.join(self.eatmydata_prefix), recommends) |
210 | + |
211 | + # check if apt failed during package download, which might be a |
212 | + # transient error, so retry |
213 | + except adtlog.AptDownloadError: |
214 | + download_fail_retries -= 1 |
215 | + if download_fail_retries > 0: |
216 | + adtlog.warning('apt failed to download packages, retrying in 10s...') |
217 | + time.sleep(10) |
218 | + continue |
219 | + else: |
220 | + self.bomb('apt repeatedly failed to download packages') |
221 | + |
222 | + except adtlog.AptPermanentError: |
223 | + rc = -1 |
224 | + if shell_on_failure: |
225 | + self.run_shell() |
226 | + |
227 | + if rc != 0: |
228 | + if self.apt_pin_for_releases and self.enable_apt_fallback: |
229 | + release = self.apt_pin_for_releases.pop() |
230 | + adtlog.warning('Test dependencies are unsatisfiable using apt pinning. ' |
231 | + 'Retrying using all packages from %s' % release) |
232 | + self.check_exec(['/bin/sh', '-ec', 'rm /etc/apt/preferences.d/autopkgtest-' + release]) |
233 | + if not self.apt_pin_for_releases: |
234 | + self.check_exec(['/bin/sh', '-ec', 'rm -f /etc/apt/preferences.d/autopkgtest-default-release']) |
235 | + continue |
236 | + |
237 | + adtlog.warning('Test dependencies are unsatisfiable - calling ' |
238 | + 'apt install on test deps directly for further ' |
239 | + 'data about failing dependencies in test logs') |
240 | + self._run_apt_build_dep('--simulate ' + what, |
241 | + ' '.join(self.eatmydata_prefix), |
242 | + recommends, ignorerc=True) |
243 | + |
244 | + if shell_on_failure: |
245 | + self.run_shell() |
246 | + if self.enable_apt_fallback: |
247 | + self.badpkg('Test dependencies are unsatisfiable. A common reason is ' |
248 | + 'that your testbed is out of date with respect to the ' |
249 | + 'archive, and you need to use a current testbed or run ' |
250 | + 'apt-get update or use -U.') |
251 | + else: |
252 | + self.badpkg('Test dependencies are unsatisfiable. A common reason is ' |
253 | + 'that the requested apt pinning prevented dependencies ' |
254 | + 'from the non-default suite to be installed. In that ' |
255 | + 'case you need to add those dependencies to the pinning ' |
256 | + 'list.') |
257 | + break |
258 | + |
259 | def satisfy_dependencies_string(self, deps, what, recommends=False, |
260 | build_dep=False, shell_on_failure=False, synth_deps=[]): |
261 | '''Install dependencies from a string into the testbed''' |
262 | diff --git a/lib/autopkgtest_args.py b/lib/autopkgtest_args.py |
263 | index 7fea2d8..9edb4a8 100644 |
264 | --- a/lib/autopkgtest_args.py |
265 | +++ b/lib/autopkgtest_args.py |
266 | @@ -210,6 +210,11 @@ for details.''' |
267 | help='Run tests from already installed click package ' |
268 | '(e. g. "com.example.myapp"), from specified click ' |
269 | 'source directory or manifest\'s x-source.') |
270 | + g_test.add_argument('-a', '--architecture', metavar='ARCH', |
271 | + help='run tests for (and when asked, build binaries ' |
272 | + 'for) ARCH instead of the testbed host architecture. ' |
273 | + 'Assumes ARCH is available as a foreign architecture ' |
274 | + 'on the testbed.') |
275 | g_test.add_argument('packages', nargs='*', |
276 | help='testsrc source package and testbinary packages as above') |
277 | |
278 | diff --git a/lib/testdesc.py b/lib/testdesc.py |
279 | index 84d24db..eb2ffd4 100644 |
280 | --- a/lib/testdesc.py |
281 | +++ b/lib/testdesc.py |
282 | @@ -239,7 +239,7 @@ def _debian_check_unknown_fields(name, record): |
283 | raise Unsupported(name, 'unknown field %s' % unknown_keys.pop()) |
284 | |
285 | |
286 | -def _debian_packages_from_source(srcdir): |
287 | +def _debian_packages_from_source(srcdir, cross_arch=None): |
288 | packages = [] |
289 | packages_no_arch = [] |
290 | |
291 | @@ -252,10 +252,17 @@ def _debian_packages_from_source(srcdir): |
292 | st.get('Package-type', 'deb') != 'deb': |
293 | continue |
294 | arch = st['Architecture'] |
295 | - if arch in ('all', 'any'): |
296 | + qual_pkg = st['Package'] |
297 | + # take care to emit an arch qualifier only for arch-dependent |
298 | + # packages, not for arch: all ones |
299 | + if cross_arch: |
300 | + qual_pkg += ':' + cross_arch |
301 | + if arch == 'all': |
302 | packages.append(st['Package']) |
303 | + elif arch == 'any': |
304 | + packages.append(qual_pkg) |
305 | else: |
306 | - packages.append('%s [%s]' % (st['Package'], arch)) |
307 | + packages.append('%s [%s]' % (qual_pkg, arch)) |
308 | packages_no_arch.append(st['Package']) |
309 | |
310 | return (packages, packages_no_arch) |
311 | @@ -353,7 +360,8 @@ def _synthesize_deps(dep, testbed_arch): |
312 | return None |
313 | |
314 | |
315 | -def _parse_debian_depends(testname, dep_str, srcdir, testbed_arch): |
316 | +def _parse_debian_depends(testname, dep_str, srcdir, testbed_arch, |
317 | + cross_arch=None): |
318 | '''Parse Depends: line in a Debian package |
319 | |
320 | Split dependencies (comma separated), validate their syntax, and expand @ |
321 | @@ -364,7 +372,12 @@ def _parse_debian_depends(testname, dep_str, srcdir, testbed_arch): |
322 | ''' |
323 | deps = [] |
324 | synthdeps = [] |
325 | - (my_packages, my_packages_no_arch) = _debian_packages_from_source(srcdir) |
326 | + (my_packages, my_packages_no_arch) = _debian_packages_from_source(srcdir, |
327 | + cross_arch=cross_arch) |
328 | + if cross_arch: |
329 | + target_arch = cross_arch |
330 | + else: |
331 | + target_arch = testbed_arch |
332 | for alt_group_str in dep_str.split(','): |
333 | alt_group_str = alt_group_str.strip() |
334 | if not alt_group_str: |
335 | @@ -375,7 +388,7 @@ def _parse_debian_depends(testname, dep_str, srcdir, testbed_arch): |
336 | for d in my_packages: |
337 | adtlog.debug('synthesised dependency %s' % d) |
338 | deps.append(d) |
339 | - s = _synthesize_deps(d, testbed_arch) |
340 | + s = _synthesize_deps(d, target_arch) |
341 | if s: |
342 | synthdeps.append(s) |
343 | elif alt_group_str == '@builddeps@': |
344 | @@ -389,8 +402,10 @@ def _parse_debian_depends(testname, dep_str, srcdir, testbed_arch): |
345 | if pkg not in my_packages_no_arch: |
346 | synthdep_alternatives = [] |
347 | break |
348 | - s = _synthesize_deps(dep, testbed_arch) |
349 | + s = _synthesize_deps(dep, target_arch) |
350 | if s: |
351 | + if cross_arch: |
352 | + s += ':' + cross_arch |
353 | synthdep_alternatives.append(s) |
354 | if synthdep_alternatives: |
355 | adtlog.debug('marked alternatives %s as a synthesised dependency' % synthdep_alternatives) |
356 | @@ -398,6 +413,9 @@ def _parse_debian_depends(testname, dep_str, srcdir, testbed_arch): |
357 | synthdeps.append(synthdep_alternatives) |
358 | else: |
359 | synthdeps.append(synthdep_alternatives[0]) |
360 | + if cross_arch and alt_group_str + ':' + cross_arch in my_packages: |
361 | + adtlog.debug('%s is from our source package, adding arch qualifier for cross-testing' % s) |
362 | + alt_group_str += ':' + cross_arch |
363 | deps.append(alt_group_str) |
364 | |
365 | return (deps, synthdeps) |
366 | @@ -429,7 +447,7 @@ def _autodep8(srcdir): |
367 | |
368 | |
369 | def parse_debian_source(srcdir, testbed_caps, testbed_arch, control_path=None, |
370 | - auto_control=True): |
371 | + auto_control=True, cross_arch=None): |
372 | '''Parse test descriptions from a Debian DEP-8 source dir |
373 | |
374 | You can specify an alternative path for the control file (default: |
375 | @@ -503,7 +521,7 @@ def parse_debian_source(srcdir, testbed_caps, testbed_arch, control_path=None, |
376 | test_names[0], |
377 | record.get('Depends', '@'), |
378 | srcdir, |
379 | - testbed_arch) |
380 | + testbed_arch, cross_arch=cross_arch) |
381 | if 'Test-command' in record: |
382 | raise InvalidControl('*', 'Only one of "Tests" or ' |
383 | '"Test-Command" may be given') |
384 | @@ -529,7 +547,7 @@ def parse_debian_source(srcdir, testbed_caps, testbed_arch, control_path=None, |
385 | command, |
386 | record.get('Depends', '@'), |
387 | srcdir, |
388 | - testbed_arch) |
389 | + testbed_arch, cross_arch=cross_arch) |
390 | if feature_test_name is None: |
391 | command_counter += 1 |
392 | name = 'command%i' % command_counter |
393 | diff --git a/runner/autopkgtest b/runner/autopkgtest |
394 | index 93c6e61..f1e2e8f 100755 |
395 | --- a/runner/autopkgtest |
396 | +++ b/runner/autopkgtest |
397 | @@ -159,7 +159,10 @@ def run_tests(tests, tree): |
398 | binaries.publish() |
399 | doTest = True |
400 | try: |
401 | - testbed.install_deps(t.depends, 'needs-recommends' in t.restrictions, opts.shell_fail, t.synth_depends) |
402 | + testbed.install_deps(t.depends, |
403 | + 'needs-recommends' in t.restrictions, |
404 | + opts.shell_fail, t.synth_depends, |
405 | + opts.architecture) |
406 | except adtlog.BadPackageError as e: |
407 | if 'skip-not-installable' in t.restrictions: |
408 | errorcode |= 2 |
409 | @@ -388,6 +391,12 @@ def build_source(kind, arg, built_binaries): |
410 | return tests_tree |
411 | |
412 | elif kind == 'apt-source': |
413 | + # Make sure we are selecting the binaries based on the actual target |
414 | + # architecture, not necessarily the testbed architecture |
415 | + if opts.architecture: |
416 | + arch = opts.architecture |
417 | + else: |
418 | + arch = testbed.dpkg_arch |
419 | # The default is to determine the version for "apt-get source |
420 | # pkg=version" that conforms to the current apt pinning. We only |
421 | # consider binaries which are shipped in all available versions, |
422 | @@ -443,7 +452,7 @@ pkgs=$(echo "$pkgs\n" | awk " |
423 | if (foundarch == 0 || archmatch == 1) thissrc[\\$1] = 1; |
424 | next } |
425 | { if (!inlist) next; |
426 | - inlist=0;''' % {'src': arg, 'arch': testbed.dpkg_arch} |
427 | + inlist=0;''' % {'src': arg, 'arch': arch} |
428 | |
429 | create_command_part2_check_all_pkgs = ''' |
430 | remaining=0; |
431 | @@ -580,24 +589,8 @@ dpkg-source -x %(src)s_*.dsc src >/dev/null''' % {'src': arg} |
432 | if kind not in ['dsc', 'apt-source']: |
433 | testbed.install_deps([], False) |
434 | |
435 | - if kind in ('apt-source', 'git-source'): |
436 | - # we need to get the downloaded debian/control from the testbed, so |
437 | - # that we can avoid calling "apt-get build-dep" and thus |
438 | - # introducing a second mechanism for installing build deps |
439 | - pkg_control = adt_testbed.Path(testbed, |
440 | - os.path.join(tmp, 'apt-control'), |
441 | - os.path.join(result_pwd, 'debian/control'), False) |
442 | - pkg_control.copyup() |
443 | - dsc = pkg_control.host |
444 | - |
445 | - with open(dsc, encoding='UTF-8') as f: |
446 | - d = deb822.Deb822(sequence=f) |
447 | - bd = d.get('Build-Depends', '') |
448 | - bdi = d.get('Build-Depends-Indep', '') |
449 | - bda = d.get('Build-Depends-Arch', '') |
450 | - |
451 | # determine build command and build-essential packages |
452 | - build_essential = ['build-essential'] |
453 | + build_essential = ['build-essential:native'] |
454 | assert testbed.nproc |
455 | dpkg_buildpackage = 'DEB_BUILD_OPTIONS="parallel=%s $DEB_BUILD_OPTIONS" dpkg-buildpackage -us -uc -b' % ( |
456 | opts.build_parallel or testbed.nproc) |
457 | @@ -607,8 +600,47 @@ dpkg-source -x %(src)s_*.dsc src >/dev/null''' % {'src': arg} |
458 | if testbed.user or 'root-on-testbed' not in testbed.caps: |
459 | build_essential += ['fakeroot'] |
460 | |
461 | - testbed.satisfy_dependencies_string(bd + ', ' + bdi + ', ' + bda + ', ' + ', '.join(build_essential), arg, |
462 | - build_dep=True, shell_on_failure=opts.shell_fail) |
463 | + if opts.architecture: |
464 | + dpkg_buildpackage += ' -a' + opts.architecture |
465 | + build_essential += ['crossbuild-essential-%s:native' % opts.architecture] |
466 | + # apt-get build-dep is the best option here, but we don't call |
467 | + # it unconditionally because it doesn't take a path to a source |
468 | + # package as an option in very old releases; so for compatibility |
469 | + # only use it when we need its multiarch build-dep resolution |
470 | + # support. |
471 | + # This is supported in apt 1.1~exp2 and newer, which covers |
472 | + # Debian oldstable (at time of writing) and Ubuntu 16.04 and |
473 | + # newer, so once we can rely on this version of apt everywhere, |
474 | + # the old build-dep resolver code should be deprecated. |
475 | + all_build_deps = '' |
476 | + testbed.satisfy_build_deps(result_pwd, |
477 | + architecture=opts.architecture, |
478 | + shell_on_failure=opts.shell_fail) |
479 | + else: |
480 | + if kind in ('apt-source', 'git-source'): |
481 | + # we need to get the downloaded debian/control from the |
482 | + # testbed, so that we can avoid calling "apt-get build-dep" |
483 | + # and thus introducing a second mechanism for installing |
484 | + # build deps |
485 | + pkg_control = adt_testbed.Path(testbed, |
486 | + os.path.join(tmp, 'apt-control'), |
487 | + os.path.join(result_pwd, 'debian/control'), False) |
488 | + pkg_control.copyup() |
489 | + dsc = pkg_control.host |
490 | + |
491 | + with open(dsc, encoding='UTF-8') as f: |
492 | + d = deb822.Deb822(sequence=f) |
493 | + bd = d.get('Build-Depends', '') |
494 | + bdi = d.get('Build-Depends-Indep', '') |
495 | + bda = d.get('Build-Depends-Arch', '') |
496 | + |
497 | + all_build_deps = bd + ', ' + bdi + ', ' + bda + ', ' |
498 | + |
499 | + testbed.satisfy_dependencies_string(all_build_deps + |
500 | + ', '.join(build_essential), |
501 | + arg, |
502 | + build_dep=True, |
503 | + shell_on_failure=opts.shell_fail) |
504 | |
505 | # keep patches applied for tests |
506 | source_rules_command([dpkg_buildpackage, 'dpkg-source --before-build .'], 'build', cwd=result_pwd) |
507 | @@ -733,7 +765,8 @@ def process_actions(): |
508 | (tests, skipped) = testdesc.parse_debian_source( |
509 | tests_tree.host, testbed.caps, testbed.dpkg_arch, |
510 | control_path=control_override, |
511 | - auto_control=opts.auto_control) |
512 | + auto_control=opts.auto_control, |
513 | + cross_arch=opts.architecture) |
514 | except testdesc.InvalidControl as e: |
515 | adtlog.badpkg(str(e)) |
516 | |
517 | diff --git a/runner/autopkgtest.1 b/runner/autopkgtest.1 |
518 | index ce4a1bf..abf181b 100644 |
519 | --- a/runner/autopkgtest.1 |
520 | +++ b/runner/autopkgtest.1 |
521 | @@ -136,6 +136,12 @@ autopkgtest --installed-click com.example.myclick -- [...] |
522 | .SH TEST OPTIONS |
523 | |
524 | .TP |
525 | +.BR -a " | " --architecture ARCH |
526 | +Run tests for the specified architecture, rather than for the host |
527 | +architecture as defined by dpkg \-\-print-architecture. When building |
528 | +packages from source, cross-build for the target architecture as well. |
529 | + |
530 | +.TP |
531 | .BR -B " | " --no-built-binaries |
532 | Binaries from unbuilt source packages (see above) |
533 | will not be built or ignored, and dependencies are satisfied with packages from |
The commits look good to me from reading them, except that one comment below. Not performed any real-world testing yet.