Merge lp:~edwin-grubbs/launchpad/bug-577492-needspackaging-duplicates into lp:launchpad

Proposed by Edwin Grubbs
Status: Merged
Approved by: Jelmer Vernooij
Approved revision: no longer in the source branch.
Merged at revision: 11248
Proposed branch: lp:~edwin-grubbs/launchpad/bug-577492-needspackaging-duplicates
Merge into: lp:launchpad
Diff against target: 1009 lines (+386/-327)
8 files modified
lib/lp/registry/browser/distroseries.py (+3/-6)
lib/lp/registry/browser/tests/test_distroseries_views.py (+52/-0)
lib/lp/registry/doc/distroseries.txt (+286/-284)
lib/lp/registry/interfaces/distroseries.py (+5/-4)
lib/lp/registry/model/distroseries.py (+25/-23)
lib/lp/registry/stories/distroseries/xx-distroseries-index.txt (+6/-1)
lib/lp/registry/templates/distroseries-portlet-packaging.pt (+1/-1)
lib/lp/registry/tests/test_distroseries.py (+8/-8)
To merge this branch: bzr merge lp:~edwin-grubbs/launchpad/bug-577492-needspackaging-duplicates
Reviewer Review Type Date Requested Status
Jelmer Vernooij (community) code Approve
Review via email: mp+31112@code.launchpad.net

Description of the change

Summary
-------

Sped up +needs-packaging page and the needs-packaging portlet on the
distroseries +index page by making getPrioritizedUnlinkedSourcePackages()
return a result set, so that batching will result in a limited query.

Previously, the result set was turned into a list in order to format
each item as a dictionary. Therefore, it would load 13,000 source
packages, and then iterate just over the first batch.

I also fixed the name of getPrioritizedPackagings() and made it
return a result set instead of a list.

Tests
-----

./bin/test -vv -t 'test_distroseries|doc/distroseries.txt'

Demo and Q/A
------------

* Open https://staging.launchpad.net/ubuntu/maverick/+needs-packaging
  * It should not timeout.
* Open https://staging.launchpad.net/ubuntu/maverick/
  * The "Upstream packaging" portlet should say
    "Needs more information or linking to upstream" and list some source
    packages.

Lint
----

There are over 700 lint errors due to bad indentation in doctests, so I
will add those changes later, so that reviewers aren't scared away.

To post a comment you must log in.
Revision history for this message
Jelmer Vernooij (jelmer) wrote :

Nice, I'm looking forward to seeing this land!

One minor comment: lib/lp/registry/browser/tests/test_distroseries_views.py mentions 2009 as the copyright year, that probably should be 2010..

review: Approve (code)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'lib/lp/registry/browser/distroseries.py'
2--- lib/lp/registry/browser/distroseries.py 2010-05-24 22:04:19 +0000
3+++ lib/lp/registry/browser/distroseries.py 2010-07-28 19:11:08 +0000
4@@ -180,7 +180,6 @@
5
6 # A search link isn't needed because the distro series overview
7 # has a search form.
8-
9 def answers(self):
10 text = 'Ask a question'
11 url = canonical_url(self.context.distribution) + '/+addquestion'
12@@ -332,10 +331,8 @@
13
14 @cachedproperty
15 def needs_linking(self):
16- """Return a list of 10 packages most in need of upstream linking."""
17- # XXX sinzui 2010-02-26 bug=528648: This method causes a timeout.
18- # return self.context.getPrioritizedUnlinkedSourcePackages()[:10]
19- return None
20+ """Return a list of 10 packages most in need of upstream linking."""
21+ return self.context.getPrioritizedUnlinkedSourcePackages()[:10]
22
23 milestone_can_release = False
24
25@@ -481,7 +478,7 @@
26 @cachedproperty
27 def cached_packagings(self):
28 """The batched upstream packaging links."""
29- packagings = self.context.getPrioritizedlPackagings()
30+ packagings = self.context.getPrioritizedPackagings()
31 navigator = BatchNavigator(packagings, self.request, size=20)
32 navigator.setHeadings('packaging', 'packagings')
33 return navigator
34
35=== added file 'lib/lp/registry/browser/tests/test_distroseries_views.py'
36--- lib/lp/registry/browser/tests/test_distroseries_views.py 1970-01-01 00:00:00 +0000
37+++ lib/lp/registry/browser/tests/test_distroseries_views.py 2010-07-28 19:11:08 +0000
38@@ -0,0 +1,52 @@
39+# Copyright 2010 Canonical Ltd. This software is licensed under the
40+# GNU Affero General Public License version 3 (see the file LICENSE).
41+
42+__metaclass__ = type
43+
44+import unittest
45+
46+from storm.zope.interfaces import IResultSet
47+
48+from zope.component import getUtility
49+from zope.security.proxy import removeSecurityProxy
50+
51+from canonical.launchpad.interfaces.launchpad import ILaunchpadCelebrities
52+from canonical.testing import LaunchpadZopelessLayer
53+from lp.testing import TestCaseWithFactory
54+from lp.testing.views import create_initialized_view
55+
56+
57+class TestDistroSeriesNeedsPackagesView(TestCaseWithFactory):
58+ """Test the distroseries +needs-packaging view."""
59+
60+ layer = LaunchpadZopelessLayer
61+
62+ def test_cached_unlinked_packages(self):
63+ ubuntu = getUtility(ILaunchpadCelebrities).ubuntu
64+ distroseries = self.factory.makeDistroSeries(distribution=ubuntu)
65+ view = create_initialized_view(distroseries, '+needs-packaging')
66+ naked_packages = removeSecurityProxy(view.cached_unlinked_packages)
67+ self.assertTrue(
68+ IResultSet.providedBy(
69+ view.cached_unlinked_packages.currentBatch().list),
70+ '%s should batch IResultSet so that slicing will limit the '
71+ 'query' % view.cached_unlinked_packages.currentBatch().list)
72+
73+
74+class TestDistroSeriesView(TestCaseWithFactory):
75+ """Test the distroseries +index view."""
76+
77+ layer = LaunchpadZopelessLayer
78+
79+ def test_needs_linking(self):
80+ ubuntu = getUtility(ILaunchpadCelebrities).ubuntu
81+ distroseries = self.factory.makeDistroSeries(distribution=ubuntu)
82+ view = create_initialized_view(distroseries, '+index')
83+ self.assertTrue(
84+ IResultSet.providedBy(view.needs_linking),
85+ '%s should implement IResultSet so that slicing will limit the '
86+ 'query' % view.needs_linking)
87+
88+
89+def test_suite():
90+ return unittest.TestLoader().loadTestsFromName(__name__)
91
92=== modified file 'lib/lp/registry/doc/distroseries.txt'
93--- lib/lp/registry/doc/distroseries.txt 2010-07-20 09:36:17 +0000
94+++ lib/lp/registry/doc/distroseries.txt 2010-07-28 19:11:08 +0000
95@@ -4,9 +4,10 @@
96 From the DerivationOverview spec
97 <https://launchpad.canonical.com/DerivationOverview>:
98
99- A distribution of GNU/Linux comprises a set of packages, an installer,
100- possibly a live-CD, some amount of metadata associated with the arrangement
101- of those elements and also a lot of information on managing it.
102+ A distribution of GNU/Linux comprises a set of packages, an
103+ installer, possibly a live-CD, some amount of metadata associated
104+ with the arrangement of those elements and also a lot of information
105+ on managing it.
106
107 A distro series is a given version of a distribution. So, for Ubuntu, there
108 are releases (or planned releases) like "warty", "hoary" and "bendy".
109@@ -165,40 +166,40 @@
110 canUploadToPocket method helps us to decide if an upload is allowed or
111 not, according the distroseries status and the upload target pocket.
112
113- >>> from canonical.launchpad.interfaces import IDistributionSet
114- >>> ubuntu = getUtility(IDistributionSet)['ubuntu']
115- >>> breezy_autotest = ubuntu['breezy-autotest']
116- >>> hoary = ubuntu['hoary']
117-
118- >>> from lp.registry.interfaces.pocket import PackagePublishingPocket
119- >>> from canonical.launchpad.interfaces import SeriesStatus
120-
121- >>> warty.status.name
122- 'CURRENT'
123- >>> warty.canUploadToPocket(PackagePublishingPocket.RELEASE)
124- False
125- >>> warty.canUploadToPocket(PackagePublishingPocket.SECURITY)
126- True
127-
128- >>> breezy_autotest.status.name
129- 'EXPERIMENTAL'
130- >>> breezy_autotest.canUploadToPocket(PackagePublishingPocket.RELEASE)
131- True
132- >>> breezy_autotest.canUploadToPocket(PackagePublishingPocket.SECURITY)
133- False
134+ >>> from canonical.launchpad.interfaces import IDistributionSet
135+ >>> ubuntu = getUtility(IDistributionSet)['ubuntu']
136+ >>> breezy_autotest = ubuntu['breezy-autotest']
137+ >>> hoary = ubuntu['hoary']
138+
139+ >>> from lp.registry.interfaces.pocket import PackagePublishingPocket
140+ >>> from canonical.launchpad.interfaces import SeriesStatus
141+
142+ >>> warty.status.name
143+ 'CURRENT'
144+ >>> warty.canUploadToPocket(PackagePublishingPocket.RELEASE)
145+ False
146+ >>> warty.canUploadToPocket(PackagePublishingPocket.SECURITY)
147+ True
148+
149+ >>> breezy_autotest.status.name
150+ 'EXPERIMENTAL'
151+ >>> breezy_autotest.canUploadToPocket(PackagePublishingPocket.RELEASE)
152+ True
153+ >>> breezy_autotest.canUploadToPocket(PackagePublishingPocket.SECURITY)
154+ False
155
156 The FROZEN status is special. Uploads are allowed for all pockets as
157 the upload will have to wait for manual approval anyway:
158
159- >>> from zope.security.proxy import removeSecurityProxy
160- >>> removeSecurityProxy(hoary).status = SeriesStatus.FROZEN
161+ >>> from zope.security.proxy import removeSecurityProxy
162+ >>> removeSecurityProxy(hoary).status = SeriesStatus.FROZEN
163
164- >>> hoary.status.name
165- 'FROZEN'
166- >>> hoary.canUploadToPocket(PackagePublishingPocket.RELEASE)
167- True
168- >>> hoary.canUploadToPocket(PackagePublishingPocket.SECURITY)
169- True
170+ >>> hoary.status.name
171+ 'FROZEN'
172+ >>> hoary.canUploadToPocket(PackagePublishingPocket.RELEASE)
173+ True
174+ >>> hoary.canUploadToPocket(PackagePublishingPocket.SECURITY)
175+ True
176
177
178 Package searching
179@@ -232,44 +233,45 @@
180 are valid for that distroseries. These selections are used by (among
181 other things) the uploader for validating incoming uploads.
182
183- >>> hoary = distroseriesset.get(3)
184- >>> for c in hoary.components:
185- ... print c.name
186- main
187- restricted
188- >>> for s in hoary.sections:
189- ... print s.name
190- base
191- web
192- editors
193- admin
194- devel
195- translations
196-
197- >>> from canonical.launchpad.interfaces import (
198- ... IComponentSet, ISectionSet)
199- >>> python = getUtility(ISectionSet).ensure('python')
200-
201- >>> hoary.addSection(python)
202-
203- >>> for c in hoary.components:
204- ... print c.name
205- main
206- restricted
207-
208- >>> for s in hoary.sections:
209- ... print s.name
210- base
211- web
212- editors
213- admin
214- devel
215- python
216- translations
217+ >>> hoary = distroseriesset.get(3)
218+ >>> for c in hoary.components:
219+ ... print c.name
220+ main
221+ restricted
222+ >>> for s in hoary.sections:
223+ ... print s.name
224+ base
225+ web
226+ editors
227+ admin
228+ devel
229+ translations
230+
231+ >>> from canonical.launchpad.interfaces import (
232+ ... IComponentSet, ISectionSet)
233+ >>> python = getUtility(ISectionSet).ensure('python')
234+
235+ >>> hoary.addSection(python)
236+
237+ >>> for c in hoary.components:
238+ ... print c.name
239+ main
240+ restricted
241+
242+ >>> for s in hoary.sections:
243+ ... print s.name
244+ base
245+ web
246+ editors
247+ admin
248+ devel
249+ python
250+ translations
251
252 Breezy-autotest has got a partner component, which is not reported:
253
254- >>> breezyautotest = distroseriesset.queryByName(ubuntu, "breezy-autotest")
255+ >>> breezyautotest = distroseriesset.queryByName(
256+ ... ubuntu, "breezy-autotest")
257 >>> for c in breezyautotest.components:
258 ... print c.name
259 main
260@@ -307,22 +309,22 @@
261 publishing records etc. Essentially this is a "Do not push this button
262 again" type set of assertions.
263
264- >>> login("foo.bar@canonical.com")
265- >>> humpy = ubuntu.newSeries('humpy', 'Humpy Hippo',
266- ... 'The Humpy Hippo', 'Fat', 'Yo Momma',
267- ... '99.2',hoary, hoary.owner)
268- >>> humpy_i386 = humpy.newArch('i386', hoary['i386'].processorfamily,
269- ... True, humpy.owner)
270- >>> humpy.nominatedarchindep = humpy_i386
271- >>> humpy.initialiseFromParent()
272- >>> len(hoary.getPublishedReleases('pmount'))
273- 1
274- >>> len(humpy.getPublishedReleases('pmount'))
275- 1
276- >>> len(hoary['i386'].getReleasedPackages('pmount'))
277- 1
278- >>> len(humpy_i386.getReleasedPackages('pmount'))
279- 1
280+ >>> login("foo.bar@canonical.com")
281+ >>> humpy = ubuntu.newSeries('humpy', 'Humpy Hippo',
282+ ... 'The Humpy Hippo', 'Fat', 'Yo Momma',
283+ ... '99.2',hoary, hoary.owner)
284+ >>> humpy_i386 = humpy.newArch('i386', hoary['i386'].processorfamily,
285+ ... True, humpy.owner)
286+ >>> humpy.nominatedarchindep = humpy_i386
287+ >>> humpy.initialiseFromParent()
288+ >>> len(hoary.getPublishedReleases('pmount'))
289+ 1
290+ >>> len(humpy.getPublishedReleases('pmount'))
291+ 1
292+ >>> len(hoary['i386'].getReleasedPackages('pmount'))
293+ 1
294+ >>> len(humpy_i386.getReleasedPackages('pmount'))
295+ 1
296
297 Check if the attributes of an DRSPR instance for the just initialised
298 distroseries are sane. A DRSPR instance should filter attributes of
299@@ -344,42 +346,42 @@
300 Initialise a new distroseries based on warty (since it has, at least
301 one coherent published source + binary, mozilla-firefox)
302
303- >>> bumpy = ubuntu.newSeries('bumpy', 'Bumpy',
304- ... 'The Bumpy', 'Fat', 'Boom',
305- ... '99.3', warty, warty.owner)
306+ >>> bumpy = ubuntu.newSeries('bumpy', 'Bumpy',
307+ ... 'The Bumpy', 'Fat', 'Boom',
308+ ... '99.3', warty, warty.owner)
309
310- >>> bumpy_i386 = bumpy.newArch('i386', warty['i386'].processorfamily,
311- ... True, bumpy.owner)
312- >>> bumpy.nominatedarchindep = bumpy_i386
313- >>> bumpy.initialiseFromParent()
314+ >>> bumpy_i386 = bumpy.newArch('i386', warty['i386'].processorfamily,
315+ ... True, bumpy.owner)
316+ >>> bumpy.nominatedarchindep = bumpy_i386
317+ >>> bumpy.initialiseFromParent()
318
319 Build a new ISourcePackage based in the new distroseries:
320
321- >>> bumpy_firefox_sp = bumpy.getSourcePackage('mozilla-firefox')
322+ >>> bumpy_firefox_sp = bumpy.getSourcePackage('mozilla-firefox')
323
324 Check the content IDRSPR binaries & builds attributes:
325
326 'binaries' should be inherited from parent release.
327
328- >>> bumpy_firefox_sp.currentrelease.binaries.count()
329- 2
330+ >>> bumpy_firefox_sp.currentrelease.binaries.count()
331+ 2
332
333- >>> for bin in bumpy_firefox_sp.currentrelease.binaries:
334- ... print bin.id, bin.title, bin.build.distro_arch_series.title
335- 27 mozilla-firefox-data-0.9 The Warty Warthog Release for i386 (x86)
336- 12 mozilla-firefox-0.9 The Warty Warthog Release for i386 (x86)
337+ >>> for bin in bumpy_firefox_sp.currentrelease.binaries:
338+ ... print bin.id, bin.title, bin.build.distro_arch_series.title
339+ 27 mozilla-firefox-data-0.9 The Warty Warthog Release for i386 (x86)
340+ 12 mozilla-firefox-0.9 The Warty Warthog Release for i386 (x86)
341
342
343 'builds' should be empty since it was built in parent (warty), not in this
344 distroseries (bumby.
345
346- >>> len(bumpy_firefox_sp.currentrelease.builds)
347- 0
348+ >>> len(bumpy_firefox_sp.currentrelease.builds)
349+ 0
350
351 the SPR returns all build records for it.
352
353- >>> bumpy_firefox_sp.currentrelease.sourcepackagerelease.builds.count()
354- 4
355+ >>> bumpy_firefox_sp.currentrelease.sourcepackagerelease.builds.count()
356+ 4
357
358 The new series also has the same packaging links as its parent series.
359
360@@ -406,22 +408,22 @@
361 You can easily find out what packages are translatable in a
362 distribution release:
363
364- >>> translatables = hoary.getTranslatableSourcePackages()
365- >>> for translatable in translatables:
366- ... print translatable.name
367- evolution
368- mozilla
369- pmount
370+ >>> translatables = hoary.getTranslatableSourcePackages()
371+ >>> for translatable in translatables:
372+ ... print translatable.name
373+ evolution
374+ mozilla
375+ pmount
376
377 Packages can be linked to upstream productseries in specific
378 distribution releases. IDistroSeries offers a way to query translatable
379 packages that are linked to upstream productseries.
380
381- >>> unlinked_translatables = hoary.getUnlinkedTranslatableSourcePackages()
382- >>> for translatable in unlinked_translatables:
383- ... print translatable.name
384- pmount
385- mozilla
386+ >>> unlinked_translatables = hoary.getUnlinkedTranslatableSourcePackages()
387+ >>> for translatable in unlinked_translatables:
388+ ... print translatable.name
389+ pmount
390+ mozilla
391
392 The links to upstream product series can be verified using the
393 packagings property:
394@@ -457,11 +459,11 @@
395 linux-source-2.6.15 0 0
396
397
398-The distroseries getPrioritizedlPackagings() method that returns a prioritized
399+The distroseries getPrioritizedPackagings() method that returns a prioritized
400 list of `IPackaging` that need more information about the upstream project to
401 share bugs, translations, and code.
402
403- >>> for packaging in hoary.getPrioritizedlPackagings():
404+ >>> for packaging in hoary.getPrioritizedPackagings():
405 ... print packaging.sourcepackagename.name
406 netapplet
407 evolution
408@@ -502,109 +504,109 @@
409 DistroSeries can build meta objects for packages
410 ------------------------------------------------
411
412- >>> from canonical.launchpad.interfaces import (
413- ... ISourcePackage,
414- ... IDistroSeriesBinaryPackage,
415- ... IDistroSeriesSourcePackageRelease)
416-
417- >>> pmount_src_name = SourcePackageName.byName('pmount')
418- >>> pmount_source = hoary.getSourcePackage(pmount_src_name)
419- >>> ISourcePackage.providedBy(pmount_source)
420- True
421-
422- >>> from lp.soyuz.model.binarypackagename import (
423- ... BinaryPackageName)
424- >>> pmount_bin_name = BinaryPackageName.byName('pmount')
425- >>> pmount_drbp = hoary.getBinaryPackage(pmount_bin_name)
426- >>> IDistroSeriesBinaryPackage.providedBy(pmount_drbp)
427- True
428- >>> len(pmount_drbp.current_publishings)
429- 3
430-
431- >>> from lp.soyuz.model.sourcepackagerelease import (
432- ... SourcePackageRelease)
433- >>> pmount_rel = SourcePackageRelease.selectOneBy(
434- ... sourcepackagenameID=pmount_src_name.id, version='0.1-1')
435- >>> pmount_rel.sourcepackagename.name
436- u'pmount'
437-
438- >>> pmount_srcrel = hoary.getSourcePackageRelease(pmount_rel)
439- >>> IDistroSeriesSourcePackageRelease.providedBy(pmount_srcrel)
440- True
441+ >>> from canonical.launchpad.interfaces import (
442+ ... ISourcePackage,
443+ ... IDistroSeriesBinaryPackage,
444+ ... IDistroSeriesSourcePackageRelease)
445+
446+ >>> pmount_src_name = SourcePackageName.byName('pmount')
447+ >>> pmount_source = hoary.getSourcePackage(pmount_src_name)
448+ >>> ISourcePackage.providedBy(pmount_source)
449+ True
450+
451+ >>> from lp.soyuz.model.binarypackagename import (
452+ ... BinaryPackageName)
453+ >>> pmount_bin_name = BinaryPackageName.byName('pmount')
454+ >>> pmount_drbp = hoary.getBinaryPackage(pmount_bin_name)
455+ >>> IDistroSeriesBinaryPackage.providedBy(pmount_drbp)
456+ True
457+ >>> len(pmount_drbp.current_publishings)
458+ 3
459+
460+ >>> from lp.soyuz.model.sourcepackagerelease import (
461+ ... SourcePackageRelease)
462+ >>> pmount_rel = SourcePackageRelease.selectOneBy(
463+ ... sourcepackagenameID=pmount_src_name.id, version='0.1-1')
464+ >>> pmount_rel.sourcepackagename.name
465+ u'pmount'
466+
467+ >>> pmount_srcrel = hoary.getSourcePackageRelease(pmount_rel)
468+ >>> IDistroSeriesSourcePackageRelease.providedBy(pmount_srcrel)
469+ True
470
471 Check some properties of DRSPR meta class
472
473 Entire publishing history:
474
475- >>> pmount_srcrel.publishing_history.count()
476- 1
477+ >>> pmount_srcrel.publishing_history.count()
478+ 1
479
480 Most recent published history row:
481
482- >>> pmount_srcrel.current_published is None
483- True
484-
485- >>> netapplet_srcrel = hoary.getSourcePackage('netapplet').currentrelease
486- >>> spph = netapplet_srcrel.current_published
487-
488- >>> spph.section.name
489- u'web'
490+ >>> pmount_srcrel.current_published is None
491+ True
492+
493+ >>> netapplet_srcrel = hoary.getSourcePackage('netapplet').currentrelease
494+ >>> spph = netapplet_srcrel.current_published
495+
496+ >>> spph.section.name
497+ u'web'
498
499 The changesfile attribute contains the package changelog. It is provided as
500 an ILibraryFileAlias:
501
502- >>> firefox_srcrel = warty.getSourcePackage(
503- ... 'mozilla-firefox').currentrelease
504- >>> print firefox_srcrel.title
505- "mozilla-firefox" 0.9 source package in The Warty Warthog Release
506+ >>> firefox_srcrel = warty.getSourcePackage(
507+ ... 'mozilla-firefox').currentrelease
508+ >>> print firefox_srcrel.title
509+ "mozilla-firefox" 0.9 source package in The Warty Warthog Release
510
511- >>> firefox_srcrel.changesfile
512- <LibraryFileAlias at ...>
513+ >>> firefox_srcrel.changesfile
514+ <LibraryFileAlias at ...>
515
516 If the package changelog is not available, that attribute is None:
517
518- >>> netapplet_srcrel.changesfile is None
519- True
520+ >>> netapplet_srcrel.changesfile is None
521+ True
522
523 Perform `post publication` override:
524
525- >>> new_section = getUtility(ISectionSet)['base']
526-
527- >>> override = netapplet_srcrel.current_published.changeOverride(
528- ... new_section=new_section)
529-
530- >>> override.section == new_section
531- True
532-
533- >>> print override.status.name
534- PENDING
535-
536- >>> netapplet_srcrel.publishing_history.count()
537- 2
538+ >>> new_section = getUtility(ISectionSet)['base']
539+
540+ >>> override = netapplet_srcrel.current_published.changeOverride(
541+ ... new_section=new_section)
542+
543+ >>> override.section == new_section
544+ True
545+
546+ >>> print override.status.name
547+ PENDING
548+
549+ >>> netapplet_srcrel.publishing_history.count()
550+ 2
551
552 Override information about 'pmount' is pending publication:
553
554- >>> print netapplet_srcrel.current_published.status.name
555- PENDING
556+ >>> print netapplet_srcrel.current_published.status.name
557+ PENDING
558
559- >>> print netapplet_srcrel.current_published.section.name
560- base
561+ >>> print netapplet_srcrel.current_published.section.name
562+ base
563
564 Supersede previous netapplet publication:
565
566- >>> last_published = netapplet_srcrel.publishing_history[1]
567- >>> last_published.supersede()
568- >>> flush_database_updates()
569-
570- >>> netapplet_srcrel.publishing_history.count()
571- 2
572-
573- >>> print last_published.status.name
574- SUPERSEDED
575-
576- >>> from canonical.database.sqlbase import get_transaction_timestamp
577- >>> last_published.datesuperseded == get_transaction_timestamp()
578- True
579+ >>> last_published = netapplet_srcrel.publishing_history[1]
580+ >>> last_published.supersede()
581+ >>> flush_database_updates()
582+
583+ >>> netapplet_srcrel.publishing_history.count()
584+ 2
585+
586+ >>> print last_published.status.name
587+ SUPERSEDED
588+
589+ >>> from canonical.database.sqlbase import get_transaction_timestamp
590+ >>> last_published.datesuperseded == get_transaction_timestamp()
591+ True
592
593
594 SourcePackagePublishingHistory
595@@ -616,114 +618,114 @@
596 instance. it can also be used to generate the archive packages list in
597 the future.
598
599- >>> ubuntu = getUtility(IDistributionSet)['ubuntu']
600- >>> hoary = ubuntu['hoary']
601-
602- >>> from canonical.launchpad.interfaces import (
603- ... PackagePublishingStatus)
604-
605- >>> hoary_pub_sources = hoary.getSourcePackagePublishing(
606- ... PackagePublishingStatus.PUBLISHED,
607- ... PackagePublishingPocket.RELEASE)
608-
609- >>> hoary_pub_sources.count()
610- 6
611-
612- >>> for pub in hoary_pub_sources:
613- ... print pub.displayname
614- alsa-utils 1.0.9a-4ubuntu1 in hoary
615- cnews cr.g7-37 in hoary
616- evolution 1.0 in hoary
617- libstdc++ b8p in hoary
618- linux-source-2.6.15 2.6.15.3 in hoary
619- pmount 0.1-2 in hoary
620-
621- >>> hoary_pub_source = hoary_pub_sources[0]
622-
623- >>> hoary_pub_source.sourcepackagerelease.name
624- u'alsa-utils'
625-
626- >>> hoary_pub_source.sourcepackagerelease.version
627- u'1.0.9a-4ubuntu1'
628-
629- >>> hoary_pub_source.component.name
630- u'main'
631-
632- >>> hoary_pub_source.section.name
633- u'base'
634-
635- >>> hoary.getSourcePackagePublishing(
636- ... PackagePublishingStatus.PUBLISHED,
637- ... PackagePublishingPocket.UPDATES).count()
638- 0
639+ >>> ubuntu = getUtility(IDistributionSet)['ubuntu']
640+ >>> hoary = ubuntu['hoary']
641+
642+ >>> from canonical.launchpad.interfaces import (
643+ ... PackagePublishingStatus)
644+
645+ >>> hoary_pub_sources = hoary.getSourcePackagePublishing(
646+ ... PackagePublishingStatus.PUBLISHED,
647+ ... PackagePublishingPocket.RELEASE)
648+
649+ >>> hoary_pub_sources.count()
650+ 6
651+
652+ >>> for pub in hoary_pub_sources:
653+ ... print pub.displayname
654+ alsa-utils 1.0.9a-4ubuntu1 in hoary
655+ cnews cr.g7-37 in hoary
656+ evolution 1.0 in hoary
657+ libstdc++ b8p in hoary
658+ linux-source-2.6.15 2.6.15.3 in hoary
659+ pmount 0.1-2 in hoary
660+
661+ >>> hoary_pub_source = hoary_pub_sources[0]
662+
663+ >>> hoary_pub_source.sourcepackagerelease.name
664+ u'alsa-utils'
665+
666+ >>> hoary_pub_source.sourcepackagerelease.version
667+ u'1.0.9a-4ubuntu1'
668+
669+ >>> hoary_pub_source.component.name
670+ u'main'
671+
672+ >>> hoary_pub_source.section.name
673+ u'base'
674+
675+ >>> hoary.getSourcePackagePublishing(
676+ ... PackagePublishingStatus.PUBLISHED,
677+ ... PackagePublishingPocket.UPDATES).count()
678+ 0
679
680 This method also allow us to restrict the results to a given
681 component:
682
683- >>> component_main = getUtility(IComponentSet)['main']
684- >>> hoary.getSourcePackagePublishing(
685- ... PackagePublishingStatus.PUBLISHED,
686- ... PackagePublishingPocket.RELEASE,
687- ... component=component_main).count()
688- 5
689+ >>> component_main = getUtility(IComponentSet)['main']
690+ >>> hoary.getSourcePackagePublishing(
691+ ... PackagePublishingStatus.PUBLISHED,
692+ ... PackagePublishingPocket.RELEASE,
693+ ... component=component_main).count()
694+ 5
695
696- >>> component_multiverse = getUtility(IComponentSet)['multiverse']
697- >>> hoary.getSourcePackagePublishing(
698- ... PackagePublishingStatus.PUBLISHED,
699- ... PackagePublishingPocket.RELEASE,
700- ... component=component_multiverse).count()
701- 0
702+ >>> component_multiverse = getUtility(IComponentSet)['multiverse']
703+ >>> hoary.getSourcePackagePublishing(
704+ ... PackagePublishingStatus.PUBLISHED,
705+ ... PackagePublishingPocket.RELEASE,
706+ ... component=component_multiverse).count()
707+ 0
708
709 By default the IDistribution 'main_archive' is considered, but It also
710 allows the callsite to specify one and then the result will be
711 restricted to it.
712
713- >>> debian_archive = getUtility(IDistributionSet)['debian'].main_archive
714- >>> print debian_archive.purpose.title
715- Primary Archive
716+ >>> debian_archive = getUtility(IDistributionSet)['debian'].main_archive
717+ >>> print debian_archive.purpose.title
718+ Primary Archive
719
720- >>> hoary.getSourcePackagePublishing(
721- ... PackagePublishingStatus.PUBLISHED,
722- ... PackagePublishingPocket.RELEASE,
723- ... component=component_main, archive=debian_archive).count()
724- 0
725+ >>> hoary.getSourcePackagePublishing(
726+ ... PackagePublishingStatus.PUBLISHED,
727+ ... PackagePublishingPocket.RELEASE,
728+ ... component=component_main, archive=debian_archive).count()
729+ 0
730
731 ISPP.getPublishedBinaries returns all the binaries generated by the
732 publication in question:
733
734- >>> warty = ubuntu['warty']
735- >>> warty_pub_sources = warty.getSourcePackagePublishing(
736- ... PackagePublishingStatus.PUBLISHED,
737- ... PackagePublishingPocket.RELEASE)
738-
739- >>> warty_pub_source = warty_pub_sources[4]
740- >>> warty_pub_source.sourcepackagerelease.name
741- u'mozilla-firefox'
742- >>> warty_pub_source.sourcepackagerelease.version
743- u'0.9'
744- >>> warty_pub_source.component.name
745- u'main'
746- >>> warty_pub_source.section.name
747- u'web'
748-
749- >>> warty_mozilla_pub_binaries = warty_pub_source.getPublishedBinaries()
750- >>> len(warty_mozilla_pub_binaries)
751- 4
752- >>> warty_mozilla_pub_bin = warty_mozilla_pub_binaries[0]
753-
754- >>> from canonical.launchpad.interfaces import (
755- ... IBinaryPackagePublishingHistory)
756- >>> verifyObject(IBinaryPackagePublishingHistory, warty_mozilla_pub_bin)
757- True
758-
759- >>> warty_mozilla_pub_bin.binarypackagerelease.name
760- u'mozilla-firefox'
761- >>> warty_mozilla_pub_bin.binarypackagerelease.version
762- u'0.9'
763- >>> warty_mozilla_pub_bin.component.name
764- u'main'
765- >>> warty_mozilla_pub_bin.section.name
766- u'base'
767+ >>> warty = ubuntu['warty']
768+ >>> warty_pub_sources = warty.getSourcePackagePublishing(
769+ ... PackagePublishingStatus.PUBLISHED,
770+ ... PackagePublishingPocket.RELEASE)
771+
772+ >>> warty_pub_source = warty_pub_sources[4]
773+ >>> warty_pub_source.sourcepackagerelease.name
774+ u'mozilla-firefox'
775+ >>> warty_pub_source.sourcepackagerelease.version
776+ u'0.9'
777+ >>> warty_pub_source.component.name
778+ u'main'
779+ >>> warty_pub_source.section.name
780+ u'web'
781+
782+ >>> warty_mozilla_pub_binaries = warty_pub_source.getPublishedBinaries()
783+ >>> len(warty_mozilla_pub_binaries)
784+ 4
785+ >>> warty_mozilla_pub_bin = warty_mozilla_pub_binaries[0]
786+
787+ >>> from canonical.launchpad.interfaces import (
788+ ... IBinaryPackagePublishingHistory)
789+ >>> verifyObject(IBinaryPackagePublishingHistory, warty_mozilla_pub_bin)
790+ True
791+
792+ >>> warty_mozilla_pub_bin.binarypackagerelease.name
793+ u'mozilla-firefox'
794+ >>> warty_mozilla_pub_bin.binarypackagerelease.version
795+ u'0.9'
796+ >>> warty_mozilla_pub_bin.component.name
797+ u'main'
798+ >>> warty_mozilla_pub_bin.section.name
799+ u'base'
800
801 DistroSeries.getBinaryPackagePublishing will return
802 BinaryPackagePublishingHistory objects for the DistroSeries:
803
804=== modified file 'lib/lp/registry/interfaces/distroseries.py'
805--- lib/lp/registry/interfaces/distroseries.py 2010-06-08 15:58:04 +0000
806+++ lib/lp/registry/interfaces/distroseries.py 2010-07-28 19:11:08 +0000
807@@ -414,7 +414,7 @@
808 and total_messages (translatable messages).
809 """
810
811- def getPrioritizedlPackagings():
812+ def getPrioritizedPackagings():
813 """Return a list of packagings that need more upstream information."""
814
815 def getMostRecentlyLinkedPackagings():
816@@ -514,15 +514,16 @@
817
818 If version is not specified, return packages with any version.
819
820- if exclude_pocket is specified we exclude results matching that pocket.
821+ If exclude_pocket is specified we exclude results matching that
822+ pocket.
823
824 If 'include_pending' is True, we return also the pending publication
825 records, those packages that will get published in the next publisher
826 run (it's only useful when we need to know if a given package is
827 known during a publisher run, mostly in pre-upload checks)
828
829- If 'archive' is not specified consider publication in the main_archive,
830- otherwise respect the given value.
831+ If 'archive' is not specified consider publication in the
832+ main_archive, otherwise respect the given value.
833 """
834
835 def getAllPublishedSources():
836
837=== modified file 'lib/lp/registry/model/distroseries.py'
838--- lib/lp/registry/model/distroseries.py 2010-07-15 15:01:18 +0000
839+++ lib/lp/registry/model/distroseries.py 2010-07-28 19:11:08 +0000
840@@ -19,7 +19,7 @@
841 BoolCol, StringCol, ForeignKey, SQLMultipleJoin, IntCol,
842 SQLObjectNotFound, SQLRelatedJoin)
843
844-from storm.locals import And, Desc, Join, SQL
845+from storm.locals import Desc, Join, SQL
846 from storm.store import Store
847
848 from zope.component import getUtility
849@@ -335,14 +335,19 @@
850 condition = SQL(conditions + "AND packaging.id IS NULL")
851 results = IStore(self).using(origin).find(find_spec, condition)
852 results = results.order_by('score DESC', SourcePackageName.name)
853- return [{
854- 'package': SourcePackage(
855+ results = results.config(distinct=True)
856+
857+ def decorator(result):
858+ spn, score, bug_count, total_messages = result
859+ return {
860+ 'package': SourcePackage(
861 sourcepackagename=spn, distroseries=self),
862- 'bug_count': bug_count,
863- 'total_messages': total_messages}
864- for (spn, score, bug_count, total_messages) in results]
865+ 'bug_count': bug_count,
866+ 'total_messages': total_messages,
867+ }
868+ return DecoratedResultSet(results, decorator)
869
870- def getPrioritizedlPackagings(self):
871+ def getPrioritizedPackagings(self):
872 """See `IDistroSeries`.
873
874 The prioritization is a heuristic rule using the branch, bug heat,
875@@ -352,18 +357,6 @@
876 # the objects that are implcitly needed to work with a
877 # Packaging object.
878 # Avoid circular import failures.
879- from lp.registry.model.product import Product
880- from lp.registry.model.productseries import ProductSeries
881- find_spec = (
882- Packaging, SourcePackageName, ProductSeries, Product,
883- SQL("""
884- CASE WHEN spr.component = 1 THEN 1000 ELSE 0 END +
885- CASE WHEN Product.bugtracker IS NULL
886- THEN coalesce(total_bug_heat, 10) ELSE 0 END +
887- CASE WHEN ProductSeries.translations_autoimport_mode = 1
888- THEN coalesce(po_messages, 10) ELSE 0 END +
889- CASE WHEN ProductSeries.branch IS NULL THEN 500
890- ELSE 0 END AS score"""))
891 joins, conditions = self._current_sourcepackage_joins_and_conditions
892 origin = SQL(joins + """
893 JOIN ProductSeries
894@@ -372,10 +365,19 @@
895 ON ProductSeries.product = Product.id
896 """)
897 condition = SQL(conditions + "AND packaging.id IS NOT NULL")
898- results = IStore(self).using(origin).find(find_spec, condition)
899- results = results.order_by('score DESC, SourcePackageName.name ASC')
900- return [packaging
901- for (packaging, spn, series, product, score) in results]
902+ results = IStore(self).using(origin).find(Packaging, condition)
903+ return results.order_by("""
904+ (
905+ CASE WHEN spr.component = 1 THEN 1000 ELSE 0 END
906+ + CASE WHEN Product.bugtracker IS NULL
907+ THEN coalesce(total_bug_heat, 10) ELSE 0 END
908+ + CASE WHEN ProductSeries.translations_autoimport_mode = 1
909+ THEN coalesce(po_messages, 10) ELSE 0 END
910+ + CASE WHEN ProductSeries.branch IS NULL THEN 500
911+ ELSE 0 END
912+ ) DESC,
913+ SourcePackageName.name ASC
914+ """)
915
916 @property
917 def _current_sourcepackage_joins_and_conditions(self):
918
919=== modified file 'lib/lp/registry/stories/distroseries/xx-distroseries-index.txt'
920--- lib/lp/registry/stories/distroseries/xx-distroseries-index.txt 2010-02-26 19:18:37 +0000
921+++ lib/lp/registry/stories/distroseries/xx-distroseries-index.txt 2010-07-28 19:11:08 +0000
922@@ -100,4 +100,9 @@
923 evolution linked...
924 mozilla-firefox linked...
925 netapplet linked 2005-07-05
926- Needs upstream links All upstream links
927+ Needs more information or linking to upstream:
928+ cdrkit
929+ iceweasel
930+ linux-source-2.6.15
931+ Needs upstream links
932+ All upstream links
933
934=== modified file 'lib/lp/registry/templates/distroseries-portlet-packaging.pt'
935--- lib/lp/registry/templates/distroseries-portlet-packaging.pt 2010-05-27 04:10:17 +0000
936+++ lib/lp/registry/templates/distroseries-portlet-packaging.pt 2010-07-28 19:11:08 +0000
937@@ -56,7 +56,7 @@
938 </dt>
939 <dd tal:condition="view/needs_linking">
940 <ul class="horizontal">
941- <li repeat="package view/needs_linking">
942+ <li tal:repeat="package view/needs_linking">
943 <a class="sprite package-source"
944 tal:attributes="href package/package/fmt:url"
945 tal:content="package/package/name">evolution</a>
946
947=== modified file 'lib/lp/registry/tests/test_distroseries.py'
948--- lib/lp/registry/tests/test_distroseries.py 2010-07-20 17:50:45 +0000
949+++ lib/lp/registry/tests/test_distroseries.py 2010-07-28 19:11:08 +0000
950@@ -271,17 +271,17 @@
951 u'main', u'hot-translatable', u'hot', u'translatable', u'normal']
952 self.assertEqual(expected, names)
953
954- def test_getPrioritizedlPackagings(self):
955+ def test_getPrioritizedPackagings(self):
956 # Verify the ordering of packagings that need more upstream info.
957 for name in ['main', 'hot-translatable', 'hot', 'translatable']:
958 self.linkPackage(name)
959- packagings = self.series.getPrioritizedlPackagings()
960+ packagings = self.series.getPrioritizedPackagings()
961 names = [packaging.sourcepackagename.name for packaging in packagings]
962 expected = [
963 u'main', u'hot-translatable', u'hot', u'translatable', u'linked']
964 self.assertEqual(expected, names)
965
966- def test_getPrioritizedlPackagings_bug_tracker(self):
967+ def test_getPrioritizedPackagings_bug_tracker(self):
968 # Verify the ordering of packagings with and without a bug tracker.
969 self.linkPackage('hot')
970 self.makeSeriesPackage('cold')
971@@ -289,12 +289,12 @@
972 naked_product_series = remove_security_proxy_and_shout_at_engineer(
973 product_series)
974 naked_product_series.product.bugtraker = self.factory.makeBugTracker()
975- packagings = self.series.getPrioritizedlPackagings()
976+ packagings = self.series.getPrioritizedPackagings()
977 names = [packaging.sourcepackagename.name for packaging in packagings]
978 expected = [u'hot', u'cold', u'linked']
979 self.assertEqual(expected, names)
980
981- def test_getPrioritizedlPackagings_branch(self):
982+ def test_getPrioritizedPackagings_branch(self):
983 # Verify the ordering of packagings with and without a branch.
984 self.linkPackage('translatable')
985 self.makeSeriesPackage('withbranch')
986@@ -302,12 +302,12 @@
987 naked_product_series = remove_security_proxy_and_shout_at_engineer(
988 product_series)
989 naked_product_series.branch = self.factory.makeBranch()
990- packagings = self.series.getPrioritizedlPackagings()
991+ packagings = self.series.getPrioritizedPackagings()
992 names = [packaging.sourcepackagename.name for packaging in packagings]
993 expected = [u'translatable', u'linked', u'withbranch']
994 self.assertEqual(expected, names)
995
996- def test_getPrioritizedlPackagings_translation(self):
997+ def test_getPrioritizedPackagings_translation(self):
998 # Verify the ordering of translatable packagings that are and are not
999 # configured to import.
1000 self.linkPackage('translatable')
1001@@ -318,7 +318,7 @@
1002 naked_product_series.branch = self.factory.makeBranch()
1003 naked_product_series.translations_autoimport_mode = (
1004 TranslationsBranchImportMode.IMPORT_TEMPLATES)
1005- packagings = self.series.getPrioritizedlPackagings()
1006+ packagings = self.series.getPrioritizedPackagings()
1007 names = [packaging.sourcepackagename.name for packaging in packagings]
1008 expected = [u'translatable', u'linked', u'importabletranslatable']
1009 self.assertEqual(expected, names)