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
=== modified file 'lib/lp/registry/browser/distroseries.py'
--- lib/lp/registry/browser/distroseries.py 2010-05-24 22:04:19 +0000
+++ lib/lp/registry/browser/distroseries.py 2010-07-28 19:11:08 +0000
@@ -180,7 +180,6 @@
180180
181 # A search link isn't needed because the distro series overview181 # A search link isn't needed because the distro series overview
182 # has a search form.182 # has a search form.
183
184 def answers(self):183 def answers(self):
185 text = 'Ask a question'184 text = 'Ask a question'
186 url = canonical_url(self.context.distribution) + '/+addquestion'185 url = canonical_url(self.context.distribution) + '/+addquestion'
@@ -332,10 +331,8 @@
332331
333 @cachedproperty332 @cachedproperty
334 def needs_linking(self):333 def needs_linking(self):
335 """Return a list of 10 packages most in need of upstream linking.""" 334 """Return a list of 10 packages most in need of upstream linking."""
336 # XXX sinzui 2010-02-26 bug=528648: This method causes a timeout.335 return self.context.getPrioritizedUnlinkedSourcePackages()[:10]
337 # return self.context.getPrioritizedUnlinkedSourcePackages()[:10]
338 return None
339336
340 milestone_can_release = False337 milestone_can_release = False
341338
@@ -481,7 +478,7 @@
481 @cachedproperty478 @cachedproperty
482 def cached_packagings(self):479 def cached_packagings(self):
483 """The batched upstream packaging links."""480 """The batched upstream packaging links."""
484 packagings = self.context.getPrioritizedlPackagings()481 packagings = self.context.getPrioritizedPackagings()
485 navigator = BatchNavigator(packagings, self.request, size=20)482 navigator = BatchNavigator(packagings, self.request, size=20)
486 navigator.setHeadings('packaging', 'packagings')483 navigator.setHeadings('packaging', 'packagings')
487 return navigator484 return navigator
488485
=== added file 'lib/lp/registry/browser/tests/test_distroseries_views.py'
--- lib/lp/registry/browser/tests/test_distroseries_views.py 1970-01-01 00:00:00 +0000
+++ lib/lp/registry/browser/tests/test_distroseries_views.py 2010-07-28 19:11:08 +0000
@@ -0,0 +1,52 @@
1# Copyright 2010 Canonical Ltd. This software is licensed under the
2# GNU Affero General Public License version 3 (see the file LICENSE).
3
4__metaclass__ = type
5
6import unittest
7
8from storm.zope.interfaces import IResultSet
9
10from zope.component import getUtility
11from zope.security.proxy import removeSecurityProxy
12
13from canonical.launchpad.interfaces.launchpad import ILaunchpadCelebrities
14from canonical.testing import LaunchpadZopelessLayer
15from lp.testing import TestCaseWithFactory
16from lp.testing.views import create_initialized_view
17
18
19class TestDistroSeriesNeedsPackagesView(TestCaseWithFactory):
20 """Test the distroseries +needs-packaging view."""
21
22 layer = LaunchpadZopelessLayer
23
24 def test_cached_unlinked_packages(self):
25 ubuntu = getUtility(ILaunchpadCelebrities).ubuntu
26 distroseries = self.factory.makeDistroSeries(distribution=ubuntu)
27 view = create_initialized_view(distroseries, '+needs-packaging')
28 naked_packages = removeSecurityProxy(view.cached_unlinked_packages)
29 self.assertTrue(
30 IResultSet.providedBy(
31 view.cached_unlinked_packages.currentBatch().list),
32 '%s should batch IResultSet so that slicing will limit the '
33 'query' % view.cached_unlinked_packages.currentBatch().list)
34
35
36class TestDistroSeriesView(TestCaseWithFactory):
37 """Test the distroseries +index view."""
38
39 layer = LaunchpadZopelessLayer
40
41 def test_needs_linking(self):
42 ubuntu = getUtility(ILaunchpadCelebrities).ubuntu
43 distroseries = self.factory.makeDistroSeries(distribution=ubuntu)
44 view = create_initialized_view(distroseries, '+index')
45 self.assertTrue(
46 IResultSet.providedBy(view.needs_linking),
47 '%s should implement IResultSet so that slicing will limit the '
48 'query' % view.needs_linking)
49
50
51def test_suite():
52 return unittest.TestLoader().loadTestsFromName(__name__)
053
=== modified file 'lib/lp/registry/doc/distroseries.txt'
--- lib/lp/registry/doc/distroseries.txt 2010-07-20 09:36:17 +0000
+++ lib/lp/registry/doc/distroseries.txt 2010-07-28 19:11:08 +0000
@@ -4,9 +4,10 @@
4From the DerivationOverview spec4From the DerivationOverview spec
5<https://launchpad.canonical.com/DerivationOverview>:5<https://launchpad.canonical.com/DerivationOverview>:
66
7 A distribution of GNU/Linux comprises a set of packages, an installer,7 A distribution of GNU/Linux comprises a set of packages, an
8 possibly a live-CD, some amount of metadata associated with the arrangement8 installer, possibly a live-CD, some amount of metadata associated
9 of those elements and also a lot of information on managing it.9 with the arrangement of those elements and also a lot of information
10 on managing it.
1011
11A distro series is a given version of a distribution. So, for Ubuntu, there12A distro series is a given version of a distribution. So, for Ubuntu, there
12are releases (or planned releases) like "warty", "hoary" and "bendy".13are releases (or planned releases) like "warty", "hoary" and "bendy".
@@ -165,40 +166,40 @@
165canUploadToPocket method helps us to decide if an upload is allowed or166canUploadToPocket method helps us to decide if an upload is allowed or
166not, according the distroseries status and the upload target pocket.167not, according the distroseries status and the upload target pocket.
167168
168 >>> from canonical.launchpad.interfaces import IDistributionSet169 >>> from canonical.launchpad.interfaces import IDistributionSet
169 >>> ubuntu = getUtility(IDistributionSet)['ubuntu']170 >>> ubuntu = getUtility(IDistributionSet)['ubuntu']
170 >>> breezy_autotest = ubuntu['breezy-autotest']171 >>> breezy_autotest = ubuntu['breezy-autotest']
171 >>> hoary = ubuntu['hoary']172 >>> hoary = ubuntu['hoary']
172173
173 >>> from lp.registry.interfaces.pocket import PackagePublishingPocket174 >>> from lp.registry.interfaces.pocket import PackagePublishingPocket
174 >>> from canonical.launchpad.interfaces import SeriesStatus175 >>> from canonical.launchpad.interfaces import SeriesStatus
175176
176 >>> warty.status.name177 >>> warty.status.name
177 'CURRENT'178 'CURRENT'
178 >>> warty.canUploadToPocket(PackagePublishingPocket.RELEASE)179 >>> warty.canUploadToPocket(PackagePublishingPocket.RELEASE)
179 False180 False
180 >>> warty.canUploadToPocket(PackagePublishingPocket.SECURITY)181 >>> warty.canUploadToPocket(PackagePublishingPocket.SECURITY)
181 True182 True
182183
183 >>> breezy_autotest.status.name184 >>> breezy_autotest.status.name
184 'EXPERIMENTAL'185 'EXPERIMENTAL'
185 >>> breezy_autotest.canUploadToPocket(PackagePublishingPocket.RELEASE)186 >>> breezy_autotest.canUploadToPocket(PackagePublishingPocket.RELEASE)
186 True187 True
187 >>> breezy_autotest.canUploadToPocket(PackagePublishingPocket.SECURITY)188 >>> breezy_autotest.canUploadToPocket(PackagePublishingPocket.SECURITY)
188 False189 False
189190
190The FROZEN status is special. Uploads are allowed for all pockets as191The FROZEN status is special. Uploads are allowed for all pockets as
191the upload will have to wait for manual approval anyway:192the upload will have to wait for manual approval anyway:
192193
193 >>> from zope.security.proxy import removeSecurityProxy194 >>> from zope.security.proxy import removeSecurityProxy
194 >>> removeSecurityProxy(hoary).status = SeriesStatus.FROZEN195 >>> removeSecurityProxy(hoary).status = SeriesStatus.FROZEN
195196
196 >>> hoary.status.name197 >>> hoary.status.name
197 'FROZEN'198 'FROZEN'
198 >>> hoary.canUploadToPocket(PackagePublishingPocket.RELEASE)199 >>> hoary.canUploadToPocket(PackagePublishingPocket.RELEASE)
199 True200 True
200 >>> hoary.canUploadToPocket(PackagePublishingPocket.SECURITY)201 >>> hoary.canUploadToPocket(PackagePublishingPocket.SECURITY)
201 True202 True
202203
203204
204Package searching205Package searching
@@ -232,44 +233,45 @@
232are valid for that distroseries. These selections are used by (among233are valid for that distroseries. These selections are used by (among
233other things) the uploader for validating incoming uploads.234other things) the uploader for validating incoming uploads.
234235
235 >>> hoary = distroseriesset.get(3)236 >>> hoary = distroseriesset.get(3)
236 >>> for c in hoary.components:237 >>> for c in hoary.components:
237 ... print c.name238 ... print c.name
238 main239 main
239 restricted240 restricted
240 >>> for s in hoary.sections:241 >>> for s in hoary.sections:
241 ... print s.name242 ... print s.name
242 base243 base
243 web244 web
244 editors245 editors
245 admin246 admin
246 devel247 devel
247 translations248 translations
248249
249 >>> from canonical.launchpad.interfaces import (250 >>> from canonical.launchpad.interfaces import (
250 ... IComponentSet, ISectionSet)251 ... IComponentSet, ISectionSet)
251 >>> python = getUtility(ISectionSet).ensure('python')252 >>> python = getUtility(ISectionSet).ensure('python')
252253
253 >>> hoary.addSection(python)254 >>> hoary.addSection(python)
254255
255 >>> for c in hoary.components:256 >>> for c in hoary.components:
256 ... print c.name257 ... print c.name
257 main258 main
258 restricted259 restricted
259260
260 >>> for s in hoary.sections:261 >>> for s in hoary.sections:
261 ... print s.name262 ... print s.name
262 base263 base
263 web264 web
264 editors265 editors
265 admin266 admin
266 devel267 devel
267 python268 python
268 translations269 translations
269270
270Breezy-autotest has got a partner component, which is not reported:271Breezy-autotest has got a partner component, which is not reported:
271272
272 >>> breezyautotest = distroseriesset.queryByName(ubuntu, "breezy-autotest")273 >>> breezyautotest = distroseriesset.queryByName(
274 ... ubuntu, "breezy-autotest")
273 >>> for c in breezyautotest.components:275 >>> for c in breezyautotest.components:
274 ... print c.name276 ... print c.name
275 main277 main
@@ -307,22 +309,22 @@
307publishing records etc. Essentially this is a "Do not push this button309publishing records etc. Essentially this is a "Do not push this button
308again" type set of assertions.310again" type set of assertions.
309311
310 >>> login("foo.bar@canonical.com")312 >>> login("foo.bar@canonical.com")
311 >>> humpy = ubuntu.newSeries('humpy', 'Humpy Hippo',313 >>> humpy = ubuntu.newSeries('humpy', 'Humpy Hippo',
312 ... 'The Humpy Hippo', 'Fat', 'Yo Momma',314 ... 'The Humpy Hippo', 'Fat', 'Yo Momma',
313 ... '99.2',hoary, hoary.owner)315 ... '99.2',hoary, hoary.owner)
314 >>> humpy_i386 = humpy.newArch('i386', hoary['i386'].processorfamily,316 >>> humpy_i386 = humpy.newArch('i386', hoary['i386'].processorfamily,
315 ... True, humpy.owner)317 ... True, humpy.owner)
316 >>> humpy.nominatedarchindep = humpy_i386318 >>> humpy.nominatedarchindep = humpy_i386
317 >>> humpy.initialiseFromParent()319 >>> humpy.initialiseFromParent()
318 >>> len(hoary.getPublishedReleases('pmount'))320 >>> len(hoary.getPublishedReleases('pmount'))
319 1321 1
320 >>> len(humpy.getPublishedReleases('pmount'))322 >>> len(humpy.getPublishedReleases('pmount'))
321 1323 1
322 >>> len(hoary['i386'].getReleasedPackages('pmount'))324 >>> len(hoary['i386'].getReleasedPackages('pmount'))
323 1325 1
324 >>> len(humpy_i386.getReleasedPackages('pmount'))326 >>> len(humpy_i386.getReleasedPackages('pmount'))
325 1327 1
326328
327Check if the attributes of an DRSPR instance for the just initialised329Check if the attributes of an DRSPR instance for the just initialised
328distroseries are sane. A DRSPR instance should filter attributes of330distroseries are sane. A DRSPR instance should filter attributes of
@@ -344,42 +346,42 @@
344Initialise a new distroseries based on warty (since it has, at least346Initialise a new distroseries based on warty (since it has, at least
345one coherent published source + binary, mozilla-firefox)347one coherent published source + binary, mozilla-firefox)
346348
347 >>> bumpy = ubuntu.newSeries('bumpy', 'Bumpy',349 >>> bumpy = ubuntu.newSeries('bumpy', 'Bumpy',
348 ... 'The Bumpy', 'Fat', 'Boom',350 ... 'The Bumpy', 'Fat', 'Boom',
349 ... '99.3', warty, warty.owner)351 ... '99.3', warty, warty.owner)
350352
351 >>> bumpy_i386 = bumpy.newArch('i386', warty['i386'].processorfamily,353 >>> bumpy_i386 = bumpy.newArch('i386', warty['i386'].processorfamily,
352 ... True, bumpy.owner)354 ... True, bumpy.owner)
353 >>> bumpy.nominatedarchindep = bumpy_i386355 >>> bumpy.nominatedarchindep = bumpy_i386
354 >>> bumpy.initialiseFromParent()356 >>> bumpy.initialiseFromParent()
355357
356Build a new ISourcePackage based in the new distroseries:358Build a new ISourcePackage based in the new distroseries:
357359
358 >>> bumpy_firefox_sp = bumpy.getSourcePackage('mozilla-firefox')360 >>> bumpy_firefox_sp = bumpy.getSourcePackage('mozilla-firefox')
359361
360Check the content IDRSPR binaries & builds attributes:362Check the content IDRSPR binaries & builds attributes:
361363
362'binaries' should be inherited from parent release.364'binaries' should be inherited from parent release.
363365
364 >>> bumpy_firefox_sp.currentrelease.binaries.count()366 >>> bumpy_firefox_sp.currentrelease.binaries.count()
365 2367 2
366368
367 >>> for bin in bumpy_firefox_sp.currentrelease.binaries:369 >>> for bin in bumpy_firefox_sp.currentrelease.binaries:
368 ... print bin.id, bin.title, bin.build.distro_arch_series.title370 ... print bin.id, bin.title, bin.build.distro_arch_series.title
369 27 mozilla-firefox-data-0.9 The Warty Warthog Release for i386 (x86)371 27 mozilla-firefox-data-0.9 The Warty Warthog Release for i386 (x86)
370 12 mozilla-firefox-0.9 The Warty Warthog Release for i386 (x86)372 12 mozilla-firefox-0.9 The Warty Warthog Release for i386 (x86)
371373
372374
373'builds' should be empty since it was built in parent (warty), not in this375'builds' should be empty since it was built in parent (warty), not in this
374distroseries (bumby.376distroseries (bumby.
375377
376 >>> len(bumpy_firefox_sp.currentrelease.builds)378 >>> len(bumpy_firefox_sp.currentrelease.builds)
377 0379 0
378380
379the SPR returns all build records for it.381the SPR returns all build records for it.
380382
381 >>> bumpy_firefox_sp.currentrelease.sourcepackagerelease.builds.count()383 >>> bumpy_firefox_sp.currentrelease.sourcepackagerelease.builds.count()
382 4384 4
383385
384The new series also has the same packaging links as its parent series.386The new series also has the same packaging links as its parent series.
385387
@@ -406,22 +408,22 @@
406You can easily find out what packages are translatable in a408You can easily find out what packages are translatable in a
407distribution release:409distribution release:
408410
409 >>> translatables = hoary.getTranslatableSourcePackages()411 >>> translatables = hoary.getTranslatableSourcePackages()
410 >>> for translatable in translatables:412 >>> for translatable in translatables:
411 ... print translatable.name413 ... print translatable.name
412 evolution414 evolution
413 mozilla415 mozilla
414 pmount416 pmount
415417
416Packages can be linked to upstream productseries in specific418Packages can be linked to upstream productseries in specific
417distribution releases. IDistroSeries offers a way to query translatable419distribution releases. IDistroSeries offers a way to query translatable
418packages that are linked to upstream productseries.420packages that are linked to upstream productseries.
419421
420 >>> unlinked_translatables = hoary.getUnlinkedTranslatableSourcePackages()422 >>> unlinked_translatables = hoary.getUnlinkedTranslatableSourcePackages()
421 >>> for translatable in unlinked_translatables:423 >>> for translatable in unlinked_translatables:
422 ... print translatable.name424 ... print translatable.name
423 pmount425 pmount
424 mozilla426 mozilla
425427
426The links to upstream product series can be verified using the428The links to upstream product series can be verified using the
427packagings property:429packagings property:
@@ -457,11 +459,11 @@
457 linux-source-2.6.15 0 0459 linux-source-2.6.15 0 0
458460
459461
460The distroseries getPrioritizedlPackagings() method that returns a prioritized462The distroseries getPrioritizedPackagings() method that returns a prioritized
461list of `IPackaging` that need more information about the upstream project to463list of `IPackaging` that need more information about the upstream project to
462share bugs, translations, and code.464share bugs, translations, and code.
463465
464 >>> for packaging in hoary.getPrioritizedlPackagings():466 >>> for packaging in hoary.getPrioritizedPackagings():
465 ... print packaging.sourcepackagename.name467 ... print packaging.sourcepackagename.name
466 netapplet468 netapplet
467 evolution469 evolution
@@ -502,109 +504,109 @@
502DistroSeries can build meta objects for packages504DistroSeries can build meta objects for packages
503------------------------------------------------505------------------------------------------------
504506
505 >>> from canonical.launchpad.interfaces import (507 >>> from canonical.launchpad.interfaces import (
506 ... ISourcePackage,508 ... ISourcePackage,
507 ... IDistroSeriesBinaryPackage,509 ... IDistroSeriesBinaryPackage,
508 ... IDistroSeriesSourcePackageRelease)510 ... IDistroSeriesSourcePackageRelease)
509511
510 >>> pmount_src_name = SourcePackageName.byName('pmount')512 >>> pmount_src_name = SourcePackageName.byName('pmount')
511 >>> pmount_source = hoary.getSourcePackage(pmount_src_name)513 >>> pmount_source = hoary.getSourcePackage(pmount_src_name)
512 >>> ISourcePackage.providedBy(pmount_source)514 >>> ISourcePackage.providedBy(pmount_source)
513 True515 True
514516
515 >>> from lp.soyuz.model.binarypackagename import (517 >>> from lp.soyuz.model.binarypackagename import (
516 ... BinaryPackageName)518 ... BinaryPackageName)
517 >>> pmount_bin_name = BinaryPackageName.byName('pmount')519 >>> pmount_bin_name = BinaryPackageName.byName('pmount')
518 >>> pmount_drbp = hoary.getBinaryPackage(pmount_bin_name)520 >>> pmount_drbp = hoary.getBinaryPackage(pmount_bin_name)
519 >>> IDistroSeriesBinaryPackage.providedBy(pmount_drbp)521 >>> IDistroSeriesBinaryPackage.providedBy(pmount_drbp)
520 True522 True
521 >>> len(pmount_drbp.current_publishings)523 >>> len(pmount_drbp.current_publishings)
522 3524 3
523525
524 >>> from lp.soyuz.model.sourcepackagerelease import (526 >>> from lp.soyuz.model.sourcepackagerelease import (
525 ... SourcePackageRelease)527 ... SourcePackageRelease)
526 >>> pmount_rel = SourcePackageRelease.selectOneBy(528 >>> pmount_rel = SourcePackageRelease.selectOneBy(
527 ... sourcepackagenameID=pmount_src_name.id, version='0.1-1')529 ... sourcepackagenameID=pmount_src_name.id, version='0.1-1')
528 >>> pmount_rel.sourcepackagename.name530 >>> pmount_rel.sourcepackagename.name
529 u'pmount'531 u'pmount'
530532
531 >>> pmount_srcrel = hoary.getSourcePackageRelease(pmount_rel)533 >>> pmount_srcrel = hoary.getSourcePackageRelease(pmount_rel)
532 >>> IDistroSeriesSourcePackageRelease.providedBy(pmount_srcrel)534 >>> IDistroSeriesSourcePackageRelease.providedBy(pmount_srcrel)
533 True535 True
534536
535Check some properties of DRSPR meta class537Check some properties of DRSPR meta class
536538
537Entire publishing history:539Entire publishing history:
538540
539 >>> pmount_srcrel.publishing_history.count()541 >>> pmount_srcrel.publishing_history.count()
540 1542 1
541543
542Most recent published history row:544Most recent published history row:
543545
544 >>> pmount_srcrel.current_published is None546 >>> pmount_srcrel.current_published is None
545 True547 True
546548
547 >>> netapplet_srcrel = hoary.getSourcePackage('netapplet').currentrelease549 >>> netapplet_srcrel = hoary.getSourcePackage('netapplet').currentrelease
548 >>> spph = netapplet_srcrel.current_published550 >>> spph = netapplet_srcrel.current_published
549551
550 >>> spph.section.name552 >>> spph.section.name
551 u'web'553 u'web'
552554
553The changesfile attribute contains the package changelog. It is provided as555The changesfile attribute contains the package changelog. It is provided as
554an ILibraryFileAlias:556an ILibraryFileAlias:
555557
556 >>> firefox_srcrel = warty.getSourcePackage(558 >>> firefox_srcrel = warty.getSourcePackage(
557 ... 'mozilla-firefox').currentrelease559 ... 'mozilla-firefox').currentrelease
558 >>> print firefox_srcrel.title560 >>> print firefox_srcrel.title
559 "mozilla-firefox" 0.9 source package in The Warty Warthog Release561 "mozilla-firefox" 0.9 source package in The Warty Warthog Release
560562
561 >>> firefox_srcrel.changesfile563 >>> firefox_srcrel.changesfile
562 <LibraryFileAlias at ...>564 <LibraryFileAlias at ...>
563565
564If the package changelog is not available, that attribute is None:566If the package changelog is not available, that attribute is None:
565567
566 >>> netapplet_srcrel.changesfile is None568 >>> netapplet_srcrel.changesfile is None
567 True569 True
568570
569Perform `post publication` override:571Perform `post publication` override:
570572
571 >>> new_section = getUtility(ISectionSet)['base']573 >>> new_section = getUtility(ISectionSet)['base']
572574
573 >>> override = netapplet_srcrel.current_published.changeOverride(575 >>> override = netapplet_srcrel.current_published.changeOverride(
574 ... new_section=new_section)576 ... new_section=new_section)
575577
576 >>> override.section == new_section578 >>> override.section == new_section
577 True579 True
578580
579 >>> print override.status.name581 >>> print override.status.name
580 PENDING582 PENDING
581583
582 >>> netapplet_srcrel.publishing_history.count()584 >>> netapplet_srcrel.publishing_history.count()
583 2585 2
584586
585Override information about 'pmount' is pending publication:587Override information about 'pmount' is pending publication:
586588
587 >>> print netapplet_srcrel.current_published.status.name589 >>> print netapplet_srcrel.current_published.status.name
588 PENDING590 PENDING
589591
590 >>> print netapplet_srcrel.current_published.section.name592 >>> print netapplet_srcrel.current_published.section.name
591 base593 base
592594
593Supersede previous netapplet publication:595Supersede previous netapplet publication:
594596
595 >>> last_published = netapplet_srcrel.publishing_history[1]597 >>> last_published = netapplet_srcrel.publishing_history[1]
596 >>> last_published.supersede()598 >>> last_published.supersede()
597 >>> flush_database_updates()599 >>> flush_database_updates()
598600
599 >>> netapplet_srcrel.publishing_history.count()601 >>> netapplet_srcrel.publishing_history.count()
600 2602 2
601603
602 >>> print last_published.status.name604 >>> print last_published.status.name
603 SUPERSEDED605 SUPERSEDED
604606
605 >>> from canonical.database.sqlbase import get_transaction_timestamp607 >>> from canonical.database.sqlbase import get_transaction_timestamp
606 >>> last_published.datesuperseded == get_transaction_timestamp()608 >>> last_published.datesuperseded == get_transaction_timestamp()
607 True609 True
608610
609611
610SourcePackagePublishingHistory612SourcePackagePublishingHistory
@@ -616,114 +618,114 @@
616instance. it can also be used to generate the archive packages list in618instance. it can also be used to generate the archive packages list in
617the future.619the future.
618620
619 >>> ubuntu = getUtility(IDistributionSet)['ubuntu']621 >>> ubuntu = getUtility(IDistributionSet)['ubuntu']
620 >>> hoary = ubuntu['hoary']622 >>> hoary = ubuntu['hoary']
621623
622 >>> from canonical.launchpad.interfaces import (624 >>> from canonical.launchpad.interfaces import (
623 ... PackagePublishingStatus)625 ... PackagePublishingStatus)
624626
625 >>> hoary_pub_sources = hoary.getSourcePackagePublishing(627 >>> hoary_pub_sources = hoary.getSourcePackagePublishing(
626 ... PackagePublishingStatus.PUBLISHED,628 ... PackagePublishingStatus.PUBLISHED,
627 ... PackagePublishingPocket.RELEASE)629 ... PackagePublishingPocket.RELEASE)
628630
629 >>> hoary_pub_sources.count()631 >>> hoary_pub_sources.count()
630 6632 6
631633
632 >>> for pub in hoary_pub_sources:634 >>> for pub in hoary_pub_sources:
633 ... print pub.displayname635 ... print pub.displayname
634 alsa-utils 1.0.9a-4ubuntu1 in hoary636 alsa-utils 1.0.9a-4ubuntu1 in hoary
635 cnews cr.g7-37 in hoary637 cnews cr.g7-37 in hoary
636 evolution 1.0 in hoary638 evolution 1.0 in hoary
637 libstdc++ b8p in hoary639 libstdc++ b8p in hoary
638 linux-source-2.6.15 2.6.15.3 in hoary640 linux-source-2.6.15 2.6.15.3 in hoary
639 pmount 0.1-2 in hoary641 pmount 0.1-2 in hoary
640642
641 >>> hoary_pub_source = hoary_pub_sources[0]643 >>> hoary_pub_source = hoary_pub_sources[0]
642644
643 >>> hoary_pub_source.sourcepackagerelease.name645 >>> hoary_pub_source.sourcepackagerelease.name
644 u'alsa-utils'646 u'alsa-utils'
645647
646 >>> hoary_pub_source.sourcepackagerelease.version648 >>> hoary_pub_source.sourcepackagerelease.version
647 u'1.0.9a-4ubuntu1'649 u'1.0.9a-4ubuntu1'
648650
649 >>> hoary_pub_source.component.name651 >>> hoary_pub_source.component.name
650 u'main'652 u'main'
651653
652 >>> hoary_pub_source.section.name654 >>> hoary_pub_source.section.name
653 u'base'655 u'base'
654656
655 >>> hoary.getSourcePackagePublishing(657 >>> hoary.getSourcePackagePublishing(
656 ... PackagePublishingStatus.PUBLISHED,658 ... PackagePublishingStatus.PUBLISHED,
657 ... PackagePublishingPocket.UPDATES).count()659 ... PackagePublishingPocket.UPDATES).count()
658 0660 0
659661
660This method also allow us to restrict the results to a given662This method also allow us to restrict the results to a given
661component:663component:
662664
663 >>> component_main = getUtility(IComponentSet)['main']665 >>> component_main = getUtility(IComponentSet)['main']
664 >>> hoary.getSourcePackagePublishing(666 >>> hoary.getSourcePackagePublishing(
665 ... PackagePublishingStatus.PUBLISHED,667 ... PackagePublishingStatus.PUBLISHED,
666 ... PackagePublishingPocket.RELEASE,668 ... PackagePublishingPocket.RELEASE,
667 ... component=component_main).count()669 ... component=component_main).count()
668 5670 5
669671
670 >>> component_multiverse = getUtility(IComponentSet)['multiverse']672 >>> component_multiverse = getUtility(IComponentSet)['multiverse']
671 >>> hoary.getSourcePackagePublishing(673 >>> hoary.getSourcePackagePublishing(
672 ... PackagePublishingStatus.PUBLISHED,674 ... PackagePublishingStatus.PUBLISHED,
673 ... PackagePublishingPocket.RELEASE,675 ... PackagePublishingPocket.RELEASE,
674 ... component=component_multiverse).count()676 ... component=component_multiverse).count()
675 0677 0
676678
677By default the IDistribution 'main_archive' is considered, but It also679By default the IDistribution 'main_archive' is considered, but It also
678allows the callsite to specify one and then the result will be680allows the callsite to specify one and then the result will be
679restricted to it.681restricted to it.
680682
681 >>> debian_archive = getUtility(IDistributionSet)['debian'].main_archive683 >>> debian_archive = getUtility(IDistributionSet)['debian'].main_archive
682 >>> print debian_archive.purpose.title684 >>> print debian_archive.purpose.title
683 Primary Archive685 Primary Archive
684686
685 >>> hoary.getSourcePackagePublishing(687 >>> hoary.getSourcePackagePublishing(
686 ... PackagePublishingStatus.PUBLISHED,688 ... PackagePublishingStatus.PUBLISHED,
687 ... PackagePublishingPocket.RELEASE,689 ... PackagePublishingPocket.RELEASE,
688 ... component=component_main, archive=debian_archive).count()690 ... component=component_main, archive=debian_archive).count()
689 0691 0
690692
691ISPP.getPublishedBinaries returns all the binaries generated by the693ISPP.getPublishedBinaries returns all the binaries generated by the
692publication in question:694publication in question:
693695
694 >>> warty = ubuntu['warty']696 >>> warty = ubuntu['warty']
695 >>> warty_pub_sources = warty.getSourcePackagePublishing(697 >>> warty_pub_sources = warty.getSourcePackagePublishing(
696 ... PackagePublishingStatus.PUBLISHED,698 ... PackagePublishingStatus.PUBLISHED,
697 ... PackagePublishingPocket.RELEASE)699 ... PackagePublishingPocket.RELEASE)
698700
699 >>> warty_pub_source = warty_pub_sources[4]701 >>> warty_pub_source = warty_pub_sources[4]
700 >>> warty_pub_source.sourcepackagerelease.name702 >>> warty_pub_source.sourcepackagerelease.name
701 u'mozilla-firefox'703 u'mozilla-firefox'
702 >>> warty_pub_source.sourcepackagerelease.version704 >>> warty_pub_source.sourcepackagerelease.version
703 u'0.9'705 u'0.9'
704 >>> warty_pub_source.component.name706 >>> warty_pub_source.component.name
705 u'main'707 u'main'
706 >>> warty_pub_source.section.name708 >>> warty_pub_source.section.name
707 u'web'709 u'web'
708710
709 >>> warty_mozilla_pub_binaries = warty_pub_source.getPublishedBinaries()711 >>> warty_mozilla_pub_binaries = warty_pub_source.getPublishedBinaries()
710 >>> len(warty_mozilla_pub_binaries)712 >>> len(warty_mozilla_pub_binaries)
711 4713 4
712 >>> warty_mozilla_pub_bin = warty_mozilla_pub_binaries[0]714 >>> warty_mozilla_pub_bin = warty_mozilla_pub_binaries[0]
713715
714 >>> from canonical.launchpad.interfaces import (716 >>> from canonical.launchpad.interfaces import (
715 ... IBinaryPackagePublishingHistory)717 ... IBinaryPackagePublishingHistory)
716 >>> verifyObject(IBinaryPackagePublishingHistory, warty_mozilla_pub_bin)718 >>> verifyObject(IBinaryPackagePublishingHistory, warty_mozilla_pub_bin)
717 True719 True
718720
719 >>> warty_mozilla_pub_bin.binarypackagerelease.name721 >>> warty_mozilla_pub_bin.binarypackagerelease.name
720 u'mozilla-firefox'722 u'mozilla-firefox'
721 >>> warty_mozilla_pub_bin.binarypackagerelease.version723 >>> warty_mozilla_pub_bin.binarypackagerelease.version
722 u'0.9'724 u'0.9'
723 >>> warty_mozilla_pub_bin.component.name725 >>> warty_mozilla_pub_bin.component.name
724 u'main'726 u'main'
725 >>> warty_mozilla_pub_bin.section.name727 >>> warty_mozilla_pub_bin.section.name
726 u'base'728 u'base'
727729
728DistroSeries.getBinaryPackagePublishing will return730DistroSeries.getBinaryPackagePublishing will return
729BinaryPackagePublishingHistory objects for the DistroSeries:731BinaryPackagePublishingHistory objects for the DistroSeries:
730732
=== modified file 'lib/lp/registry/interfaces/distroseries.py'
--- lib/lp/registry/interfaces/distroseries.py 2010-06-08 15:58:04 +0000
+++ lib/lp/registry/interfaces/distroseries.py 2010-07-28 19:11:08 +0000
@@ -414,7 +414,7 @@
414 and total_messages (translatable messages).414 and total_messages (translatable messages).
415 """415 """
416416
417 def getPrioritizedlPackagings():417 def getPrioritizedPackagings():
418 """Return a list of packagings that need more upstream information."""418 """Return a list of packagings that need more upstream information."""
419419
420 def getMostRecentlyLinkedPackagings():420 def getMostRecentlyLinkedPackagings():
@@ -514,15 +514,16 @@
514514
515 If version is not specified, return packages with any version.515 If version is not specified, return packages with any version.
516516
517 if exclude_pocket is specified we exclude results matching that pocket.517 If exclude_pocket is specified we exclude results matching that
518 pocket.
518519
519 If 'include_pending' is True, we return also the pending publication520 If 'include_pending' is True, we return also the pending publication
520 records, those packages that will get published in the next publisher521 records, those packages that will get published in the next publisher
521 run (it's only useful when we need to know if a given package is522 run (it's only useful when we need to know if a given package is
522 known during a publisher run, mostly in pre-upload checks)523 known during a publisher run, mostly in pre-upload checks)
523524
524 If 'archive' is not specified consider publication in the main_archive,525 If 'archive' is not specified consider publication in the
525 otherwise respect the given value.526 main_archive, otherwise respect the given value.
526 """527 """
527528
528 def getAllPublishedSources():529 def getAllPublishedSources():
529530
=== modified file 'lib/lp/registry/model/distroseries.py'
--- lib/lp/registry/model/distroseries.py 2010-07-15 15:01:18 +0000
+++ lib/lp/registry/model/distroseries.py 2010-07-28 19:11:08 +0000
@@ -19,7 +19,7 @@
19 BoolCol, StringCol, ForeignKey, SQLMultipleJoin, IntCol,19 BoolCol, StringCol, ForeignKey, SQLMultipleJoin, IntCol,
20 SQLObjectNotFound, SQLRelatedJoin)20 SQLObjectNotFound, SQLRelatedJoin)
2121
22from storm.locals import And, Desc, Join, SQL22from storm.locals import Desc, Join, SQL
23from storm.store import Store23from storm.store import Store
2424
25from zope.component import getUtility25from zope.component import getUtility
@@ -335,14 +335,19 @@
335 condition = SQL(conditions + "AND packaging.id IS NULL")335 condition = SQL(conditions + "AND packaging.id IS NULL")
336 results = IStore(self).using(origin).find(find_spec, condition)336 results = IStore(self).using(origin).find(find_spec, condition)
337 results = results.order_by('score DESC', SourcePackageName.name)337 results = results.order_by('score DESC', SourcePackageName.name)
338 return [{338 results = results.config(distinct=True)
339 'package': SourcePackage(339
340 def decorator(result):
341 spn, score, bug_count, total_messages = result
342 return {
343 'package': SourcePackage(
340 sourcepackagename=spn, distroseries=self),344 sourcepackagename=spn, distroseries=self),
341 'bug_count': bug_count,345 'bug_count': bug_count,
342 'total_messages': total_messages}346 'total_messages': total_messages,
343 for (spn, score, bug_count, total_messages) in results]347 }
348 return DecoratedResultSet(results, decorator)
344349
345 def getPrioritizedlPackagings(self):350 def getPrioritizedPackagings(self):
346 """See `IDistroSeries`.351 """See `IDistroSeries`.
347352
348 The prioritization is a heuristic rule using the branch, bug heat,353 The prioritization is a heuristic rule using the branch, bug heat,
@@ -352,18 +357,6 @@
352 # the objects that are implcitly needed to work with a357 # the objects that are implcitly needed to work with a
353 # Packaging object.358 # Packaging object.
354 # Avoid circular import failures.359 # Avoid circular import failures.
355 from lp.registry.model.product import Product
356 from lp.registry.model.productseries import ProductSeries
357 find_spec = (
358 Packaging, SourcePackageName, ProductSeries, Product,
359 SQL("""
360 CASE WHEN spr.component = 1 THEN 1000 ELSE 0 END +
361 CASE WHEN Product.bugtracker IS NULL
362 THEN coalesce(total_bug_heat, 10) ELSE 0 END +
363 CASE WHEN ProductSeries.translations_autoimport_mode = 1
364 THEN coalesce(po_messages, 10) ELSE 0 END +
365 CASE WHEN ProductSeries.branch IS NULL THEN 500
366 ELSE 0 END AS score"""))
367 joins, conditions = self._current_sourcepackage_joins_and_conditions360 joins, conditions = self._current_sourcepackage_joins_and_conditions
368 origin = SQL(joins + """361 origin = SQL(joins + """
369 JOIN ProductSeries362 JOIN ProductSeries
@@ -372,10 +365,19 @@
372 ON ProductSeries.product = Product.id365 ON ProductSeries.product = Product.id
373 """)366 """)
374 condition = SQL(conditions + "AND packaging.id IS NOT NULL")367 condition = SQL(conditions + "AND packaging.id IS NOT NULL")
375 results = IStore(self).using(origin).find(find_spec, condition)368 results = IStore(self).using(origin).find(Packaging, condition)
376 results = results.order_by('score DESC, SourcePackageName.name ASC')369 return results.order_by("""
377 return [packaging370 (
378 for (packaging, spn, series, product, score) in results]371 CASE WHEN spr.component = 1 THEN 1000 ELSE 0 END
372 + CASE WHEN Product.bugtracker IS NULL
373 THEN coalesce(total_bug_heat, 10) ELSE 0 END
374 + CASE WHEN ProductSeries.translations_autoimport_mode = 1
375 THEN coalesce(po_messages, 10) ELSE 0 END
376 + CASE WHEN ProductSeries.branch IS NULL THEN 500
377 ELSE 0 END
378 ) DESC,
379 SourcePackageName.name ASC
380 """)
379381
380 @property382 @property
381 def _current_sourcepackage_joins_and_conditions(self):383 def _current_sourcepackage_joins_and_conditions(self):
382384
=== modified file 'lib/lp/registry/stories/distroseries/xx-distroseries-index.txt'
--- lib/lp/registry/stories/distroseries/xx-distroseries-index.txt 2010-02-26 19:18:37 +0000
+++ lib/lp/registry/stories/distroseries/xx-distroseries-index.txt 2010-07-28 19:11:08 +0000
@@ -100,4 +100,9 @@
100 evolution linked...100 evolution linked...
101 mozilla-firefox linked...101 mozilla-firefox linked...
102 netapplet linked 2005-07-05102 netapplet linked 2005-07-05
103 Needs upstream links All upstream links103 Needs more information or linking to upstream:
104 cdrkit
105 iceweasel
106 linux-source-2.6.15
107 Needs upstream links
108 All upstream links
104109
=== modified file 'lib/lp/registry/templates/distroseries-portlet-packaging.pt'
--- lib/lp/registry/templates/distroseries-portlet-packaging.pt 2010-05-27 04:10:17 +0000
+++ lib/lp/registry/templates/distroseries-portlet-packaging.pt 2010-07-28 19:11:08 +0000
@@ -56,7 +56,7 @@
56 </dt>56 </dt>
57 <dd tal:condition="view/needs_linking">57 <dd tal:condition="view/needs_linking">
58 <ul class="horizontal">58 <ul class="horizontal">
59 <li repeat="package view/needs_linking">59 <li tal:repeat="package view/needs_linking">
60 <a class="sprite package-source"60 <a class="sprite package-source"
61 tal:attributes="href package/package/fmt:url"61 tal:attributes="href package/package/fmt:url"
62 tal:content="package/package/name">evolution</a>62 tal:content="package/package/name">evolution</a>
6363
=== modified file 'lib/lp/registry/tests/test_distroseries.py'
--- lib/lp/registry/tests/test_distroseries.py 2010-07-20 17:50:45 +0000
+++ lib/lp/registry/tests/test_distroseries.py 2010-07-28 19:11:08 +0000
@@ -271,17 +271,17 @@
271 u'main', u'hot-translatable', u'hot', u'translatable', u'normal']271 u'main', u'hot-translatable', u'hot', u'translatable', u'normal']
272 self.assertEqual(expected, names)272 self.assertEqual(expected, names)
273273
274 def test_getPrioritizedlPackagings(self):274 def test_getPrioritizedPackagings(self):
275 # Verify the ordering of packagings that need more upstream info.275 # Verify the ordering of packagings that need more upstream info.
276 for name in ['main', 'hot-translatable', 'hot', 'translatable']:276 for name in ['main', 'hot-translatable', 'hot', 'translatable']:
277 self.linkPackage(name)277 self.linkPackage(name)
278 packagings = self.series.getPrioritizedlPackagings()278 packagings = self.series.getPrioritizedPackagings()
279 names = [packaging.sourcepackagename.name for packaging in packagings]279 names = [packaging.sourcepackagename.name for packaging in packagings]
280 expected = [280 expected = [
281 u'main', u'hot-translatable', u'hot', u'translatable', u'linked']281 u'main', u'hot-translatable', u'hot', u'translatable', u'linked']
282 self.assertEqual(expected, names)282 self.assertEqual(expected, names)
283283
284 def test_getPrioritizedlPackagings_bug_tracker(self):284 def test_getPrioritizedPackagings_bug_tracker(self):
285 # Verify the ordering of packagings with and without a bug tracker.285 # Verify the ordering of packagings with and without a bug tracker.
286 self.linkPackage('hot')286 self.linkPackage('hot')
287 self.makeSeriesPackage('cold')287 self.makeSeriesPackage('cold')
@@ -289,12 +289,12 @@
289 naked_product_series = remove_security_proxy_and_shout_at_engineer(289 naked_product_series = remove_security_proxy_and_shout_at_engineer(
290 product_series)290 product_series)
291 naked_product_series.product.bugtraker = self.factory.makeBugTracker()291 naked_product_series.product.bugtraker = self.factory.makeBugTracker()
292 packagings = self.series.getPrioritizedlPackagings()292 packagings = self.series.getPrioritizedPackagings()
293 names = [packaging.sourcepackagename.name for packaging in packagings]293 names = [packaging.sourcepackagename.name for packaging in packagings]
294 expected = [u'hot', u'cold', u'linked']294 expected = [u'hot', u'cold', u'linked']
295 self.assertEqual(expected, names)295 self.assertEqual(expected, names)
296296
297 def test_getPrioritizedlPackagings_branch(self):297 def test_getPrioritizedPackagings_branch(self):
298 # Verify the ordering of packagings with and without a branch.298 # Verify the ordering of packagings with and without a branch.
299 self.linkPackage('translatable')299 self.linkPackage('translatable')
300 self.makeSeriesPackage('withbranch')300 self.makeSeriesPackage('withbranch')
@@ -302,12 +302,12 @@
302 naked_product_series = remove_security_proxy_and_shout_at_engineer(302 naked_product_series = remove_security_proxy_and_shout_at_engineer(
303 product_series)303 product_series)
304 naked_product_series.branch = self.factory.makeBranch()304 naked_product_series.branch = self.factory.makeBranch()
305 packagings = self.series.getPrioritizedlPackagings()305 packagings = self.series.getPrioritizedPackagings()
306 names = [packaging.sourcepackagename.name for packaging in packagings]306 names = [packaging.sourcepackagename.name for packaging in packagings]
307 expected = [u'translatable', u'linked', u'withbranch']307 expected = [u'translatable', u'linked', u'withbranch']
308 self.assertEqual(expected, names)308 self.assertEqual(expected, names)
309309
310 def test_getPrioritizedlPackagings_translation(self):310 def test_getPrioritizedPackagings_translation(self):
311 # Verify the ordering of translatable packagings that are and are not311 # Verify the ordering of translatable packagings that are and are not
312 # configured to import.312 # configured to import.
313 self.linkPackage('translatable')313 self.linkPackage('translatable')
@@ -318,7 +318,7 @@
318 naked_product_series.branch = self.factory.makeBranch()318 naked_product_series.branch = self.factory.makeBranch()
319 naked_product_series.translations_autoimport_mode = (319 naked_product_series.translations_autoimport_mode = (
320 TranslationsBranchImportMode.IMPORT_TEMPLATES)320 TranslationsBranchImportMode.IMPORT_TEMPLATES)
321 packagings = self.series.getPrioritizedlPackagings()321 packagings = self.series.getPrioritizedPackagings()
322 names = [packaging.sourcepackagename.name for packaging in packagings]322 names = [packaging.sourcepackagename.name for packaging in packagings]
323 expected = [u'translatable', u'linked', u'importabletranslatable']323 expected = [u'translatable', u'linked', u'importabletranslatable']
324 self.assertEqual(expected, names)324 self.assertEqual(expected, names)