Merge lp:~mwhudson/launchpad/move-some-code-vocabularies into lp:launchpad
- move-some-code-vocabularies
- Merge into devel
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 |
Related bugs: |
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.
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'lib/canonical/launchpad/browser/tests/test_widgets.py' |
2 | --- lib/canonical/launchpad/browser/tests/test_widgets.py 2010-08-20 20:31:18 +0000 |
3 | +++ lib/canonical/launchpad/browser/tests/test_widgets.py 2010-09-20 22:41:19 +0000 |
4 | @@ -24,7 +24,7 @@ |
5 | login, |
6 | logout, |
7 | ) |
8 | -from canonical.launchpad.vocabularies import ( |
9 | +from lp.code.vocabularies.branch import ( |
10 | BranchRestrictedOnProductVocabulary, |
11 | BranchVocabulary, |
12 | ) |
13 | |
14 | === modified file 'lib/canonical/launchpad/doc/vocabularies.txt' |
15 | --- lib/canonical/launchpad/doc/vocabularies.txt 2010-08-27 14:27:22 +0000 |
16 | +++ lib/canonical/launchpad/doc/vocabularies.txt 2010-09-20 22:41:19 +0000 |
17 | @@ -364,143 +364,6 @@ |
18 | [('pmount', u'pmount')] |
19 | |
20 | |
21 | -BranchVocabulary |
22 | -................ |
23 | - |
24 | -The list of bzr branches registered in Launchpad. |
25 | - |
26 | -Searchable by branch name or URL, registrant name, and project name. |
27 | -Results are not restricted in any way by the context, but the results |
28 | -are restricted based on who is asking (as far as private branches is |
29 | -concerned). |
30 | - |
31 | - # Just use None as the context. |
32 | - >>> branch_vocabulary = get_naked_vocab(None, "Branch") |
33 | - >>> def print_vocab_branches(vocab, search): |
34 | - ... for term in vocab.searchForTerms(search): |
35 | - ... print term.value.unique_name |
36 | - |
37 | - >>> print_vocab_branches(branch_vocabulary, 'main') |
38 | - ~name12/firefox/main |
39 | - ~stevea/thunderbird/main |
40 | - ~justdave/+junk/main |
41 | - ~kiko/+junk/main |
42 | - ~vcs-imports/evolution/main |
43 | - ~name12/gnome-terminal/main |
44 | - |
45 | - >>> print_vocab_branches(branch_vocabulary, 'vcs-imports') |
46 | - ~vcs-imports/gnome-terminal/import |
47 | - ~vcs-imports/evolution/import |
48 | - ~vcs-imports/evolution/main |
49 | - |
50 | - >>> print_vocab_branches(branch_vocabulary, 'evolution') |
51 | - ~carlos/evolution/2.0 |
52 | - ~vcs-imports/evolution/import |
53 | - ~vcs-imports/evolution/main |
54 | - |
55 | -A search with the full branch unique name should also find the branch. |
56 | - |
57 | - >>> print_vocab_branches(branch_vocabulary, '~name12/firefox/main') |
58 | - ~name12/firefox/main |
59 | - |
60 | -The tokens used by terms retrieved from BranchVocabulary use the |
61 | -branch unique name as an ID: |
62 | - |
63 | - >>> from lp.code.interfaces.branchlookup import IBranchLookup |
64 | - >>> branch = getUtility(IBranchLookup).get(15) |
65 | - >>> print branch.unique_name |
66 | - ~name12/gnome-terminal/main |
67 | - >>> term = branch_vocabulary.toTerm(branch) |
68 | - >>> print term.token |
69 | - ~name12/gnome-terminal/main |
70 | - |
71 | -The BranchVocabulary recognises both unique names and URLs as tokens: |
72 | - |
73 | - >>> term = branch_vocabulary.getTermByToken('~name12/gnome-terminal/main') |
74 | - >>> term.value == branch |
75 | - True |
76 | - >>> term = branch_vocabulary.getTermByToken( |
77 | - ... 'http://bazaar.launchpad.dev/~name12/gnome-terminal/main/') |
78 | - >>> term.value == branch |
79 | - True |
80 | - >>> term = branch_vocabulary.getTermByToken( |
81 | - ... 'http://example.com/gnome-terminal/main') |
82 | - >>> term.value == branch |
83 | - True |
84 | - |
85 | -The searches that the BranchVocabulary does are private branch aware. |
86 | -The results are effectively filtered on what the logged in user is |
87 | -able to see. |
88 | - |
89 | - >>> print_vocab_branches(branch_vocabulary, 'trunk') |
90 | - ~spiv/+junk/trunk |
91 | - ~limi/+junk/trunk |
92 | - ~landscape-developers/landscape/trunk |
93 | - |
94 | - >>> login('no-priv@canonical.com') |
95 | - >>> print_vocab_branches(branch_vocabulary, 'trunk') |
96 | - ~spiv/+junk/trunk |
97 | - ~limi/+junk/trunk |
98 | - |
99 | - >>> login('foo.bar@canonical.com') |
100 | - |
101 | - |
102 | -BranchRestrictedOnProduct |
103 | -......................... |
104 | - |
105 | -The BranchRestrictedOnProduct vocabulary restricts the result set to |
106 | -those of the product of the context. Currently only two types of |
107 | -context are supported: Product; and Branch. If a branch is the context, |
108 | -then the product of the branch is used to restrict the query. |
109 | - |
110 | - >>> gnome_terminal = getUtility(IProductSet)["gnome-terminal"] |
111 | - >>> branch_vocabulary = vocabulary_registry.get( |
112 | - ... gnome_terminal, "BranchRestrictedOnProduct") |
113 | - >>> print_vocab_branches(branch_vocabulary, 'main') |
114 | - ~name12/gnome-terminal/main |
115 | - |
116 | - >>> print_vocab_branches(branch_vocabulary, 'vcs-imports') |
117 | - ~vcs-imports/gnome-terminal/import |
118 | - |
119 | -If a full unique name is entered that has a different product, the |
120 | -branch is not part of the vocabulary. |
121 | - |
122 | - >>> print_vocab_branches(branch_vocabulary, '~name12/gnome-terminal/main') |
123 | - ~name12/gnome-terminal/main |
124 | - |
125 | - >>> print_vocab_branches(branch_vocabulary, '~name12/firefox/main') |
126 | - |
127 | - |
128 | -The BranchRestrictedOnProduct behaves the same way as the more generic |
129 | -BranchVocabulary with respect to the tokens and privacy awareness. |
130 | - |
131 | - |
132 | -HostedBranchRestrictedOnOwner |
133 | -............................. |
134 | - |
135 | -Here's a vocabulary for all hosted branches owned by the current user. |
136 | - |
137 | - >>> from lp.code.enums import BranchType |
138 | - |
139 | - >>> a_user = factory.makePerson(name='a-branching-user') |
140 | - >>> product1 = factory.makeProduct(name='product-one') |
141 | - >>> mirrored_branch = factory.makeBranch( |
142 | - ... owner=a_user, product=product1, name='mirrored', |
143 | - ... branch_type=BranchType.MIRRORED) |
144 | - >>> product2 = factory.makeProduct(name='product-two') |
145 | - >>> hosted_branch = factory.makeBranch( |
146 | - ... owner=a_user, product=product2, name='hosted') |
147 | - >>> foreign_branch = factory.makeBranch() |
148 | - |
149 | -It returns branches owned by the user, but not ones owned by others, nor |
150 | -ones that aren't hosted on Launchpad. |
151 | - |
152 | - >>> branch_vocabulary = vocabulary_registry.get( |
153 | - ... a_user, "HostedBranchRestrictedOnOwner") |
154 | - >>> print_vocab_branches(branch_vocabulary, None) |
155 | - ~a-branching-user/product-two/hosted |
156 | - |
157 | - |
158 | Processor |
159 | ......... |
160 | |
161 | |
162 | === modified file 'lib/canonical/launchpad/vocabularies/configure.zcml' |
163 | --- lib/canonical/launchpad/vocabularies/configure.zcml 2010-08-25 04:12:59 +0000 |
164 | +++ lib/canonical/launchpad/vocabularies/configure.zcml 2010-09-20 22:41:19 +0000 |
165 | @@ -13,45 +13,6 @@ |
166 | </class> |
167 | |
168 | <securedutility |
169 | - name="Branch" |
170 | - component="canonical.launchpad.vocabularies.BranchVocabulary" |
171 | - provides="zope.schema.interfaces.IVocabularyFactory" |
172 | - > |
173 | - <allow interface="zope.schema.interfaces.IVocabularyFactory"/> |
174 | - </securedutility> |
175 | - |
176 | - <class class="canonical.launchpad.vocabularies.BranchVocabulary"> |
177 | - <allow interface="canonical.launchpad.webapp.vocabulary.IHugeVocabulary"/> |
178 | - </class> |
179 | - |
180 | - |
181 | - <securedutility |
182 | - name="HostedBranchRestrictedOnOwner" |
183 | - component="canonical.launchpad.vocabularies.HostedBranchRestrictedOnOwnerVocabulary" |
184 | - provides="zope.schema.interfaces.IVocabularyFactory" |
185 | - > |
186 | - <allow interface="zope.schema.interfaces.IVocabularyFactory"/> |
187 | - </securedutility> |
188 | - |
189 | - <class class="canonical.launchpad.vocabularies.HostedBranchRestrictedOnOwnerVocabulary"> |
190 | - <allow interface="canonical.launchpad.webapp.vocabulary.IHugeVocabulary"/> |
191 | - </class> |
192 | - |
193 | - |
194 | - <securedutility |
195 | - name="BranchRestrictedOnProduct" |
196 | - component="canonical.launchpad.vocabularies.BranchRestrictedOnProductVocabulary" |
197 | - provides="zope.schema.interfaces.IVocabularyFactory" |
198 | - > |
199 | - <allow interface="zope.schema.interfaces.IVocabularyFactory"/> |
200 | - </securedutility> |
201 | - |
202 | - <class class="canonical.launchpad.vocabularies.BranchRestrictedOnProductVocabulary"> |
203 | - <allow interface="canonical.launchpad.webapp.vocabulary.IHugeVocabulary"/> |
204 | - </class> |
205 | - |
206 | - |
207 | - <securedutility |
208 | name="Bug" |
209 | component="canonical.launchpad.vocabularies.BugVocabulary" |
210 | provides="zope.schema.interfaces.IVocabularyFactory" |
211 | |
212 | === modified file 'lib/canonical/launchpad/vocabularies/dbobjects.py' |
213 | --- lib/canonical/launchpad/vocabularies/dbobjects.py 2010-08-27 14:27:22 +0000 |
214 | +++ lib/canonical/launchpad/vocabularies/dbobjects.py 2010-09-20 22:41:19 +0000 |
215 | @@ -1,5 +1,5 @@ |
216 | -# Copyright 2009 Canonical Ltd. This software is licensed under the |
217 | -# GNU Affero General Public License version 3 (see the file LICENSE). |
218 | +# Copyright 2009, 2010 Canonical Ltd. This software is licensed under the GNU |
219 | +# Affero General Public License version 3 (see the file LICENSE). |
220 | |
221 | """Vocabularies pulling stuff from the database. |
222 | |
223 | @@ -10,8 +10,6 @@ |
224 | __metaclass__ = type |
225 | |
226 | __all__ = [ |
227 | - 'BranchRestrictedOnProductVocabulary', |
228 | - 'BranchVocabulary', |
229 | 'BugNominatableDistroSeriesVocabulary', |
230 | 'BugNominatableProductSeriesVocabulary', |
231 | 'BugNominatableSeriesVocabulary', |
232 | @@ -26,7 +24,6 @@ |
233 | 'FilteredFullLanguagePackVocabulary', |
234 | 'FilteredLanguagePackVocabulary', |
235 | 'FutureSprintVocabulary', |
236 | - 'HostedBranchRestrictedOnOwnerVocabulary', |
237 | 'LanguageVocabulary', |
238 | 'PackageReleaseVocabulary', |
239 | 'PPAVocabulary', |
240 | @@ -92,15 +89,8 @@ |
241 | from lp.bugs.interfaces.bugtracker import BugTrackerType |
242 | from lp.bugs.model.bug import Bug |
243 | from lp.bugs.model.bugtracker import BugTracker |
244 | -from lp.code.enums import BranchType |
245 | -from lp.code.interfaces.branch import IBranch |
246 | -from lp.code.interfaces.branchcollection import IAllBranches |
247 | -from lp.code.model.branch import Branch |
248 | from lp.registry.interfaces.distribution import IDistribution |
249 | from lp.registry.interfaces.distroseries import IDistroSeries |
250 | -from lp.registry.interfaces.person import IPerson |
251 | -from lp.registry.interfaces.product import IProduct |
252 | -from lp.registry.interfaces.productseries import IProductSeries |
253 | from lp.registry.interfaces.projectgroup import IProjectGroup |
254 | from lp.registry.interfaces.series import SeriesStatus |
255 | from lp.registry.model.distribution import Distribution |
256 | @@ -146,106 +136,6 @@ |
257 | return SimpleTerm(obj, obj.id, obj.name) |
258 | |
259 | |
260 | -class BranchVocabularyBase(SQLObjectVocabularyBase): |
261 | - """A base class for Branch vocabularies. |
262 | - |
263 | - Override `BranchVocabularyBase._getCollection` to provide the collection |
264 | - of branches which make up the vocabulary. |
265 | - """ |
266 | - |
267 | - implements(IHugeVocabulary) |
268 | - |
269 | - _table = Branch |
270 | - _orderBy = ['name', 'id'] |
271 | - displayname = 'Select a branch' |
272 | - |
273 | - def toTerm(self, branch): |
274 | - """The display should include the URL if there is one.""" |
275 | - return SimpleTerm(branch, branch.unique_name, branch.unique_name) |
276 | - |
277 | - def getTermByToken(self, token): |
278 | - """See `IVocabularyTokenized`.""" |
279 | - search_results = self.searchForTerms(token) |
280 | - if search_results.count() == 1: |
281 | - return iter(search_results).next() |
282 | - raise LookupError(token) |
283 | - |
284 | - def _getCollection(self): |
285 | - """Override this to return the collection to which the search is |
286 | - restricted. |
287 | - """ |
288 | - raise NotImplementedError(self._getCollection) |
289 | - |
290 | - def searchForTerms(self, query=None): |
291 | - """See `IHugeVocabulary`.""" |
292 | - logged_in_user = getUtility(ILaunchBag).user |
293 | - collection = self._getCollection().visibleByUser(logged_in_user) |
294 | - if query is None: |
295 | - branches = collection.getBranches() |
296 | - else: |
297 | - branches = collection.search(query) |
298 | - return CountableIterator(branches.count(), branches, self.toTerm) |
299 | - |
300 | - def __len__(self): |
301 | - """See `IVocabulary`.""" |
302 | - return self.search().count() |
303 | - |
304 | - |
305 | -class BranchVocabulary(BranchVocabularyBase): |
306 | - """A vocabulary for searching branches. |
307 | - |
308 | - The name and URL of the branch, the name of the product, and the |
309 | - name of the registrant of the branches is checked for the entered |
310 | - value. |
311 | - """ |
312 | - |
313 | - def _getCollection(self): |
314 | - return getUtility(IAllBranches) |
315 | - |
316 | - |
317 | -class BranchRestrictedOnProductVocabulary(BranchVocabularyBase): |
318 | - """A vocabulary for searching branches restricted on product. |
319 | - |
320 | - The query entered checks the name or URL of the branch, or the |
321 | - name of the registrant of the branch. |
322 | - """ |
323 | - |
324 | - def __init__(self, context=None): |
325 | - BranchVocabularyBase.__init__(self, context) |
326 | - if IProduct.providedBy(self.context): |
327 | - self.product = self.context |
328 | - elif IProductSeries.providedBy(self.context): |
329 | - self.product = self.context.product |
330 | - elif IBranch.providedBy(self.context): |
331 | - self.product = self.context.product |
332 | - else: |
333 | - # An unexpected type. |
334 | - raise AssertionError('Unexpected context type') |
335 | - |
336 | - def _getCollection(self): |
337 | - return getUtility(IAllBranches).inProduct(self.product) |
338 | - |
339 | - |
340 | -class HostedBranchRestrictedOnOwnerVocabulary(BranchVocabularyBase): |
341 | - """A vocabulary for hosted branches owned by the current user. |
342 | - |
343 | - These are branches that the user is guaranteed to be able to push |
344 | - to. |
345 | - """ |
346 | - |
347 | - def __init__(self, context=None): |
348 | - """Pass a Person as context, or anything else for the current user.""" |
349 | - super(HostedBranchRestrictedOnOwnerVocabulary, self).__init__(context) |
350 | - if IPerson.providedBy(self.context): |
351 | - self.user = context |
352 | - else: |
353 | - self.user = getUtility(ILaunchBag).user |
354 | - |
355 | - def _getCollection(self): |
356 | - return getUtility(IAllBranches).ownedBy(self.user).withBranchType( |
357 | - BranchType.HOSTED) |
358 | - |
359 | - |
360 | class BugVocabulary(SQLObjectVocabularyBase): |
361 | |
362 | _table = Bug |
363 | |
364 | === modified file 'lib/canonical/launchpad/webapp/configure.zcml' |
365 | --- lib/canonical/launchpad/webapp/configure.zcml 2010-09-10 06:38:15 +0000 |
366 | +++ lib/canonical/launchpad/webapp/configure.zcml 2010-09-20 22:41:19 +0000 |
367 | @@ -828,7 +828,7 @@ |
368 | <view |
369 | type="zope.publisher.interfaces.browser.IBrowserRequest" |
370 | for="zope.schema.interfaces.IChoice |
371 | - canonical.launchpad.vocabularies.dbobjects.BranchVocabularyBase" |
372 | + lp.code.vocabularies.branch.BranchVocabularyBase" |
373 | provides="zope.app.form.interfaces.IInputWidget" |
374 | factory="canonical.launchpad.browser.widgets.BranchPopupWidget" |
375 | permission="zope.Public" |
376 | |
377 | === modified file 'lib/lp/code/browser/configure.zcml' |
378 | --- lib/lp/code/browser/configure.zcml 2010-08-24 02:17:19 +0000 |
379 | +++ lib/lp/code/browser/configure.zcml 2010-09-20 22:41:19 +0000 |
380 | @@ -1306,19 +1306,5 @@ |
381 | factory="canonical.launchpad.webapp.breadcrumb.NameBreadcrumb" |
382 | permission="zope.Public"/> |
383 | </facet> |
384 | - <securedutility |
385 | - name="BuildableDistroSeries" |
386 | - component="lp.code.vocabularies.sourcepackagerecipe.buildable_distroseries_vocabulary" |
387 | - provides="zope.schema.interfaces.IVocabularyFactory" |
388 | - > |
389 | - <allow interface="zope.schema.interfaces.IVocabularyFactory"/> |
390 | - </securedutility> |
391 | - <securedutility |
392 | - name="TargetPPAs" |
393 | - component="lp.code.vocabularies.sourcepackagerecipe.target_ppas_vocabulary" |
394 | - provides="zope.schema.interfaces.IVocabularyFactory" |
395 | - > |
396 | - <allow interface="zope.schema.interfaces.IVocabularyFactory"/> |
397 | - </securedutility> |
398 | |
399 | </configure> |
400 | |
401 | === modified file 'lib/lp/code/configure.zcml' |
402 | --- lib/lp/code/configure.zcml 2010-09-15 16:03:39 +0000 |
403 | +++ lib/lp/code/configure.zcml 2010-09-20 22:41:19 +0000 |
404 | @@ -11,6 +11,7 @@ |
405 | xmlns:webservice="http://namespaces.canonical.com/webservice" |
406 | i18n_domain="launchpad"> |
407 | <include package=".browser"/> |
408 | + <include package=".vocabularies"/> |
409 | <authorizations module="lp.code.security" /> |
410 | |
411 | <publisher |
412 | |
413 | === added file 'lib/lp/code/vocabularies/branch.py' |
414 | --- lib/lp/code/vocabularies/branch.py 1970-01-01 00:00:00 +0000 |
415 | +++ lib/lp/code/vocabularies/branch.py 2010-09-20 22:41:19 +0000 |
416 | @@ -0,0 +1,133 @@ |
417 | +# Copyright 2009 Canonical Ltd. This software is licensed under the |
418 | +# GNU Affero General Public License version 3 (see the file LICENSE). |
419 | + |
420 | +"""Vocabularies that contain branches.""" |
421 | + |
422 | + |
423 | +__metaclass__ = type |
424 | + |
425 | +__all__ = [ |
426 | + 'BranchRestrictedOnProductVocabulary', |
427 | + 'BranchVocabulary', |
428 | + 'HostedBranchRestrictedOnOwnerVocabulary', |
429 | + ] |
430 | + |
431 | +from zope.component import getUtility |
432 | +from zope.interface import implements |
433 | +from zope.schema.vocabulary import SimpleTerm |
434 | + |
435 | +from canonical.launchpad.webapp.interfaces import ILaunchBag |
436 | +from canonical.launchpad.webapp.vocabulary import ( |
437 | + CountableIterator, |
438 | + IHugeVocabulary, |
439 | + SQLObjectVocabularyBase, |
440 | + ) |
441 | + |
442 | +from lp.code.enums import BranchType |
443 | +from lp.code.interfaces.branch import IBranch |
444 | +from lp.code.interfaces.branchcollection import IAllBranches |
445 | +from lp.code.model.branch import Branch |
446 | +from lp.registry.interfaces.person import IPerson |
447 | +from lp.registry.interfaces.product import IProduct |
448 | +from lp.registry.interfaces.productseries import IProductSeries |
449 | + |
450 | + |
451 | +class BranchVocabularyBase(SQLObjectVocabularyBase): |
452 | + """A base class for Branch vocabularies. |
453 | + |
454 | + Override `BranchVocabularyBase._getCollection` to provide the collection |
455 | + of branches which make up the vocabulary. |
456 | + """ |
457 | + |
458 | + implements(IHugeVocabulary) |
459 | + |
460 | + _table = Branch |
461 | + _orderBy = ['name', 'id'] |
462 | + displayname = 'Select a branch' |
463 | + |
464 | + def toTerm(self, branch): |
465 | + """The display should include the URL if there is one.""" |
466 | + return SimpleTerm(branch, branch.unique_name, branch.unique_name) |
467 | + |
468 | + def getTermByToken(self, token): |
469 | + """See `IVocabularyTokenized`.""" |
470 | + search_results = self.searchForTerms(token) |
471 | + if search_results.count() == 1: |
472 | + return iter(search_results).next() |
473 | + raise LookupError(token) |
474 | + |
475 | + def _getCollection(self): |
476 | + """Return the collection of branches the vocabulary searches. |
477 | + |
478 | + Subclasses MUST override and implement this. |
479 | + """ |
480 | + raise NotImplementedError(self._getCollection) |
481 | + |
482 | + def searchForTerms(self, query=None): |
483 | + """See `IHugeVocabulary`.""" |
484 | + logged_in_user = getUtility(ILaunchBag).user |
485 | + collection = self._getCollection().visibleByUser(logged_in_user) |
486 | + if query is None: |
487 | + branches = collection.getBranches() |
488 | + else: |
489 | + branches = collection.search(query) |
490 | + return CountableIterator(branches.count(), branches, self.toTerm) |
491 | + |
492 | + def __len__(self): |
493 | + """See `IVocabulary`.""" |
494 | + return self.search().count() |
495 | + |
496 | + |
497 | +class BranchVocabulary(BranchVocabularyBase): |
498 | + """A vocabulary for searching branches. |
499 | + |
500 | + The name and URL of the branch, the name of the product, and the |
501 | + name of the registrant of the branches is checked for the entered |
502 | + value. |
503 | + """ |
504 | + |
505 | + def _getCollection(self): |
506 | + return getUtility(IAllBranches) |
507 | + |
508 | + |
509 | +class BranchRestrictedOnProductVocabulary(BranchVocabularyBase): |
510 | + """A vocabulary for searching branches restricted on product. |
511 | + |
512 | + The query entered checks the name or URL of the branch, or the |
513 | + name of the registrant of the branch. |
514 | + """ |
515 | + |
516 | + def __init__(self, context=None): |
517 | + BranchVocabularyBase.__init__(self, context) |
518 | + if IProduct.providedBy(self.context): |
519 | + self.product = self.context |
520 | + elif IProductSeries.providedBy(self.context): |
521 | + self.product = self.context.product |
522 | + elif IBranch.providedBy(self.context): |
523 | + self.product = self.context.product |
524 | + else: |
525 | + # An unexpected type. |
526 | + raise AssertionError('Unexpected context type') |
527 | + |
528 | + def _getCollection(self): |
529 | + return getUtility(IAllBranches).inProduct(self.product) |
530 | + |
531 | + |
532 | +class HostedBranchRestrictedOnOwnerVocabulary(BranchVocabularyBase): |
533 | + """A vocabulary for hosted branches owned by the current user. |
534 | + |
535 | + These are branches that the user is guaranteed to be able to push |
536 | + to. |
537 | + """ |
538 | + |
539 | + def __init__(self, context=None): |
540 | + """Pass a Person as context, or anything else for the current user.""" |
541 | + super(HostedBranchRestrictedOnOwnerVocabulary, self).__init__(context) |
542 | + if IPerson.providedBy(self.context): |
543 | + self.user = context |
544 | + else: |
545 | + self.user = getUtility(ILaunchBag).user |
546 | + |
547 | + def _getCollection(self): |
548 | + return getUtility(IAllBranches).ownedBy(self.user).withBranchType( |
549 | + BranchType.HOSTED) |
550 | |
551 | === added file 'lib/lp/code/vocabularies/configure.zcml' |
552 | --- lib/lp/code/vocabularies/configure.zcml 1970-01-01 00:00:00 +0000 |
553 | +++ lib/lp/code/vocabularies/configure.zcml 2010-09-20 22:41:19 +0000 |
554 | @@ -0,0 +1,54 @@ |
555 | +<!-- Copyright 2010 Canonical Ltd. This software is licensed under the |
556 | + GNU Affero General Public License version 3 (see the file LICENSE). |
557 | +--> |
558 | + |
559 | +<configure xmlns="http://namespaces.zope.org/zope"> |
560 | + |
561 | + <securedutility |
562 | + name="BuildableDistroSeries" |
563 | + component=".sourcepackagerecipe.buildable_distroseries_vocabulary" |
564 | + provides="zope.schema.interfaces.IVocabularyFactory"> |
565 | + <allow interface="zope.schema.interfaces.IVocabularyFactory"/> |
566 | + </securedutility> |
567 | + |
568 | + <securedutility |
569 | + name="TargetPPAs" |
570 | + component=".sourcepackagerecipe.target_ppas_vocabulary" |
571 | + provides="zope.schema.interfaces.IVocabularyFactory"> |
572 | + <allow interface="zope.schema.interfaces.IVocabularyFactory"/> |
573 | + </securedutility> |
574 | + |
575 | + <securedutility |
576 | + name="Branch" |
577 | + component=".branch.BranchVocabulary" |
578 | + provides="zope.schema.interfaces.IVocabularyFactory"> |
579 | + <allow interface="zope.schema.interfaces.IVocabularyFactory"/> |
580 | + </securedutility> |
581 | + |
582 | + <class class=".branch.BranchVocabulary"> |
583 | + <allow interface="canonical.launchpad.webapp.vocabulary.IHugeVocabulary"/> |
584 | + </class> |
585 | + |
586 | + <securedutility |
587 | + name="HostedBranchRestrictedOnOwner" |
588 | + component=".branch.HostedBranchRestrictedOnOwnerVocabulary" |
589 | + provides="zope.schema.interfaces.IVocabularyFactory"> |
590 | + <allow interface="zope.schema.interfaces.IVocabularyFactory"/> |
591 | + </securedutility> |
592 | + |
593 | + <class class=".branch.HostedBranchRestrictedOnOwnerVocabulary"> |
594 | + <allow interface="canonical.launchpad.webapp.vocabulary.IHugeVocabulary"/> |
595 | + </class> |
596 | + |
597 | + <securedutility |
598 | + name="BranchRestrictedOnProduct" |
599 | + component=".branch.BranchRestrictedOnProductVocabulary" |
600 | + provides="zope.schema.interfaces.IVocabularyFactory"> |
601 | + <allow interface="zope.schema.interfaces.IVocabularyFactory"/> |
602 | + </securedutility> |
603 | + |
604 | + <class class=".branch.BranchRestrictedOnProductVocabulary"> |
605 | + <allow interface="canonical.launchpad.webapp.vocabulary.IHugeVocabulary"/> |
606 | + </class> |
607 | + |
608 | +</configure> |
609 | |
610 | === added file 'lib/lp/code/vocabularies/tests/branch.txt' |
611 | --- lib/lp/code/vocabularies/tests/branch.txt 1970-01-01 00:00:00 +0000 |
612 | +++ lib/lp/code/vocabularies/tests/branch.txt 2010-09-20 22:41:19 +0000 |
613 | @@ -0,0 +1,148 @@ |
614 | +Branch Vocabularies |
615 | +=================== |
616 | + |
617 | +Launchpad has a few vocabularies that contain branches filtered in |
618 | +various ways. |
619 | + |
620 | + >>> from zope.schema.vocabulary import getVocabularyRegistry |
621 | + >>> vocabulary_registry = getVocabularyRegistry() |
622 | + |
623 | +BranchVocabulary |
624 | +---------------- |
625 | + |
626 | +The list of bzr branches registered in Launchpad. |
627 | + |
628 | +Searchable by branch name or URL, registrant name, and project name. |
629 | +Results are not restricted in any way by the context, but the results |
630 | +are restricted based on who is asking (as far as private branches is |
631 | +concerned). |
632 | + |
633 | + # Just use None as the context. |
634 | + >>> branch_vocabulary = vocabulary_registry.get(None, "Branch") |
635 | + >>> def print_vocab_branches(vocab, search): |
636 | + ... for term in vocab.searchForTerms(search): |
637 | + ... print term.value.unique_name |
638 | + |
639 | + >>> print_vocab_branches(branch_vocabulary, 'main') |
640 | + ~name12/firefox/main |
641 | + ~stevea/thunderbird/main |
642 | + ~justdave/+junk/main |
643 | + ~kiko/+junk/main |
644 | + ~vcs-imports/evolution/main |
645 | + ~name12/gnome-terminal/main |
646 | + |
647 | + >>> print_vocab_branches(branch_vocabulary, 'vcs-imports') |
648 | + ~vcs-imports/gnome-terminal/import |
649 | + ~vcs-imports/evolution/import |
650 | + ~vcs-imports/evolution/main |
651 | + |
652 | + >>> print_vocab_branches(branch_vocabulary, 'evolution') |
653 | + ~carlos/evolution/2.0 |
654 | + ~vcs-imports/evolution/import |
655 | + ~vcs-imports/evolution/main |
656 | + |
657 | +A search with the full branch unique name should also find the branch. |
658 | + |
659 | + >>> print_vocab_branches(branch_vocabulary, '~name12/firefox/main') |
660 | + ~name12/firefox/main |
661 | + |
662 | +The tokens used by terms retrieved from BranchVocabulary use the |
663 | +branch unique name as an ID: |
664 | + |
665 | + >>> from lp.code.interfaces.branchlookup import IBranchLookup |
666 | + >>> branch = getUtility(IBranchLookup).get(15) |
667 | + >>> print branch.unique_name |
668 | + ~name12/gnome-terminal/main |
669 | + >>> from zope.security.proxy import removeSecurityProxy |
670 | + >>> term = removeSecurityProxy(branch_vocabulary).toTerm(branch) |
671 | + >>> print term.token |
672 | + ~name12/gnome-terminal/main |
673 | + |
674 | +The BranchVocabulary recognises both unique names and URLs as tokens: |
675 | + |
676 | + >>> term = branch_vocabulary.getTermByToken('~name12/gnome-terminal/main') |
677 | + >>> term.value == branch |
678 | + True |
679 | + >>> term = branch_vocabulary.getTermByToken( |
680 | + ... 'http://bazaar.launchpad.dev/~name12/gnome-terminal/main/') |
681 | + >>> term.value == branch |
682 | + True |
683 | + >>> term = branch_vocabulary.getTermByToken( |
684 | + ... 'http://example.com/gnome-terminal/main') |
685 | + >>> term.value == branch |
686 | + True |
687 | + |
688 | +The searches that the BranchVocabulary does are private branch aware. |
689 | +The results are effectively filtered on what the logged in user is |
690 | +able to see. |
691 | + |
692 | + >>> from lp.testing import login, ANONYMOUS |
693 | + >>> from lp.testing.sampledata import ADMIN_EMAIL |
694 | + |
695 | + >>> login(ADMIN_EMAIL) |
696 | + >>> print_vocab_branches(branch_vocabulary, 'trunk') |
697 | + ~spiv/+junk/trunk |
698 | + ~limi/+junk/trunk |
699 | + ~landscape-developers/landscape/trunk |
700 | + |
701 | + >>> login(ANONYMOUS) |
702 | + >>> print_vocab_branches(branch_vocabulary, 'trunk') |
703 | + ~spiv/+junk/trunk |
704 | + ~limi/+junk/trunk |
705 | + |
706 | + |
707 | +BranchRestrictedOnProduct |
708 | +------------------------- |
709 | + |
710 | +The BranchRestrictedOnProduct vocabulary restricts the result set to |
711 | +those of the product of the context. Currently only two types of |
712 | +context are supported: Product; and Branch. If a branch is the context, |
713 | +then the product of the branch is used to restrict the query. |
714 | + |
715 | + >>> from lp.registry.interfaces.product import IProductSet |
716 | + >>> gnome_terminal = getUtility(IProductSet)["gnome-terminal"] |
717 | + >>> branch_vocabulary = vocabulary_registry.get( |
718 | + ... gnome_terminal, "BranchRestrictedOnProduct") |
719 | + >>> print_vocab_branches(branch_vocabulary, 'main') |
720 | + ~name12/gnome-terminal/main |
721 | + |
722 | + >>> print_vocab_branches(branch_vocabulary, 'vcs-imports') |
723 | + ~vcs-imports/gnome-terminal/import |
724 | + |
725 | +If a full unique name is entered that has a different product, the |
726 | +branch is not part of the vocabulary. |
727 | + |
728 | + >>> print_vocab_branches(branch_vocabulary, '~name12/gnome-terminal/main') |
729 | + ~name12/gnome-terminal/main |
730 | + |
731 | + >>> print_vocab_branches(branch_vocabulary, '~name12/firefox/main') |
732 | + |
733 | + |
734 | +The BranchRestrictedOnProduct behaves the same way as the more generic |
735 | +BranchVocabulary with respect to the tokens and privacy awareness. |
736 | + |
737 | + |
738 | +HostedBranchRestrictedOnOwner |
739 | +----------------------------- |
740 | + |
741 | +Here's a vocabulary for all hosted branches owned by the current user. |
742 | + |
743 | + >>> from lp.code.enums import BranchType |
744 | + |
745 | + >>> a_user = factory.makePerson(name='a-branching-user') |
746 | + >>> product1 = factory.makeProduct(name='product-one') |
747 | + >>> mirrored_branch = factory.makeBranch( |
748 | + ... owner=a_user, product=product1, name='mirrored', |
749 | + ... branch_type=BranchType.MIRRORED) |
750 | + >>> product2 = factory.makeProduct(name='product-two') |
751 | + >>> hosted_branch = factory.makeBranch( |
752 | + ... owner=a_user, product=product2, name='hosted') |
753 | + >>> foreign_branch = factory.makeBranch() |
754 | + |
755 | +It returns branches owned by the user, but not ones owned by others, nor |
756 | +ones that aren't hosted on Launchpad. |
757 | + |
758 | + >>> branch_vocabulary = vocabulary_registry.get( |
759 | + ... a_user, "HostedBranchRestrictedOnOwner") |
760 | + >>> print_vocab_branches(branch_vocabulary, None) |
761 | + ~a-branching-user/product-two/hosted |
762 | |
763 | === modified file 'lib/lp/code/vocabularies/tests/test_branch_vocabularies.py' |
764 | --- lib/lp/code/vocabularies/tests/test_branch_vocabularies.py 2010-08-20 20:31:18 +0000 |
765 | +++ lib/lp/code/vocabularies/tests/test_branch_vocabularies.py 2010-09-20 22:41:19 +0000 |
766 | @@ -17,7 +17,7 @@ |
767 | login, |
768 | logout, |
769 | ) |
770 | -from canonical.launchpad.vocabularies.dbobjects import ( |
771 | +from lp.code.vocabularies.branch import ( |
772 | BranchRestrictedOnProductVocabulary, |
773 | BranchVocabulary, |
774 | ) |
775 | |
776 | === added file 'lib/lp/code/vocabularies/tests/test_doc.py' |
777 | --- lib/lp/code/vocabularies/tests/test_doc.py 1970-01-01 00:00:00 +0000 |
778 | +++ lib/lp/code/vocabularies/tests/test_doc.py 2010-09-20 22:41:19 +0000 |
779 | @@ -0,0 +1,17 @@ |
780 | +# Copyright 2010 Canonical Ltd. This software is licensed under the |
781 | +# GNU Affero General Public License version 3 (see the file LICENSE). |
782 | + |
783 | +""" |
784 | +Run the doctests. |
785 | +""" |
786 | + |
787 | +import os |
788 | + |
789 | +from lp.services.testing import build_doctest_suite |
790 | + |
791 | + |
792 | +here = os.path.dirname(os.path.realpath(__file__)) |
793 | + |
794 | + |
795 | +def test_suite(): |
796 | + return build_doctest_suite(here, '') |
+ """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.
"""