Merge lp:~cjohnston/launchpad/ppa-rtm-fixes into lp:launchpad

Proposed by Chris Johnston
Status: Rejected
Rejected by: William Grant
Proposed branch: lp:~cjohnston/launchpad/ppa-rtm-fixes
Merge into: lp:launchpad
Diff against target: 504 lines (+130/-57)
9 files modified
lib/lp/code/javascript/tests/test_requestbuild_overlay.html (+1/-1)
lib/lp/soyuz/browser/archive.py (+2/-3)
lib/lp/soyuz/browser/tests/archive-views.txt (+8/-8)
lib/lp/soyuz/doc/vocabularies.txt (+13/-13)
lib/lp/soyuz/model/archive.py (+7/-1)
lib/lp/soyuz/stories/ppa/xx-edit-dependencies.txt (+47/-10)
lib/lp/soyuz/tests/test_archive.py (+25/-1)
lib/lp/soyuz/tests/test_vocabularies.py (+1/-1)
lib/lp/soyuz/vocabularies.py (+26/-19)
To merge this branch: bzr merge lp:~cjohnston/launchpad/ppa-rtm-fixes
Reviewer Review Type Date Requested Status
Launchpad code reviewers Pending
Review via email: mp+229777@code.launchpad.net
To post a comment you must log in.
Revision history for this message
William Grant (wgrant) :

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'lib/lp/code/javascript/tests/test_requestbuild_overlay.html'
2--- lib/lp/code/javascript/tests/test_requestbuild_overlay.html 2012-10-26 09:54:28 +0000
3+++ lib/lp/code/javascript/tests/test_requestbuild_overlay.html 2014-08-29 01:29:58 +0000
4@@ -73,7 +73,7 @@
5 <script type="text/x-template" id="requestbuilds-form-template">
6 <div class="form" id="launchpad-form-widgets">
7 <select id="field.archive" name="field.archive" size="1" >
8- <option selected="selected" value="mark/ppa">
9+ <option selected="selected" value="~mark/ubuntu/ppa">
10 PPA for Mark Shuttleworth</option>
11 </select>
12 <input name="field.archive-empty-marker" type="hidden" value="1" />
13
14=== modified file 'lib/lp/soyuz/browser/archive.py'
15--- lib/lp/soyuz/browser/archive.py 2014-08-01 08:47:00 +0000
16+++ lib/lp/soyuz/browser/archive.py 2014-08-29 01:29:58 +0000
17@@ -1391,6 +1391,7 @@
18 for archive in archives:
19 label = '%s [%s]' % (archive.displayname, archive.reference)
20 terms.append(SimpleTerm(archive, archive.reference, label))
21+ terms.sort(key=lambda x: x.value.reference)
22 return SimpleVocabulary(terms)
23
24
25@@ -1627,10 +1628,8 @@
26 canonical_url(dependency), archive_dependency.title)
27 else:
28 dependency_label = archive_dependency.title
29- dependency_token = '%s/%s' % (
30- dependency.owner.name, dependency.name)
31 term = SimpleTerm(
32- dependency, dependency_token, dependency_label)
33+ dependency, dependency.reference, dependency_label)
34 terms.append(term)
35 return form.Fields(
36 List(__name__='selected_dependencies',
37
38=== modified file 'lib/lp/soyuz/browser/tests/archive-views.txt'
39--- lib/lp/soyuz/browser/tests/archive-views.txt 2014-07-24 09:37:03 +0000
40+++ lib/lp/soyuz/browser/tests/archive-views.txt 2014-08-29 01:29:58 +0000
41@@ -716,7 +716,7 @@
42
43 Let's emulate a dependency addition. Note that the form contains, a
44 empty 'selected_dependencies' (as it was rendered in the empty
45-request) and 'dependency_candidate' contains a valid PPA owner name.
46+request) and 'dependency_candidate' contains a valid PPA name.
47 Validation checks are documented in
48 pagetests/ppa/xx-edit-dependencies.txt.
49
50@@ -724,7 +724,7 @@
51 ... cprov.archive, name="+edit-dependencies",
52 ... form={
53 ... 'field.selected_dependencies': [],
54- ... 'field.dependency_candidate': 'mark/ppa',
55+ ... 'field.dependency_candidate': '~mark/ubuntu/ppa',
56 ... 'field.primary_dependencies': 'UPDATES',
57 ... 'field.primary_components': 'ALL_COMPONENTS',
58 ... 'field.actions.save': 'Save',
59@@ -762,7 +762,7 @@
60 PPA for Mark Shuttleworth
61
62 >>> print dependency.token
63- mark/ppa
64+ ~mark/ubuntu/ppa
65
66 >>> print dependency.title.escapedtext
67 <a href="http://launchpad.dev/~mark/+archive/ubuntu/ppa">PPA for Mark
68@@ -794,7 +794,7 @@
69 PPA for Mark Shuttleworth
70
71 >>> print dependency.token
72- mark/ppa
73+ ~mark/ubuntu/ppa
74
75 >>> print dependency.title
76 PPA for Mark Shuttleworth
77@@ -805,7 +805,7 @@
78 >>> view = create_initialized_view(
79 ... cprov.archive, name="+edit-dependencies",
80 ... form={
81- ... 'field.selected_dependencies': ['mark/ppa'],
82+ ... 'field.selected_dependencies': ['~mark/ubuntu/ppa'],
83 ... 'field.dependency_candidate': '',
84 ... 'field.primary_dependencies': 'UPDATES',
85 ... 'field.primary_components': 'ALL_COMPONENTS',
86@@ -849,7 +849,7 @@
87 >>> view.widgets.get('primary_dependencies')._getCurrentValue()
88 <DBItem PackagePublishingPocket.UPDATES, (20) Updates>
89
90-A similar widget is used for the primary archive component overrides ,
91+A similar widget is used for the primary archive component overrides,
92 which contains two pre-defined options. By default all PPAs use all
93 ubuntu components available to satisfy build dependencies, i.e. the
94 'multiverse' component.
95@@ -965,7 +965,7 @@
96 <DBItem PackagePublishingPocket.UPDATES, (20) Updates>
97
98 Dependencies on private PPAs can be only set if the user performing
99-the action also have permission to view the private PPA and if the
100+the action also has permission to view the private PPA and if the
101 context PPA is also private.
102
103 The latter guarantee that the P3A buildd_secret won't get exposed in
104@@ -988,7 +988,7 @@
105
106 >>> add_private_form = {
107 ... 'field.selected_dependencies': [],
108- ... 'field.dependency_candidate': 'pirulito-team/ppa',
109+ ... 'field.dependency_candidate': '~pirulito-team/ubuntu/ppa',
110 ... 'field.primary_dependencies': 'UPDATES',
111 ... 'field.primary_components': 'FOLLOW_PRIMARY',
112 ... 'field.actions.save': 'Save',
113
114=== modified file 'lib/lp/soyuz/doc/vocabularies.txt'
115--- lib/lp/soyuz/doc/vocabularies.txt 2013-07-12 06:14:22 +0000
116+++ lib/lp/soyuz/doc/vocabularies.txt 2014-08-29 01:29:58 +0000
117@@ -189,13 +189,13 @@
118 * value: the IArchive object;
119 * title: the first line of the PPA description text.
120
121- >>> cprov_term = vocabulary.getTermByToken('cprov/ppa')
122+ >>> cprov_term = vocabulary.getTermByToken('~cprov/ubuntu/ppa')
123
124 >>> print cprov_term.token
125- cprov/ppa
126+ ~cprov/ubuntu/ppa
127
128 >>> print cprov_term.value
129- <Archive ...>
130+ <... lp.soyuz.model.archive.Archive instance ...>
131
132 >>> print cprov_term.title
133 packages to help my friends.
134@@ -216,15 +216,15 @@
135
136 >>> cprov_search = vocabulary.search(u'cprov')
137 >>> print_search_results(cprov_search)
138- cprov/ppa: packages to help my friends.
139+ ~cprov/ubuntu/ppa: packages to help my friends.
140
141 >>> celso_search = vocabulary.search(u'celso')
142 >>> print_search_results(celso_search)
143- cprov/ppa: packages to help my friends.
144+ ~cprov/ubuntu/ppa: packages to help my friends.
145
146 >>> friends_search = vocabulary.search(u'friends')
147 >>> print_search_results(friends_search)
148- cprov/ppa: packages to help my friends.
149+ ~cprov/ubuntu/ppa: packages to help my friends.
150
151 We will create an additional PPA for Celso named 'testing'
152
153@@ -242,15 +242,15 @@
154
155 >>> cprov_search = vocabulary.search(u'cprov')
156 >>> print_search_results(cprov_search)
157- cprov/ppa: packages to help my friends.
158- cprov/testing: testing packages.
159+ ~cprov/ubuntu/ppa: packages to help my friends.
160+ ~cprov/ubuntu/testing: testing packages.
161
162 The vocabulary search also supports specific named PPA lookups
163 follwing the same combined syntax used to build unique tokens.
164
165- >>> named_search = vocabulary.search(u'cprov/testing')
166+ >>> named_search = vocabulary.search(u'~cprov/ubuntu/testing')
167 >>> print_search_results(named_search)
168- cprov/testing: testing packages.
169+ ~cprov/ubuntu/testing: testing packages.
170
171 As mentioned the PPA vocabulary term title only contains the first
172 line of the PPA description.
173@@ -258,14 +258,14 @@
174 >>> cprov.archive.description = "Single line."
175 >>> flush_database_updates()
176
177- >>> cprov_term = vocabulary.getTermByToken('cprov/ppa')
178+ >>> cprov_term = vocabulary.getTermByToken('~cprov/ubuntu/ppa')
179 >>> print cprov_term.title
180 Single line.
181
182 >>> cprov.archive.description = "First line\nSecond line."
183 >>> flush_database_updates()
184
185- >>> cprov_term = vocabulary.getTermByToken('cprov/ppa')
186+ >>> cprov_term = vocabulary.getTermByToken('~cprov/ubuntu/ppa')
187 >>> print cprov_term.title
188 First line
189
190@@ -274,7 +274,7 @@
191 >>> cprov.archive.description = None
192 >>> flush_database_updates()
193
194- >>> cprov_term = vocabulary.getTermByToken('cprov/ppa')
195+ >>> cprov_term = vocabulary.getTermByToken('~cprov/ubuntu/ppa')
196 >>> print cprov_term.title
197 No description available
198
199
200=== modified file 'lib/lp/soyuz/model/archive.py'
201--- lib/lp/soyuz/model/archive.py 2014-08-14 10:08:28 +0000
202+++ lib/lp/soyuz/model/archive.py 2014-08-29 01:29:58 +0000
203@@ -1,4 +1,4 @@
204-# Copyright 2009-2013 Canonical Ltd. This software is licensed under the
205+# Copyright 2009-2014 Canonical Ltd. This software is licensed under the
206 # GNU Affero General Public License version 3 (see the file LICENSE).
207
208 """Database class for table Archive."""
209@@ -1076,7 +1076,13 @@
210 raise ArchiveDependencyError(
211 "Non-primary archives only support the '%s' component." %
212 dependency.default_component.name)
213+ if dependency.distribution != self.distribution:
214+ raise ArchiveDependencyError(
215+ "This dependency uses a different archive.")
216
217+ if not dependency.enabled:
218+ raise ArchiveDependencyError(
219+ "This dependency is not active.")
220 return ArchiveDependency(
221 archive=self, dependency=dependency, pocket=pocket,
222 component=component)
223
224=== modified file 'lib/lp/soyuz/stories/ppa/xx-edit-dependencies.txt'
225--- lib/lp/soyuz/stories/ppa/xx-edit-dependencies.txt 2014-07-24 09:37:03 +0000
226+++ lib/lp/soyuz/stories/ppa/xx-edit-dependencies.txt 2014-08-29 01:29:58 +0000
227@@ -112,7 +112,7 @@
228 is rendered on top of the page and the list of dependencies available
229 for removal is updated.
230
231- >>> admin_browser.getControl("Add PPA dependency").value = 'mark/ppa'
232+ >>> admin_browser.getControl("Add PPA dependency").value = '~mark/ubuntu/ppa'
233 >>> admin_browser.getControl("Save").click()
234 >>> print_feedback_messages(admin_browser.contents)
235 Dependency added: PPA for Mark Shuttleworth
236@@ -123,7 +123,7 @@
237
238 Trying to add a dependency that is already recorded results in a error.
239
240- >>> admin_browser.getControl("Add PPA dependency").value = 'mark/ppa'
241+ >>> admin_browser.getControl("Add PPA dependency").value = '~mark/ubuntu/ppa'
242 >>> admin_browser.getControl("Save").click()
243 >>> print_feedback_messages(admin_browser.contents)
244 There is 1 error.
245@@ -132,7 +132,7 @@
246 Trying to add a dependency for the context PPA itself also results in
247 a error.
248
249- >>> admin_browser.getControl("Add PPA dependency").value = 'cprov/ppa'
250+ >>> admin_browser.getControl("Add PPA dependency").value = '~cprov/ubuntu/ppa'
251 >>> admin_browser.getControl("Save").click()
252 >>> print_feedback_messages(admin_browser.contents)
253 There is 1 error.
254@@ -140,7 +140,7 @@
255
256 If it's a new dependency everything is fine.
257
258- >>> admin_browser.getControl("Add PPA dependency").value = 'no-priv/ppa'
259+ >>> admin_browser.getControl("Add PPA dependency").value = '~no-priv/ubuntu/ppa'
260 >>> admin_browser.getControl("Save").click()
261 >>> print_feedback_messages(admin_browser.contents)
262 Dependency added: PPA for No Privileges Person
263@@ -234,7 +234,7 @@
264
265 >>> admin_browser.getControl(
266 ... name="field.selected_dependencies").value = [
267- ... 'mark/ppa', 'no-priv/ppa']
268+ ... '~mark/ubuntu/ppa', '~no-priv/ubuntu/ppa']
269 >>> admin_browser.getControl("Save").click()
270 >>> print_feedback_messages(admin_browser.contents)
271 Dependencies removed:
272@@ -258,6 +258,43 @@
273 ... user_browser.contents, 'archive-dependencies')
274 None
275
276+We should also make sure that a user is unable to add a disabled PPA as a
277+dependency.
278+
279+ # Disable Mark's PPA.
280+ >>> login('foo.bar@canonical.com')
281+ >>> from zope.component import getUtility
282+ >>> from lp.registry.interfaces.person import IPersonSet
283+ >>> mark = getUtility(IPersonSet).getByName('mark')
284+ >>> mark.archive.disable()
285+ >>> logout()
286+
287+ # Attempt to add Mark's PPA
288+ >>> admin_browser.getControl("Add PPA dependency").value = '~mark/ubuntu/ppa'
289+ >>> admin_browser.getControl("Save").click()
290+ >>> print_feedback_messages(admin_browser.contents)
291+ There is 1 error.
292+ Invalid value
293+
294+ # When the page is reloaded, there shouldn't be any dependencies.
295+ >>> admin_browser.reload()
296+ >>> print_ppa_dependencies(admin_browser.contents)
297+ No dependencies recorded for this PPA yet.
298+
299+Re-enable Mark's PPA for subsequent tests.
300+
301+ >>> login('foo.bar@canonical.com')
302+ >>> mark.archive.enable()
303+ >>> logout()
304+
305+Clear the page.
306+
307+ >>> admin_browser.getControl("Add PPA dependency").value = ''
308+ >>> admin_browser.getControl("Save").click()
309+ >>> admin_browser.reload()
310+ >>> print_ppa_dependencies(admin_browser.contents)
311+ No dependencies recorded for this PPA yet.
312+
313 == Primary dependencies ==
314
315 A user can modify how a PPA depends on its corresponding
316@@ -420,7 +457,7 @@
317
318 First we will create a PPA dependency for No privileged' PPA.
319
320- >>> admin_browser.getControl("Add PPA dependency").value = 'no-priv/ppa'
321+ >>> admin_browser.getControl("Add PPA dependency").value = '~no-priv/ubuntu/ppa'
322 >>> admin_browser.getControl("Save").click()
323 >>> print_feedback_messages(admin_browser.contents)
324 Dependency added: PPA for No Privileges Person
325@@ -450,12 +487,12 @@
326 RELEASE.
327
328 >>> admin_browser.getControl(
329- ... name="field.selected_dependencies").value = ['no-priv/ppa']
330+ ... name="field.selected_dependencies").value = ['~no-priv/ubuntu/ppa']
331
332 >>> admin_browser.getControl(
333 ... "Use all Ubuntu components available.").selected = True
334
335- >>> admin_browser.getControl("Add PPA dependency").value = 'mark/ppa'
336+ >>> admin_browser.getControl("Add PPA dependency").value = '~mark/ubuntu/ppa'
337
338 >>> admin_browser.getControl(
339 ... "Basic (only released packages).").selected = True
340@@ -513,9 +550,9 @@
341
342 >>> admin_browser.getLink('Edit PPA dependencies').click()
343
344- >>> admin_browser.getControl("Add PPA dependency").value = 'no-priv/ppa'
345+ >>> admin_browser.getControl("Add PPA dependency").value = '~no-priv/ubuntu/ppa'
346 >>> admin_browser.getControl(
347- ... name="field.selected_dependencies").value = ['mark/ppa']
348+ ... name="field.selected_dependencies").value = ['~mark/ubuntu/ppa']
349 >>> admin_browser.getControl(
350 ... "Default (security dependencies and recommended updates)."
351 ... ).selected = True
352
353=== modified file 'lib/lp/soyuz/tests/test_archive.py'
354--- lib/lp/soyuz/tests/test_archive.py 2014-08-07 07:53:27 +0000
355+++ lib/lp/soyuz/tests/test_archive.py 2014-08-29 01:29:58 +0000
356@@ -1,4 +1,4 @@
357-# Copyright 2009-2013 Canonical Ltd. This software is licensed under the
358+# Copyright 2009-2014 Canonical Ltd. This software is licensed under the
359 # GNU Affero General Public License version 3 (see the file LICENSE).
360
361 """Test Archive features."""
362@@ -1415,6 +1415,30 @@
363 PackagePublishingPocket.RELEASE)
364 self.assertContentEqual(archive.dependencies, [archive_dependency])
365
366+ def test_dependency_has_different_distribution(self):
367+ # A public archive may not depend on a private archive.
368+ archive = self.factory.makeArchive()
369+ distro = self.factory.makeDistribution()
370+ dependency = self.factory.makeArchive(
371+ distribution=distro, owner=archive.owner)
372+ with person_logged_in(archive.owner):
373+ with ExpectedException(
374+ ArchiveDependencyError,
375+ "This dependency uses a different archive."):
376+ archive.addArchiveDependency(
377+ dependency, PackagePublishingPocket.RELEASE)
378+
379+ def test_dependency_is_disabled(self):
380+ # A public archive may not depend on a private archive.
381+ archive = self.factory.makeArchive()
382+ dependency = self.factory.makeArchive(
383+ owner=archive.owner, enabled=False)
384+ with person_logged_in(archive.owner):
385+ with ExpectedException(
386+ ArchiveDependencyError,
387+ "This dependency is not active."):
388+ archive.addArchiveDependency(
389+ dependency, PackagePublishingPocket.RELEASE)
390
391 class TestArchiveDependencies(TestCaseWithFactory):
392
393
394=== modified file 'lib/lp/soyuz/tests/test_vocabularies.py'
395--- lib/lp/soyuz/tests/test_vocabularies.py 2014-06-11 08:29:40 +0000
396+++ lib/lp/soyuz/tests/test_vocabularies.py 2014-08-29 01:29:58 +0000
397@@ -22,5 +22,5 @@
398 term = vocab.toTerm(archive)
399 self.assertThat(term, MatchesStructure.byEquality(
400 value=archive,
401- token='%s/%s' % (archive.owner.name, archive.name),
402+ token=archive.reference,
403 title='No description available'))
404
405=== modified file 'lib/lp/soyuz/vocabularies.py'
406--- lib/lp/soyuz/vocabularies.py 2013-09-10 06:28:26 +0000
407+++ lib/lp/soyuz/vocabularies.py 2014-08-29 01:29:58 +0000
408@@ -1,4 +1,4 @@
409-# Copyright 2009-2013 Canonical Ltd. This software is licensed under the GNU
410+# Copyright 2009-2014 Canonical Ltd. This software is licensed under the GNU
411 # Affero General Public License version 3 (see the file LICENSE).
412
413 """Soyuz vocabularies."""
414@@ -20,6 +20,7 @@
415 from zope.component import getUtility
416 from zope.interface import implements
417 from zope.schema.vocabulary import SimpleTerm
418+from zope.security.interfaces import Unauthorized
419
420 from lp.registry.model.distroseries import DistroSeries
421 from lp.registry.model.person import Person
422@@ -32,6 +33,7 @@
423 SQLObjectVocabularyBase,
424 )
425 from lp.soyuz.enums import ArchivePurpose
426+from lp.soyuz.interfaces.archive import IArchiveSet
427 from lp.soyuz.model.archive import Archive
428 from lp.soyuz.model.component import Component
429 from lp.soyuz.model.distroarchseries import DistroArchSeries
430@@ -88,6 +90,7 @@
431 _orderBy = ['Person.name, Archive.name']
432 _clauseTables = ['Person']
433 _filter = And(
434+ Archive._enabled == True,
435 Person.q.id == Archive.q.ownerID,
436 Archive.q.purpose == ArchivePurpose.PPA)
437 displayname = 'Select a PPA'
438@@ -95,35 +98,33 @@
439
440 def toTerm(self, archive):
441 """See `IVocabulary`."""
442- description = archive.description
443- if description:
444- summary = description.splitlines()[0]
445- else:
446- summary = "No description available"
447+ try:
448+ description = archive.description
449+ if description:
450+ summary = description.splitlines()[0]
451+ else:
452+ summary = "No description available"
453+ except Unauthorized:
454+ summary = None
455
456- token = '%s/%s' % (archive.owner.name, archive.name)
457+ token = archive.reference
458
459 return SimpleTerm(archive, token, summary)
460
461 def getTermByToken(self, token):
462 """See `IVocabularyTokenized`."""
463 try:
464- owner_name, archive_name = token.split('/')
465+ owner_name, distro_name, archive_name = token.split('/')
466 except ValueError:
467 raise LookupError(token)
468
469- clause = And(
470- self._filter,
471- Person.name == owner_name,
472- Archive.name == archive_name)
473-
474- obj = self._table.selectOne(
475- clause, clauseTables=self._clauseTables)
476-
477+ obj = getUtility(IArchiveSet).getByReference(token)
478 if obj is None:
479- raise LookupError(token)
480- else:
481+ return LookupError(token)
482+ elif obj.enabled:
483 return self.toTerm(obj)
484+ else:
485+ raise LookupError(token)
486
487 def search(self, query, vocab_filter=None):
488 """Return a resultset of archives.
489@@ -135,8 +136,14 @@
490
491 query = query.lower()
492
493+ if query.startswith('~'):
494+ query = query.strip('~')
495 try:
496- owner_name, archive_name = query.split('/')
497+ query_split = query.split('/')
498+ if len(query_split) == 3:
499+ owner_name, distro_name, archive_name = query_split
500+ else:
501+ owner_name, archive_name = query_split
502 except ValueError:
503 clause = And(
504 self._filter,