Merge lp:~wgrant/launchpad/archive-processors into lp:launchpad

Proposed by William Grant
Status: Merged
Merged at revision: 17510
Proposed branch: lp:~wgrant/launchpad/archive-processors
Merge into: lp:launchpad
Diff against target: 880 lines (+255/-150)
16 files modified
database/schema/security.cfg (+1/-0)
lib/lp/_schema_circular_imports.py (+0/-5)
lib/lp/soyuz/browser/tests/test_archive_webservice.py (+50/-3)
lib/lp/soyuz/configure.zcml (+1/-1)
lib/lp/soyuz/interfaces/archive.py (+27/-8)
lib/lp/soyuz/interfaces/archivearch.py (+0/-10)
lib/lp/soyuz/model/archive.py (+42/-14)
lib/lp/soyuz/model/archivearch.py (+0/-16)
lib/lp/soyuz/model/binarypackagebuild.py (+1/-3)
lib/lp/soyuz/scripts/populate_archive.py (+1/-11)
lib/lp/soyuz/stories/webservice/xx-archive.txt (+1/-0)
lib/lp/soyuz/tests/test_archive.py (+95/-8)
lib/lp/soyuz/tests/test_archivearch.py (+5/-45)
lib/lp/soyuz/tests/test_build_set.py (+21/-10)
lib/lp/soyuz/tests/test_packagecloner.py (+6/-13)
lib/lp/testing/factory.py (+4/-3)
To merge this branch: bzr merge lp:~wgrant/launchpad/archive-processors
Reviewer Review Type Date Requested Status
Colin Watson (community) Approve
Review via email: mp+259346@code.launchpad.net

Commit message

Add Archive.processors and explicitly enable default architectures when creating an archive.

Description of the change

As part of making all architecture toggleable, this branch adds Archive.processors and Archive.setProcessors in a transitional way.

Archive.processors returns all unrestricted architectures plus any enabled restricted architectures, and setProcessors will only add or remove rows for restricted architectures. Both will change to directly reflect ArchiveArch rows once that table has been backfilled.

ArchiveSet.new creates ArchiveArch rows for build_by_default architectures, except for copy archives which actually already used the future meaning of ArchiveArch (that's how ARM-only rebuilds work). The missing ones will be inserted with a hot DB patch.

Once Archive.processors represents exactly what's in ArchiveArch, ArchiveArch will be accessed exclusively via that property.

To post a comment you must log in.
Revision history for this message
Colin Watson (cjwatson) wrote :

Looks mostly fine, just a few nits.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'database/schema/security.cfg'
2--- database/schema/security.cfg 2015-04-29 14:37:10 +0000
3+++ database/schema/security.cfg 2015-05-19 00:51:34 +0000
4@@ -1027,6 +1027,7 @@
5 [initializedistroseries]
6 groups=script
7 public.archive = SELECT
8+public.archivearch = SELECT
9 public.archivepermission = SELECT, INSERT
10 public.binarypackagebuild = SELECT, INSERT
11 public.binarypackagefile = SELECT
12
13=== modified file 'lib/lp/_schema_circular_imports.py'
14--- lib/lp/_schema_circular_imports.py 2015-04-24 12:58:46 +0000
15+++ lib/lp/_schema_circular_imports.py 2015-05-19 00:51:34 +0000
16@@ -58,7 +58,6 @@
17 )
18 from lp.buildmaster.interfaces.buildfarmjob import IBuildFarmJob
19 from lp.buildmaster.interfaces.buildqueue import IBuildQueue
20-from lp.buildmaster.interfaces.processor import IProcessor
21 from lp.code.interfaces.branch import (
22 IBranch,
23 IBranchSet,
24@@ -385,8 +384,6 @@
25 # IArchive apocalypse.
26 patch_reference_property(IArchive, 'distribution', IDistribution)
27 patch_collection_property(IArchive, 'dependencies', IArchiveDependency)
28-patch_collection_property(
29- IArchive, 'enabled_restricted_processors', IProcessor)
30 patch_collection_return_type(IArchive, 'getAllPermissions', IArchivePermission)
31 patch_collection_return_type(
32 IArchive, 'getPermissionsForPerson', IArchivePermission)
33@@ -484,8 +481,6 @@
34 IArchive, '_addArchiveDependency', 'pocket', PackagePublishingPocket)
35 patch_entry_return_type(
36 IArchive, '_addArchiveDependency', IArchiveDependency)
37-patch_plain_parameter_type(
38- IArchive, 'enableRestrictedProcessor', 'processor', IProcessor)
39
40 # IBuildFarmJob
41 patch_choice_property(IBuildFarmJob, 'status', BuildStatus)
42
43=== modified file 'lib/lp/soyuz/browser/tests/test_archive_webservice.py'
44--- lib/lp/soyuz/browser/tests/test_archive_webservice.py 2014-08-07 06:46:31 +0000
45+++ lib/lp/soyuz/browser/tests/test_archive_webservice.py 2015-05-19 00:51:34 +0000
46@@ -18,6 +18,7 @@
47
48 from lp.app.interfaces.launchpad import ILaunchpadCelebrities
49 from lp.registry.interfaces.pocket import PackagePublishingPocket
50+from lp.services.webapp.interfaces import OAuthPermission
51 from lp.soyuz.enums import (
52 ArchivePermissionType,
53 ArchivePurpose,
54@@ -28,6 +29,7 @@
55 from lp.soyuz.model.archivepermission import ArchivePermission
56 from lp.testing import (
57 admin_logged_in,
58+ api_url,
59 launchpadlib_for,
60 person_logged_in,
61 record_two_runs,
62@@ -265,11 +267,54 @@
63 self.assertEqual('New ARM Title', ws_proc.title)
64 self.assertEqual('New ARM Description', ws_proc.description)
65
66+ def test_setProcessors(self):
67+ """A new processor can be added to the enabled restricted set."""
68+ commercial = getUtility(ILaunchpadCelebrities).commercial_admin
69+ commercial_admin = self.factory.makePerson(member_of=[commercial])
70+ self.factory.makeProcessor(
71+ 'arm', 'ARM', 'ARM', restricted=True, build_by_default=False)
72+ ppa_url = api_url(self.factory.makeArchive(purpose=ArchivePurpose.PPA))
73+
74+ body = webservice_for_person(commercial_admin).get(
75+ ppa_url + '/processors', api_version='devel').jsonBody()
76+ self.assertContentEqual(
77+ ['386', 'hppa', 'amd64'],
78+ [entry['name'] for entry in body['entries']])
79+
80+ response = webservice_for_person(
81+ commercial_admin,
82+ permission=OAuthPermission.WRITE_PUBLIC).named_post(
83+ ppa_url, 'setProcessors',
84+ processors=['/+processors/386', '/+processors/arm'],
85+ api_version='devel')
86+ self.assertEqual(200, response.status)
87+
88+ body = webservice_for_person(commercial_admin).get(
89+ ppa_url + '/processors', api_version='devel').jsonBody()
90+ self.assertContentEqual(
91+ ['386', 'hppa', 'amd64', 'arm'],
92+ [entry['name'] for entry in body['entries']])
93+
94+ def test_setProcessors_owner_forbidden(self):
95+ """Only commercial admins can call setProcessors."""
96+ self.factory.makeProcessor(
97+ 'arm', 'ARM', 'ARM', restricted=True, build_by_default=False)
98+ archive = self.factory.makeArchive(purpose=ArchivePurpose.PPA)
99+ ppa_url = api_url(archive)
100+ owner = archive.owner
101+
102+ response = webservice_for_person(owner).named_post(
103+ ppa_url, 'setProcessors',
104+ processors=['/+processors/386', '/+processors/arm'],
105+ api_version='devel')
106+ self.assertEqual(401, response.status)
107+
108 def test_enableRestrictedProcessor(self):
109 """A new processor can be added to the enabled restricted set."""
110 self.ws_version = 'devel'
111 archive = self.factory.makeArchive()
112- self.factory.makeProcessor(name='arm', restricted=True)
113+ self.factory.makeProcessor(
114+ name='arm', restricted=True, build_by_default=False)
115 commercial = getUtility(ILaunchpadCelebrities).commercial_admin
116 commercial_admin = self.factory.makePerson(member_of=[commercial])
117 transaction.commit()
118@@ -287,7 +332,8 @@
119 """
120 self.ws_version = 'devel'
121 archive = self.factory.makeArchive()
122- self.factory.makeProcessor(name='arm', restricted=True)
123+ self.factory.makeProcessor(
124+ name='arm', restricted=True, build_by_default=False)
125 transaction.commit()
126 ws_arm = self.service.processors.getByName(name='arm')
127 ws_archive = self.wsObject(archive, user=archive.owner)
128@@ -304,7 +350,8 @@
129 """
130 self.ws_version = 'devel'
131 archive = self.factory.makeArchive()
132- self.factory.makeProcessor(name='arm', restricted=True)
133+ self.factory.makeProcessor(
134+ name='arm', restricted=True, build_by_default=False)
135 just_some_guy = self.factory.makePerson()
136 transaction.commit()
137 ws_arm = self.service.processors.getByName(name='arm')
138
139=== modified file 'lib/lp/soyuz/configure.zcml'
140--- lib/lp/soyuz/configure.zcml 2015-05-07 10:52:10 +0000
141+++ lib/lp/soyuz/configure.zcml 2015-05-19 00:51:34 +0000
142@@ -394,7 +394,7 @@
143 buildd_secret enabled_restricted_processors
144 external_dependencies name
145 permit_obsolete_series_uploads
146- private publish_debug_symbols
147+ private processors publish_debug_symbols
148 require_virtualized"/>
149 <require
150 permission="launchpad.Moderate"
151
152=== modified file 'lib/lp/soyuz/interfaces/archive.py'
153--- lib/lp/soyuz/interfaces/archive.py 2015-04-24 14:25:12 +0000
154+++ lib/lp/soyuz/interfaces/archive.py 2015-05-19 00:51:34 +0000
155@@ -94,6 +94,7 @@
156 from lp.app.errors import NameLookupFailed
157 from lp.app.interfaces.launchpad import IPrivacy
158 from lp.app.validators.name import name_validator
159+from lp.buildmaster.interfaces.processor import IProcessor
160 from lp.registry.interfaces.gpg import IGPGKey
161 from lp.registry.interfaces.person import IPerson
162 from lp.registry.interfaces.role import IHasOwner
163@@ -622,14 +623,19 @@
164 "context build.\n"
165 "NOTE: This is for migration of OEM PPAs only!")))
166
167+ processors = exported(
168+ CollectionField(
169+ title=_("Processors"),
170+ description=_("The architectures on which the archive can build."),
171+ value_type=Reference(schema=IProcessor),
172+ readonly=True),
173+ as_of='devel')
174+
175 enabled_restricted_processors = exported(
176 CollectionField(
177 title=_("Enabled restricted processors"),
178- description=_(
179- "The restricted architectures on which the archive "
180- "can build."),
181- value_type=Reference(schema=Interface),
182- # Really IProcessor.
183+ description=_("DEPRECATED. Use processors instead."),
184+ value_type=Reference(schema=IProcessor),
185 readonly=True),
186 as_of='devel')
187
188@@ -2030,14 +2036,24 @@
189 """Archive interface for operations restricted by commercial."""
190
191 @operation_parameters(
192- processor=Reference(schema=Interface, required=True),
193- # Really IProcessor.
194+ processors=List(
195+ value_type=Reference(schema=IProcessor), required=True),
196+ )
197+ @export_write_operation()
198+ @operation_for_version('devel')
199+ def setProcessors(processors):
200+ """Set the architectures on which the archive can build."""
201+
202+ @operation_parameters(
203+ processor=Reference(schema=IProcessor, required=True),
204 )
205 @export_write_operation()
206 @operation_for_version('devel')
207 def enableRestrictedProcessor(processor):
208 """Add the processor to the set of enabled restricted processors.
209
210+ DEPRECATED. Use setProcessors instead.
211+
212 :param processor: is an `IProcessor` object.
213 """
214
215@@ -2087,7 +2103,8 @@
216
217 def new(purpose, owner, name=None, displayname=None, distribution=None,
218 description=None, enabled=True, require_virtualized=True,
219- private=False, suppress_subscription_notifications=False):
220+ private=False, suppress_subscription_notifications=False,
221+ processors=None):
222 """Create a new archive.
223
224 On named-ppa creation, the signing key for the default PPA for the
225@@ -2112,6 +2129,8 @@
226 :param private: whether or not to make the PPA private
227 :param suppress_subscription_notifications: whether to suppress
228 emails to subscribers about new subscriptions.
229+ :param processors: list of `IProcessors` for which the archive should
230+ build. If omitted, processors with `build_by_default` will be used.
231
232 :return: an `IArchive` object.
233 :raises AssertionError if name is already taken within distribution.
234
235=== modified file 'lib/lp/soyuz/interfaces/archivearch.py'
236--- lib/lp/soyuz/interfaces/archivearch.py 2015-04-20 09:48:57 +0000
237+++ lib/lp/soyuz/interfaces/archivearch.py 2015-05-19 00:51:34 +0000
238@@ -60,13 +60,3 @@
239
240 :return: A (potentially empty) result set of `IArchiveArch` instances.
241 """
242-
243- def getRestrictedProcessors(archive):
244- """All restricted processor, paired with `ArchiveArch`
245- instances if associated with `archive`.
246-
247- :return: A sequence containing a (`Processor`, `ArchiveArch`)
248- 2-tuple for each processor.
249- The second value in the tuple will be None if the given `archive`
250- is not associated with the `Processor` yet.
251- """
252
253=== modified file 'lib/lp/soyuz/model/archive.py'
254--- lib/lp/soyuz/model/archive.py 2015-05-12 05:45:08 +0000
255+++ lib/lp/soyuz/model/archive.py 2015-05-19 00:51:34 +0000
256@@ -62,6 +62,7 @@
257 BuildStatus,
258 )
259 from lp.buildmaster.interfaces.buildfarmjob import IBuildFarmJobSet
260+from lp.buildmaster.interfaces.processor import IProcessorSet
261 from lp.registry.enums import (
262 INCLUSIVE_TEAM_POLICY,
263 PersonVisibility,
264@@ -2059,28 +2060,48 @@
265
266 def _getEnabledRestrictedProcessors(self):
267 """Retrieve the restricted architectures this archive can build on."""
268- processors = getUtility(IArchiveArchSet).getRestrictedProcessors(self)
269- return [
270- processor for (processor, archive_arch) in processors
271- if archive_arch is not None]
272+ return [proc for proc in self.processors if proc.restricted]
273
274 def _setEnabledRestrictedProcessors(self, value):
275 """Set the restricted architectures this archive can build on."""
276- archive_arch_set = getUtility(IArchiveArchSet)
277- restricted_processors = archive_arch_set.getRestrictedProcessors(self)
278- for (processor, archive_arch) in restricted_processors:
279- if processor in value and archive_arch is None:
280- archive_arch_set.new(self, processor)
281- if processor not in value and archive_arch is not None:
282- Store.of(self).remove(archive_arch)
283+ self.processors = (
284+ [proc for proc in self.processors if not proc.restricted]
285+ + list(value))
286
287 enabled_restricted_processors = property(
288 _getEnabledRestrictedProcessors, _setEnabledRestrictedProcessors)
289
290 def enableRestrictedProcessor(self, processor):
291 """See `IArchive`."""
292- self.enabled_restricted_processors = set(
293- self.enabled_restricted_processors + [processor])
294+ self.processors = set(self.processors + [processor])
295+
296+ def _getProcessors(self):
297+ # To match existing behaviour we always include non-restricted
298+ # processors during the transition.
299+ enabled = [
300+ aa.processor for aa in
301+ getUtility(IArchiveArchSet).getByArchive(self)]
302+ return [
303+ proc for proc in getUtility(IProcessorSet).getAll()
304+ if not proc.restricted or proc in enabled]
305+
306+ def setProcessors(self, processors):
307+ """See `IArchive`."""
308+ enablements = {
309+ aa.processor: aa for aa in
310+ getUtility(IArchiveArchSet).getByArchive(self)}
311+ # Remove any enabled restricted processors that aren't in the
312+ # new set. _getProcessors currently always includes
313+ # non-restricted processors, but this'll change later.
314+ for proc in enablements:
315+ if proc.restricted and proc not in processors:
316+ Store.of(self).remove(enablements[proc])
317+ # Add any new processors regardless of restrictedness.
318+ for proc in processors:
319+ if proc not in self.processors:
320+ getUtility(IArchiveArchSet).new(self, proc)
321+
322+ processors = property(_getProcessors, setProcessors)
323
324 def getPockets(self):
325 """See `IArchive`."""
326@@ -2352,7 +2373,7 @@
327 def new(self, purpose, owner, name=None, displayname=None,
328 distribution=None, description=None, enabled=True,
329 require_virtualized=True, private=False,
330- suppress_subscription_notifications=False):
331+ suppress_subscription_notifications=False, processors=None):
332 """See `IArchiveSet`."""
333 if distribution is None:
334 distribution = getUtility(ILaunchpadCelebrities).ubuntu
335@@ -2431,6 +2452,13 @@
336 new_archive.suppress_subscription_notifications = (
337 suppress_subscription_notifications)
338
339+ if processors is None:
340+ processors = [
341+ p for p in getUtility(IProcessorSet).getAll()
342+ if p.build_by_default]
343+ for processor in processors:
344+ getUtility(IArchiveArchSet).new(new_archive, processor)
345+
346 return new_archive
347
348 def __iter__(self):
349
350=== modified file 'lib/lp/soyuz/model/archivearch.py'
351--- lib/lp/soyuz/model/archivearch.py 2015-04-20 09:48:57 +0000
352+++ lib/lp/soyuz/model/archivearch.py 2015-05-19 00:51:34 +0000
353@@ -7,10 +7,6 @@
354 'ArchiveArchSet'
355 ]
356
357-from storm.expr import (
358- And,
359- LeftJoin,
360- )
361 from storm.locals import (
362 Int,
363 Reference,
364@@ -58,15 +54,3 @@
365
366 return IStore(ArchiveArch).find(ArchiveArch, *clauses).order_by(
367 ArchiveArch.id)
368-
369- def getRestrictedProcessors(self, archive):
370- """See `IArchiveArchSet`."""
371- origin = (
372- Processor,
373- LeftJoin(
374- ArchiveArch,
375- And(ArchiveArch.archive == archive.id,
376- ArchiveArch.processor == Processor.id)))
377- return IStore(ArchiveArch).using(*origin).find(
378- (Processor, ArchiveArch),
379- Processor.restricted == True).order_by(Processor.name)
380
381=== modified file 'lib/lp/soyuz/model/binarypackagebuild.py'
382--- lib/lp/soyuz/model/binarypackagebuild.py 2015-05-14 12:45:06 +0000
383+++ lib/lp/soyuz/model/binarypackagebuild.py 2015-05-19 00:51:34 +0000
384@@ -1392,9 +1392,7 @@
385 das for das in available_archs
386 if (
387 das.enabled
388- and (
389- not das.processor.restricted
390- or das.processor in archive.enabled_restricted_processors)
391+ and das.processor in archive.processors
392 and (
393 das.processor.supports_virtualized
394 or not archive.require_virtualized))]
395
396=== modified file 'lib/lp/soyuz/scripts/populate_archive.py'
397--- lib/lp/soyuz/scripts/populate_archive.py 2015-04-20 09:48:57 +0000
398+++ lib/lp/soyuz/scripts/populate_archive.py 2015-05-19 00:51:34 +0000
399@@ -22,7 +22,6 @@
400 from lp.soyuz.adapters.packagelocation import build_package_location
401 from lp.soyuz.enums import ArchivePurpose
402 from lp.soyuz.interfaces.archive import IArchiveSet
403-from lp.soyuz.interfaces.archivearch import IArchiveArchSet
404 from lp.soyuz.interfaces.component import IComponentSet
405 from lp.soyuz.interfaces.packagecloner import IPackageCloner
406 from lp.soyuz.interfaces.packagecopyrequest import IPackageCopyRequestSet
407@@ -104,12 +103,6 @@
408 "Invalid architecture tag: '%s'" % name)
409 return processors
410
411- def set_archive_architectures(archive, processors):
412- """Associate the archive with the processors."""
413- aa_set = getUtility(IArchiveArchSet)
414- for processor in processors:
415- aa_set.new(archive, processor)
416-
417 def build_location(distro, suite, component, packageset_names=None):
418 """Build and return package location."""
419 location = build_package_location(
420@@ -213,11 +206,8 @@
421 ArchivePurpose.COPY, registrant, name=to_archive,
422 distribution=the_destination.distribution,
423 description=reason, enabled=False,
424- require_virtualized=virtual)
425+ require_virtualized=virtual, processors=processors)
426 the_destination.archive = copy_archive
427- # Associate the newly created copy archive with the processors
428- # specified by the user.
429- set_archive_architectures(copy_archive, processors)
430 else:
431 # Archive name clash! Creation requested for existing archive with
432 # the same name and distribution.
433
434=== modified file 'lib/lp/soyuz/stories/webservice/xx-archive.txt'
435--- lib/lp/soyuz/stories/webservice/xx-archive.txt 2015-04-24 14:25:12 +0000
436+++ lib/lp/soyuz/stories/webservice/xx-archive.txt 2015-05-19 00:51:34 +0000
437@@ -52,6 +52,7 @@
438 owner_link: u'http://.../~cprov'
439 permit_obsolete_series_uploads: False
440 private: False
441+ processors_collection_link: u'http://.../~cprov/+archive/ubuntu/ppa/processors'
442 publish_debug_symbols: False
443 reference: u'~cprov/ubuntu/ppa'
444 relative_build_score: 0
445
446=== modified file 'lib/lp/soyuz/tests/test_archive.py'
447--- lib/lp/soyuz/tests/test_archive.py 2015-04-20 09:48:57 +0000
448+++ lib/lp/soyuz/tests/test_archive.py 2015-05-19 00:51:34 +0000
449@@ -1002,7 +1002,7 @@
450 self.assertEqual(3, self.archive.getPackageDownloadTotal(self.bpr_2))
451
452
453-class TestEnabledRestrictedBuilds(TestCaseWithFactory):
454+class TestProcessors(TestCaseWithFactory):
455 """Ensure that restricted architectures builds can be allowed and
456 disallowed correctly."""
457
458@@ -1010,39 +1010,124 @@
459
460 def setUp(self):
461 """Setup an archive with relevant publications."""
462- super(TestEnabledRestrictedBuilds, self).setUp()
463+ super(TestProcessors, self).setUp()
464 self.publisher = SoyuzTestPublisher()
465 self.publisher.prepareBreezyAutotest()
466 self.archive = self.factory.makeArchive()
467 self.archive_arch_set = getUtility(IArchiveArchSet)
468- self.arm = self.factory.makeProcessor(name='arm', restricted=True)
469+ self.default_procs = [
470+ getUtility(IProcessorSet).getByName("386"),
471+ getUtility(IProcessorSet).getByName("amd64")]
472+ self.unrestricted_procs = (
473+ self.default_procs + [getUtility(IProcessorSet).getByName("hppa")])
474+ self.arm = self.factory.makeProcessor(
475+ name='arm', restricted=True, build_by_default=False)
476+
477+ def test_new_default_processors(self):
478+ # ArchiveSet.new creates an ArchiveArch for each Processor with
479+ # build_by_default set.
480+ archive = getUtility(IArchiveSet).new(
481+ owner=self.factory.makePerson(), purpose=ArchivePurpose.PPA,
482+ distribution=self.factory.makeDistribution(), name='ppa')
483+ self.assertContentEqual(
484+ ['386', 'amd64'],
485+ [aa.processor.name for aa in
486+ self.archive_arch_set.getByArchive(archive)])
487+
488+ def test_new_override_processors(self):
489+ # ArchiveSet.new can be given a custom set of processors.
490+ archive = getUtility(IArchiveSet).new(
491+ owner=self.factory.makePerson(), purpose=ArchivePurpose.PPA,
492+ distribution=self.factory.makeDistribution(), name='ppa',
493+ processors=[self.arm])
494+ self.assertContentEqual(
495+ ['arm'],
496+ [aa.processor.name for aa in
497+ self.archive_arch_set.getByArchive(archive)])
498
499 def test_default(self):
500 """By default, ARM builds are not allowed as ARM is restricted."""
501 self.assertEqual(0,
502 self.archive_arch_set.getByArchive(
503 self.archive, self.arm).count())
504+ self.assertContentEqual(
505+ self.unrestricted_procs, self.archive.processors)
506 self.assertContentEqual([], self.archive.enabled_restricted_processors)
507
508 def test_get_uses_archivearch(self):
509 """Adding an entry to ArchiveArch for ARM and an archive will
510 enable enabled_restricted_processors for arm for that archive."""
511+ self.assertContentEqual(
512+ self.unrestricted_procs, self.archive.processors)
513 self.assertContentEqual([], self.archive.enabled_restricted_processors)
514 self.archive_arch_set.new(self.archive, self.arm)
515- self.assertEqual(
516- [self.arm], list(self.archive.enabled_restricted_processors))
517+ self.assertContentEqual(
518+ [self.arm] + self.unrestricted_procs, self.archive.processors)
519+ self.assertContentEqual(
520+ [self.arm], self.archive.enabled_restricted_processors)
521
522 def test_get_returns_restricted_only(self):
523 """Adding an entry to ArchiveArch for something that is not
524 restricted does not make it show up in enabled_restricted_processors.
525 """
526+ self.assertContentEqual(
527+ self.unrestricted_procs, self.archive.processors)
528 self.assertContentEqual([], self.archive.enabled_restricted_processors)
529- self.archive_arch_set.new(
530- self.archive, getUtility(IProcessorSet).getByName('amd64'))
531+ new_proc = self.factory.makeProcessor(
532+ restricted=False, build_by_default=True)
533+ self.archive_arch_set.new(self.archive, new_proc)
534+ self.assertContentEqual(
535+ self.unrestricted_procs + [new_proc], self.archive.processors)
536 self.assertContentEqual([], self.archive.enabled_restricted_processors)
537
538 def test_set(self):
539- """The property remembers its value correctly and sets ArchiveArch."""
540+ """The property remembers its value correctly and sets ArchiveArch.
541+
542+ It's not yet possible to remove the default processors from the set.
543+ """
544+ self.archive.processors = [self.arm]
545+ allowed_restricted_processors = self.archive_arch_set.getByArchive(
546+ self.archive, self.arm)
547+ self.assertEqual(1, allowed_restricted_processors.count())
548+ self.assertEqual(
549+ self.arm, allowed_restricted_processors[0].processor)
550+ self.assertContentEqual(
551+ [self.arm] + self.unrestricted_procs, self.archive.processors)
552+ self.archive.processors = []
553+ self.assertEqual(
554+ 0,
555+ self.archive_arch_set.getByArchive(self.archive, self.arm).count())
556+ self.assertContentEqual(
557+ self.unrestricted_procs, self.archive.processors)
558+
559+ def test_set_doesnt_remove_default(self):
560+ """During the data migration the property must not remove defaults.
561+
562+ _getProcessors doesn't yet rely on ArchiveArches for
563+ non-restricted processors, since the rows don't exist on
564+ production yet, but if they do exist then they won't be removed
565+ on set. We'll backfill them while this version of the code is
566+ running.
567+ """
568+ i386 = getUtility(IProcessorSet).getByName("386")
569+ self.archive.processors = [i386, self.arm]
570+ self.assertContentEqual(
571+ self.default_procs + [self.arm],
572+ [aa.processor for aa in
573+ self.archive_arch_set.getByArchive(self.archive)])
574+ self.archive.processors = []
575+ self.assertContentEqual(
576+ self.default_procs,
577+ [aa.processor for aa in
578+ self.archive_arch_set.getByArchive(self.archive)])
579+ self.assertContentEqual(
580+ self.unrestricted_procs, self.archive.processors)
581+
582+ def test_set_enabled_restricted_processors(self):
583+ """The deprecated enabled_restricted_processors property still works.
584+
585+ It's like processors, but only including those that are restricted.
586+ """
587 self.archive.enabled_restricted_processors = [self.arm]
588 allowed_restricted_processors = self.archive_arch_set.getByArchive(
589 self.archive, self.arm)
590@@ -1055,6 +1140,8 @@
591 self.assertEqual(
592 0,
593 self.archive_arch_set.getByArchive(self.archive, self.arm).count())
594+ self.assertContentEqual(
595+ self.unrestricted_procs, self.archive.processors)
596 self.assertContentEqual([], self.archive.enabled_restricted_processors)
597
598
599
600=== modified file 'lib/lp/soyuz/tests/test_archivearch.py'
601--- lib/lp/soyuz/tests/test_archivearch.py 2013-09-27 06:29:02 +0000
602+++ lib/lp/soyuz/tests/test_archivearch.py 2015-05-19 00:51:34 +0000
603@@ -26,58 +26,18 @@
604 self.ubuntu_archive = ubuntu.main_archive
605 self.cell_proc = self.factory.makeProcessor(
606 'cell-proc', 'PS cell processor', 'Screamingly faaaaaaaaaaaast',
607- True)
608+ restricted=True, build_by_default=False)
609 self.omap = self.factory.makeProcessor(
610 'omap', 'Multimedia applications processor',
611- 'Does all your sound & video', True)
612-
613- def test_getRestrictedProcessors_no_restricted_associations(self):
614- # Our archive is not associated with any restricted processors yet.
615- result_set = list(
616- self.archive_arch_set.getRestrictedProcessors(self.ppa))
617- archivearches = [row[1] for row in result_set]
618- self.assertTrue(all(aa is None for aa in archivearches))
619-
620- def test_getRestrictedProcessors_single_restricted_association(self):
621- # Our archive is now associated with one of the restricted processors.
622- self.archive_arch_set.new(self.ppa, self.cell_proc)
623- result_set = list(
624- self.archive_arch_set.getRestrictedProcessors(self.ppa))
625- results = dict(
626- (row[0].name, row[1] is not None) for row in result_set)
627- self.assertEqual({'cell-proc': True, 'omap': False}, results)
628-
629- def test_getRestrictedProcessors_archive_only(self):
630- # Test that only the associated archs for the archive itself are
631- # returned.
632- self.archive_arch_set.new(self.ppa, self.cell_proc)
633- self.archive_arch_set.new(self.ubuntu_archive, self.omap)
634- result_set = list(
635- self.archive_arch_set.getRestrictedProcessors(self.ppa))
636- results = dict(
637- (row[0].name, row[1] is not None) for row in result_set)
638- self.assertEqual({'cell-proc': True, 'omap': False}, results)
639+ 'Does all your sound & video', restricted=True,
640+ build_by_default=False)
641
642 def test_getByArchive_no_other_archives(self):
643 # Test ArchiveArchSet.getByArchive returns no other archives.
644 self.archive_arch_set.new(self.ppa, self.cell_proc)
645 self.archive_arch_set.new(self.ubuntu_archive, self.omap)
646- result_set = list(self.archive_arch_set.getByArchive(self.ppa))
647- self.assertEqual(1, len(result_set))
648- self.assertEqual(self.ppa, result_set[0].archive)
649- self.assertEqual(self.cell_proc, result_set[0].processor)
650-
651- def test_getByArchive_follows_creation_order(self):
652- # The result of ArchiveArchSet.getByArchive follows the order in
653- # which architecture associations were added.
654- self.archive_arch_set.new(self.ppa, self.cell_proc)
655- self.archive_arch_set.new(self.ppa, self.omap)
656- result_set = list(self.archive_arch_set.getByArchive(self.ppa))
657- self.assertEqual(2, len(result_set))
658- self.assertEqual(self.ppa, result_set[0].archive)
659- self.assertEqual(self.cell_proc, result_set[0].processor)
660- self.assertEqual(self.ppa, result_set[1].archive)
661- self.assertEqual(self.omap, result_set[1].processor)
662+ result = self.archive_arch_set.getByArchive(self.ppa)
663+ self.assertContentEqual([self.ppa], set(aa.archive for aa in result))
664
665 def test_getByArchive_specific_architecture(self):
666 # ArchiveArchSet.getByArchive can query for a specific architecture
667
668=== modified file 'lib/lp/soyuz/tests/test_build_set.py'
669--- lib/lp/soyuz/tests/test_build_set.py 2015-05-14 08:28:10 +0000
670+++ lib/lp/soyuz/tests/test_build_set.py 2015-05-19 00:51:34 +0000
671@@ -278,35 +278,39 @@
672 self.sparc = self.factory.makeProcessor(
673 name="sparc64", supports_virtualized=True)
674 self.distroseries = self.factory.makeDistroSeries()
675+ self.distro = self.distroseries.distribution
676 for name, arch in (('avr', self.avr), ('sparc', self.sparc)):
677 self.factory.makeDistroArchSeries(
678 architecturetag=name, processor=arch,
679 distroseries=self.distroseries)
680- self.archive = self.factory.makeArchive(
681- distribution=self.distroseries.distribution)
682
683 def test_normal(self):
684 self.assertContentEqual(
685 [self.distroseries['sparc'], self.distroseries['avr']],
686 BinaryPackageBuildSet()._getAllowedArchitectures(
687- self.archive, self.distroseries.architectures))
688+ self.factory.makeArchive(distribution=self.distro),
689+ self.distroseries.architectures))
690
691 def test_restricted(self):
692 # Restricted architectures aren't returned by default.
693+ self.avr.build_by_default = False
694 self.avr.restricted = True
695 self.assertContentEqual(
696 [self.distroseries['sparc']],
697 BinaryPackageBuildSet()._getAllowedArchitectures(
698- self.archive, self.distroseries.architectures))
699+ self.factory.makeArchive(distribution=self.distro),
700+ self.distroseries.architectures))
701
702 def test_restricted_override(self):
703 # Restricted architectures are returned if allowed by the archive.
704+ self.avr.build_by_default = False
705 self.avr.restricted = True
706- getUtility(IArchiveArchSet).new(self.archive, self.avr)
707+ archive = self.factory.makeArchive(distribution=self.distro)
708+ getUtility(IArchiveArchSet).new(archive, self.avr)
709 self.assertContentEqual(
710 [self.distroseries['sparc'], self.distroseries['avr']],
711 BinaryPackageBuildSet()._getAllowedArchitectures(
712- self.archive, self.distroseries.architectures))
713+ archive, self.distroseries.architectures))
714
715 def test_disabled_architectures_omitted(self):
716 # Disabled architectures are not buildable, so are excluded.
717@@ -314,7 +318,8 @@
718 self.assertContentEqual(
719 [self.distroseries['avr']],
720 BinaryPackageBuildSet()._getAllowedArchitectures(
721- self.archive, self.distroseries.architectures))
722+ self.factory.makeArchive(distribution=self.distro),
723+ self.distroseries.architectures))
724
725 def test_virt_archives_have_only_virt_archs(self):
726 # For archives which must build on virtual builders, only
727@@ -323,16 +328,18 @@
728 self.assertContentEqual(
729 [self.distroseries['avr']],
730 BinaryPackageBuildSet()._getAllowedArchitectures(
731- self.archive, self.distroseries.architectures))
732+ self.factory.makeArchive(distribution=self.distro),
733+ self.distroseries.architectures))
734
735 def test_nonvirt_archives_have_only_all_archs(self):
736 # Non-virtual archives can build on all unrestricted architectures.
737 self.sparc.supports_virtualized = False
738- self.archive.require_virtualized = False
739 self.assertContentEqual(
740 [self.distroseries['sparc'], self.distroseries['avr']],
741 BinaryPackageBuildSet()._getAllowedArchitectures(
742- self.archive, self.distroseries.architectures))
743+ self.factory.makeArchive(
744+ distribution=self.distro, virtualized=False),
745+ self.distroseries.architectures))
746
747
748 class BuildRecordCreationTests(TestNativePublishingBase):
749@@ -408,6 +415,7 @@
750 """createForSource() should limit builds targeted at 'any'
751 architecture to those allowed for the archive.
752 """
753+ self.avr.build_by_default = False
754 self.avr.restricted = True
755 spr = self.factory.makeSourcePackageRelease(architecturehintlist='any')
756 builds = self.createBuilds(spr, self.distroseries)
757@@ -417,6 +425,7 @@
758 """createForSource() limits builds targeted at a variety of
759 architectures architecture to those allowed for the archive.
760 """
761+ self.avr.build_by_default = False
762 self.avr.restricted = True
763 spr = self.factory.makeSourcePackageRelease(
764 architecturehintlist='sparc i386 avr')
765@@ -428,6 +437,7 @@
766 architectures to the nominated independent architecture,
767 if that is allowed for the archive.
768 """
769+ self.avr.build_by_default = False
770 self.avr.restricted = True
771 spr = self.factory.makeSourcePackageRelease(architecturehintlist='all')
772 builds = self.createBuilds(spr, self.distroseries)
773@@ -438,6 +448,7 @@
774 architecture to architectures that are unrestricted or
775 explicitly associated with the archive.
776 """
777+ self.avr.build_by_default = False
778 self.avr.restricted = True
779 getUtility(IArchiveArchSet).new(self.archive, self.avr)
780 spr = self.factory.makeSourcePackageRelease(architecturehintlist='any')
781
782=== modified file 'lib/lp/soyuz/tests/test_packagecloner.py'
783--- lib/lp/soyuz/tests/test_packagecloner.py 2015-04-20 15:59:52 +0000
784+++ lib/lp/soyuz/tests/test_packagecloner.py 2015-05-19 00:51:34 +0000
785@@ -14,7 +14,6 @@
786 ArchivePurpose,
787 PackagePublishingStatus,
788 )
789-from lp.soyuz.interfaces.archivearch import IArchiveArchSet
790 from lp.soyuz.interfaces.binarypackagebuild import IBinaryPackageBuildSet
791 from lp.soyuz.interfaces.component import IComponentSet
792 from lp.soyuz.interfaces.packagecloner import IPackageCloner
793@@ -82,11 +81,11 @@
794 distroseries.nominatedarchindep = das
795 return distroseries
796
797- def getTargetArchive(self, distribution):
798+ def getTargetArchive(self, distribution, processors=None):
799 """Get a target archive for copying in to."""
800 return self.factory.makeArchive(
801 name="test-copy-archive", purpose=ArchivePurpose.COPY,
802- distribution=distribution)
803+ distribution=distribution, processors=processors)
804
805 def createSourcePublication(self, info, distroseries):
806 """Create a SourcePackagePublishingHistory based on a PackageInfo."""
807@@ -116,7 +115,8 @@
808 processors=None):
809 """Make a copy archive based on a new distribution."""
810 distroseries = self.createSourceDistribution(package_infos)
811- copy_archive = self.getTargetArchive(distroseries.distribution)
812+ copy_archive = self.getTargetArchive(
813+ distroseries.distribution, processors=processors)
814 to_component = getUtility(IComponentSet).ensure(component)
815 self.copyArchive(
816 copy_archive, distroseries, from_pocket=source_pocket,
817@@ -588,12 +588,6 @@
818 self.checkCopiedSources(
819 copy_archive, distroseries, [package_infos[1]] + package_infos2)
820
821- def setArchiveArchitectures(self, archive, processors):
822- """Associate the archive with the processors."""
823- aa_set = getUtility(IArchiveArchSet)
824- for processor in processors:
825- aa_set.new(archive, processor)
826-
827 def testMergeCopyCreatesBuilds(self):
828 package_infos = [
829 PackageInfo(
830@@ -604,7 +598,6 @@
831 processors = [getUtility(IProcessorSet).getByName('386')]
832 copy_archive, distroseries = self.makeCopyArchive(
833 package_infos, processors=processors)
834- self.setArchiveArchitectures(copy_archive, processors)
835 package_infos2 = [
836 PackageInfo(
837 "bzr", "2.2", status=PackagePublishingStatus.PUBLISHED),
838@@ -650,8 +643,8 @@
839 # The request builds for both processors, so we expect two builds
840 # per source.
841 processors = [getUtility(IProcessorSet).getByName('386'), amd64]
842- copy_archive = self.getTargetArchive(distroseries.distribution)
843- self.setArchiveArchitectures(copy_archive, processors)
844+ copy_archive = self.getTargetArchive(
845+ distroseries.distribution, processors=processors)
846 self.copyArchive(
847 copy_archive, distroseries, processors=processors)
848 package_infos2 = [
849
850=== modified file 'lib/lp/testing/factory.py'
851--- lib/lp/testing/factory.py 2015-05-13 08:27:03 +0000
852+++ lib/lp/testing/factory.py 2015-05-19 00:51:34 +0000
853@@ -869,7 +869,7 @@
854 name=name, active=active, dateexpected=dateexpected))
855
856 def makeProcessor(self, name=None, title=None, description=None,
857- restricted=False, build_by_default=False,
858+ restricted=False, build_by_default=True,
859 supports_virtualized=False,
860 supports_nonvirtualized=True):
861 """Create a new processor.
862@@ -2756,7 +2756,8 @@
863 def makeArchive(self, distribution=None, owner=None, name=None,
864 purpose=None, enabled=True, private=False,
865 virtualized=True, description=None, displayname=None,
866- suppress_subscription_notifications=False):
867+ suppress_subscription_notifications=False,
868+ processors=None):
869 """Create and return a new arbitrary archive.
870
871 :param distribution: Supply IDistribution, defaults to a new one
872@@ -2803,7 +2804,7 @@
873 owner=owner, purpose=purpose,
874 distribution=distribution, name=name, displayname=displayname,
875 enabled=enabled, require_virtualized=virtualized,
876- description=description)
877+ description=description, processors=processors)
878
879 if private:
880 naked_archive = removeSecurityProxy(archive)