Merge lp:~rvb/launchpad/virtuality-restricted-bug-837975 into lp:launchpad
- virtuality-restricted-bug-837975
- Merge into devel
Status: | Merged |
---|---|
Approved by: | Graham Binns |
Approved revision: | no longer in the source branch. |
Merged at revision: | 13895 |
Proposed branch: | lp:~rvb/launchpad/virtuality-restricted-bug-837975 |
Merge into: | lp:launchpad |
Diff against target: |
683 lines (+387/-45) 8 files modified
lib/lp/registry/browser/distribution.py (+110/-3) lib/lp/registry/browser/tests/distribution-views.txt (+2/-0) lib/lp/registry/browser/tests/test_distribution_views.py (+192/-14) lib/lp/registry/stories/distribution/xx-distribution-launchpad-usage.txt (+5/-0) lib/lp/soyuz/browser/archive.py (+51/-18) lib/lp/soyuz/model/archive.py (+10/-7) lib/lp/soyuz/tests/test_archive.py (+16/-3) lib/lp/translations/browser/distribution.py (+1/-0) |
To merge this branch: | bzr merge lp:~rvb/launchpad/virtuality-restricted-bug-837975 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Graham Binns (community) | code | Approve | |
Review via email:
|
Commit message
[r=gmb][bug=837975] Add two fields to distro's +add and +edit pages.
Description of the change
This branch adds two fields to distro's +add and +edit pages. They will be used to tweak the virtuality and the restricted architectures of the distro's main archive (http://
= Tests =
./bin/test -vvc test_distributi
./bin/test -vvc test_distributi
./bin/test -vvc test_distributi
./bin/test -vvc test_distributi
./bin/test -vvc test_distributi
./bin/test -vvc test_distributi
./bin/test -vvc test_distributi
./bin/test -vvc test_distributi
./bin/test -vvc test_distributi
./bin/test -vvc test_distributi
./bin/test -vvc test_archive test_main_
./bin/test -vvc test_archive test_main_
= QA =
Create a new distro
https:/
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Graham Binns (gmb) : | # |
Preview Diff
1 | === modified file 'lib/lp/registry/browser/distribution.py' |
2 | --- lib/lp/registry/browser/distribution.py 2011-06-16 13:50:58 +0000 |
3 | +++ lib/lp/registry/browser/distribution.py 2011-09-07 09:26:38 +0000 |
4 | @@ -41,11 +41,13 @@ |
5 | from collections import defaultdict |
6 | import datetime |
7 | |
8 | +from zope.app.form.browser.boolwidgets import CheckBoxWidget |
9 | from zope.component import getUtility |
10 | from zope.event import notify |
11 | from zope.formlib import form |
12 | from zope.interface import implements |
13 | from zope.lifecycleevent import ObjectCreatedEvent |
14 | +from zope.schema import Bool |
15 | from zope.security.interfaces import Unauthorized |
16 | |
17 | from canonical.launchpad.browser.feeds import FeedsMixin |
18 | @@ -82,6 +84,7 @@ |
19 | ) |
20 | from lp.app.errors import NotFoundError |
21 | from lp.app.widgets.image import ImageChangeWidget |
22 | +from lp.app.widgets.itemswidgets import LabeledMultiCheckBoxWidget |
23 | from lp.archivepublisher.interfaces.publisherconfig import ( |
24 | IPublisherConfig, |
25 | IPublisherConfigSet, |
26 | @@ -104,8 +107,8 @@ |
27 | IRegistryCollectionNavigationMenu, |
28 | RegistryCollectionActionMenuBase, |
29 | ) |
30 | +from lp.registry.browser.objectreassignment import ObjectReassignmentView |
31 | from lp.registry.browser.pillar import PillarBugsMenu |
32 | -from lp.registry.browser.objectreassignment import ObjectReassignmentView |
33 | from lp.registry.interfaces.distribution import ( |
34 | IDerivativeDistribution, |
35 | IDistribution, |
36 | @@ -123,9 +126,11 @@ |
37 | request_country, |
38 | ) |
39 | from lp.services.propertycache import cachedproperty |
40 | +from lp.soyuz.browser.archive import EnableRestrictedFamiliesMixin |
41 | from lp.soyuz.browser.packagesearch import PackageSearchViewBase |
42 | from lp.soyuz.enums import ArchivePurpose |
43 | from lp.soyuz.interfaces.archive import IArchiveSet |
44 | +from lp.soyuz.interfaces.processor import IProcessorFamilySet |
45 | |
46 | |
47 | class DistributionNavigation( |
48 | @@ -772,7 +777,27 @@ |
49 | return self.context.count() |
50 | |
51 | |
52 | -class DistributionAddView(LaunchpadFormView): |
53 | +class RequireVirtualizedBuildersMixin: |
54 | + """A mixin that provides require_virtualized field support""" |
55 | + |
56 | + def createRequireVirtualized(self): |
57 | + return form.Fields( |
58 | + Bool( |
59 | + __name__='require_virtualized', |
60 | + title=u"Require virtualized builders", |
61 | + description=( |
62 | + u"Only build the distribution's packages on virtual " |
63 | + "builders."), |
64 | + required=True)) |
65 | + |
66 | + def updateRequireVirtualized(self, require_virtualized, archive): |
67 | + if archive.require_virtualized != require_virtualized: |
68 | + archive.require_virtualized = require_virtualized |
69 | + |
70 | + |
71 | +class DistributionAddView(LaunchpadFormView, |
72 | + RequireVirtualizedBuildersMixin, |
73 | + EnableRestrictedFamiliesMixin): |
74 | |
75 | schema = IDistribution |
76 | label = "Register a new distribution" |
77 | @@ -789,17 +814,40 @@ |
78 | "official_rosetta", |
79 | "answers_usage", |
80 | ] |
81 | + custom_widget('require_virtualized', CheckBoxWidget) |
82 | + custom_widget('enabled_restricted_families', LabeledMultiCheckBoxWidget) |
83 | |
84 | @property |
85 | def page_title(self): |
86 | """The page title.""" |
87 | return self.label |
88 | |
89 | + def validate(self, data): |
90 | + self.validate_enabled_restricted_families( |
91 | + data, ENABLED_RESTRICTED_FAMILITES_ERROR_MSG) |
92 | + |
93 | + @property |
94 | + def initial_values(self): |
95 | + proc_family_set = getUtility(IProcessorFamilySet) |
96 | + restricted_families = set(proc_family_set.getRestricted()) |
97 | + return { |
98 | + 'enabled_restricted_families': restricted_families, |
99 | + 'require_virtualized': False, |
100 | + } |
101 | + |
102 | @property |
103 | def cancel_url(self): |
104 | """See `LaunchpadFormView`.""" |
105 | return canonical_url(self.context) |
106 | |
107 | + def setUpFields(self): |
108 | + """See `LaunchpadFormView`.""" |
109 | + LaunchpadFormView.setUpFields(self) |
110 | + self.form_fields += self.createRequireVirtualized() |
111 | + self.form_fields += self.createEnabledRestrictedFamilies( |
112 | + u'The restricted architecture families on which the ' |
113 | + "distribution's main archive can build.") |
114 | + |
115 | @action("Save", name='save') |
116 | def save_action(self, action, data): |
117 | distribution = getUtility(IDistributionSet).new( |
118 | @@ -813,11 +861,25 @@ |
119 | owner=self.user, |
120 | registrant=self.user, |
121 | ) |
122 | + archive = distribution.main_archive |
123 | + self.updateRequireVirtualized(data['require_virtualized'], archive) |
124 | + if archive.require_virtualized is True: |
125 | + archive.enabled_restricted_families = ( |
126 | + data['enabled_restricted_families']) |
127 | + |
128 | notify(ObjectCreatedEvent(distribution)) |
129 | self.next_url = canonical_url(distribution) |
130 | |
131 | |
132 | -class DistributionEditView(RegistryEditFormView): |
133 | +ENABLED_RESTRICTED_FAMILITES_ERROR_MSG = ( |
134 | + u"This distribution's main archive can not be restricted to " |
135 | + 'certain architectures unless the archive is also set ' |
136 | + 'to build on virtualized builders.') |
137 | + |
138 | + |
139 | +class DistributionEditView(RegistryEditFormView, |
140 | + RequireVirtualizedBuildersMixin, |
141 | + EnableRestrictedFamiliesMixin): |
142 | |
143 | schema = IDistribution |
144 | field_names = [ |
145 | @@ -841,12 +903,31 @@ |
146 | custom_widget('icon', ImageChangeWidget, ImageChangeWidget.EDIT_STYLE) |
147 | custom_widget('logo', ImageChangeWidget, ImageChangeWidget.EDIT_STYLE) |
148 | custom_widget('mugshot', ImageChangeWidget, ImageChangeWidget.EDIT_STYLE) |
149 | + custom_widget('require_virtualized', CheckBoxWidget) |
150 | + custom_widget('enabled_restricted_families', LabeledMultiCheckBoxWidget) |
151 | |
152 | @property |
153 | def label(self): |
154 | """See `LaunchpadFormView`.""" |
155 | return 'Change %s details' % self.context.displayname |
156 | |
157 | + def setUpFields(self): |
158 | + """See `LaunchpadFormView`.""" |
159 | + RegistryEditFormView.setUpFields(self) |
160 | + self.form_fields += self.createRequireVirtualized() |
161 | + self.form_fields += self.createEnabledRestrictedFamilies( |
162 | + u'The restricted architecture families on which the ' |
163 | + "distribution's main archive can build.") |
164 | + |
165 | + @property |
166 | + def initial_values(self): |
167 | + return { |
168 | + 'require_virtualized': |
169 | + self.context.main_archive.require_virtualized, |
170 | + 'enabled_restricted_families': |
171 | + self.context.main_archive.enabled_restricted_families, |
172 | + } |
173 | + |
174 | def validate(self, data): |
175 | """Constrain bug expiration to Launchpad Bugs tracker.""" |
176 | # enable_bug_expiration is disabled by JavaScript when official_malone |
177 | @@ -856,6 +937,32 @@ |
178 | if not official_malone: |
179 | data['enable_bug_expiration'] = False |
180 | |
181 | + # Validate enabled_restricted_families. |
182 | + self.validate_enabled_restricted_families( |
183 | + data, |
184 | + ENABLED_RESTRICTED_FAMILITES_ERROR_MSG) |
185 | + |
186 | + def change_archive_fields(self, data): |
187 | + # Update context.main_archive. |
188 | + new_require_virtualized = data.get('require_virtualized') |
189 | + if new_require_virtualized is not None: |
190 | + self.updateRequireVirtualized( |
191 | + new_require_virtualized, self.context.main_archive) |
192 | + del(data['require_virtualized']) |
193 | + new_enabled_restricted_families = data.get( |
194 | + 'enabled_restricted_families') |
195 | + if new_enabled_restricted_families is not None: |
196 | + if (set(self.context.main_archive.enabled_restricted_families) != |
197 | + set(new_enabled_restricted_families)): |
198 | + self.context.main_archive.enabled_restricted_families = ( |
199 | + new_enabled_restricted_families) |
200 | + del(data['enabled_restricted_families']) |
201 | + |
202 | + @action("Change", name='change') |
203 | + def change_action(self, action, data): |
204 | + self.change_archive_fields(data) |
205 | + self.updateContextFromData(data) |
206 | + |
207 | |
208 | class DistributionSeriesBaseView(LaunchpadView): |
209 | """A base view to list distroseries.""" |
210 | |
211 | === modified file 'lib/lp/registry/browser/tests/distribution-views.txt' |
212 | --- lib/lp/registry/browser/tests/distribution-views.txt 2011-04-08 13:04:24 +0000 |
213 | +++ lib/lp/registry/browser/tests/distribution-views.txt 2011-09-07 09:26:38 +0000 |
214 | @@ -79,6 +79,8 @@ |
215 | ... 'field.description': 'description', |
216 | ... 'field.domainname': 'youbuntu.me', |
217 | ... 'field.members': 'landscape-developers', |
218 | + ... 'field.require_virtualized': 'on', |
219 | + ... 'field.enabled_restricted_families': [], |
220 | ... 'field.actions.save': 'Save', |
221 | ... } |
222 | >>> view = create_initialized_view(distributionset, '+add', form=form) |
223 | |
224 | === modified file 'lib/lp/registry/browser/tests/test_distribution_views.py' |
225 | --- lib/lp/registry/browser/tests/test_distribution_views.py 2011-03-16 17:14:26 +0000 |
226 | +++ lib/lp/registry/browser/tests/test_distribution_views.py 2011-09-07 09:26:38 +0000 |
227 | @@ -12,6 +12,7 @@ |
228 | from lp.archivepublisher.interfaces.publisherconfig import IPublisherConfigSet |
229 | from lp.registry.browser.distribution import DistributionPublisherConfigView |
230 | from lp.registry.interfaces.distribution import IDistributionSet |
231 | +from lp.soyuz.interfaces.processor import IProcessorFamilySet |
232 | from lp.testing import ( |
233 | login_celebrity, |
234 | TestCaseWithFactory, |
235 | @@ -83,7 +84,7 @@ |
236 | |
237 | def test_change_existing_config(self): |
238 | # Test POSTing to change existing config. |
239 | - pubconf = self.factory.makePublisherConfig( |
240 | + self.factory.makePublisherConfig( |
241 | distribution=self.distro, |
242 | root_dir=u"random", |
243 | base_url=u"blah", |
244 | @@ -102,13 +103,13 @@ |
245 | self.owner = self.factory.makePerson() |
246 | self.registrant = self.factory.makePerson() |
247 | self.simple_user = self.factory.makePerson() |
248 | + self.admin = login_celebrity('admin') |
249 | + self.distributionset = getUtility(IDistributionSet) |
250 | + proc_family_set = getUtility(IProcessorFamilySet) |
251 | + self.restricted_families = proc_family_set.getRestricted() |
252 | |
253 | - def test_registrant_set_by_creation(self): |
254 | - # The registrant field should be set to the Person creating |
255 | - # the distribution. |
256 | - admin = login_celebrity('admin') |
257 | - distributionset = getUtility(IDistributionSet) |
258 | - creation_form = { |
259 | + def getDefaultAddDict(self): |
260 | + return { |
261 | 'field.name': 'newbuntu', |
262 | 'field.displayname': 'newbuntu', |
263 | 'field.title': 'newbuntu', |
264 | @@ -116,14 +117,191 @@ |
265 | 'field.description': 'newbuntu', |
266 | 'field.domainname': 'newbuntu', |
267 | 'field.members': self.simple_user.name, |
268 | + 'field.require_virtualized': '', |
269 | + 'field.enabled_restricted_families': [family.name |
270 | + for family in self.restricted_families], |
271 | 'field.actions.save': 'Save', |
272 | } |
273 | - view = create_initialized_view( |
274 | - distributionset, '+add', principal=admin, |
275 | - method='POST', form=creation_form) |
276 | - distribution = distributionset.getByName('newbuntu') |
277 | - self.assertEqual(distribution.owner, admin) |
278 | - self.assertEqual(distribution.registrant, admin) |
279 | + |
280 | + def test_registrant_set_by_creation(self): |
281 | + # The registrant field should be set to the Person creating |
282 | + # the distribution. |
283 | + creation_form = self.getDefaultAddDict() |
284 | + create_initialized_view( |
285 | + self.distributionset, '+add', principal=self.admin, |
286 | + method='POST', form=creation_form) |
287 | + distribution = self.distributionset.getByName('newbuntu') |
288 | + self.assertEqual(distribution.owner, self.admin) |
289 | + self.assertEqual(distribution.registrant, self.admin) |
290 | + |
291 | + def test_add_distro_default_value_require_virtualized(self): |
292 | + view = create_initialized_view( |
293 | + self.distributionset, '+add', principal=self.admin, |
294 | + method='GET') |
295 | + |
296 | + widget = view.widgets['require_virtualized'] |
297 | + self.assertEqual(False, widget._getCurrentValue()) |
298 | + |
299 | + def test_add_distro_init_value_enabled_restricted_families(self): |
300 | + view = create_initialized_view( |
301 | + self.distributionset, '+add', principal=self.admin, |
302 | + method='GET') |
303 | + |
304 | + widget = view.widgets['enabled_restricted_families'] |
305 | + self.assertContentEqual( |
306 | + self.restricted_families, widget._getCurrentValue()) |
307 | + self.assertContentEqual( |
308 | + self.restricted_families, |
309 | + [item.value for item in widget.vocabulary]) |
310 | + |
311 | + def test_add_distro_require_virtualized(self): |
312 | + creation_form = self.getDefaultAddDict() |
313 | + creation_form['field.require_virtualized'] = '' |
314 | + create_initialized_view( |
315 | + self.distributionset, '+add', principal=self.admin, |
316 | + method='POST', form=creation_form) |
317 | + |
318 | + distribution = self.distributionset.getByName('newbuntu') |
319 | + self.assertEqual( |
320 | + False, |
321 | + distribution.main_archive.require_virtualized) |
322 | + |
323 | + def test_add_distro_enabled_restricted_families(self): |
324 | + creation_form = self.getDefaultAddDict() |
325 | + creation_form['field.enabled_restricted_families'] = [] |
326 | + creation_form['field.require_virtualized'] = 'on' |
327 | + create_initialized_view( |
328 | + self.distributionset, '+add', principal=self.admin, |
329 | + method='POST', form=creation_form) |
330 | + |
331 | + distribution = self.distributionset.getByName('newbuntu') |
332 | + self.assertEqual( |
333 | + True, |
334 | + distribution.main_archive.require_virtualized) |
335 | + self.assertContentEqual( |
336 | + [], |
337 | + distribution.main_archive.enabled_restricted_families) |
338 | + |
339 | + def test_add_distro_enabled_restricted_families_error(self): |
340 | + # If require_virtualized is False, enabled_restricted_families |
341 | + # cannot be changed. |
342 | + creation_form = self.getDefaultAddDict() |
343 | + creation_form['field.enabled_restricted_families'] = [] |
344 | + creation_form['field.require_virtualized'] = '' |
345 | + view = create_initialized_view( |
346 | + self.distributionset, '+add', principal=self.admin, |
347 | + method='POST', form=creation_form) |
348 | + |
349 | + error_msg = ( |
350 | + u"This distribution's main archive can not be restricted to " |
351 | + "certain architectures unless the archive is also set to build " |
352 | + "on virtualized builders.") |
353 | + self.assertEqual( |
354 | + error_msg, |
355 | + view.widget_errors.get('enabled_restricted_families')) |
356 | + self.assertEqual( |
357 | + error_msg, |
358 | + view.widget_errors.get('require_virtualized')) |
359 | + |
360 | + |
361 | +class TestDistroEditView(TestCaseWithFactory): |
362 | + """Test the +edit page for a distribution.""" |
363 | + |
364 | + layer = DatabaseFunctionalLayer |
365 | + |
366 | + def setUp(self): |
367 | + super(TestDistroEditView, self).setUp() |
368 | + self.admin = login_celebrity('admin') |
369 | + self.distribution = self.factory.makeDistribution() |
370 | + proc_family_set = getUtility(IProcessorFamilySet) |
371 | + self.restricted_families = proc_family_set.getRestricted() |
372 | + |
373 | + def test_edit_distro_init_value_require_virtualized(self): |
374 | + view = create_initialized_view( |
375 | + self.distribution, '+edit', principal=self.admin, |
376 | + method='GET') |
377 | + |
378 | + widget = view.widgets['require_virtualized'] |
379 | + self.assertEqual( |
380 | + self.distribution.main_archive.require_virtualized, |
381 | + widget._getCurrentValue()) |
382 | + |
383 | + def test_edit_distro_init_value_enabled_restricted_families(self): |
384 | + self.distribution.main_archive.require_virtualized = False |
385 | + view = create_initialized_view( |
386 | + self.distribution, '+edit', principal=self.admin, |
387 | + method='GET') |
388 | + |
389 | + widget = view.widgets['enabled_restricted_families'] |
390 | + self.assertContentEqual( |
391 | + self.restricted_families, widget._getCurrentValue()) |
392 | + self.assertContentEqual( |
393 | + self.restricted_families, |
394 | + [item.value for item in widget.vocabulary]) |
395 | + |
396 | + def getDefaultEditDict(self): |
397 | + return { |
398 | + 'field.displayname': 'newbuntu', |
399 | + 'field.title': 'newbuntu', |
400 | + 'field.summary': 'newbuntu', |
401 | + 'field.description': 'newbuntu', |
402 | + 'field.require_virtualized.used': u'', |
403 | + 'field.enabled_restricted_families': [family.name |
404 | + for family in self.restricted_families], |
405 | + 'field.actions.change': 'Change', |
406 | + } |
407 | + |
408 | + def test_change_require_virtualized(self): |
409 | + edit_form = self.getDefaultEditDict() |
410 | + edit_form['field.require_virtualized'] = 'on' |
411 | + |
412 | + self.distribution.main_archive.require_virtualized = False |
413 | + create_initialized_view( |
414 | + self.distribution, '+edit', principal=self.admin, |
415 | + method='POST', form=edit_form) |
416 | + self.assertEqual( |
417 | + True, |
418 | + self.distribution.main_archive.require_virtualized) |
419 | + |
420 | + def test_change_enabled_restricted_families(self): |
421 | + # If require_virtualized is True, enabled_restricted_families |
422 | + # can be changed. |
423 | + edit_form = self.getDefaultEditDict() |
424 | + edit_form['field.require_virtualized'] = 'on' |
425 | + edit_form['field.enabled_restricted_families'] = [] |
426 | + |
427 | + self.distribution.main_archive.require_virtualized = False |
428 | + self.assertContentEqual( |
429 | + self.restricted_families, |
430 | + self.distribution.main_archive.enabled_restricted_families) |
431 | + create_initialized_view( |
432 | + self.distribution, '+edit', principal=self.admin, |
433 | + method='POST', form=edit_form) |
434 | + |
435 | + self.assertContentEqual( |
436 | + [], |
437 | + self.distribution.main_archive.enabled_restricted_families) |
438 | + |
439 | + def test_cannot_change_enabled_restricted_families(self): |
440 | + # If require_virtualized is False, enabled_restricted_families |
441 | + # cannot be changed. |
442 | + edit_form = self.getDefaultEditDict() |
443 | + edit_form['field.require_virtualized'] = '' |
444 | + edit_form['field.enabled_restricted_families'] = [] |
445 | + |
446 | + view = create_initialized_view( |
447 | + self.distribution, '+edit', principal=self.admin, |
448 | + method='POST', form=edit_form) |
449 | + error_msg = ( |
450 | + u"This distribution's main archive can not be restricted to " |
451 | + "certain architectures unless the archive is also set to build " |
452 | + "on virtualized builders.") |
453 | + self.assertEqual( |
454 | + error_msg, |
455 | + view.widget_errors.get('enabled_restricted_families')) |
456 | + self.assertEqual( |
457 | + error_msg, |
458 | + view.widget_errors.get('require_virtualized')) |
459 | |
460 | |
461 | class TestDistroReassignView(TestCaseWithFactory): |
462 | @@ -147,7 +325,7 @@ |
463 | 'field.existing': 'existing', |
464 | 'field.actions.change': 'Change', |
465 | } |
466 | - view = create_initialized_view( |
467 | + create_initialized_view( |
468 | distribution, '+reassign', principal=admin, |
469 | method='POST', form=reassign_form) |
470 | self.assertEqual(distribution.owner, self.simple_user) |
471 | |
472 | === modified file 'lib/lp/registry/stories/distribution/xx-distribution-launchpad-usage.txt' |
473 | --- lib/lp/registry/stories/distribution/xx-distribution-launchpad-usage.txt 2011-03-08 17:09:15 +0000 |
474 | +++ lib/lp/registry/stories/distribution/xx-distribution-launchpad-usage.txt 2011-09-07 09:26:38 +0000 |
475 | @@ -39,6 +39,11 @@ |
476 | LAUNCHPAD |
477 | >>> print registrant.getControl(name='field.answers_usage').value[0] |
478 | LAUNCHPAD |
479 | + >>> print registrant.getControl(name='field.require_virtualized').value |
480 | + False |
481 | + >>> print registrant.getControl( |
482 | + ... name='field.enabled_restricted_families').value |
483 | + ['arm'] |
484 | |
485 | >>> registrant.getControl(name='field.official_rosetta').value = False |
486 | >>> registrant.getControl('Change', index=3).click() |
487 | |
488 | === modified file 'lib/lp/soyuz/browser/archive.py' |
489 | --- lib/lp/soyuz/browser/archive.py 2011-08-17 13:02:26 +0000 |
490 | +++ lib/lp/soyuz/browser/archive.py 2011-09-07 09:26:38 +0000 |
491 | @@ -22,6 +22,7 @@ |
492 | 'ArchivePackagesView', |
493 | 'ArchiveView', |
494 | 'ArchiveViewBase', |
495 | + 'EnableRestrictedFamiliesMixin', |
496 | 'make_archive_vocabulary', |
497 | 'PackageCopyingMixin', |
498 | 'traverse_named_ppa', |
499 | @@ -2033,7 +2034,39 @@ |
500 | return 'Edit %s' % self.context.displayname |
501 | |
502 | |
503 | -class ArchiveAdminView(BaseArchiveEditView): |
504 | +class EnableRestrictedFamiliesMixin: |
505 | + """A mixin that provides enabled_restricted_families field support""" |
506 | + |
507 | + def createEnabledRestrictedFamilies(self, description=None): |
508 | + """Creates the 'enabled_restricted_families' field. |
509 | + |
510 | + """ |
511 | + terms = [] |
512 | + for family in getUtility(IProcessorFamilySet).getRestricted(): |
513 | + terms.append(SimpleTerm( |
514 | + family, token=family.name, title=family.title)) |
515 | + old_field = IArchive['enabled_restricted_families'] |
516 | + return form.Fields( |
517 | + List(__name__=old_field.__name__, |
518 | + title=old_field.title, |
519 | + value_type=Choice(vocabulary=SimpleVocabulary(terms)), |
520 | + required=False, |
521 | + description=old_field.description if description is None |
522 | + else description), |
523 | + render_context=self.render_context) |
524 | + |
525 | + def validate_enabled_restricted_families(self, data, error_msg): |
526 | + enabled_restricted_families = data['enabled_restricted_families'] |
527 | + require_virtualized = data.get('require_virtualized', False) |
528 | + proc_family_set = getUtility(IProcessorFamilySet) |
529 | + if (not require_virtualized and |
530 | + set(enabled_restricted_families) != |
531 | + set(proc_family_set.getRestricted())): |
532 | + self.setFieldError('enabled_restricted_families', error_msg) |
533 | + self.setFieldError('require_virtualized', error_msg) |
534 | + |
535 | + |
536 | +class ArchiveAdminView(BaseArchiveEditView, EnableRestrictedFamiliesMixin): |
537 | |
538 | field_names = ['enabled', 'private', 'commercial', 'require_virtualized', |
539 | 'build_debug_symbols', 'buildd_secret', 'authorized_size', |
540 | @@ -2097,6 +2130,16 @@ |
541 | 'commercial', |
542 | 'Can only set commericial for private archives.') |
543 | |
544 | + enabled_restricted_families = data.get('enabled_restricted_families') |
545 | + if (enabled_restricted_families and |
546 | + not self.context.canSetEnabledRestrictedFamilies( |
547 | + enabled_restricted_families)): |
548 | + self.setFieldError( |
549 | + 'enabled_restricted_families', |
550 | + 'Main archives can not be restricted to certain ' |
551 | + 'architectures unless they are set to build on ' |
552 | + 'virtualized builders.') |
553 | + |
554 | @property |
555 | def owner_is_private_team(self): |
556 | """Is the owner a private team? |
557 | @@ -2106,6 +2149,13 @@ |
558 | """ |
559 | return self.context.owner.visibility == PersonVisibility.PRIVATE |
560 | |
561 | + @property |
562 | + def initial_values(self): |
563 | + return { |
564 | + 'enabled_restricted_families': |
565 | + self.context.enabled_restricted_families, |
566 | + } |
567 | + |
568 | def setUpFields(self): |
569 | """Override `LaunchpadEditFormView`. |
570 | |
571 | @@ -2114,23 +2164,6 @@ |
572 | super(ArchiveAdminView, self).setUpFields() |
573 | self.form_fields += self.createEnabledRestrictedFamilies() |
574 | |
575 | - def createEnabledRestrictedFamilies(self): |
576 | - """Creates the 'enabled_restricted_families' field. |
577 | - |
578 | - """ |
579 | - terms = [] |
580 | - for family in getUtility(IProcessorFamilySet).getRestricted(): |
581 | - terms.append(SimpleTerm( |
582 | - family, token=family.name, title=family.title)) |
583 | - old_field = IArchive['enabled_restricted_families'] |
584 | - return form.Fields( |
585 | - List(__name__=old_field.__name__, |
586 | - title=old_field.title, |
587 | - value_type=Choice(vocabulary=SimpleVocabulary(terms)), |
588 | - required=False, |
589 | - description=old_field.description), |
590 | - render_context=self.render_context) |
591 | - |
592 | |
593 | class ArchiveDeleteView(LaunchpadFormView): |
594 | """View class for deleting `IArchive`s""" |
595 | |
596 | === modified file 'lib/lp/soyuz/model/archive.py' |
597 | --- lib/lp/soyuz/model/archive.py 2011-08-25 11:29:29 +0000 |
598 | +++ lib/lp/soyuz/model/archive.py 2011-09-07 09:26:38 +0000 |
599 | @@ -1910,8 +1910,8 @@ |
600 | """Retrieve the restricted architecture families this archive can |
601 | build on.""" |
602 | # Main archives are always allowed to build on restricted |
603 | - # architectures. |
604 | - if self.is_main: |
605 | + # architectures if require_virtualized is False. |
606 | + if self.is_main and not self.require_virtualized: |
607 | return getUtility(IProcessorFamilySet).getRestricted() |
608 | archive_arch_set = getUtility(IArchiveArchSet) |
609 | restricted_families = archive_arch_set.getRestrictedFamilies(self) |
610 | @@ -1921,13 +1921,16 @@ |
611 | def _setEnabledRestrictedFamilies(self, value): |
612 | """Set the restricted architecture families this archive can |
613 | build on.""" |
614 | - # Main archives are always allowed to build on restricted |
615 | - # architectures. |
616 | - if self.is_main: |
617 | + # Main archives are not allowed to build on restricted |
618 | + # architectures unless they are set to build on virtualized |
619 | + # builders. |
620 | + if (self.is_main and not self.require_virtualized): |
621 | proc_family_set = getUtility(IProcessorFamilySet) |
622 | if set(value) != set(proc_family_set.getRestricted()): |
623 | - raise CannotRestrictArchitectures("Main archives can not " |
624 | - "be restricted to certain architectures") |
625 | + raise CannotRestrictArchitectures( |
626 | + "Main archives can not be restricted to certain " |
627 | + "architectures unless they are set to build on " |
628 | + "virtualized builders") |
629 | archive_arch_set = getUtility(IArchiveArchSet) |
630 | restricted_families = archive_arch_set.getRestrictedFamilies(self) |
631 | for (family, archive_arch) in restricted_families: |
632 | |
633 | === modified file 'lib/lp/soyuz/tests/test_archive.py' |
634 | --- lib/lp/soyuz/tests/test_archive.py 2011-08-29 19:28:47 +0000 |
635 | +++ lib/lp/soyuz/tests/test_archive.py 2011-09-07 09:26:38 +0000 |
636 | @@ -981,14 +981,17 @@ |
637 | |
638 | def test_main_archive_can_use_restricted(self): |
639 | # Main archives for distributions can always use restricted |
640 | - # architectures. |
641 | + # architectures if they are not using virtual builders. |
642 | distro = self.factory.makeDistribution() |
643 | + distro.main_archive.require_virtualized = False |
644 | self.assertContentEqual([self.arm], |
645 | distro.main_archive.enabled_restricted_families) |
646 | |
647 | - def test_main_archive_can_not_be_restricted(self): |
648 | - # A main archive can not be restricted to certain architectures. |
649 | + def test_main_archive_can_not_be_restricted_not_virtualized(self): |
650 | + # A main archive can not be restricted to certain architectures |
651 | + # (unless it's set to build on virtualized builders). |
652 | distro = self.factory.makeDistribution() |
653 | + distro.main_archive.require_virtualized = False |
654 | # Restricting to all restricted architectures is fine |
655 | distro.main_archive.enabled_restricted_families = [self.arm] |
656 | |
657 | @@ -997,6 +1000,16 @@ |
658 | |
659 | self.assertRaises(CannotRestrictArchitectures, restrict) |
660 | |
661 | + def test_main_virtualized_archive_can_be_restricted(self): |
662 | + # A main archive can be restricted to certain architectures |
663 | + # if it's set to build on virtualized builders. |
664 | + distro = self.factory.makeDistribution() |
665 | + distro.main_archive.require_virtualized = True |
666 | + |
667 | + # Restricting to architectures is fine. |
668 | + distro.main_archive.enabled_restricted_families = [self.arm] |
669 | + distro.main_archive.enabled_restricted_families = [] |
670 | + |
671 | def test_default(self): |
672 | """By default, ARM builds are not allowed as ARM is restricted.""" |
673 | self.assertEquals(0, |
674 | |
675 | === modified file 'lib/lp/translations/browser/distribution.py' |
676 | --- lib/lp/translations/browser/distribution.py 2010-12-30 12:50:16 +0000 |
677 | +++ lib/lp/translations/browser/distribution.py 2011-09-07 09:26:38 +0000 |
678 | @@ -146,4 +146,5 @@ |
679 | |
680 | @action('Change', name='change') |
681 | def edit(self, action, data): |
682 | + self.change_archive_fields(data) |
683 | self.updateContextFromData(data) |