Merge lp:~stevenk/launchpad/destroy-dsp_picker-ff into lp:launchpad

Proposed by Steve Kowalik on 2012-10-04
Status: Merged
Approved by: William Grant on 2012-10-04
Approved revision: no longer in the source branch.
Merged at revision: 16097
Proposed branch: lp:~stevenk/launchpad/destroy-dsp_picker-ff
Merge into: lp:launchpad
Diff against target: 833 lines (+5/-630)
9 files modified
lib/lp/app/widgets/launchpadtarget.py (+1/-11)
lib/lp/app/widgets/tests/test_launchpadtarget.py (+0/-29)
lib/lp/bugs/browser/bugalsoaffects.py (+2/-6)
lib/lp/bugs/browser/tests/test_bugalsoaffects.py (+1/-33)
lib/lp/bugs/browser/widgets/bugtask.py (+0/-13)
lib/lp/registry/tests/test_dsp_vocabularies.py (+0/-345)
lib/lp/registry/vocabularies.py (+1/-171)
lib/lp/registry/vocabularies.zcml (+0/-15)
lib/lp/services/features/flags.py (+0/-7)
To merge this branch: bzr merge lp:~stevenk/launchpad/destroy-dsp_picker-ff
Reviewer Review Type Date Requested Status
Ian Booth (community) Approve on 2012-10-04
William Grant code 2012-10-04 Approve on 2012-10-04
Review via email: mp+128138@code.launchpad.net

Commit Message

Destroy DistributionSourcePackageVocabulary and its related feature flag.

Description of the Change

DistributionSourcePackageVocabulary was written quite some time ago to write one vocab that could be certain that a source package was published in a distribution so that the current source package picker doesn't have to show errors that a source isn't published in that distro.

This would be fine, except it's dangerous to turn on because it breaks the branch case, and can be quite slow. Since it's been disabled for so long, it should die. To this end, I have destroyed the vocab and the feature flag that governs its use.

So adios DistributionSourcePackageVocabulary, and the horse you rode in on.

To post a comment you must log in.
William Grant (wgrant) :
review: Approve (code)
Ian Booth (wallyworld) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'lib/lp/app/widgets/launchpadtarget.py'
2--- lib/lp/app/widgets/launchpadtarget.py 2012-09-14 01:21:13 +0000
3+++ lib/lp/app/widgets/launchpadtarget.py 2012-10-04 23:23:22 +0000
4@@ -35,7 +35,6 @@
5 IDistributionSourcePackage,
6 )
7 from lp.registry.interfaces.product import IProduct
8-from lp.services.features import getFeatureFlag
9 from lp.services.webapp.interfaces import (
10 IAlwaysSubmittedWidget,
11 IMultiLineWidgetLayout,
12@@ -57,12 +56,6 @@
13 def setUpSubWidgets(self):
14 if self._widgets_set_up:
15 return
16- if bool(getFeatureFlag('disclosure.dsp_picker.enabled')):
17- # Replace the default field with a field that uses the better
18- # vocabulary.
19- package_vocab = 'DistributionSourcePackage'
20- else:
21- package_vocab = 'BinaryAndSourcePackageName'
22 fields = [
23 Choice(
24 __name__='product', title=u'Project',
25@@ -73,7 +66,7 @@
26 default=getUtility(ILaunchpadCelebrities).ubuntu),
27 Choice(
28 __name__='package', title=u"Package",
29- required=False, vocabulary=package_vocab),
30+ required=False, vocabulary='BinaryAndSourcePackageName'),
31 ]
32 self.distribution_widget = CustomWidgetFactory(
33 LaunchpadDropdownWidget)
34@@ -135,9 +128,6 @@
35 " Launchpad" % entered_name)
36
37 if self.package_widget.hasInput():
38- if bool(getFeatureFlag('disclosure.dsp_picker.enabled')):
39- self.package_widget.vocabulary.setDistribution(
40- distribution)
41 try:
42 package_name = self.package_widget.getInputValue()
43 except ConversionError:
44
45=== modified file 'lib/lp/app/widgets/tests/test_launchpadtarget.py'
46--- lib/lp/app/widgets/tests/test_launchpadtarget.py 2012-02-22 01:24:55 +0000
47+++ lib/lp/app/widgets/tests/test_launchpadtarget.py 2012-10-04 23:23:22 +0000
48@@ -17,11 +17,9 @@
49 from lp.app.validators import LaunchpadValidationError
50 from lp.app.widgets.launchpadtarget import LaunchpadTargetWidget
51 from lp.registry.vocabularies import (
52- DistributionSourcePackageVocabulary,
53 DistributionVocabulary,
54 ProductVocabulary,
55 )
56-from lp.services.features.testing import FeatureFixture
57 from lp.services.webapp.servers import LaunchpadTestRequest
58 from lp.services.webapp.testing import verifyObject
59 from lp.soyuz.model.binaryandsourcepackagename import (
60@@ -119,15 +117,6 @@
61 self.assertIs(None, getattr(self.widget, 'package_widget', None))
62 self.assertIs(None, getattr(self.widget, 'product_widget', None))
63
64- def test_setUpSubWidgets_dsp_picker_feature_flag(self):
65- # The DistributionSourcePackageVocabulary is used when the
66- # disclosure.dsp_picker.enabled is true.
67- with FeatureFixture({u"disclosure.dsp_picker.enabled": u"on"}):
68- self.widget.setUpSubWidgets()
69- self.assertIsInstance(
70- self.widget.package_widget.context.vocabulary,
71- DistributionSourcePackageVocabulary)
72-
73 def test_setUpOptions_default_package_checked(self):
74 # The radio button options are composed of the setup widgets with
75 # the package widget set as the default.
76@@ -189,24 +178,6 @@
77 self.widget.request = LaunchpadTestRequest(form=self.form)
78 self.assertEqual(self.package, self.widget.getInputValue())
79
80- def test_getInputValue_package_spn_dsp_picker_feature_flag(self):
81- # The field value is the package when the package radio button
82- # is selected and the package sub field has a official dsp.
83- self.widget.request = LaunchpadTestRequest(form=self.form)
84- with FeatureFixture({u"disclosure.dsp_picker.enabled": u"on"}):
85- self.widget.setUpSubWidgets()
86- self.assertEqual(self.package, self.widget.getInputValue())
87-
88- def test_getInputValue_package_dsp_dsp_picker_feature_flag(self):
89- # The field value is the package when the package radio button
90- # is selected and the package sub field has valid input.
91- form = self.form
92- form['field.target.package'] = 'fnord/snarf'
93- self.widget.request = LaunchpadTestRequest(form=form)
94- with FeatureFixture({u"disclosure.dsp_picker.enabled": u"on"}):
95- self.widget.setUpSubWidgets()
96- self.assertEqual(self.package, self.widget.getInputValue())
97-
98 def test_getInputValue_package_invalid(self):
99 # An error is raised when the package is not published in the distro.
100 form = self.form
101
102=== modified file 'lib/lp/bugs/browser/bugalsoaffects.py'
103--- lib/lp/bugs/browser/bugalsoaffects.py 2012-08-30 05:17:23 +0000
104+++ lib/lp/bugs/browser/bugalsoaffects.py 2012-10-04 23:23:22 +0000
105@@ -1,4 +1,4 @@
106-# Copyright 2009-2011 Canonical Ltd. This software is licensed under the
107+# Copyright 2009-2012 Canonical Ltd. This software is licensed under the
108 # GNU Affero General Public License version 3 (see the file LICENSE).
109
110 __metaclass__ = type
111@@ -81,7 +81,6 @@
112 IProductSet,
113 License,
114 )
115-from lp.services.features import getFeatureFlag
116 from lp.services.fields import StrippedTextLine
117 from lp.services.propertycache import cachedproperty
118 from lp.services.webapp import canonical_url
119@@ -361,10 +360,7 @@
120
121 @property
122 def schema(self):
123- if bool(getFeatureFlag('disclosure.dsp_picker.enabled')):
124- return IAddDistroBugTaskForm
125- else:
126- return IAddBugTaskForm
127+ return IAddBugTaskForm
128
129 custom_widget(
130 'sourcepackagename', BugTaskAlsoAffectsSourcePackageNameWidget)
131
132=== modified file 'lib/lp/bugs/browser/tests/test_bugalsoaffects.py'
133--- lib/lp/bugs/browser/tests/test_bugalsoaffects.py 2012-01-01 02:58:52 +0000
134+++ lib/lp/bugs/browser/tests/test_bugalsoaffects.py 2012-10-04 23:23:22 +0000
135@@ -1,11 +1,10 @@
136-# Copyright 2011 Canonical Ltd. This software is licensed under the
137+# Copyright 2011-2012 Canonical Ltd. This software is licensed under the
138 # GNU Affero General Public License version 3 (see the file LICENSE).
139
140 __metaclass__ = type
141
142 from zope.security.proxy import removeSecurityProxy
143
144-from lp.services.features.testing import FeatureFixture
145 from lp.services.webapp import canonical_url
146 from lp.soyuz.enums import PackagePublishingStatus
147 from lp.testing import TestCaseWithFactory
148@@ -38,37 +37,6 @@
149 browser.getControl('Continue').click()
150 self.assertEqual([], get_feedback_messages(browser.contents))
151
152- def test_bug_alsoaffects_spn_exists_dsp_picker_feature_flag(self):
153- # If the distribution source package for an spn is official,
154- # there is no error.
155- bug = self.factory.makeBug()
156- distribution, dsp = self.factory.makeDSPCache(
157- distro_name=self.distribution.name, package_name='snarf',
158- make_distro=False)
159- with FeatureFixture({u"disclosure.dsp_picker.enabled": u"on"}):
160- browser = self.openBugPage(bug)
161- browser.getLink(url='+distrotask').click()
162- browser.getControl('Distribution').value = [distribution.name]
163- browser.getControl('Source Package Name').value = (
164- dsp.sourcepackagename.name)
165- browser.getControl('Continue').click()
166- self.assertEqual([], get_feedback_messages(browser.contents))
167-
168- def test_bug_alsoaffects_dsp_exists_dsp_picker_feature_flag(self):
169- # If the distribution source package is official, there is no error.
170- bug = self.factory.makeBug()
171- distribution, dsp = self.factory.makeDSPCache(
172- distro_name=self.distribution.name, package_name='snarf',
173- make_distro=False)
174- with FeatureFixture({u"disclosure.dsp_picker.enabled": u"on"}):
175- browser = self.openBugPage(bug)
176- browser.getLink(url='+distrotask').click()
177- browser.getControl('Distribution').value = [distribution.name]
178- browser.getControl('Source Package Name').value = (
179- '%s/%s' % (distribution.name, dsp.name))
180- browser.getControl('Continue').click()
181- self.assertEqual([], get_feedback_messages(browser.contents))
182-
183 def test_bug_alsoaffects_spn_not_exists_with_published_binaries(self):
184 # When the distribution has published binaries, we search both
185 # source and binary package names.
186
187=== modified file 'lib/lp/bugs/browser/widgets/bugtask.py'
188--- lib/lp/bugs/browser/widgets/bugtask.py 2012-10-04 01:52:19 +0000
189+++ lib/lp/bugs/browser/widgets/bugtask.py 2012-10-04 23:23:22 +0000
190@@ -71,7 +71,6 @@
191 )
192 from lp.bugs.vocabularies import UsesBugsDistributionVocabulary
193 from lp.registry.interfaces.distribution import IDistributionSet
194-from lp.services.features import getFeatureFlag
195 from lp.services.fields import URIField
196 from lp.services.webapp import canonical_url
197 from lp.services.webapp.interfaces import ILaunchBag
198@@ -508,18 +507,6 @@
199
200 distribution = self.getDistribution()
201
202- if bool(getFeatureFlag('disclosure.dsp_picker.enabled')):
203- try:
204- self.context.vocabulary.setDistribution(distribution)
205- source = self.context.vocabulary.getTermByToken(input).value
206- except NotFoundError:
207- raise ConversionError(
208- "Launchpad doesn't know of any source package named"
209- " '%s' in %s." % (input, distribution.displayname))
210- else:
211- return source
212- # Else the untrusted SPN vocab was used so it needs seconday
213- # verification.
214 try:
215 source = distribution.guessPublishedSourcePackageName(input)
216 except NotFoundError:
217
218=== removed file 'lib/lp/registry/tests/test_dsp_vocabularies.py'
219--- lib/lp/registry/tests/test_dsp_vocabularies.py 2012-01-20 22:31:09 +0000
220+++ lib/lp/registry/tests/test_dsp_vocabularies.py 1970-01-01 00:00:00 +0000
221@@ -1,345 +0,0 @@
222-# Copyright 2011 Canonical Ltd. This software is licensed under the
223-# GNU Affero General Public License version 3 (see the file LICENSE).
224-
225-"""Test the Distribution Source Package vocabulary."""
226-
227-__metaclass__ = type
228-
229-
230-from lp.registry.vocabularies import DistributionSourcePackageVocabulary
231-from lp.services.webapp.vocabulary import IHugeVocabulary
232-from lp.testing import TestCaseWithFactory
233-from lp.testing.layers import DatabaseFunctionalLayer
234-
235-
236-class TestDistributionSourcePackageVocabulary(TestCaseWithFactory):
237- """Test that the vocabulary behaves as expected."""
238- layer = DatabaseFunctionalLayer
239-
240- def test_provides_ihugevocabulary(self):
241- vocabulary = DistributionSourcePackageVocabulary(
242- self.factory.makeDistribution())
243- self.assertProvides(vocabulary, IHugeVocabulary)
244-
245- def test_init_IDistribution(self):
246- # When the context is adaptable to IDistribution, it also provides
247- # the distribution.
248- dsp = self.factory.makeDistributionSourcePackage(
249- sourcepackagename='foo')
250- vocabulary = DistributionSourcePackageVocabulary(dsp)
251- self.assertEqual(dsp, vocabulary.context)
252- self.assertEqual(dsp.distribution, vocabulary.distribution)
253- self.assertEqual(dsp, vocabulary.dsp)
254-
255- def test_init_dsp_bugtask(self):
256- # A dsp bugtask can be the context
257- dsp = self.factory.makeDistributionSourcePackage(
258- sourcepackagename='foo')
259- bugtask = self.factory.makeBugTask(target=dsp)
260- vocabulary = DistributionSourcePackageVocabulary(bugtask)
261- self.assertEqual(bugtask, vocabulary.context)
262- self.assertEqual(dsp.distribution, vocabulary.distribution)
263- self.assertEqual(dsp, vocabulary.dsp)
264-
265- def test_init_dsp_question(self):
266- # A dsp bugtask can be the context
267- dsp = self.factory.makeDistributionSourcePackage(
268- sourcepackagename='foo')
269- question = self.factory.makeQuestion(
270- target=dsp, owner=dsp.distribution.owner)
271- vocabulary = DistributionSourcePackageVocabulary(question)
272- self.assertEqual(question, vocabulary.context)
273- self.assertEqual(dsp.distribution, vocabulary.distribution)
274- self.assertEqual(dsp, vocabulary.dsp)
275-
276- def test_init_no_distribution(self):
277- # The distribution is None if the context cannot be adapted to a
278- # distribution.
279- project = self.factory.makeProduct()
280- vocabulary = DistributionSourcePackageVocabulary(project)
281- self.assertEqual(project, vocabulary.context)
282- self.assertEqual(None, vocabulary.distribution)
283- self.assertEqual(None, vocabulary.dsp)
284-
285- def test_setDistribution(self):
286- # Callsites can set the distribution after the vocabulary was
287- # instantiated.
288- new_distro = self.factory.makeDistribution(name='fnord')
289- vocabulary = DistributionSourcePackageVocabulary(None)
290- vocabulary.setDistribution(new_distro)
291- self.assertEqual(new_distro, vocabulary.distribution)
292-
293- def test_getDistributionAndPackageName_distro_and_package(self):
294- # getDistributionAndPackageName() returns a tuple of distribution
295- # and package name when the text contains both.
296- new_distro = self.factory.makeDistribution(name='fnord')
297- vocabulary = DistributionSourcePackageVocabulary(None)
298- distribution, package_name = vocabulary.getDistributionAndPackageName(
299- 'fnord/pting')
300- self.assertEqual(new_distro, distribution)
301- self.assertEqual('pting', package_name)
302-
303- def test_getDistributionAndPackageName_default_distro_and_package(self):
304- # getDistributionAndPackageName() returns a tuple of the default
305- # distribution and package name when the text is just a package name.
306- default_distro = self.factory.makeDistribution(name='fnord')
307- vocabulary = DistributionSourcePackageVocabulary(default_distro)
308- distribution, package_name = vocabulary.getDistributionAndPackageName(
309- 'pting')
310- self.assertEqual(default_distro, distribution)
311- self.assertEqual('pting', package_name)
312-
313- def test_getDistributionAndPackageName_bad_distro_and_package(self):
314- # getDistributionAndPackageName() returns a tuple of the default
315- # distribution and package name when the distro in the text cannot
316- # be matched to a real distro.
317- default_distro = self.factory.makeDistribution(name='fnord')
318- vocabulary = DistributionSourcePackageVocabulary(default_distro)
319- distribution, package_name = vocabulary.getDistributionAndPackageName(
320- 'misspelled/pting')
321- self.assertEqual(default_distro, distribution)
322- self.assertEqual('pting', package_name)
323-
324- def test_contains_true_without_init(self):
325- # The vocabulary contains official DSPs.
326- dsp = self.factory.makeDistributionSourcePackage(with_db=True)
327- vocabulary = DistributionSourcePackageVocabulary(None)
328- self.assertTrue(dsp in vocabulary)
329-
330- def test_contains_true_with_init(self):
331- # The vocabulary does contain the DSP passed to init when
332- # it is not official.
333- dsp = self.factory.makeDistributionSourcePackage(with_db=False)
334- vocabulary = DistributionSourcePackageVocabulary(dsp)
335- self.assertTrue(dsp in vocabulary)
336-
337- def test_contains_false_without_init(self):
338- # The vocabulary does not contain DSPs that are not official
339- # that were not passed to init.
340- dsp = self.factory.makeDistributionSourcePackage(with_db=False)
341- vocabulary = DistributionSourcePackageVocabulary(None)
342- self.assertFalse(dsp in vocabulary)
343-
344- def test_toTerm_raises_error(self):
345- # An error is raised for DSP/SPNs that are not official and are
346- # not in the vocabulary.
347- dsp = self.factory.makeDistributionSourcePackage(
348- sourcepackagename='foo')
349- vocabulary = DistributionSourcePackageVocabulary(dsp.distribution)
350- self.assertRaises(LookupError, vocabulary.toTerm, dsp.name)
351-
352- def test_toTerm_none_raises_error(self):
353- # An error is raised for SPN does not exist.
354- vocabulary = DistributionSourcePackageVocabulary(None)
355- self.assertRaises(LookupError, vocabulary.toTerm, 'non-existant')
356-
357- def test_toTerm_spn_and_default_distribution(self):
358- # The vocabulary's distribution is used when only a SPN is passed.
359- spph = self.factory.makeSourcePackagePublishingHistory()
360- dsp = spph.sourcepackagerelease.distrosourcepackage
361- vocabulary = DistributionSourcePackageVocabulary(dsp.distribution)
362- term = vocabulary.toTerm(dsp.sourcepackagename)
363- expected_token = '%s/%s' % (dsp.distribution.name, dsp.name)
364- self.assertEqual(expected_token, term.token)
365- self.assertEqual(expected_token, term.title)
366- self.assertEqual(dsp, term.value)
367-
368- def test_toTerm_spn_and_distribution(self):
369- # The distribution is used with the spn if it is passed.
370- spph = self.factory.makeSourcePackagePublishingHistory()
371- dsp = spph.sourcepackagerelease.distrosourcepackage
372- vocabulary = DistributionSourcePackageVocabulary(None)
373- term = vocabulary.toTerm(dsp.sourcepackagename, dsp.distribution)
374- expected_token = '%s/%s' % (dsp.distribution.name, dsp.name)
375- self.assertEqual(expected_token, term.token)
376- self.assertEqual(expected_token, term.title)
377- self.assertEqual(dsp, term.value)
378-
379- def test_toTerm_dsp(self):
380- # The DSP's distribution is used when a DSP is passed.
381- spph = self.factory.makeSourcePackagePublishingHistory()
382- dsp = spph.sourcepackagerelease.distrosourcepackage
383- vocabulary = DistributionSourcePackageVocabulary(dsp)
384- term = vocabulary.toTerm(dsp)
385- expected_token = '%s/%s' % (dsp.distribution.name, dsp.name)
386- self.assertEqual(expected_token, term.token)
387- self.assertEqual(expected_token, term.title)
388- self.assertEqual(dsp, term.value)
389-
390- def test_toTerm_dsp_and_binary_names(self):
391- # The DSP can be passed with a string on binary names that will
392- # be cached as a list in DSP.binary_names.
393- spph = self.factory.makeSourcePackagePublishingHistory()
394- dsp = spph.sourcepackagerelease.distrosourcepackage
395- vocabulary = DistributionSourcePackageVocabulary(dsp)
396- term = vocabulary.toTerm((dsp, 'one two'))
397- expected_token = '%s/%s' % (dsp.distribution.name, dsp.name)
398- self.assertEqual(expected_token, term.token)
399- self.assertEqual(expected_token, term.title)
400- self.assertEqual(dsp, term.value)
401- self.assertEqual(['one', 'two'], term.value.binary_names)
402-
403- def test_getTermByToken_error(self):
404- # An error is raised if the token does not match a official DSP.
405- dsp = self.factory.makeDistributionSourcePackage(
406- sourcepackagename='foo')
407- vocabulary = DistributionSourcePackageVocabulary(dsp.distribution)
408- token = '%s/%s' % (dsp.distribution.name, dsp.name)
409- self.assertRaises(LookupError, vocabulary.getTermByToken, token)
410-
411- def test_getTermByToken_token(self):
412- # The term is return if it matches an official DSP.
413- spph = self.factory.makeSourcePackagePublishingHistory()
414- dsp = spph.sourcepackagerelease.distrosourcepackage
415- vocabulary = DistributionSourcePackageVocabulary(dsp.distribution)
416- token = '%s/%s' % (dsp.distribution.name, dsp.name)
417- term = vocabulary.getTermByToken(token)
418- self.assertEqual(dsp, term.value)
419-
420- def test_searchForTerms_without_distribution(self):
421- # An empty result set is return if the vocabulary has no distribution
422- # and the search does not provide distribution information.
423- spph = self.factory.makeSourcePackagePublishingHistory()
424- dsp = spph.sourcepackagerelease.distrosourcepackage
425- vocabulary = DistributionSourcePackageVocabulary(dsp.name)
426- results = vocabulary.searchForTerms(dsp.name)
427- self.assertIs(0, results.count())
428-
429- def test_searchForTerms_None(self):
430- # Searching for nothing gets you that.
431- vocabulary = DistributionSourcePackageVocabulary(
432- self.factory.makeDistribution())
433- results = vocabulary.searchForTerms()
434- self.assertIs(0, results.count())
435-
436- def test_searchForTerms_exact_offcial_source_name(self):
437- # Exact source name matches are found.
438- self.factory.makeDSPCache('fnord', 'snarf')
439- vocabulary = DistributionSourcePackageVocabulary(None)
440- results = vocabulary.searchForTerms(query='fnord/snarf')
441- terms = list(results)
442- self.assertEqual(1, len(terms))
443- self.assertEqual('fnord/snarf', terms[0].token)
444-
445- def test_searchForTerms_exact_unpublished_offcial_source_name(self):
446- # Exact source name matches of unpublished packages are found.
447- distribution = self.factory.makeDistribution(name='fnord')
448- self.factory.makeDistributionSourcePackage(
449- distribution=distribution, sourcepackagename='snarf',
450- with_db=True)
451- vocabulary = DistributionSourcePackageVocabulary(None)
452- results = vocabulary.searchForTerms(query='fnord/snarf')
453- terms = list(results)
454- self.assertEqual(1, len(terms))
455- self.assertEqual('fnord/snarf', terms[0].token)
456-
457- def test_searchForTerms_similar_official_source_name(self):
458- # Partial source name matches are found.
459- self.factory.makeDSPCache('fnord', 'pting-snarf-ack')
460- vocabulary = DistributionSourcePackageVocabulary(None)
461- results = vocabulary.searchForTerms(query='fnord/snarf')
462- terms = list(results)
463- self.assertEqual(1, len(terms))
464- self.assertEqual('fnord/pting-snarf-ack', terms[0].token)
465-
466- def test_searchForTerms_exact_binary_name(self):
467- # Exact binary name matches are found.
468- self.factory.makeDSPCache(
469- 'fnord', 'snarf', binary_names='pting-dev pting ack')
470- vocabulary = DistributionSourcePackageVocabulary(None)
471- results = vocabulary.searchForTerms(query='fnord/pting')
472- terms = list(results)
473- self.assertEqual(1, len(terms))
474- self.assertEqual('fnord/snarf', terms[0].token)
475-
476- def test_searchForTerms_similar_binary_name(self):
477- # Partial binary name matches are found.
478- self.factory.makeDSPCache(
479- 'fnord', 'snarf', binary_names='thrpp pting-dev ack')
480- vocabulary = DistributionSourcePackageVocabulary(None)
481- results = vocabulary.searchForTerms(query='fnord/pting')
482- terms = list(results)
483- self.assertEqual(1, len(terms))
484- self.assertEqual('fnord/snarf', terms[0].token)
485-
486- def test_searchForTerms_exact_unofficial_source_name(self):
487- # Unofficial source packages are not found by search.
488- self.factory.makeDSPCache('fnord', 'snarf', official=False)
489- vocabulary = DistributionSourcePackageVocabulary(None)
490- results = vocabulary.searchForTerms(query='fnord/snarf')
491- terms = list(results)
492- self.assertEqual(0, len(terms))
493-
494- def test_searchForTerms_similar_unofficial_binary_name(self):
495- # Unofficial binary packages are not found by search.
496- self.factory.makeDSPCache(
497- 'fnord', 'snarf', official=False, binary_names='thrpp pting ack')
498- vocabulary = DistributionSourcePackageVocabulary(None)
499- results = vocabulary.searchForTerms(query='fnord/pting')
500- terms = list(results)
501- self.assertEqual(0, len(terms))
502-
503- def test_searchForTerms_match_official_source_package_branch(self):
504- # The official package that is only a branch can be matched
505- # by source name if it was built in another distro.
506- self.factory.makeDSPCache('fnord', 'snarf')
507- distribution = self.factory.makeDistribution(name='pting')
508- self.factory.makeDistributionSourcePackage(
509- distribution=distribution, sourcepackagename='snarf',
510- with_db=True)
511- vocabulary = DistributionSourcePackageVocabulary(None)
512- results = vocabulary.searchForTerms(query='pting/snarf')
513- terms = list(results)
514- self.assertEqual(1, len(terms))
515- self.assertEqual('pting/snarf', terms[0].token)
516-
517- def test_searchForTerms_match_official_binary_package_branch(self):
518- # The official package that is only a branch can be matched
519- # by binary name if it was built in another distro.
520- self.factory.makeDSPCache(
521- 'fnord', 'snarf', binary_names='thrpp snarf-dev ack')
522- distribution = self.factory.makeDistribution(name='pting')
523- self.factory.makeDistributionSourcePackage(
524- distribution=distribution, sourcepackagename='snarf',
525- with_db=True)
526- vocabulary = DistributionSourcePackageVocabulary(None)
527- results = vocabulary.searchForTerms(query='pting/ack')
528- terms = list(results)
529- self.assertEqual(1, len(terms))
530- self.assertEqual('pting/snarf', terms[0].token)
531-
532- def test_searchForTerms_ranking(self):
533- # Exact matches are ranked higher than similar matches.
534- self.factory.makeDSPCache('fnord', 'snarf')
535- self.factory.makeDSPCache('fnord', 'snarf-server', make_distro=False)
536- self.factory.makeDSPCache(
537- 'fnord', 'pting-devel', binary_names='snarf', make_distro=False)
538- self.factory.makeDSPCache(
539- 'fnord', 'pting-client', binary_names='snarf-common',
540- make_distro=False)
541- vocabulary = DistributionSourcePackageVocabulary(None)
542- results = vocabulary.searchForTerms(query='fnord/snarf')
543- terms = list(results)
544- self.assertEqual(4, len(terms))
545- self.assertEqual('fnord/snarf', terms[0].token)
546- self.assertEqual('fnord/pting-devel', terms[1].token)
547- self.assertEqual('fnord/snarf-server', terms[2].token)
548- self.assertEqual('fnord/pting-client', terms[3].token)
549-
550- def test_searchForTerms_partner_archive(self):
551- # Packages in partner archives are searched.
552- self.factory.makeDSPCache('fnord', 'snarf', archive='partner')
553- vocabulary = DistributionSourcePackageVocabulary(None)
554- results = vocabulary.searchForTerms(query='fnord/snarf')
555- terms = list(results)
556- self.assertEqual(1, len(terms))
557- self.assertEqual('fnord/snarf', terms[0].token)
558-
559- def test_searchForTerms_ppa_archive(self):
560- # Packages in PPAs are ignored.
561- self.factory.makeDSPCache(
562- 'fnord', 'snarf', official=False, archive='ppa')
563- vocabulary = DistributionSourcePackageVocabulary(None)
564- results = vocabulary.searchForTerms(query='fnord/snarf')
565- terms = list(results)
566- self.assertEqual(0, len(terms))
567
568=== modified file 'lib/lp/registry/vocabularies.py'
569--- lib/lp/registry/vocabularies.py 2012-09-28 06:25:44 +0000
570+++ lib/lp/registry/vocabularies.py 2012-10-04 23:23:22 +0000
571@@ -31,7 +31,6 @@
572 'CommercialProjectsVocabulary',
573 'DistributionOrProductOrProjectGroupVocabulary',
574 'DistributionOrProductVocabulary',
575- 'DistributionSourcePackageVocabulary',
576 'DistributionVocabulary',
577 'DistroSeriesDerivationVocabulary',
578 'DistroSeriesDifferencesVocabulary',
579@@ -64,8 +63,6 @@
580
581 from operator import attrgetter
582
583-from lazr.restful.interfaces import IReference
584-from lazr.restful.utils import safe_hasattr
585 from sqlobject import (
586 AND,
587 CONTAINSSTRING,
588@@ -85,7 +82,6 @@
589 With,
590 )
591 from storm.info import ClassAlias
592-from storm.store import EmptyResultSet
593 from zope.component import getUtility
594 from zope.interface import implements
595 from zope.schema.interfaces import IVocabularyTokenized
596@@ -107,10 +103,7 @@
597 PersonVisibility,
598 )
599 from lp.registry.interfaces.accesspolicy import IAccessPolicySource
600-from lp.registry.interfaces.distribution import (
601- IDistribution,
602- IDistributionSet,
603- )
604+from lp.registry.interfaces.distribution import IDistribution
605 from lp.registry.interfaces.distributionsourcepackage import (
606 IDistributionSourcePackage,
607 )
608@@ -143,11 +136,7 @@
609 from lp.registry.interfaces.projectgroup import IProjectGroup
610 from lp.registry.interfaces.role import IPersonRoles
611 from lp.registry.interfaces.sourcepackage import ISourcePackage
612-from lp.registry.interfaces.sourcepackagename import ISourcePackageName
613 from lp.registry.model.distribution import Distribution
614-from lp.registry.model.distributionsourcepackage import (
615- DistributionSourcePackageInDatabase,
616- )
617 from lp.registry.model.distroseries import DistroSeries
618 from lp.registry.model.distroseriesdifference import DistroSeriesDifference
619 from lp.registry.model.distroseriesparent import DistroSeriesParent
620@@ -208,7 +197,6 @@
621 SQLObjectVocabularyBase,
622 VocabularyFilter,
623 )
624-from lp.soyuz.enums import ArchivePurpose
625 from lp.soyuz.model.distroarchseries import DistroArchSeries
626
627
628@@ -2099,161 +2087,3 @@
629 # package names are always lowercase.
630 return super(SourcePackageNameVocabulary, self).getTermByToken(
631 token.lower())
632-
633-
634-class DistributionSourcePackageVocabulary(FilteredVocabularyBase):
635-
636- implements(IHugeVocabulary)
637- displayname = 'Select a package'
638- step_title = 'Search by name or distro/name'
639- LIMIT = 60
640-
641- def __init__(self, context):
642- self.context = context
643- # Avoid circular import issues.
644- from lp.answers.interfaces.question import IQuestion
645- if IReference.providedBy(context):
646- target = context.context.target
647- elif IBugTask.providedBy(context) or IQuestion.providedBy(context):
648- target = context.target
649- else:
650- target = context
651- try:
652- self.distribution = IDistribution(target)
653- except TypeError:
654- self.distribution = None
655- if IDistributionSourcePackage.providedBy(target):
656- self.dsp = target
657- else:
658- self.dsp = None
659-
660- def __contains__(self, spn_or_dsp):
661- if spn_or_dsp == self.dsp:
662- # Historic values are always valid. The DSP used to
663- # initialize the vocabulary is always included.
664- return True
665- try:
666- self.toTerm(spn_or_dsp)
667- return True
668- except LookupError:
669- return False
670-
671- def __iter__(self):
672- pass
673-
674- def __len__(self):
675- pass
676-
677- def setDistribution(self, distribution):
678- """Set the distribution after the vocabulary was instantiated."""
679- self.distribution = distribution
680-
681- def getDistributionAndPackageName(self, text):
682- "Return the distribution and package name from the parsed text."
683- # Match the toTerm() format, but also use it to select a distribution.
684- distribution = None
685- if '/' in text:
686- distro_name, text = text.split('/', 1)
687- distribution = getUtility(IDistributionSet).getByName(distro_name)
688- if distribution is None:
689- distribution = self.distribution
690- return distribution, text
691-
692- def toTerm(self, spn_or_dsp, distribution=None):
693- """See `IVocabulary`."""
694- dsp = None
695- binary_names = None
696- if isinstance(spn_or_dsp, tuple):
697- # The DSP in DB was passed with its binary_names.
698- spn_or_dsp, binary_names = spn_or_dsp
699- if binary_names is not None:
700- binary_names = binary_names.split()
701- if IDistributionSourcePackage.providedBy(spn_or_dsp):
702- dsp = spn_or_dsp
703- distribution = spn_or_dsp.distribution
704- elif (not ISourcePackageName.providedBy(spn_or_dsp) and
705- safe_hasattr(spn_or_dsp, 'distribution')
706- and safe_hasattr(spn_or_dsp, 'sourcepackagename')):
707- # We use the hasattr checks rather than adaption because the
708- # DistributionSourcePackageInDatabase object is a little bit
709- # broken, and does not provide any interface.
710- distribution = spn_or_dsp.distribution
711- dsp = distribution.getSourcePackage(spn_or_dsp.sourcepackagename)
712- else:
713- distribution = distribution or self.distribution
714- if distribution is not None and spn_or_dsp is not None:
715- dsp = distribution.getSourcePackage(spn_or_dsp)
716- if dsp is not None and (dsp == self.dsp or dsp.is_official):
717- if binary_names:
718- # Search already did the hard work of looking up binary names.
719- cache = get_property_cache(dsp)
720- cache.binary_names = binary_names
721- token = '%s/%s' % (dsp.distribution.name, dsp.name)
722- return SimpleTerm(dsp, token, token)
723- raise LookupError(distribution, spn_or_dsp)
724-
725- def getTerm(self, spn_or_dsp):
726- """See `IBaseVocabulary`."""
727- return self.toTerm(spn_or_dsp)
728-
729- def getTermByToken(self, token):
730- """See `IVocabularyTokenized`."""
731- distribution, package_name = self.getDistributionAndPackageName(token)
732- return self.toTerm(package_name, distribution)
733-
734- def searchForTerms(self, query=None, vocab_filter=None):
735- """See `IHugeVocabulary`."""
736- if not query:
737- return EmptyResultSet()
738- distribution, query = self.getDistributionAndPackageName(query)
739- if distribution is None:
740- # This could failover to ubuntu, but that is non-obvious. The
741- # Python widget must set the default distribution and the JS
742- # widget must encourage the <distro>/<package> search format.
743- return EmptyResultSet()
744- search_term = unicode(query)
745- store = IStore(DistributionSourcePackageInDatabase)
746- # Construct the searchable text that could live in the DSP table.
747- # Limit the results to ensure the user could see all the batches.
748- # Rank only what is returned: exact source name, exact binary
749- # name, partial source name, and lastly partial binary name.
750- searchable_dsp = SQL("""
751- SELECT dsp.id, dsps.name, dsps.binpkgnames, rank
752- FROM DistributionSourcePackage dsp
753- JOIN (
754- SELECT DISTINCT ON (spn.id)
755- spn.id, spn.name, dspc.binpkgnames,
756- CASE WHEN spn.name = ? THEN 100
757- WHEN dspc.binpkgnames
758- ~ ('(^| )' || ? || '( |$)') THEN 75
759- WHEN spn.name
760- ~ ('(^|.*-)' || ? || '(-|$)') THEN 50
761- WHEN dspc.binpkgnames
762- ~ ('(^|.*-)' || ? || '(-| |$)') THEN 25
763- ELSE 1
764- END AS rank
765- FROM SourcePackageName spn
766- LEFT JOIN DistributionSourcePackageCache dspc
767- ON dspc.sourcepackagename = spn.id
768- LEFT JOIN Archive a ON dspc.archive = a.id
769- AND a.purpose IN (?, ?)
770- WHERE
771- spn.name like '%%' || ? || '%%'
772- OR dspc.binpkgnames like '%%' || ? || '%%'
773- LIMIT ?
774- ) dsps ON dsp.sourcepackagename = dsps.id
775- WHERE
776- dsp.distribution = ?
777- ORDER BY rank DESC
778- """, (search_term, search_term, search_term, search_term,
779- ArchivePurpose.PRIMARY.value, ArchivePurpose.PARTNER.value,
780- search_term, search_term, self.LIMIT, distribution.id))
781- matching_with = With('SearchableDSP', searchable_dsp)
782- # It might be possible to return the source name and binary names to
783- # reduce the work of the picker adapter.
784- dsps = store.with_(matching_with).using(
785- SQL('SearchableDSP'), DistributionSourcePackageInDatabase).find(
786- (DistributionSourcePackageInDatabase, SQL('binpkgnames')),
787- SQL('DistributionSourcePackage.id = SearchableDSP.id'))
788-
789- return CountableIterator(dsps.count(), dsps, self.toTerm)
790
791=== modified file 'lib/lp/registry/vocabularies.zcml'
792--- lib/lp/registry/vocabularies.zcml 2012-09-20 13:59:25 +0000
793+++ lib/lp/registry/vocabularies.zcml 2012-10-04 23:23:22 +0000
794@@ -493,21 +493,6 @@
795 <allow interface="lp.services.webapp.vocabulary.ICountableIterator"/>
796 </class>
797
798- <securedutility
799- name="DistributionSourcePackage"
800- component="lp.registry.vocabularies.DistributionSourcePackageVocabulary"
801- provides="zope.schema.interfaces.IVocabularyFactory"
802- >
803- <allow interface="zope.schema.interfaces.IVocabularyFactory"/>
804- </securedutility>
805-
806- <class class="lp.registry.vocabularies.DistributionSourcePackageVocabulary">
807- <allow interface="lp.services.webapp.vocabulary.IHugeVocabulary"/>
808- <require
809- permission="zope.Public"
810- attributes="setDistribution"/>
811- </class>
812-
813 <class
814 class="lp.services.webapp.vocabulary.VocabularyFilterAll">
815 <require
816
817=== modified file 'lib/lp/services/features/flags.py'
818--- lib/lp/services/features/flags.py 2012-10-03 03:41:55 +0000
819+++ lib/lp/services/features/flags.py 2012-10-04 23:23:22 +0000
820@@ -184,13 +184,6 @@
821 '',
822 '',
823 ''),
824- ('disclosure.dsp_picker.enabled',
825- 'boolean',
826- 'Enables the use of the new DistributionSourcePackage vocabulary for '
827- 'the source and binary package name pickers.',
828- '',
829- '',
830- ''),
831 ('bugs.autoconfirm.enabled_distribution_names',
832 'space delimited',
833 ('Enables auto-confirming bugtasks for distributions (and their '