Merge lp:~cjwatson/launchpad/archive-dependencies-unittest into lp:launchpad

Proposed by Colin Watson
Status: Merged
Merged at revision: 18378
Proposed branch: lp:~cjwatson/launchpad/archive-dependencies-unittest
Merge into: lp:launchpad
Diff against target: 1256 lines (+541/-643)
5 files modified
lib/lp/soyuz/adapters/tests/test_archivedependencies.py (+517/-0)
lib/lp/soyuz/doc/archive-dependencies.txt (+0/-637)
lib/lp/soyuz/interfaces/archive.py (+2/-2)
lib/lp/soyuz/tests/test_archive.py (+14/-1)
lib/lp/testing/factory.py (+8/-3)
To merge this branch: bzr merge lp:~cjwatson/launchpad/archive-dependencies-unittest
Reviewer Review Type Date Requested Status
William Grant code Approve
Review via email: mp+323129@code.launchpad.net

Commit message

Convert archive-dependencies.txt to unit tests. Make InvalidExternalDependencies have a slightly more sensible message in the process.

Description of the change

I needed to do this to make it less painful to change get_sources_list_for_building to talk to the keyserver, which I need in order to fix bug 1626739.

To post a comment you must log in.
Revision history for this message
William Grant (wgrant) :
review: Approve (code)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== added file 'lib/lp/soyuz/adapters/tests/test_archivedependencies.py'
2--- lib/lp/soyuz/adapters/tests/test_archivedependencies.py 1970-01-01 00:00:00 +0000
3+++ lib/lp/soyuz/adapters/tests/test_archivedependencies.py 2017-04-25 11:47:06 +0000
4@@ -0,0 +1,517 @@
5+# Copyright 2017 Canonical Ltd. This software is licensed under the
6+# GNU Affero General Public License version 3 (see the file LICENSE).
7+
8+"""Test archive dependencies."""
9+
10+from __future__ import absolute_import, print_function, unicode_literals
11+
12+__metaclass__ = type
13+
14+from testtools.matchers import StartsWith
15+import transaction
16+from zope.component import getUtility
17+
18+from lp.registry.interfaces.distribution import IDistributionSet
19+from lp.registry.interfaces.pocket import PackagePublishingPocket
20+from lp.services.log.logger import BufferLogger
21+from lp.soyuz.adapters.archivedependencies import (
22+ default_component_dependency_name,
23+ default_pocket_dependency,
24+ get_components_for_context,
25+ get_primary_current_component,
26+ get_sources_list_for_building,
27+ pocket_dependencies,
28+ )
29+from lp.soyuz.enums import PackagePublishingStatus
30+from lp.soyuz.interfaces.archive import IArchive
31+from lp.soyuz.interfaces.component import IComponentSet
32+from lp.soyuz.tests.test_publishing import SoyuzTestPublisher
33+from lp.testing import TestCaseWithFactory
34+from lp.testing.layers import (
35+ LaunchpadZopelessLayer,
36+ ZopelessDatabaseLayer,
37+ )
38+
39+
40+class TestOgreModel(TestCaseWithFactory):
41+ """Test ogre-model component handling.
42+
43+ The Ubuntu "ogre model" (cf. Shrek) ensures that build-dependencies are
44+ consistent with the component in which the source is published.
45+ """
46+
47+ layer = ZopelessDatabaseLayer
48+
49+ def setUpComponents(self, distroseries, component_names):
50+ for component_name in component_names:
51+ component = getUtility(IComponentSet)[component_name]
52+ self.factory.makeComponentSelection(distroseries, component)
53+
54+ def assertComponentMap(self, expected, distroseries, pocket):
55+ for component_name, expected_components in expected.items():
56+ component = getUtility(IComponentSet)[component_name]
57+ self.assertEqual(
58+ expected_components,
59+ get_components_for_context(component, distroseries, pocket))
60+
61+ def test_strict_supported_component_dependencies(self):
62+ # In strict-supported-component-dependencies mode, a source
63+ # published in main is only allowed to build-depend on binaries also
64+ # published in main, while a source published in universe is allowed
65+ # to build-depend on main and universe.
66+ distroseries = self.factory.makeDistroSeries()
67+ expected = {
68+ "main": ["main"],
69+ "restricted": ["main", "restricted"],
70+ "universe": ["main", "universe"],
71+ "multiverse": ["main", "restricted", "universe", "multiverse"],
72+ "partner": ["partner"],
73+ }
74+ self.setUpComponents(distroseries, expected.keys())
75+ self.assertComponentMap(
76+ expected, distroseries, PackagePublishingPocket.RELEASE)
77+
78+ def test_lax_supported_component_dependencies(self):
79+ # In lax-supported-component-dependencies mode, source packages in
80+ # "supported" components (main and restricted) may additionally
81+ # build-depend on binary packages in "unsupported" components
82+ # (universe and multiverse).
83+ distroseries = self.factory.makeDistroSeries()
84+ distroseries.strict_supported_component_dependencies = False
85+ expected = {
86+ "main": ["main", "universe"],
87+ "restricted": ["main", "restricted", "universe", "multiverse"],
88+ "universe": ["main", "universe"],
89+ "multiverse": ["main", "restricted", "universe", "multiverse"],
90+ "partner": ["partner"],
91+ }
92+ self.setUpComponents(distroseries, expected.keys())
93+ self.assertComponentMap(
94+ expected, distroseries, PackagePublishingPocket.RELEASE)
95+
96+ def test_backports(self):
97+ # Source packages in the BACKPORTS pocket are allowed to
98+ # build-depend on binary packages in any component. This avoids
99+ # having to make potentially-invasive changes to accommodate
100+ # backporting to stable series.
101+ distroseries = self.factory.makeDistroSeries()
102+ expected = {
103+ "main": ["main", "restricted", "universe", "multiverse"],
104+ "restricted": ["main", "restricted", "universe", "multiverse"],
105+ "universe": ["main", "restricted", "universe", "multiverse"],
106+ "multiverse": ["main", "restricted", "universe", "multiverse"],
107+ "partner": ["main", "restricted", "universe", "multiverse"],
108+ }
109+ self.setUpComponents(distroseries, expected.keys())
110+ self.assertComponentMap(
111+ expected, distroseries, PackagePublishingPocket.BACKPORTS)
112+
113+
114+class TestSourcesList(TestCaseWithFactory):
115+ """Test sources.list contents for building, and related mechanisms."""
116+
117+ layer = LaunchpadZopelessLayer
118+
119+ ubuntu_components = [
120+ "main", "restricted", "universe", "multiverse", "partner"]
121+
122+ def setUp(self):
123+ super(TestSourcesList, self).setUp()
124+ self.publisher = SoyuzTestPublisher()
125+ self.ubuntu = getUtility(IDistributionSet).getByName("ubuntu")
126+ self.hoary = self.ubuntu.getSeries("hoary")
127+ self.publisher.addFakeChroots(self.hoary)
128+ self.publisher.setUpDefaultDistroSeries(self.hoary)
129+ for component_name in self.ubuntu_components:
130+ component = getUtility(IComponentSet)[component_name]
131+ if component not in self.hoary.components:
132+ self.factory.makeComponentSelection(self.hoary, component)
133+
134+ def test_defaults(self):
135+ # Non-primary archives by default use the Release, Security and
136+ # Updates pockets from the primary archive, and all its available
137+ # components.
138+ self.assertEqual(
139+ PackagePublishingPocket.UPDATES, default_pocket_dependency)
140+ self.assertEqual("multiverse", default_component_dependency_name)
141+ self.assertEqual(
142+ (PackagePublishingPocket.RELEASE,
143+ PackagePublishingPocket.SECURITY,
144+ PackagePublishingPocket.UPDATES),
145+ pocket_dependencies[default_pocket_dependency])
146+
147+ def makeArchive(self, publish_binary=False, **kwargs):
148+ archive = self.factory.makeArchive(distribution=self.ubuntu, **kwargs)
149+ if publish_binary:
150+ self.publisher.getPubBinaries(
151+ archive=archive, status=PackagePublishingStatus.PUBLISHED)
152+ return archive
153+
154+ def makeBuild(self, **kwargs):
155+ pub_source = self.publisher.getPubSource(**kwargs)
156+ [build] = pub_source.createMissingBuilds()
157+ return build
158+
159+ def assertPrimaryCurrentComponent(self, expected, build):
160+ self.assertEqual(
161+ expected,
162+ get_primary_current_component(
163+ build.archive, build.distro_series,
164+ build.source_package_release.name).name)
165+
166+ def assertSourcesList(self, expected, build, **kwargs):
167+ expected_lines = []
168+ for archive_or_prefix, suffixes in expected:
169+ if IArchive.providedBy(archive_or_prefix):
170+ prefix = "deb %s " % archive_or_prefix.archive_url
171+ else:
172+ prefix = archive_or_prefix + " "
173+ expected_lines.extend([prefix + suffix for suffix in suffixes])
174+ sources_list = get_sources_list_for_building(
175+ build, build.distro_arch_series, build.source_package_release.name,
176+ **kwargs)
177+ self.assertEqual(expected_lines, sources_list)
178+
179+ def test_ppa_with_no_binaries(self):
180+ # If there are no published binaries in a PPA, only its primary
181+ # archive dependencies need to be considered.
182+ ppa = self.makeArchive()
183+ build = self.makeBuild(archive=ppa)
184+ self.assertEqual(
185+ 0, ppa.getAllPublishedBinaries(
186+ distroarchseries=build.distro_arch_series,
187+ status=PackagePublishingStatus.PUBLISHED).count())
188+ self.assertSourcesList(
189+ [(self.ubuntu.main_archive, [
190+ "hoary main restricted universe multiverse",
191+ "hoary-security main restricted universe multiverse",
192+ "hoary-updates main restricted universe multiverse",
193+ ]),
194+ ], build)
195+
196+ def test_ppa_with_binaries(self):
197+ # If there are binaries published in a PPA, then the PPA is
198+ # considered as well as its primary dependencies.
199+ ppa = self.makeArchive(publish_binary=True)
200+ build = self.makeBuild(archive=ppa)
201+ self.assertSourcesList(
202+ [(ppa, ["hoary main"]),
203+ (self.ubuntu.main_archive, [
204+ "hoary main restricted universe multiverse",
205+ "hoary-security main restricted universe multiverse",
206+ "hoary-updates main restricted universe multiverse",
207+ ]),
208+ ], build)
209+
210+ def test_dependent_ppa_with_no_binaries(self):
211+ # A depended-upon PPA is not considered if it has no published
212+ # binaries.
213+ lower_ppa = self.makeArchive()
214+ upper_ppa = self.makeArchive(publish_binary=True)
215+ upper_ppa.addArchiveDependency(
216+ lower_ppa, PackagePublishingPocket.RELEASE,
217+ getUtility(IComponentSet)["main"])
218+ build = self.makeBuild(archive=upper_ppa)
219+ self.assertSourcesList(
220+ [(upper_ppa, ["hoary main"]),
221+ (self.ubuntu.main_archive, [
222+ "hoary main restricted universe multiverse",
223+ "hoary-security main restricted universe multiverse",
224+ "hoary-updates main restricted universe multiverse",
225+ ]),
226+ ], build)
227+
228+ def test_dependent_ppa_with_binaries(self):
229+ # A depended-upon PPA is considered if it has published binaries.
230+ lower_ppa = self.makeArchive(publish_binary=True)
231+ upper_ppa = self.makeArchive(publish_binary=True)
232+ upper_ppa.addArchiveDependency(
233+ lower_ppa, PackagePublishingPocket.RELEASE,
234+ getUtility(IComponentSet)["main"])
235+ build = self.makeBuild(archive=upper_ppa)
236+ self.assertSourcesList(
237+ [(upper_ppa, ["hoary main"]),
238+ (lower_ppa, ["hoary main"]),
239+ (self.ubuntu.main_archive, [
240+ "hoary main restricted universe multiverse",
241+ "hoary-security main restricted universe multiverse",
242+ "hoary-updates main restricted universe multiverse",
243+ ]),
244+ ], build)
245+
246+ def test_lax_supported_component_dependencies(self):
247+ # Dependencies for series with
248+ # strict_supported_component_dependencies=False are reasonable.
249+ # PPAs only have the "main" component.
250+ lower_ppa = self.makeArchive(publish_binary=True)
251+ upper_ppa = self.makeArchive(publish_binary=True)
252+ upper_ppa.addArchiveDependency(
253+ lower_ppa, PackagePublishingPocket.RELEASE,
254+ getUtility(IComponentSet)["main"])
255+ upper_ppa.addArchiveDependency(
256+ self.ubuntu.main_archive, PackagePublishingPocket.UPDATES,
257+ getUtility(IComponentSet)["restricted"])
258+ build = self.makeBuild(archive=upper_ppa)
259+ self.assertSourcesList(
260+ [(upper_ppa, ["hoary main"]),
261+ (lower_ppa, ["hoary main"]),
262+ (self.ubuntu.main_archive, [
263+ "hoary main restricted",
264+ "hoary-security main restricted",
265+ "hoary-updates main restricted",
266+ ]),
267+ ], build)
268+ self.hoary.strict_supported_component_dependencies = False
269+ transaction.commit()
270+ self.assertSourcesList(
271+ [(upper_ppa, ["hoary main"]),
272+ (lower_ppa, ["hoary main"]),
273+ (self.ubuntu.main_archive, [
274+ "hoary main restricted universe multiverse",
275+ "hoary-security main restricted universe multiverse",
276+ "hoary-updates main restricted universe multiverse",
277+ ]),
278+ ], build)
279+
280+ def test_no_op_primary_archive_dependency(self):
281+ # Overriding the default primary archive dependencies with exactly
282+ # the same values has no effect.
283+ ppa = self.makeArchive()
284+ ppa.addArchiveDependency(
285+ self.ubuntu.main_archive, PackagePublishingPocket.UPDATES,
286+ getUtility(IComponentSet)["multiverse"])
287+ build = self.makeBuild(archive=ppa)
288+ self.assertSourcesList(
289+ [(self.ubuntu.main_archive, [
290+ "hoary main restricted universe multiverse",
291+ "hoary-security main restricted universe multiverse",
292+ "hoary-updates main restricted universe multiverse",
293+ ]),
294+ ], build)
295+
296+ def test_primary_archive_dependency_security(self):
297+ # The primary archive dependency can be modified to behave as an
298+ # embargoed archive that builds security updates. This is done by
299+ # setting the SECURITY pocket dependencies (RELEASE and SECURITY)
300+ # and following the component dependencies of the component where
301+ # the source was last published in the primary archive.
302+ ppa = self.makeArchive()
303+ ppa.addArchiveDependency(
304+ self.ubuntu.main_archive, PackagePublishingPocket.SECURITY)
305+ build = self.makeBuild(archive=ppa)
306+ self.assertPrimaryCurrentComponent("universe", build)
307+ self.assertSourcesList(
308+ [(self.ubuntu.main_archive, [
309+ "hoary main universe",
310+ "hoary-security main universe",
311+ ]),
312+ ], build)
313+ self.publisher.getPubSource(
314+ sourcename="with-ancestry", version="1.0",
315+ archive=self.ubuntu.main_archive)
316+ [build_with_ancestry] = self.publisher.getPubSource(
317+ sourcename="with-ancestry", version="1.1",
318+ archive=ppa).createMissingBuilds()
319+ self.assertPrimaryCurrentComponent("main", build_with_ancestry)
320+ self.assertSourcesList(
321+ [(self.ubuntu.main_archive, [
322+ "hoary main",
323+ "hoary-security main",
324+ ]),
325+ ], build_with_ancestry)
326+
327+ def test_primary_archive_dependency_release(self):
328+ # The primary archive dependency can be modified to behave as a
329+ # pristine build environment based only on what was included in the
330+ # original release of the corresponding series.
331+ ppa = self.makeArchive()
332+ ppa.addArchiveDependency(
333+ self.ubuntu.main_archive, PackagePublishingPocket.RELEASE,
334+ getUtility(IComponentSet)["restricted"])
335+ build = self.makeBuild(archive=ppa)
336+ self.assertSourcesList(
337+ [(self.ubuntu.main_archive, ["hoary main restricted"])], build)
338+
339+ def test_primary_archive_dependency_proposed(self):
340+ # The primary archive dependency can be modified to extend the build
341+ # environment for PROPOSED.
342+ ppa = self.makeArchive()
343+ ppa.addArchiveDependency(
344+ self.ubuntu.main_archive, PackagePublishingPocket.PROPOSED,
345+ getUtility(IComponentSet)["multiverse"])
346+ build = self.makeBuild(archive=ppa)
347+ self.assertSourcesList(
348+ [(self.ubuntu.main_archive, [
349+ "hoary main restricted universe multiverse",
350+ "hoary-security main restricted universe multiverse",
351+ "hoary-updates main restricted universe multiverse",
352+ "hoary-proposed main restricted universe multiverse",
353+ ]),
354+ ], build)
355+
356+ def test_primary_archive_dependency_backports(self):
357+ # The primary archive dependency can be modified to extend the build
358+ # environment for PROPOSED.
359+ ppa = self.makeArchive()
360+ ppa.addArchiveDependency(
361+ self.ubuntu.main_archive, PackagePublishingPocket.BACKPORTS,
362+ getUtility(IComponentSet)["multiverse"])
363+ build = self.makeBuild(archive=ppa)
364+ self.assertSourcesList(
365+ [(self.ubuntu.main_archive, [
366+ "hoary main restricted universe multiverse",
367+ "hoary-security main restricted universe multiverse",
368+ "hoary-updates main restricted universe multiverse",
369+ "hoary-backports main restricted universe multiverse",
370+ ]),
371+ ], build)
372+
373+ def test_partner(self):
374+ # Similarly to what happens with PPA builds, partner builds may
375+ # depend on any component in the primary archive. This behaviour
376+ # allows scenarios where partner packages may use other
377+ # restricted/non-free applications from multiverse, and also other
378+ # partner applications.
379+ primary, partner = self.ubuntu.all_distro_archives
380+ self.publisher.getPubBinaries(
381+ archive=partner, component="partner",
382+ status=PackagePublishingStatus.PUBLISHED)
383+ build = self.makeBuild(archive=partner, component="partner")
384+ self.assertSourcesList(
385+ [(partner, ["hoary partner"]),
386+ (primary, [
387+ "hoary main restricted universe multiverse",
388+ "hoary-security main restricted universe multiverse",
389+ "hoary-updates main restricted universe multiverse",
390+ ]),
391+ ], build)
392+
393+ def test_partner_proposed(self):
394+ # The partner archive's PROPOSED pocket builds against itself, but
395+ # still uses the default UPDATES dependency for the primary archive
396+ # unless overridden by ArchiveDependency.
397+ primary, partner = self.ubuntu.all_distro_archives
398+ self.publisher.getPubBinaries(
399+ archive=partner, component="partner",
400+ status=PackagePublishingStatus.PUBLISHED)
401+ self.publisher.getPubBinaries(
402+ archive=partner, component="partner",
403+ status=PackagePublishingStatus.PUBLISHED,
404+ pocket=PackagePublishingPocket.PROPOSED)
405+ build = self.makeBuild(
406+ archive=partner, component="partner",
407+ pocket=PackagePublishingPocket.PROPOSED)
408+ self.assertSourcesList(
409+ [(partner, [
410+ "hoary partner",
411+ "hoary-proposed partner",
412+ ]),
413+ (primary, [
414+ "hoary main restricted universe multiverse",
415+ "hoary-security main restricted universe multiverse",
416+ "hoary-updates main restricted universe multiverse",
417+ ]),
418+ ], build)
419+
420+ def test_archive_external_dependencies(self):
421+ # An archive can be manually given additional external dependencies.
422+ # If present, "%(series)s" is replaced with the series name for the
423+ # build being dispatched.
424+ ppa = self.makeArchive(publish_binary=True)
425+ ppa.external_dependencies = (
426+ "deb http://user:pass@repository zoing everything\n"
427+ "deb http://user:pass@repository %(series)s public private\n"
428+ "deb http://user:pass@repository %(series)s-extra public")
429+ build = self.makeBuild(archive=ppa)
430+ self.assertSourcesList(
431+ [(ppa, ["hoary main"]),
432+ ("deb http://user:pass@repository", [
433+ "zoing everything",
434+ "hoary public private",
435+ "hoary-extra public",
436+ ]),
437+ (self.ubuntu.main_archive, [
438+ "hoary main restricted universe multiverse",
439+ "hoary-security main restricted universe multiverse",
440+ "hoary-updates main restricted universe multiverse",
441+ ]),
442+ ], build)
443+
444+ def test_build_external_dependencies(self):
445+ # A single build can be manually given additional external
446+ # dependencies.
447+ ppa = self.makeArchive(publish_binary=True)
448+ build = self.makeBuild(archive=ppa)
449+ build.api_external_dependencies = (
450+ "deb http://user:pass@repository foo bar")
451+ self.assertSourcesList(
452+ [(ppa, ["hoary main"]),
453+ ("deb http://user:pass@repository", ["foo bar"]),
454+ (self.ubuntu.main_archive, [
455+ "hoary main restricted universe multiverse",
456+ "hoary-security main restricted universe multiverse",
457+ "hoary-updates main restricted universe multiverse",
458+ ]),
459+ ], build)
460+
461+ def test_build_tools(self):
462+ # We can force an extra build tools line to be added to
463+ # sources.list, which is useful for specialised build types.
464+ ppa = self.makeArchive(publish_binary=True)
465+ build = self.makeBuild(archive=ppa)
466+ self.assertSourcesList(
467+ [(ppa, ["hoary main"]),
468+ ("deb http://example.org", ["hoary main"]),
469+ (self.ubuntu.main_archive, [
470+ "hoary main restricted universe multiverse",
471+ "hoary-security main restricted universe multiverse",
472+ "hoary-updates main restricted universe multiverse",
473+ ]),
474+ ], build, tools_source="deb http://example.org %(series)s main")
475+
476+ def test_build_tools_bad_formatting(self):
477+ # If tools_source is badly formatted, we log the error but don't
478+ # blow up. (Note the missing "s" at the end of "%(series)".)
479+ ppa = self.makeArchive(publish_binary=True)
480+ build = self.makeBuild(archive=ppa)
481+ logger = BufferLogger()
482+ self.assertSourcesList(
483+ [(ppa, ["hoary main"]),
484+ (self.ubuntu.main_archive, [
485+ "hoary main restricted universe multiverse",
486+ "hoary-security main restricted universe multiverse",
487+ "hoary-updates main restricted universe multiverse",
488+ ]),
489+ ],
490+ build, tools_source="deb http://example.org %(series) main",
491+ logger=logger)
492+ self.assertThat(logger.getLogBuffer(), StartsWith(
493+ "ERROR Exception processing build tools sources.list entry:\n"))
494+
495+ def test_overlay(self):
496+ # An overlay distroseries is a derived distribution which works like
497+ # a PPA. This means that the parent's details gets added to the
498+ # sources.list passed to the builders.
499+ depdistro = self.factory.makeDistribution(
500+ "depdistro", publish_base_url="http://archive.launchpad.dev/")
501+ depseries = self.factory.makeDistroSeries(
502+ distribution=depdistro, name="depseries")
503+ self.factory.makeDistroArchSeries(
504+ distroseries=depseries, architecturetag="i386")
505+ self.publisher.addFakeChroots(depseries)
506+ for component_name in self.ubuntu_components:
507+ component = getUtility(IComponentSet)[component_name]
508+ self.factory.makeComponentSelection(depseries, component)
509+ self.factory.makeDistroSeriesParent(
510+ derived_series=self.hoary, parent_series=depseries,
511+ initialized=True, is_overlay=True,
512+ pocket=PackagePublishingPocket.SECURITY,
513+ component=getUtility(IComponentSet)["universe"])
514+ build = self.makeBuild()
515+ self.assertSourcesList(
516+ [(self.ubuntu.main_archive, ["hoary main"]),
517+ (depdistro.main_archive, [
518+ "depseries main universe",
519+ "depseries-security main universe",
520+ ]),
521+ ], build)
522
523=== removed file 'lib/lp/soyuz/doc/archive-dependencies.txt'
524--- lib/lp/soyuz/doc/archive-dependencies.txt 2016-04-07 00:04:42 +0000
525+++ lib/lp/soyuz/doc/archive-dependencies.txt 1970-01-01 00:00:00 +0000
526@@ -1,637 +0,0 @@
527-= Archive dependencies =
528-
529-`ArchiveDependencies` class models archive dependencies mechanics and
530-is used to provided the contents of 'sources_list' file used to build
531-sources in the given IBuildQueue context.
532-
533-
534-== Testing scenario setup ==
535-
536-We use `SoyuzTestPublisher` to generate a source publications and
537-build candidates for ubuntu/hoary.
538-
539- >>> from lp.registry.interfaces.distribution import IDistributionSet
540- >>> from lp.soyuz.interfaces.component import IComponentSet
541- >>> from lp.soyuz.tests.test_publishing import SoyuzTestPublisher
542- >>> from lp.testing import login
543-
544- >>> login('foo.bar@canonical.com')
545-
546- >>> test_publisher = SoyuzTestPublisher()
547-
548- >>> ubuntu = getUtility(IDistributionSet).getByName('ubuntu')
549- >>> hoary = ubuntu.getSeries('hoary')
550-
551- >>> test_publisher.addFakeChroots(hoary)
552- >>> _ = test_publisher.setUpDefaultDistroSeries(hoary)
553-
554- >>> ubuntu_components = [
555- ... 'main', 'restricted', 'universe', 'multiverse', 'partner']
556- >>> for component_name in ubuntu_components:
557- ... component = getUtility(IComponentSet)[component_name]
558- ... if component not in hoary.components:
559- ... _ = factory.makeComponentSelection(hoary, component)
560-
561-
562-== Static dependency maps ==
563-
564-`pocket_dependencies` contains a static map of the default ubuntu
565-pocket dependencies.
566-
567- >>> from lp.soyuz.adapters.archivedependencies import pocket_dependencies
568-
569- >>> def show_pocket_deps():
570- ... print "Pocket | Dependencies"
571- ... print "----------+---------------"
572- ... for (key, value) in sorted(pocket_dependencies.items()):
573- ... print "%7s |" % (key.name,),
574- ... for pocket in value:
575- ... print pocket.name,
576- ... print
577-
578- >>> show_pocket_deps()
579- Pocket | Dependencies
580- ----------+---------------
581- RELEASE | RELEASE
582- SECURITY | RELEASE SECURITY
583- UPDATES | RELEASE SECURITY UPDATES
584- PROPOSED | RELEASE SECURITY UPDATES PROPOSED
585- BACKPORTS | RELEASE SECURITY UPDATES BACKPORTS
586-
587-
588-== 'Ogre' components ==
589-
590-The ubuntu 'ogre-model' ensures that build dependencies are
591-consistently spread according to the source target component, i.e. a
592-source published in 'main' component is only allowed to depend on
593-binaries also published in 'main', on the other hand a source
594-published in 'universe' is allowed to depend on binaries published in
595-'main' and 'universe' components.
596-
597-A proper name for this "model" would be 'cross-component-dependency'.
598-
599- >>> from lp.services.database.sqlbase import flush_database_caches
600-
601- >>> from zope.security.proxy import removeSecurityProxy
602- >>> from lp.registry.interfaces.pocket import (
603- ... PackagePublishingPocket)
604- >>> from lp.soyuz.adapters.archivedependencies import (
605- ... get_components_for_context)
606- >>> from lp.soyuz.enums import ArchivePurpose
607-
608- >>> def testOgreComponents(build):
609- ... print " Component | Ogre-Model"
610- ... print "-----------+---------------"
611- ... for component in ubuntu_components:
612- ... component = getUtility(IComponentSet)[component]
613- ... npub = removeSecurityProxy(build.current_source_publication)
614- ... npub.component = component
615- ... flush_database_caches()
616- ... components_term = " ".join(get_components_for_context(
617- ... build.current_component, build.distro_series,
618- ... build.pocket))
619- ... print '%10s | %s' % (build.current_component.name,
620- ... components_term)
621-
622- >>> archive = factory.makeArchive(
623- ... distribution=ubuntu, purpose=ArchivePurpose.PRIMARY)
624- >>> ogre_build = factory.makeBinaryPackageBuild(
625- ... distroarchseries=hoary.architectures[0], archive=archive,
626- ... pocket=PackagePublishingPocket.RELEASE)
627- >>> testOgreComponents(ogre_build)
628- Component | Ogre-Model
629- -----------+---------------
630- main | main
631- restricted | main restricted
632- universe | main universe
633- multiverse | main restricted universe multiverse
634- partner | partner
635-
636-Series with strict_supported_component_dependencies=False additionally allow
637-source packages in 'supported' components (main and restricted) to
638-build-depend on binary packages in 'unsupported' components (universe and
639-multiverse).
640-
641- >>> from lp.buildmaster.interfaces.processor import IProcessorSet
642-
643- >>> lax_distroseries = factory.makeDistroSeries(
644- ... distribution=archive.distribution, name='lax')
645- >>> lax_distroseries.strict_supported_component_dependencies = False
646- >>> lax_distroarchseries = factory.makeDistroArchSeries(
647- ... distroseries=lax_distroseries, architecturetag='i386',
648- ... processor=getUtility(IProcessorSet).getByName('386'))
649- >>> test_publisher.addFakeChroots(lax_distroseries)
650- >>> for component_name in ubuntu_components:
651- ... component = getUtility(IComponentSet)[component_name]
652- ... _ = factory.makeComponentSelection(lax_distroseries, component)
653- >>> lax_ogre_build = factory.makeBinaryPackageBuild(
654- ... distroarchseries=lax_distroarchseries, archive=archive,
655- ... pocket=PackagePublishingPocket.RELEASE)
656- >>> testOgreComponents(lax_ogre_build)
657- Component | Ogre-Model
658- -----------+---------------
659- main | main universe
660- restricted | main restricted universe multiverse
661- universe | main universe
662- multiverse | main restricted universe multiverse
663- partner | partner
664-
665-As fixed for bug #198936, builds for the BACKPORTS pocket are allowed
666-to use any component available, independently of the component they
667-are currently published. This special-case is important because it
668-avoids changes to accommodate the backported source in the already
669-released series.
670-
671-Ultimately, it means that a build targeted to the BACKPORTS pocket
672-will behave as if it were published in the multiverse component,
673-despite the component it is actually published in.
674-
675- >>> back_build = factory.makeBinaryPackageBuild(
676- ... distroarchseries=hoary.architectures[0],
677- ... archive=archive, pocket=PackagePublishingPocket.BACKPORTS)
678- >>> testOgreComponents(back_build)
679- Component | Ogre-Model
680- -----------+---------------
681- main | main restricted universe multiverse
682- restricted | main restricted universe multiverse
683- universe | main restricted universe multiverse
684- multiverse | main restricted universe multiverse
685- partner | main restricted universe multiverse
686-
687-
688-== Sources.list contents for building ==
689-
690-We will use Celso's PPA for testing these mechanisms.
691-
692- >>> from lp.registry.interfaces.person import IPersonSet
693- >>> cprov = getUtility(IPersonSet).getByName('cprov')
694- >>> print cprov.archive.displayname
695- PPA for Celso Providelo
696-
697-Non-primary archives by default use primary Release, Security and Updates
698-pockets and all its available components.
699-
700- >>> from lp.soyuz.adapters.archivedependencies import (
701- ... default_component_dependency_name, default_pocket_dependency)
702-
703- >>> print default_pocket_dependency
704- Updates
705-
706- >>> print default_component_dependency_name
707- multiverse
708-
709-The default values get applied to their corresponding dependency maps
710-and then will expand to distinct values that will be used to produce
711-the building 'sources_list' contents.
712-
713- >>> for pocket in pocket_dependencies[default_pocket_dependency]:
714- ... print pocket
715- Release
716- Security
717- Updates
718-
719- >>> for component_name in get_components_for_context(
720- ... getUtility(IComponentSet)[default_component_dependency_name],
721- ... hoary, pocket):
722- ... print component_name
723- main
724- restricted
725- universe
726- multiverse
727-
728-We will create a testing source publication and probe its build
729-environment.
730-
731- >>> pub_source = test_publisher.getPubSource(
732- ... version='1.1', archive=cprov.archive)
733- >>> [a_build] = pub_source.createMissingBuilds()
734-
735-Now we can verify if get_sources_list_for_building() method returns the
736-expected content for building the just-created source.
737-
738- >>> from lp.soyuz.adapters.archivedependencies import (
739- ... get_sources_list_for_building)
740-
741- >>> def print_building_sources_list(candidate):
742- ... sources_list = get_sources_list_for_building(
743- ... candidate, candidate.distro_arch_series,
744- ... candidate.source_package_release.name)
745- ... for line in sources_list:
746- ... print line
747-
748-Note that only the default ubuntu dependencies for a public PPA will be
749-considered when building the source candidate. That's because there is
750-no binary published in Celso's PPA hoary/i386, so there is
751-no need to request the builder to load its archive indexes.
752-
753- >>> from lp.soyuz.enums import PackagePublishingStatus
754-
755- >>> cprov.archive.getAllPublishedBinaries(
756- ... distroarchseries=a_build.distro_arch_series,
757- ... status=PackagePublishingStatus.PUBLISHED).count()
758- 0
759-
760- >>> print_building_sources_list(a_build)
761- deb http://archive.launchpad.dev/ubuntu hoary
762- main restricted universe multiverse
763- deb http://archive.launchpad.dev/ubuntu hoary-security
764- main restricted universe multiverse
765- deb http://archive.launchpad.dev/ubuntu hoary-updates
766- main restricted universe multiverse
767-
768-Once we publish a test binary in Celso's PPA hoary/i386,
769-this archive becomes relevant for building, and thus listed in the
770-returned 'sources_list' content.
771-
772- >>> pub_binaries = test_publisher.getPubBinaries(
773- ... binaryname='dep-bin', archive=cprov.archive,
774- ... status=PackagePublishingStatus.PUBLISHED)
775-
776- >>> print_building_sources_list(a_build)
777- deb http://ppa.launchpad.dev/cprov/ppa/ubuntu hoary main
778- deb http://archive.launchpad.dev/ubuntu hoary
779- main restricted universe multiverse
780- deb http://archive.launchpad.dev/ubuntu hoary-security
781- main restricted universe multiverse
782- deb http://archive.launchpad.dev/ubuntu hoary-updates
783- main restricted universe multiverse
784-
785-Similarly, unpopulated PPA dependencies are *not* listed in the building
786-'sources_list'.
787-
788- >>> mark = getUtility(IPersonSet).getByName('mark')
789- >>> archive_dependency = cprov.archive.addArchiveDependency(
790- ... mark.archive, PackagePublishingPocket.RELEASE,
791- ... getUtility(IComponentSet)['main'])
792- >>> print_building_sources_list(a_build)
793- deb http://ppa.launchpad.dev/cprov/ppa/ubuntu hoary main
794- deb http://archive.launchpad.dev/ubuntu hoary
795- main restricted universe multiverse
796- deb http://archive.launchpad.dev/ubuntu hoary-security
797- main restricted universe multiverse
798- deb http://archive.launchpad.dev/ubuntu hoary-updates
799- main restricted universe multiverse
800-
801-But *populated* PPA dependencies *are* listed in the building 'sources_list'.
802-
803- >>> pub_binaries = test_publisher.getPubBinaries(
804- ... binaryname='dep-bin', archive=mark.archive,
805- ... status=PackagePublishingStatus.PUBLISHED)
806- >>> print_building_sources_list(a_build)
807- deb http://ppa.launchpad.dev/cprov/ppa/ubuntu hoary main
808- deb http://ppa.launchpad.dev/mark/ppa/ubuntu hoary main
809- deb http://archive.launchpad.dev/ubuntu hoary
810- main restricted universe multiverse
811- deb http://archive.launchpad.dev/ubuntu hoary-security
812- main restricted universe multiverse
813- deb http://archive.launchpad.dev/ubuntu hoary-updates
814- main restricted universe multiverse
815-
816-Dependencies for series with strict_supported_component_dependencies=False
817-are reasonable too. PPAs only have the 'main' component.
818-
819- >>> lax_pub_source = test_publisher.getPubSource(
820- ... version='1.2', distroseries=lax_distroseries,
821- ... archive=cprov.archive)
822- >>> [lax_build] = lax_pub_source.createMissingBuilds()
823- >>> _ = test_publisher.getPubBinaries(
824- ... binaryname='dep-bin', distroseries=lax_distroseries,
825- ... archive=cprov.archive, status=PackagePublishingStatus.PUBLISHED)
826- >>> _ = test_publisher.getPubBinaries(
827- ... binaryname='dep-bin', distroseries=lax_distroseries,
828- ... archive=mark.archive, status=PackagePublishingStatus.PUBLISHED)
829- >>> print_building_sources_list(lax_build)
830- deb http://ppa.launchpad.dev/cprov/ppa/ubuntu lax main
831- deb http://ppa.launchpad.dev/mark/ppa/ubuntu lax main
832- deb http://archive.launchpad.dev/ubuntu lax
833- main restricted universe multiverse
834- deb http://archive.launchpad.dev/ubuntu lax-security
835- main restricted universe multiverse
836- deb http://archive.launchpad.dev/ubuntu lax-updates
837- main restricted universe multiverse
838-
839- >>> cprov.archive.removeArchiveDependency(mark.archive)
840-
841-What when we supply invalid dependencies, an exception is raised.
842-
843- >>> cprov.archive.external_dependencies = (
844- ... "Malformed format string here --> %(series)")
845- Traceback (most recent call last):
846- InvalidExternalDependencies: (InvalidExternalDependencies(...),
847- "Invalid external dependencies:\nMalformed format string here
848- --> %(series): Must start with 'deb'\nMalformed format string here
849- --> %(series): Invalid URL\n")
850-
851-
852-== Overriding default primary archive dependencies ==
853-
854-Despite being private or public, default primary archive dependencies
855-can be overridden by simply creating a `ArchiveDependency`record
856-targeted to the primary archive.
857-
858-The 'pocket' and 'component' dependency attributes can be adjusted to
859-produce the desired build behaviour.
860-
861-By default, public PPAs depend on all of the pocket dependencies of
862-UPDATES, and all of the primary archive's 'multiverse' component
863-dependencies.
864-
865- >>> print_building_sources_list(a_build)
866- deb http://ppa.launchpad.dev/cprov/ppa/ubuntu hoary main
867- deb http://archive.launchpad.dev/ubuntu hoary
868- main restricted universe multiverse
869- deb http://archive.launchpad.dev/ubuntu hoary-security
870- main restricted universe multiverse
871- deb http://archive.launchpad.dev/ubuntu hoary-updates
872- main restricted universe multiverse
873-
874-The default build behaviour will remain unchanged when we override the
875-default primary archive dependencies with exactly the same values.
876-
877- >>> default_dependency = cprov.archive.addArchiveDependency(
878- ... ubuntu.main_archive, PackagePublishingPocket.UPDATES,
879- ... getUtility(IComponentSet)['multiverse'])
880-
881- >>> print_building_sources_list(a_build)
882- deb http://ppa.launchpad.dev/cprov/ppa/ubuntu hoary main
883- deb http://archive.launchpad.dev/ubuntu hoary
884- main restricted universe multiverse
885- deb http://archive.launchpad.dev/ubuntu hoary-security
886- main restricted universe multiverse
887- deb http://archive.launchpad.dev/ubuntu hoary-updates
888- main restricted universe multiverse
889-
890- >>> cprov.archive.removeArchiveDependency(ubuntu.main_archive)
891-
892-The dependency can be modified to behave as an embargoed archive that
893-builds security updates. This is done by setting the SECURITY pocket
894-dependencies (RELEASE and SECURITY) and following the component
895-dependencies of the component where the source was last published in
896-the primary archive.
897-
898- >>> security_dependency = cprov.archive.addArchiveDependency(
899- ... ubuntu.main_archive, PackagePublishingPocket.SECURITY)
900-
901- >>> from lp.soyuz.adapters.archivedependencies import (
902- ... get_primary_current_component)
903-
904- >>> print get_primary_current_component(a_build.archive,
905- ... a_build.distro_series, a_build.source_package_release.name).name
906- universe
907-
908- >>> print_building_sources_list(a_build)
909- deb http://ppa.launchpad.dev/cprov/ppa/ubuntu hoary main
910- deb http://archive.launchpad.dev/ubuntu hoary
911- main universe
912- deb http://archive.launchpad.dev/ubuntu hoary-security
913- main universe
914-
915- >>> _ = test_publisher.getPubSource(
916- ... sourcename='with-ancestry', version='1.0',
917- ... archive=ubuntu.main_archive)
918- >>> [build_with_ancestry] = test_publisher.getPubSource(
919- ... sourcename='with-ancestry', version='1.1',
920- ... archive=cprov.archive).createMissingBuilds()
921- >>> print get_primary_current_component(
922- ... build_with_ancestry.archive, build_with_ancestry.distro_series,
923- ... build_with_ancestry.source_package_release.name).name
924- main
925- >>> print_building_sources_list(build_with_ancestry)
926- deb http://ppa.launchpad.dev/cprov/ppa/ubuntu hoary main
927- deb http://archive.launchpad.dev/ubuntu hoary main
928- deb http://archive.launchpad.dev/ubuntu hoary-security main
929-
930- >>> cprov.archive.removeArchiveDependency(ubuntu.main_archive)
931-
932-It's also possible to modify the PPA to act as a super-free and
933-pristine build environment based only on what was included in the
934-original ubuntu release.
935-
936- >>> release_dependency = cprov.archive.addArchiveDependency(
937- ... ubuntu.main_archive, PackagePublishingPocket.RELEASE,
938- ... getUtility(IComponentSet)['restricted'])
939-
940- >>> print_building_sources_list(a_build)
941- deb http://ppa.launchpad.dev/cprov/ppa/ubuntu hoary main
942- deb http://archive.launchpad.dev/ubuntu hoary main restricted
943-
944- >>> cprov.archive.removeArchiveDependency(ubuntu.main_archive)
945-
946-The PPA can also be configured to extend the ubuntu PROPOSED build
947-environment.
948-
949- >>> proposed_dependency = cprov.archive.addArchiveDependency(
950- ... ubuntu.main_archive, PackagePublishingPocket.PROPOSED,
951- ... getUtility(IComponentSet)['multiverse'])
952-
953- >>> print_building_sources_list(a_build)
954- deb http://ppa.launchpad.dev/cprov/ppa/ubuntu hoary main
955- deb http://archive.launchpad.dev/ubuntu hoary
956- main restricted universe multiverse
957- deb http://archive.launchpad.dev/ubuntu hoary-security
958- main restricted universe multiverse
959- deb http://archive.launchpad.dev/ubuntu hoary-updates
960- main restricted universe multiverse
961- deb http://archive.launchpad.dev/ubuntu hoary-proposed
962- main restricted universe multiverse
963-
964- >>> cprov.archive.removeArchiveDependency(ubuntu.main_archive)
965-
966-Similarly an extension of the BACKPORTS environment can be set.
967-
968- >>> backports_dependency = cprov.archive.addArchiveDependency(
969- ... ubuntu.main_archive, PackagePublishingPocket.BACKPORTS,
970- ... getUtility(IComponentSet)['multiverse'])
971-
972- >>> print_building_sources_list(a_build)
973- deb http://ppa.launchpad.dev/cprov/ppa/ubuntu hoary main
974- deb http://archive.launchpad.dev/ubuntu hoary
975- main restricted universe multiverse
976- deb http://archive.launchpad.dev/ubuntu hoary-security
977- main restricted universe multiverse
978- deb http://archive.launchpad.dev/ubuntu hoary-updates
979- main restricted universe multiverse
980- deb http://archive.launchpad.dev/ubuntu hoary-backports
981- main restricted universe multiverse
982-
983- >>> cprov.archive.removeArchiveDependency(ubuntu.main_archive)
984-
985-
986-== Partner archive builds ==
987-
988-Similarly to what happens with PPA builds, PARTNER builds may depend
989-on any Ubuntu component in the PRIMARY archive. This behaviour allows
990-scenarios where partner packages may use other restricted/non-free
991-applications from 'multiverse', for instance 'sun-java', and also
992-other partner applications by default.
993-
994- # Populate the ubuntutest PARTNER archive with one built and one
995- # pending build source.
996- >>> primary, partner = ubuntu.all_distro_archives
997- >>> unused_source = test_publisher.getPubSource(
998- ... archive=partner, component='partner')
999- >>> unused = test_publisher.getPubBinaries(
1000- ... pub_source=unused_source,
1001- ... status=PackagePublishingStatus.PUBLISHED)
1002- >>> pub_source = test_publisher.getPubSource(
1003- ... version='1.2', archive=partner, component='partner')
1004- >>> [partner_build] = pub_source.createMissingBuilds()
1005-
1006- >>> print_building_sources_list(partner_build)
1007- deb http://archive.launchpad.dev/ubuntu-partner hoary partner
1008- deb http://archive.launchpad.dev/ubuntu hoary
1009- main restricted universe multiverse
1010- deb http://archive.launchpad.dev/ubuntu hoary-security
1011- main restricted universe multiverse
1012- deb http://archive.launchpad.dev/ubuntu hoary-updates
1013- main restricted universe multiverse
1014-
1015-PARTNER's PROPOSED pocket builds against itself, but still uses the
1016-default UPDATES dependency for PRIMARY unless overridden by
1017-ArchiveDependency.
1018-
1019- >>> proposed_source = test_publisher.getPubSource(
1020- ... version='1.2', archive=partner, component='partner',
1021- ... pocket=PackagePublishingPocket.PROPOSED)
1022- >>> unused = test_publisher.getPubBinaries(
1023- ... archive=partner, distroseries=proposed_source.distroseries,
1024- ... pocket=PackagePublishingPocket.PROPOSED,
1025- ... status=PackagePublishingStatus.PUBLISHED)
1026- >>> [partner_proposed_build] = proposed_source.createMissingBuilds()
1027-
1028- >>> print_building_sources_list(partner_proposed_build)
1029- deb http://archive.launchpad.dev/ubuntu-partner hoary partner
1030- deb http://archive.launchpad.dev/ubuntu-partner hoary-proposed partner
1031- deb http://archive.launchpad.dev/ubuntu hoary
1032- main restricted universe multiverse
1033- deb http://archive.launchpad.dev/ubuntu hoary-security
1034- main restricted universe multiverse
1035- deb http://archive.launchpad.dev/ubuntu hoary-updates
1036- main restricted universe multiverse
1037-
1038-== External build dependencies ==
1039-
1040-Via an administrator change, any PPA hosted in launchpad can be
1041-assigned to one or more 'external' build dependencies additionally to
1042-the internal ones.
1043-
1044-There is a column on IArchive called 'external_dependencies' which can be set
1045-for any hosted PPA. It is a string listing the comma-separated external
1046-dependencies in the debian sources_list format.
1047-
1048- deb http[s]://[user:pass@]<host>[/path] %(series)s[-pocket] [components]
1049-
1050-The '%(series)s' part is optional and will be replaced on-the-fly with
1051-the series name for the build record being dispatched.
1052-
1053-We will create some dependencies for Celso's PPA.
1054-
1055- >>> cprov.archive.external_dependencies = (
1056- ... "deb http://user:pass@repository zoing everything\n"
1057- ... "deb http://user:pass@repository %(series)s public private\n"
1058- ... "deb http://user:pass@repository %(series)s-extra public")
1059-
1060-Now builds in Celso's PPA will use the external dependencies.
1061-
1062- >>> print_building_sources_list(a_build)
1063- deb http://ppa.launchpad.dev/cprov/ppa/ubuntu hoary main
1064- deb http://user:pass@repository zoing everything
1065- deb http://user:pass@repository hoary public private
1066- deb http://user:pass@repository hoary-extra public
1067- deb http://archive.launchpad.dev/ubuntu hoary
1068- main restricted universe multiverse
1069- deb http://archive.launchpad.dev/ubuntu hoary-security
1070- main restricted universe multiverse
1071- deb http://archive.launchpad.dev/ubuntu hoary-updates
1072- main restricted universe multiverse
1073-
1074- >>> cprov.archive.external_dependencies = None
1075-
1076-We can also set external dependencies for a single build.
1077-
1078- >>> a_build.api_external_dependencies = (
1079- ... u"deb http://user:pass@repository foo bar")
1080- >>> print_building_sources_list(a_build)
1081- deb http://ppa.launchpad.dev/cprov/ppa/ubuntu hoary main
1082- deb http://user:pass@repository foo bar
1083- deb http://archive.launchpad.dev/ubuntu hoary
1084- main restricted universe multiverse
1085- deb http://archive.launchpad.dev/ubuntu hoary-security
1086- main restricted universe multiverse
1087- deb http://archive.launchpad.dev/ubuntu hoary-updates
1088- main restricted universe multiverse
1089- >>> a_build.api_external_dependencies = None
1090-
1091-
1092-== Build tools sources.list entries ==
1093-
1094-We can force an extra build tools line to be added to the sources.list,
1095-which is useful for specialised build types.
1096-
1097- >>> for line in get_sources_list_for_building(
1098- ... a_build, a_build.distro_arch_series,
1099- ... a_build.source_package_release.name,
1100- ... tools_source="deb http://example.org %(series)s main"):
1101- ... print line
1102- deb http://ppa.launchpad.dev/cprov/ppa/ubuntu hoary main
1103- deb http://example.org hoary main
1104- deb http://archive.launchpad.dev/ubuntu hoary
1105- main restricted universe multiverse
1106- deb http://archive.launchpad.dev/ubuntu hoary-security
1107- main restricted universe multiverse
1108- deb http://archive.launchpad.dev/ubuntu hoary-updates
1109- main restricted universe multiverse
1110-
1111-If tools_source is badly formatted, we log the error but don't blow up.
1112-(Note the missing "s" at the end of "%(series)".)
1113-
1114- >>> from lp.services.log.logger import BufferLogger
1115- >>> logger = BufferLogger()
1116- >>> for line in get_sources_list_for_building(
1117- ... a_build, a_build.distro_arch_series,
1118- ... a_build.source_package_release.name,
1119- ... tools_source="deb http://example.org %(series) main",
1120- ... logger=logger):
1121- ... print line
1122- deb http://ppa.launchpad.dev/cprov/ppa/ubuntu hoary main
1123- deb http://archive.launchpad.dev/ubuntu hoary
1124- main restricted universe multiverse
1125- deb http://archive.launchpad.dev/ubuntu hoary-security
1126- main restricted universe multiverse
1127- deb http://archive.launchpad.dev/ubuntu hoary-updates
1128- main restricted universe multiverse
1129- >>> print logger.getLogBuffer()
1130- ERROR Exception processing build tools sources.list entry:
1131- ...
1132-
1133-
1134-== Overlays ==
1135-
1136-An overlay distroseries is a derived distribution which works like a PPA.
1137-This means that the parent's details gets added to the sources.list passed to
1138-the builders.
1139-
1140- >>> depdistro = factory.makeDistribution('depdistro',
1141- ... publish_base_url=u'http://archive.launchpad.dev/')
1142- >>> depseries = factory.makeDistroSeries(
1143- ... name='depseries', distribution=depdistro)
1144- >>> deparchseries = factory.makeDistroArchSeries(
1145- ... distroseries = depseries, architecturetag = 'i386')
1146- >>> test_publisher.addFakeChroots(depseries)
1147- >>> for component_name in ubuntu_components:
1148- ... component = getUtility(IComponentSet)[component_name]
1149- ... _ = factory.makeComponentSelection(depseries, component)
1150- >>> universe_component = getUtility(IComponentSet)['universe']
1151- >>> dsp = factory.makeDistroSeriesParent(
1152- ... derived_series=hoary, parent_series=depseries,
1153- ... initialized=True, is_overlay=True,
1154- ... pocket=PackagePublishingPocket.SECURITY,
1155- ... component=universe_component)
1156- >>> pub_source = test_publisher.getPubSource(
1157- ... version='1.1', archive=hoary.main_archive)
1158- >>> [hoary_build] = pub_source.createMissingBuilds()
1159- >>> print_building_sources_list(hoary_build)
1160- deb http://archive.launchpad.dev/ubuntu hoary main
1161- deb http://archive.launchpad.dev/depdistro depseries main universe
1162- deb http://archive.launchpad.dev/depdistro depseries-security
1163- main universe
1164
1165=== modified file 'lib/lp/soyuz/interfaces/archive.py'
1166--- lib/lp/soyuz/interfaces/archive.py 2016-11-14 19:55:07 +0000
1167+++ lib/lp/soyuz/interfaces/archive.py 2017-04-25 11:47:06 +0000
1168@@ -1,4 +1,4 @@
1169-# Copyright 2009-2016 Canonical Ltd. This software is licensed under the
1170+# Copyright 2009-2017 Canonical Ltd. This software is licensed under the
1171 # GNU Affero General Public License version 3 (see the file LICENSE).
1172
1173 """Archive interfaces."""
1174@@ -306,7 +306,7 @@
1175
1176 def __init__(self, errors):
1177 error_msg = 'Invalid external dependencies:\n%s\n' % '\n'.join(errors)
1178- super(Exception, self).__init__(self, error_msg)
1179+ super(Exception, self).__init__(error_msg)
1180 self.errors = errors
1181
1182
1183
1184=== modified file 'lib/lp/soyuz/tests/test_archive.py'
1185--- lib/lp/soyuz/tests/test_archive.py 2016-11-07 16:42:23 +0000
1186+++ lib/lp/soyuz/tests/test_archive.py 2017-04-25 11:47:06 +0000
1187@@ -1,4 +1,4 @@
1188-# Copyright 2009-2016 Canonical Ltd. This software is licensed under the
1189+# Copyright 2009-2017 Canonical Ltd. This software is licensed under the
1190 # GNU Affero General Public License version 3 (see the file LICENSE).
1191
1192 """Test Archive features."""
1193@@ -78,6 +78,7 @@
1194 DuplicateTokenName,
1195 IArchiveSet,
1196 InsufficientUploadRights,
1197+ InvalidExternalDependencies,
1198 InvalidPocketForPartnerArchive,
1199 InvalidPocketForPPA,
1200 NAMED_AUTH_TOKEN_FEATURE_FLAG,
1201@@ -1767,6 +1768,18 @@
1202 "person-name-.*/dependency/ubuntu distroseries-.* main")
1203 self.assertThat(sources_list[0], matches)
1204
1205+ def test_invalid_external_dependencies(self):
1206+ """Trying to set invalid external dependencies raises an exception."""
1207+ ppa = self.factory.makeArchive()
1208+ self.assertRaisesWithContent(
1209+ InvalidExternalDependencies,
1210+ "Invalid external dependencies:\n"
1211+ "Malformed format string here --> %(series): "
1212+ "Must start with 'deb'\n"
1213+ "Malformed format string here --> %(series): Invalid URL\n",
1214+ setattr, ppa, "external_dependencies",
1215+ "Malformed format string here --> %(series)")
1216+
1217
1218 class TestFindDepCandidates(TestCaseWithFactory):
1219 """Tests for Archive.findDepCandidates."""
1220
1221=== modified file 'lib/lp/testing/factory.py'
1222--- lib/lp/testing/factory.py 2016-12-02 12:04:11 +0000
1223+++ lib/lp/testing/factory.py 2017-04-25 11:47:06 +0000
1224@@ -2,7 +2,7 @@
1225 # NOTE: The first line above must stay first; do not move the copyright
1226 # notice to the top. See http://www.python.org/dev/peps/pep-0263/.
1227 #
1228-# Copyright 2009-2016 Canonical Ltd. This software is licensed under the
1229+# Copyright 2009-2017 Canonical Ltd. This software is licensed under the
1230 # GNU Affero General Public License version 3 (see the file LICENSE).
1231
1232 """Testing infrastructure for the Launchpad application.
1233@@ -268,7 +268,10 @@
1234 )
1235 from lp.services.oauth.interfaces import IOAuthConsumerSet
1236 from lp.services.openid.model.openididentifier import OpenIdIdentifier
1237-from lp.services.propertycache import clear_property_cache
1238+from lp.services.propertycache import (
1239+ clear_property_cache,
1240+ get_property_cache,
1241+ )
1242 from lp.services.temporaryblobstorage.interfaces import (
1243 ITemporaryStorageManager,
1244 )
1245@@ -2832,8 +2835,10 @@
1246 if not IComponent.providedBy(component):
1247 component = self.makeComponent(component)
1248
1249- return ComponentSelection(
1250+ selection = ComponentSelection(
1251 distroseries=distroseries, component=component)
1252+ del get_property_cache(distroseries).components
1253+ return selection
1254
1255 def makeArchive(self, distribution=None, owner=None, name=None,
1256 purpose=None, enabled=True, private=False,