launchpad-reviewers team mailing list archive
-
launchpad-reviewers team
-
Mailing list archive
-
Message #02333
[Merge] lp:~edwin-grubbs/launchpad/bug-663857-product-packages-timeout into lp:launchpad
Edwin Grubbs has proposed merging lp:~edwin-grubbs/launchpad/bug-663857-product-packages-timeout into lp:launchpad.
Requested reviews:
Launchpad code reviewers (launchpad-reviewers)
Related bugs:
#663857 Product:+packages timesout with no packages and one series
https://bugs.launchpad.net/bugs/663857
For more details, see:
https://code.launchpad.net/~edwin-grubbs/launchpad/bug-663857-product-packages-timeout/+merge/46222
Summary
-------
This branch fixes the timeout on the $project/+packages page. It
restricts the results to series that are active or have packages. It
also batches the results.
I cleaned up the formatting, since a list of tables is fairly
confusing. I also sorted the results descending. If the series are named
by version number, the latest versions will appear at the top.
Implementation details
----------------------
lib/lp/registry/browser/product.py
lib/lp/registry/browser/tests/packaging-views.txt
lib/lp/registry/interfaces/product.py
lib/lp/registry/model/product.py
lib/lp/registry/templates/product-packages.pt
Tests
-----
./bin/test -vv -t 'packaging-views.txt|xx-product-package-pages.txt'
Demo and Q/A
------------
* Open https://code.edge.launchpad.net/obsolete-junk/+packages
* The page should not timeout.
Lint
----
The one remaining lint item shouldn't be fixed.
Linting changed files:
lib/lp/registry/browser/product.py
lib/lp/registry/browser/tests/packaging-views.txt
lib/lp/registry/interfaces/product.py
lib/lp/registry/model/product.py
lib/lp/registry/templates/product-packages.pt
./lib/lp/registry/interfaces/product.py
981: E301 expected 1 blank line, found 2
--
https://code.launchpad.net/~edwin-grubbs/launchpad/bug-663857-product-packages-timeout/+merge/46222
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~edwin-grubbs/launchpad/bug-663857-product-packages-timeout into lp:launchpad.
=== modified file 'lib/lp/registry/browser/product.py'
--- lib/lp/registry/browser/product.py 2010-12-30 16:22:22 +0000
+++ lib/lp/registry/browser/product.py 2011-01-14 03:33:35 +0000
@@ -1117,25 +1117,10 @@
page_title = label
@cachedproperty
- def series_packages(self):
- """A hierarchy of product series, packaging and field data.
-
- A dict of series and packagings. Each packaging is a dict of the
- packaging and a hidden HTML field for forms:
- [{series: <hoary>,
- packagings: {
- packaging: <packaging>,
- field: '<input type=''hidden' ...>},
- }]
- """
- packaged_series = []
- for series in self.context.series:
- packagings = []
- for packaging in series.packagings:
- packagings.append(packaging)
- packaged_series.append(dict(
- series=series, packagings=packagings))
- return packaged_series
+ def series_batch(self):
+ """A batch of series that are active or have packages."""
+ return BatchNavigator(
+ self.context.active_or_packaged_series, self.request)
@property
def distro_packaging(self):
=== modified file 'lib/lp/registry/browser/tests/packaging-views.txt'
--- lib/lp/registry/browser/tests/packaging-views.txt 2010-05-27 04:22:46 +0000
+++ lib/lp/registry/browser/tests/packaging-views.txt 2011-01-14 03:33:35 +0000
@@ -224,20 +224,19 @@
>>> print view.label
Linked packages
-The view provides the series_packages property that returns a list of
-dicts. Each dict as a series and a list of packages.
+The view provides the series_batch property.
>>> def print_packages(view):
- ... for series_dict in view.series_packages:
- ... print series_dict['series'].name
- ... for package in series_dict['packagings']:
- ... print package.distroseries.name
+ ... for series in view.series_batch.batch:
+ ... print series.name
+ ... for package in series.packagings:
+ ... print ' Package:', package.distroseries.name
>>> print_packages(view)
+ trunk
+ hotter
+ Package: grumpy
+ Package: hoary
cold
- hotter
- grumpy
- hoary
- trunk
The view provides the distro_packaging property that is a list of
dictionaries for the distributions and their packaging. The list is
@@ -255,11 +254,11 @@
>>> view = create_initialized_view(
... product, name='+packages', principal=a_user)
>>> print_packages(view)
+ trunk
+ hotter
+ Package: grumpy
+ Package: hoary
cold
- hotter
- grumpy
- hoary
- trunk
# There are links to the +remove-packaging page.
>>> table = find_tag_by_id(view.render(), 'packages-hotter')
@@ -270,8 +269,8 @@
http://launchpad.dev/ubuntu/hoary/+source/thunderbird/+remove-packaging
>>> [hoary_package] = [
- ... package for series_dict in view.series_packages
- ... for package in series_dict['packagings']
+ ... package for series in view.series_batch.batch
+ ... for package in series.packagings
... if package.distroseries.name == 'hoary']
>>> form = {'field.actions.unlink': 'Unlink'}
>>> unlink_view = create_initialized_view(
@@ -279,13 +278,13 @@
>>> unlink_view.errors
[]
- # The view has to be reloaded since view.series_packages is cached.
+ # The view has to be reloaded since view.series_batch is cached.
>>> view = create_initialized_view(product, name='+packages')
>>> print_packages(view)
+ trunk
+ hotter
+ Package: grumpy
cold
- hotter
- grumpy
- trunk
Distro series +packaging view
=== modified file 'lib/lp/registry/interfaces/product.py'
--- lib/lp/registry/interfaces/product.py 2010-12-31 03:39:53 +0000
+++ lib/lp/registry/interfaces/product.py 2011-01-14 03:33:35 +0000
@@ -732,6 +732,9 @@
"Some bug trackers host multiple projects at the same URL "
"and require an identifier for the specific project.")))
+ active_or_packaged_series = Attribute(
+ _("Series that are active and/or have been packaged."))
+
def getVersionSortedSeries(statuses=None, filter_statuses=None):
"""Return all the series sorted by the name field as a version.
=== modified file 'lib/lp/registry/model/product.py'
--- lib/lp/registry/model/product.py 2010-12-02 16:13:51 +0000
+++ lib/lp/registry/model/product.py 2011-01-14 03:33:35 +0000
@@ -28,13 +28,17 @@
SQLObjectNotFound,
StringCol,
)
-from storm.expr import NamedFunc
+from storm.expr import (
+ LeftJoin,
+ NamedFunc,
+ )
from storm.locals import (
And,
Desc,
Int,
Join,
Not,
+ Or,
Select,
SQL,
Store,
@@ -48,9 +52,6 @@
)
from zope.security.proxy import removeSecurityProxy
-from canonical.launchpad.components.decoratedresultset import (
- DecoratedResultSet,
- )
from canonical.database.constants import UTC_NOW
from canonical.database.datetimecol import UtcDateTimeCol
from canonical.database.enumcol import EnumCol
@@ -59,6 +60,9 @@
SQLBase,
sqlvalues,
)
+from canonical.launchpad.components.decoratedresultset import (
+ DecoratedResultSet,
+ )
from canonical.launchpad.interfaces.launchpad import (
IHasIcon,
IHasLogo,
@@ -74,7 +78,6 @@
IStoreSelector,
MAIN_STORE,
)
-from lp.registry.model.series import ACTIVE_STATUSES
from lp.answers.interfaces.faqtarget import IFAQTarget
from lp.answers.interfaces.questioncollection import (
QUESTION_STATUS_DEFAULT_SEARCH,
@@ -145,6 +148,7 @@
from lp.registry.model.commercialsubscription import CommercialSubscription
from lp.registry.model.distribution import Distribution
from lp.registry.model.distroseries import DistroSeries
+from lp.registry.model.hasdrivers import HasDriversMixin
from lp.registry.model.karma import KarmaContextMixin
from lp.registry.model.milestone import (
HasMilestonesMixin,
@@ -156,7 +160,7 @@
from lp.registry.model.productlicense import ProductLicense
from lp.registry.model.productrelease import ProductRelease
from lp.registry.model.productseries import ProductSeries
-from lp.registry.model.hasdrivers import HasDriversMixin
+from lp.registry.model.series import ACTIVE_STATUSES
from lp.registry.model.sourcepackagename import SourcePackageName
from lp.registry.model.structuralsubscription import (
StructuralSubscriptionTargetMixin,
@@ -801,6 +805,22 @@
orderBy='name')
@property
+ def active_or_packaged_series(self):
+ store = Store.of(self)
+ tables = [
+ ProductSeries,
+ LeftJoin(Packaging, Packaging.productseries == ProductSeries.id),
+ ]
+ result = store.using(*tables).find(
+ ProductSeries,
+ ProductSeries.product == self,
+ Or(ProductSeries.status.is_in(ACTIVE_STATUSES),
+ Packaging.id != None))
+ result = result.order_by(Desc(ProductSeries.name))
+ result.config(distinct=True)
+ return result
+
+ @property
def name_with_project(self):
"""See lib.canonical.launchpad.interfaces.IProduct"""
if self.project and self.project.name != self.name:
@@ -1572,7 +1592,7 @@
def getTranslatables(self):
"""See `IProductSet`"""
- # XXX j.c.sackett 2010-11-19 bug=677532 It's less than ideal that
+ # XXX j.c.sackett 2010-11-19 bug=677532 It's less than ideal that
# this query is using _translations_usage, but there's no cleaner
# way to deal with it. Once the bug above is resolved, this should
# should be fixed to use translations_usage.
=== modified file 'lib/lp/registry/templates/product-packages.pt'
--- lib/lp/registry/templates/product-packages.pt 2010-03-03 18:35:08 +0000
+++ lib/lp/registry/templates/product-packages.pt 2011-01-14 03:33:35 +0000
@@ -10,28 +10,44 @@
<body>
<div metal:fill-slot="main">
- <div class="top-portlet">
+ <div class="top-portlet"
+ tal:define="batch_nav view/series_batch">
<h2>Packages by project series</h2>
- <tal:series_dict repeat="series_dict view/series_packages">
- <tal:series_packagings
- define="series series_dict/series;
- packagings series_dict/packagings">
+ <tal:multipage tal:condition="batch_nav/has_multiple_pages">
+ <tal:navigation
+ replace="structure batch_nav/@@+navigation-links-upper"/>
+ </tal:multipage>
+ <table class="listing">
+ <tr tal:repeat="series batch_nav/batch">
+ <td tal:define="packagings series/packagings">
+ <table style="width: 100%; margin: 0.5em 0 0 0">
+ <tr>
+ <td style="width: 33%">
<h3>
<a tal:attributes="href series/name">
<span tal:replace="series/name">main</span> series
</a>
</h3>
+ </td>
- <p tal:condition="not: packagings">
+ <tal:no-packages condition="not: packagings">
+ <td style="width: 33%; text-align: center">
No packages linked to this series.
- </p>
+ </td>
+ <td style="width: 33%; padding: 0 1.5em 0 0; text-align: right">
+ <a tal:condition="series/menu:overview/ubuntupkg/linked"
+ tal:replace="structure series/menu:overview/ubuntupkg/fmt:link" />
+ </td>
+ </tal:no-packages>
+ </tr>
+ </table>
<tal:comment condition="nothing">
This DIV is necessary for the table-actions:nth-child stylesheet.
</tal:comment>
<div>
- <table class="listing"
+ <table class="listing" style="border: 0"
tal:condition="packagings"
tal:attributes="id series/name/fmt:css-id/packages-">
<thead>
@@ -73,15 +89,19 @@
</tbody>
</table>
- <ul class="table-actions"
- tal:condition="series/menu:overview/ubuntupkg/linked">
- <li>
+ <ul class="table-actions" tal:condition="packagings">
+ <li tal:condition="series/menu:overview/ubuntupkg/linked">
<a tal:replace="structure series/menu:overview/ubuntupkg/fmt:link" />
</li>
</ul>
</div>
- </tal:series_packagings>
- </tal:series_dict>
+ </td>
+ </tr>
+ </table>
+ <tal:multipage condition="batch_nav/has_multiple_pages">
+ <tal:navigation
+ replace="structure batch_nav/@@+navigation-links-lower"/>
+ </tal:multipage>
</div>
<div class="portlet">