Merge lp:~mwhudson/launchpad/move-some-code-vocabularies into lp:launchpad

Proposed by Michael Hudson-Doyle
Status: Merged
Approved by: Robert Collins
Approved revision: no longer in the source branch.
Merged at revision: 11583
Proposed branch: lp:~mwhudson/launchpad/move-some-code-vocabularies
Merge into: lp:launchpad
Diff against target: 796 lines (+358/-305)
12 files modified
lib/canonical/launchpad/browser/tests/test_widgets.py (+1/-1)
lib/canonical/launchpad/doc/vocabularies.txt (+0/-137)
lib/canonical/launchpad/vocabularies/configure.zcml (+0/-39)
lib/canonical/launchpad/vocabularies/dbobjects.py (+2/-112)
lib/canonical/launchpad/webapp/configure.zcml (+1/-1)
lib/lp/code/browser/configure.zcml (+0/-14)
lib/lp/code/configure.zcml (+1/-0)
lib/lp/code/vocabularies/branch.py (+133/-0)
lib/lp/code/vocabularies/configure.zcml (+54/-0)
lib/lp/code/vocabularies/tests/branch.txt (+148/-0)
lib/lp/code/vocabularies/tests/test_branch_vocabularies.py (+1/-1)
lib/lp/code/vocabularies/tests/test_doc.py (+17/-0)
To merge this branch: bzr merge lp:~mwhudson/launchpad/move-some-code-vocabularies
Reviewer Review Type Date Requested Status
Robert Collins (community) Approve
Review via email: mp+35974@code.launchpad.net

Commit message

Move the remaining code-related vocabularies to the lp.code tree

Description of the change

Hi,

This lunch hour branch moves the remaining code-related vocabularies to the lp.code tree.

Cheers,
mwh

To post a comment you must log in.
Revision history for this message
Robert Collins (lifeless) wrote :

+ """Override this to return the collection to which the search is
477 + restricted.
478

-> """Return the collection of branches the vocabulary searches.

Subclasses MUST override and implement this.
"""

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'lib/canonical/launchpad/browser/tests/test_widgets.py'
--- lib/canonical/launchpad/browser/tests/test_widgets.py 2010-08-20 20:31:18 +0000
+++ lib/canonical/launchpad/browser/tests/test_widgets.py 2010-09-20 22:41:19 +0000
@@ -24,7 +24,7 @@
24 login,24 login,
25 logout,25 logout,
26 )26 )
27from canonical.launchpad.vocabularies import (27from lp.code.vocabularies.branch import (
28 BranchRestrictedOnProductVocabulary,28 BranchRestrictedOnProductVocabulary,
29 BranchVocabulary,29 BranchVocabulary,
30 )30 )
3131
=== modified file 'lib/canonical/launchpad/doc/vocabularies.txt'
--- lib/canonical/launchpad/doc/vocabularies.txt 2010-08-27 14:27:22 +0000
+++ lib/canonical/launchpad/doc/vocabularies.txt 2010-09-20 22:41:19 +0000
@@ -364,143 +364,6 @@
364 [('pmount', u'pmount')]364 [('pmount', u'pmount')]
365365
366366
367BranchVocabulary
368................
369
370The list of bzr branches registered in Launchpad.
371
372Searchable by branch name or URL, registrant name, and project name.
373Results are not restricted in any way by the context, but the results
374are restricted based on who is asking (as far as private branches is
375concerned).
376
377 # Just use None as the context.
378 >>> branch_vocabulary = get_naked_vocab(None, "Branch")
379 >>> def print_vocab_branches(vocab, search):
380 ... for term in vocab.searchForTerms(search):
381 ... print term.value.unique_name
382
383 >>> print_vocab_branches(branch_vocabulary, 'main')
384 ~name12/firefox/main
385 ~stevea/thunderbird/main
386 ~justdave/+junk/main
387 ~kiko/+junk/main
388 ~vcs-imports/evolution/main
389 ~name12/gnome-terminal/main
390
391 >>> print_vocab_branches(branch_vocabulary, 'vcs-imports')
392 ~vcs-imports/gnome-terminal/import
393 ~vcs-imports/evolution/import
394 ~vcs-imports/evolution/main
395
396 >>> print_vocab_branches(branch_vocabulary, 'evolution')
397 ~carlos/evolution/2.0
398 ~vcs-imports/evolution/import
399 ~vcs-imports/evolution/main
400
401A search with the full branch unique name should also find the branch.
402
403 >>> print_vocab_branches(branch_vocabulary, '~name12/firefox/main')
404 ~name12/firefox/main
405
406The tokens used by terms retrieved from BranchVocabulary use the
407branch unique name as an ID:
408
409 >>> from lp.code.interfaces.branchlookup import IBranchLookup
410 >>> branch = getUtility(IBranchLookup).get(15)
411 >>> print branch.unique_name
412 ~name12/gnome-terminal/main
413 >>> term = branch_vocabulary.toTerm(branch)
414 >>> print term.token
415 ~name12/gnome-terminal/main
416
417The BranchVocabulary recognises both unique names and URLs as tokens:
418
419 >>> term = branch_vocabulary.getTermByToken('~name12/gnome-terminal/main')
420 >>> term.value == branch
421 True
422 >>> term = branch_vocabulary.getTermByToken(
423 ... 'http://bazaar.launchpad.dev/~name12/gnome-terminal/main/')
424 >>> term.value == branch
425 True
426 >>> term = branch_vocabulary.getTermByToken(
427 ... 'http://example.com/gnome-terminal/main')
428 >>> term.value == branch
429 True
430
431The searches that the BranchVocabulary does are private branch aware.
432The results are effectively filtered on what the logged in user is
433able to see.
434
435 >>> print_vocab_branches(branch_vocabulary, 'trunk')
436 ~spiv/+junk/trunk
437 ~limi/+junk/trunk
438 ~landscape-developers/landscape/trunk
439
440 >>> login('no-priv@canonical.com')
441 >>> print_vocab_branches(branch_vocabulary, 'trunk')
442 ~spiv/+junk/trunk
443 ~limi/+junk/trunk
444
445 >>> login('foo.bar@canonical.com')
446
447
448BranchRestrictedOnProduct
449.........................
450
451The BranchRestrictedOnProduct vocabulary restricts the result set to
452those of the product of the context. Currently only two types of
453context are supported: Product; and Branch. If a branch is the context,
454then the product of the branch is used to restrict the query.
455
456 >>> gnome_terminal = getUtility(IProductSet)["gnome-terminal"]
457 >>> branch_vocabulary = vocabulary_registry.get(
458 ... gnome_terminal, "BranchRestrictedOnProduct")
459 >>> print_vocab_branches(branch_vocabulary, 'main')
460 ~name12/gnome-terminal/main
461
462 >>> print_vocab_branches(branch_vocabulary, 'vcs-imports')
463 ~vcs-imports/gnome-terminal/import
464
465If a full unique name is entered that has a different product, the
466branch is not part of the vocabulary.
467
468 >>> print_vocab_branches(branch_vocabulary, '~name12/gnome-terminal/main')
469 ~name12/gnome-terminal/main
470
471 >>> print_vocab_branches(branch_vocabulary, '~name12/firefox/main')
472
473
474The BranchRestrictedOnProduct behaves the same way as the more generic
475BranchVocabulary with respect to the tokens and privacy awareness.
476
477
478HostedBranchRestrictedOnOwner
479.............................
480
481Here's a vocabulary for all hosted branches owned by the current user.
482
483 >>> from lp.code.enums import BranchType
484
485 >>> a_user = factory.makePerson(name='a-branching-user')
486 >>> product1 = factory.makeProduct(name='product-one')
487 >>> mirrored_branch = factory.makeBranch(
488 ... owner=a_user, product=product1, name='mirrored',
489 ... branch_type=BranchType.MIRRORED)
490 >>> product2 = factory.makeProduct(name='product-two')
491 >>> hosted_branch = factory.makeBranch(
492 ... owner=a_user, product=product2, name='hosted')
493 >>> foreign_branch = factory.makeBranch()
494
495It returns branches owned by the user, but not ones owned by others, nor
496ones that aren't hosted on Launchpad.
497
498 >>> branch_vocabulary = vocabulary_registry.get(
499 ... a_user, "HostedBranchRestrictedOnOwner")
500 >>> print_vocab_branches(branch_vocabulary, None)
501 ~a-branching-user/product-two/hosted
502
503
504Processor367Processor
505.........368.........
506369
507370
=== modified file 'lib/canonical/launchpad/vocabularies/configure.zcml'
--- lib/canonical/launchpad/vocabularies/configure.zcml 2010-08-25 04:12:59 +0000
+++ lib/canonical/launchpad/vocabularies/configure.zcml 2010-09-20 22:41:19 +0000
@@ -13,45 +13,6 @@
13 </class>13 </class>
1414
15 <securedutility15 <securedutility
16 name="Branch"
17 component="canonical.launchpad.vocabularies.BranchVocabulary"
18 provides="zope.schema.interfaces.IVocabularyFactory"
19 >
20 <allow interface="zope.schema.interfaces.IVocabularyFactory"/>
21 </securedutility>
22
23 <class class="canonical.launchpad.vocabularies.BranchVocabulary">
24 <allow interface="canonical.launchpad.webapp.vocabulary.IHugeVocabulary"/>
25 </class>
26
27
28 <securedutility
29 name="HostedBranchRestrictedOnOwner"
30 component="canonical.launchpad.vocabularies.HostedBranchRestrictedOnOwnerVocabulary"
31 provides="zope.schema.interfaces.IVocabularyFactory"
32 >
33 <allow interface="zope.schema.interfaces.IVocabularyFactory"/>
34 </securedutility>
35
36 <class class="canonical.launchpad.vocabularies.HostedBranchRestrictedOnOwnerVocabulary">
37 <allow interface="canonical.launchpad.webapp.vocabulary.IHugeVocabulary"/>
38 </class>
39
40
41 <securedutility
42 name="BranchRestrictedOnProduct"
43 component="canonical.launchpad.vocabularies.BranchRestrictedOnProductVocabulary"
44 provides="zope.schema.interfaces.IVocabularyFactory"
45 >
46 <allow interface="zope.schema.interfaces.IVocabularyFactory"/>
47 </securedutility>
48
49 <class class="canonical.launchpad.vocabularies.BranchRestrictedOnProductVocabulary">
50 <allow interface="canonical.launchpad.webapp.vocabulary.IHugeVocabulary"/>
51 </class>
52
53
54 <securedutility
55 name="Bug"16 name="Bug"
56 component="canonical.launchpad.vocabularies.BugVocabulary"17 component="canonical.launchpad.vocabularies.BugVocabulary"
57 provides="zope.schema.interfaces.IVocabularyFactory"18 provides="zope.schema.interfaces.IVocabularyFactory"
5819
=== modified file 'lib/canonical/launchpad/vocabularies/dbobjects.py'
--- lib/canonical/launchpad/vocabularies/dbobjects.py 2010-08-27 14:27:22 +0000
+++ lib/canonical/launchpad/vocabularies/dbobjects.py 2010-09-20 22:41:19 +0000
@@ -1,5 +1,5 @@
1# Copyright 2009 Canonical Ltd. This software is licensed under the1# Copyright 2009, 2010 Canonical Ltd. This software is licensed under the GNU
2# GNU Affero General Public License version 3 (see the file LICENSE).2# Affero General Public License version 3 (see the file LICENSE).
33
4"""Vocabularies pulling stuff from the database.4"""Vocabularies pulling stuff from the database.
55
@@ -10,8 +10,6 @@
10__metaclass__ = type10__metaclass__ = type
1111
12__all__ = [12__all__ = [
13 'BranchRestrictedOnProductVocabulary',
14 'BranchVocabulary',
15 'BugNominatableDistroSeriesVocabulary',13 'BugNominatableDistroSeriesVocabulary',
16 'BugNominatableProductSeriesVocabulary',14 'BugNominatableProductSeriesVocabulary',
17 'BugNominatableSeriesVocabulary',15 'BugNominatableSeriesVocabulary',
@@ -26,7 +24,6 @@
26 'FilteredFullLanguagePackVocabulary',24 'FilteredFullLanguagePackVocabulary',
27 'FilteredLanguagePackVocabulary',25 'FilteredLanguagePackVocabulary',
28 'FutureSprintVocabulary',26 'FutureSprintVocabulary',
29 'HostedBranchRestrictedOnOwnerVocabulary',
30 'LanguageVocabulary',27 'LanguageVocabulary',
31 'PackageReleaseVocabulary',28 'PackageReleaseVocabulary',
32 'PPAVocabulary',29 'PPAVocabulary',
@@ -92,15 +89,8 @@
92from lp.bugs.interfaces.bugtracker import BugTrackerType89from lp.bugs.interfaces.bugtracker import BugTrackerType
93from lp.bugs.model.bug import Bug90from lp.bugs.model.bug import Bug
94from lp.bugs.model.bugtracker import BugTracker91from lp.bugs.model.bugtracker import BugTracker
95from lp.code.enums import BranchType
96from lp.code.interfaces.branch import IBranch
97from lp.code.interfaces.branchcollection import IAllBranches
98from lp.code.model.branch import Branch
99from lp.registry.interfaces.distribution import IDistribution92from lp.registry.interfaces.distribution import IDistribution
100from lp.registry.interfaces.distroseries import IDistroSeries93from lp.registry.interfaces.distroseries import IDistroSeries
101from lp.registry.interfaces.person import IPerson
102from lp.registry.interfaces.product import IProduct
103from lp.registry.interfaces.productseries import IProductSeries
104from lp.registry.interfaces.projectgroup import IProjectGroup94from lp.registry.interfaces.projectgroup import IProjectGroup
105from lp.registry.interfaces.series import SeriesStatus95from lp.registry.interfaces.series import SeriesStatus
106from lp.registry.model.distribution import Distribution96from lp.registry.model.distribution import Distribution
@@ -146,106 +136,6 @@
146 return SimpleTerm(obj, obj.id, obj.name)136 return SimpleTerm(obj, obj.id, obj.name)
147137
148138
149class BranchVocabularyBase(SQLObjectVocabularyBase):
150 """A base class for Branch vocabularies.
151
152 Override `BranchVocabularyBase._getCollection` to provide the collection
153 of branches which make up the vocabulary.
154 """
155
156 implements(IHugeVocabulary)
157
158 _table = Branch
159 _orderBy = ['name', 'id']
160 displayname = 'Select a branch'
161
162 def toTerm(self, branch):
163 """The display should include the URL if there is one."""
164 return SimpleTerm(branch, branch.unique_name, branch.unique_name)
165
166 def getTermByToken(self, token):
167 """See `IVocabularyTokenized`."""
168 search_results = self.searchForTerms(token)
169 if search_results.count() == 1:
170 return iter(search_results).next()
171 raise LookupError(token)
172
173 def _getCollection(self):
174 """Override this to return the collection to which the search is
175 restricted.
176 """
177 raise NotImplementedError(self._getCollection)
178
179 def searchForTerms(self, query=None):
180 """See `IHugeVocabulary`."""
181 logged_in_user = getUtility(ILaunchBag).user
182 collection = self._getCollection().visibleByUser(logged_in_user)
183 if query is None:
184 branches = collection.getBranches()
185 else:
186 branches = collection.search(query)
187 return CountableIterator(branches.count(), branches, self.toTerm)
188
189 def __len__(self):
190 """See `IVocabulary`."""
191 return self.search().count()
192
193
194class BranchVocabulary(BranchVocabularyBase):
195 """A vocabulary for searching branches.
196
197 The name and URL of the branch, the name of the product, and the
198 name of the registrant of the branches is checked for the entered
199 value.
200 """
201
202 def _getCollection(self):
203 return getUtility(IAllBranches)
204
205
206class BranchRestrictedOnProductVocabulary(BranchVocabularyBase):
207 """A vocabulary for searching branches restricted on product.
208
209 The query entered checks the name or URL of the branch, or the
210 name of the registrant of the branch.
211 """
212
213 def __init__(self, context=None):
214 BranchVocabularyBase.__init__(self, context)
215 if IProduct.providedBy(self.context):
216 self.product = self.context
217 elif IProductSeries.providedBy(self.context):
218 self.product = self.context.product
219 elif IBranch.providedBy(self.context):
220 self.product = self.context.product
221 else:
222 # An unexpected type.
223 raise AssertionError('Unexpected context type')
224
225 def _getCollection(self):
226 return getUtility(IAllBranches).inProduct(self.product)
227
228
229class HostedBranchRestrictedOnOwnerVocabulary(BranchVocabularyBase):
230 """A vocabulary for hosted branches owned by the current user.
231
232 These are branches that the user is guaranteed to be able to push
233 to.
234 """
235
236 def __init__(self, context=None):
237 """Pass a Person as context, or anything else for the current user."""
238 super(HostedBranchRestrictedOnOwnerVocabulary, self).__init__(context)
239 if IPerson.providedBy(self.context):
240 self.user = context
241 else:
242 self.user = getUtility(ILaunchBag).user
243
244 def _getCollection(self):
245 return getUtility(IAllBranches).ownedBy(self.user).withBranchType(
246 BranchType.HOSTED)
247
248
249class BugVocabulary(SQLObjectVocabularyBase):139class BugVocabulary(SQLObjectVocabularyBase):
250140
251 _table = Bug141 _table = Bug
252142
=== modified file 'lib/canonical/launchpad/webapp/configure.zcml'
--- lib/canonical/launchpad/webapp/configure.zcml 2010-09-10 06:38:15 +0000
+++ lib/canonical/launchpad/webapp/configure.zcml 2010-09-20 22:41:19 +0000
@@ -828,7 +828,7 @@
828 <view828 <view
829 type="zope.publisher.interfaces.browser.IBrowserRequest"829 type="zope.publisher.interfaces.browser.IBrowserRequest"
830 for="zope.schema.interfaces.IChoice830 for="zope.schema.interfaces.IChoice
831 canonical.launchpad.vocabularies.dbobjects.BranchVocabularyBase"831 lp.code.vocabularies.branch.BranchVocabularyBase"
832 provides="zope.app.form.interfaces.IInputWidget"832 provides="zope.app.form.interfaces.IInputWidget"
833 factory="canonical.launchpad.browser.widgets.BranchPopupWidget"833 factory="canonical.launchpad.browser.widgets.BranchPopupWidget"
834 permission="zope.Public"834 permission="zope.Public"
835835
=== modified file 'lib/lp/code/browser/configure.zcml'
--- lib/lp/code/browser/configure.zcml 2010-08-24 02:17:19 +0000
+++ lib/lp/code/browser/configure.zcml 2010-09-20 22:41:19 +0000
@@ -1306,19 +1306,5 @@
1306 factory="canonical.launchpad.webapp.breadcrumb.NameBreadcrumb"1306 factory="canonical.launchpad.webapp.breadcrumb.NameBreadcrumb"
1307 permission="zope.Public"/>1307 permission="zope.Public"/>
1308 </facet>1308 </facet>
1309 <securedutility
1310 name="BuildableDistroSeries"
1311 component="lp.code.vocabularies.sourcepackagerecipe.buildable_distroseries_vocabulary"
1312 provides="zope.schema.interfaces.IVocabularyFactory"
1313 >
1314 <allow interface="zope.schema.interfaces.IVocabularyFactory"/>
1315 </securedutility>
1316 <securedutility
1317 name="TargetPPAs"
1318 component="lp.code.vocabularies.sourcepackagerecipe.target_ppas_vocabulary"
1319 provides="zope.schema.interfaces.IVocabularyFactory"
1320 >
1321 <allow interface="zope.schema.interfaces.IVocabularyFactory"/>
1322 </securedutility>
13231309
1324</configure>1310</configure>
13251311
=== modified file 'lib/lp/code/configure.zcml'
--- lib/lp/code/configure.zcml 2010-09-15 16:03:39 +0000
+++ lib/lp/code/configure.zcml 2010-09-20 22:41:19 +0000
@@ -11,6 +11,7 @@
11 xmlns:webservice="http://namespaces.canonical.com/webservice"11 xmlns:webservice="http://namespaces.canonical.com/webservice"
12 i18n_domain="launchpad">12 i18n_domain="launchpad">
13 <include package=".browser"/>13 <include package=".browser"/>
14 <include package=".vocabularies"/>
14 <authorizations module="lp.code.security" />15 <authorizations module="lp.code.security" />
1516
16 <publisher17 <publisher
1718
=== added file 'lib/lp/code/vocabularies/branch.py'
--- lib/lp/code/vocabularies/branch.py 1970-01-01 00:00:00 +0000
+++ lib/lp/code/vocabularies/branch.py 2010-09-20 22:41:19 +0000
@@ -0,0 +1,133 @@
1# Copyright 2009 Canonical Ltd. This software is licensed under the
2# GNU Affero General Public License version 3 (see the file LICENSE).
3
4"""Vocabularies that contain branches."""
5
6
7__metaclass__ = type
8
9__all__ = [
10 'BranchRestrictedOnProductVocabulary',
11 'BranchVocabulary',
12 'HostedBranchRestrictedOnOwnerVocabulary',
13 ]
14
15from zope.component import getUtility
16from zope.interface import implements
17from zope.schema.vocabulary import SimpleTerm
18
19from canonical.launchpad.webapp.interfaces import ILaunchBag
20from canonical.launchpad.webapp.vocabulary import (
21 CountableIterator,
22 IHugeVocabulary,
23 SQLObjectVocabularyBase,
24 )
25
26from lp.code.enums import BranchType
27from lp.code.interfaces.branch import IBranch
28from lp.code.interfaces.branchcollection import IAllBranches
29from lp.code.model.branch import Branch
30from lp.registry.interfaces.person import IPerson
31from lp.registry.interfaces.product import IProduct
32from lp.registry.interfaces.productseries import IProductSeries
33
34
35class BranchVocabularyBase(SQLObjectVocabularyBase):
36 """A base class for Branch vocabularies.
37
38 Override `BranchVocabularyBase._getCollection` to provide the collection
39 of branches which make up the vocabulary.
40 """
41
42 implements(IHugeVocabulary)
43
44 _table = Branch
45 _orderBy = ['name', 'id']
46 displayname = 'Select a branch'
47
48 def toTerm(self, branch):
49 """The display should include the URL if there is one."""
50 return SimpleTerm(branch, branch.unique_name, branch.unique_name)
51
52 def getTermByToken(self, token):
53 """See `IVocabularyTokenized`."""
54 search_results = self.searchForTerms(token)
55 if search_results.count() == 1:
56 return iter(search_results).next()
57 raise LookupError(token)
58
59 def _getCollection(self):
60 """Return the collection of branches the vocabulary searches.
61
62 Subclasses MUST override and implement this.
63 """
64 raise NotImplementedError(self._getCollection)
65
66 def searchForTerms(self, query=None):
67 """See `IHugeVocabulary`."""
68 logged_in_user = getUtility(ILaunchBag).user
69 collection = self._getCollection().visibleByUser(logged_in_user)
70 if query is None:
71 branches = collection.getBranches()
72 else:
73 branches = collection.search(query)
74 return CountableIterator(branches.count(), branches, self.toTerm)
75
76 def __len__(self):
77 """See `IVocabulary`."""
78 return self.search().count()
79
80
81class BranchVocabulary(BranchVocabularyBase):
82 """A vocabulary for searching branches.
83
84 The name and URL of the branch, the name of the product, and the
85 name of the registrant of the branches is checked for the entered
86 value.
87 """
88
89 def _getCollection(self):
90 return getUtility(IAllBranches)
91
92
93class BranchRestrictedOnProductVocabulary(BranchVocabularyBase):
94 """A vocabulary for searching branches restricted on product.
95
96 The query entered checks the name or URL of the branch, or the
97 name of the registrant of the branch.
98 """
99
100 def __init__(self, context=None):
101 BranchVocabularyBase.__init__(self, context)
102 if IProduct.providedBy(self.context):
103 self.product = self.context
104 elif IProductSeries.providedBy(self.context):
105 self.product = self.context.product
106 elif IBranch.providedBy(self.context):
107 self.product = self.context.product
108 else:
109 # An unexpected type.
110 raise AssertionError('Unexpected context type')
111
112 def _getCollection(self):
113 return getUtility(IAllBranches).inProduct(self.product)
114
115
116class HostedBranchRestrictedOnOwnerVocabulary(BranchVocabularyBase):
117 """A vocabulary for hosted branches owned by the current user.
118
119 These are branches that the user is guaranteed to be able to push
120 to.
121 """
122
123 def __init__(self, context=None):
124 """Pass a Person as context, or anything else for the current user."""
125 super(HostedBranchRestrictedOnOwnerVocabulary, self).__init__(context)
126 if IPerson.providedBy(self.context):
127 self.user = context
128 else:
129 self.user = getUtility(ILaunchBag).user
130
131 def _getCollection(self):
132 return getUtility(IAllBranches).ownedBy(self.user).withBranchType(
133 BranchType.HOSTED)
0134
=== added file 'lib/lp/code/vocabularies/configure.zcml'
--- lib/lp/code/vocabularies/configure.zcml 1970-01-01 00:00:00 +0000
+++ lib/lp/code/vocabularies/configure.zcml 2010-09-20 22:41:19 +0000
@@ -0,0 +1,54 @@
1<!-- Copyright 2010 Canonical Ltd. This software is licensed under the
2 GNU Affero General Public License version 3 (see the file LICENSE).
3-->
4
5<configure xmlns="http://namespaces.zope.org/zope">
6
7 <securedutility
8 name="BuildableDistroSeries"
9 component=".sourcepackagerecipe.buildable_distroseries_vocabulary"
10 provides="zope.schema.interfaces.IVocabularyFactory">
11 <allow interface="zope.schema.interfaces.IVocabularyFactory"/>
12 </securedutility>
13
14 <securedutility
15 name="TargetPPAs"
16 component=".sourcepackagerecipe.target_ppas_vocabulary"
17 provides="zope.schema.interfaces.IVocabularyFactory">
18 <allow interface="zope.schema.interfaces.IVocabularyFactory"/>
19 </securedutility>
20
21 <securedutility
22 name="Branch"
23 component=".branch.BranchVocabulary"
24 provides="zope.schema.interfaces.IVocabularyFactory">
25 <allow interface="zope.schema.interfaces.IVocabularyFactory"/>
26 </securedutility>
27
28 <class class=".branch.BranchVocabulary">
29 <allow interface="canonical.launchpad.webapp.vocabulary.IHugeVocabulary"/>
30 </class>
31
32 <securedutility
33 name="HostedBranchRestrictedOnOwner"
34 component=".branch.HostedBranchRestrictedOnOwnerVocabulary"
35 provides="zope.schema.interfaces.IVocabularyFactory">
36 <allow interface="zope.schema.interfaces.IVocabularyFactory"/>
37 </securedutility>
38
39 <class class=".branch.HostedBranchRestrictedOnOwnerVocabulary">
40 <allow interface="canonical.launchpad.webapp.vocabulary.IHugeVocabulary"/>
41 </class>
42
43 <securedutility
44 name="BranchRestrictedOnProduct"
45 component=".branch.BranchRestrictedOnProductVocabulary"
46 provides="zope.schema.interfaces.IVocabularyFactory">
47 <allow interface="zope.schema.interfaces.IVocabularyFactory"/>
48 </securedutility>
49
50 <class class=".branch.BranchRestrictedOnProductVocabulary">
51 <allow interface="canonical.launchpad.webapp.vocabulary.IHugeVocabulary"/>
52 </class>
53
54</configure>
055
=== added file 'lib/lp/code/vocabularies/tests/branch.txt'
--- lib/lp/code/vocabularies/tests/branch.txt 1970-01-01 00:00:00 +0000
+++ lib/lp/code/vocabularies/tests/branch.txt 2010-09-20 22:41:19 +0000
@@ -0,0 +1,148 @@
1Branch Vocabularies
2===================
3
4Launchpad has a few vocabularies that contain branches filtered in
5various ways.
6
7 >>> from zope.schema.vocabulary import getVocabularyRegistry
8 >>> vocabulary_registry = getVocabularyRegistry()
9
10BranchVocabulary
11----------------
12
13The list of bzr branches registered in Launchpad.
14
15Searchable by branch name or URL, registrant name, and project name.
16Results are not restricted in any way by the context, but the results
17are restricted based on who is asking (as far as private branches is
18concerned).
19
20 # Just use None as the context.
21 >>> branch_vocabulary = vocabulary_registry.get(None, "Branch")
22 >>> def print_vocab_branches(vocab, search):
23 ... for term in vocab.searchForTerms(search):
24 ... print term.value.unique_name
25
26 >>> print_vocab_branches(branch_vocabulary, 'main')
27 ~name12/firefox/main
28 ~stevea/thunderbird/main
29 ~justdave/+junk/main
30 ~kiko/+junk/main
31 ~vcs-imports/evolution/main
32 ~name12/gnome-terminal/main
33
34 >>> print_vocab_branches(branch_vocabulary, 'vcs-imports')
35 ~vcs-imports/gnome-terminal/import
36 ~vcs-imports/evolution/import
37 ~vcs-imports/evolution/main
38
39 >>> print_vocab_branches(branch_vocabulary, 'evolution')
40 ~carlos/evolution/2.0
41 ~vcs-imports/evolution/import
42 ~vcs-imports/evolution/main
43
44A search with the full branch unique name should also find the branch.
45
46 >>> print_vocab_branches(branch_vocabulary, '~name12/firefox/main')
47 ~name12/firefox/main
48
49The tokens used by terms retrieved from BranchVocabulary use the
50branch unique name as an ID:
51
52 >>> from lp.code.interfaces.branchlookup import IBranchLookup
53 >>> branch = getUtility(IBranchLookup).get(15)
54 >>> print branch.unique_name
55 ~name12/gnome-terminal/main
56 >>> from zope.security.proxy import removeSecurityProxy
57 >>> term = removeSecurityProxy(branch_vocabulary).toTerm(branch)
58 >>> print term.token
59 ~name12/gnome-terminal/main
60
61The BranchVocabulary recognises both unique names and URLs as tokens:
62
63 >>> term = branch_vocabulary.getTermByToken('~name12/gnome-terminal/main')
64 >>> term.value == branch
65 True
66 >>> term = branch_vocabulary.getTermByToken(
67 ... 'http://bazaar.launchpad.dev/~name12/gnome-terminal/main/')
68 >>> term.value == branch
69 True
70 >>> term = branch_vocabulary.getTermByToken(
71 ... 'http://example.com/gnome-terminal/main')
72 >>> term.value == branch
73 True
74
75The searches that the BranchVocabulary does are private branch aware.
76The results are effectively filtered on what the logged in user is
77able to see.
78
79 >>> from lp.testing import login, ANONYMOUS
80 >>> from lp.testing.sampledata import ADMIN_EMAIL
81
82 >>> login(ADMIN_EMAIL)
83 >>> print_vocab_branches(branch_vocabulary, 'trunk')
84 ~spiv/+junk/trunk
85 ~limi/+junk/trunk
86 ~landscape-developers/landscape/trunk
87
88 >>> login(ANONYMOUS)
89 >>> print_vocab_branches(branch_vocabulary, 'trunk')
90 ~spiv/+junk/trunk
91 ~limi/+junk/trunk
92
93
94BranchRestrictedOnProduct
95-------------------------
96
97The BranchRestrictedOnProduct vocabulary restricts the result set to
98those of the product of the context. Currently only two types of
99context are supported: Product; and Branch. If a branch is the context,
100then the product of the branch is used to restrict the query.
101
102 >>> from lp.registry.interfaces.product import IProductSet
103 >>> gnome_terminal = getUtility(IProductSet)["gnome-terminal"]
104 >>> branch_vocabulary = vocabulary_registry.get(
105 ... gnome_terminal, "BranchRestrictedOnProduct")
106 >>> print_vocab_branches(branch_vocabulary, 'main')
107 ~name12/gnome-terminal/main
108
109 >>> print_vocab_branches(branch_vocabulary, 'vcs-imports')
110 ~vcs-imports/gnome-terminal/import
111
112If a full unique name is entered that has a different product, the
113branch is not part of the vocabulary.
114
115 >>> print_vocab_branches(branch_vocabulary, '~name12/gnome-terminal/main')
116 ~name12/gnome-terminal/main
117
118 >>> print_vocab_branches(branch_vocabulary, '~name12/firefox/main')
119
120
121The BranchRestrictedOnProduct behaves the same way as the more generic
122BranchVocabulary with respect to the tokens and privacy awareness.
123
124
125HostedBranchRestrictedOnOwner
126-----------------------------
127
128Here's a vocabulary for all hosted branches owned by the current user.
129
130 >>> from lp.code.enums import BranchType
131
132 >>> a_user = factory.makePerson(name='a-branching-user')
133 >>> product1 = factory.makeProduct(name='product-one')
134 >>> mirrored_branch = factory.makeBranch(
135 ... owner=a_user, product=product1, name='mirrored',
136 ... branch_type=BranchType.MIRRORED)
137 >>> product2 = factory.makeProduct(name='product-two')
138 >>> hosted_branch = factory.makeBranch(
139 ... owner=a_user, product=product2, name='hosted')
140 >>> foreign_branch = factory.makeBranch()
141
142It returns branches owned by the user, but not ones owned by others, nor
143ones that aren't hosted on Launchpad.
144
145 >>> branch_vocabulary = vocabulary_registry.get(
146 ... a_user, "HostedBranchRestrictedOnOwner")
147 >>> print_vocab_branches(branch_vocabulary, None)
148 ~a-branching-user/product-two/hosted
0149
=== modified file 'lib/lp/code/vocabularies/tests/test_branch_vocabularies.py'
--- lib/lp/code/vocabularies/tests/test_branch_vocabularies.py 2010-08-20 20:31:18 +0000
+++ lib/lp/code/vocabularies/tests/test_branch_vocabularies.py 2010-09-20 22:41:19 +0000
@@ -17,7 +17,7 @@
17 login,17 login,
18 logout,18 logout,
19 )19 )
20from canonical.launchpad.vocabularies.dbobjects import (20from lp.code.vocabularies.branch import (
21 BranchRestrictedOnProductVocabulary,21 BranchRestrictedOnProductVocabulary,
22 BranchVocabulary,22 BranchVocabulary,
23 )23 )
2424
=== added file 'lib/lp/code/vocabularies/tests/test_doc.py'
--- lib/lp/code/vocabularies/tests/test_doc.py 1970-01-01 00:00:00 +0000
+++ lib/lp/code/vocabularies/tests/test_doc.py 2010-09-20 22:41:19 +0000
@@ -0,0 +1,17 @@
1# Copyright 2010 Canonical Ltd. This software is licensed under the
2# GNU Affero General Public License version 3 (see the file LICENSE).
3
4"""
5Run the doctests.
6"""
7
8import os
9
10from lp.services.testing import build_doctest_suite
11
12
13here = os.path.dirname(os.path.realpath(__file__))
14
15
16def test_suite():
17 return build_doctest_suite(here, '')