Merge lp:~michael.nelson/launchpad/443353-api-builds-from-private into lp:launchpad/db-devel

Proposed by Michael Nelson
Status: Merged
Approved by: Jonathan Lange
Approved revision: not available
Merged at revision: not available
Proposed branch: lp:~michael.nelson/launchpad/443353-api-builds-from-private
Merge into: lp:launchpad/db-devel
Diff against target: 1274 lines (+453/-125)
43 files modified
lib/lp/archiveuploader/nascentuploadfile.py (+1/-1)
lib/lp/archiveuploader/tests/nascentuploadfile.txt (+71/-0)
lib/lp/bugs/templates/bug-portlet-subscribers.pt (+1/-1)
lib/lp/bugs/templates/bugtarget-filebug-submit-bug.pt (+1/-1)
lib/lp/bugs/templates/bugtarget-portlet-bugfilters.pt (+1/-1)
lib/lp/bugs/templates/bugtarget-portlet-bugtags.pt (+1/-1)
lib/lp/bugs/templates/bugtask-index.pt (+3/-3)
lib/lp/bugs/templates/bugtask-tasks-and-nominations-table-row.pt (+1/-1)
lib/lp/bugs/templates/bugtasks-and-nominations-table.pt (+1/-1)
lib/lp/bugs/templates/official-bug-target-manage-tags.pt (+1/-1)
lib/lp/code/templates/branch-import-details.pt (+1/-1)
lib/lp/code/templates/branch-index.pt (+1/-1)
lib/lp/code/templates/branch-listing.pt (+1/-1)
lib/lp/code/templates/branch-portlet-subscribers.pt (+1/-1)
lib/lp/code/templates/branch-related-bugs-specs.pt (+1/-1)
lib/lp/code/templates/branchmergeproposal-generic-listing.pt (+1/-1)
lib/lp/registry/templates/object-timeline-graph.pt (+1/-1)
lib/lp/registry/templates/person-macros.pt (+1/-1)
lib/lp/registry/templates/product-new.pt (+1/-1)
lib/lp/registry/templates/productrelease-add-from-series.pt (+1/-1)
lib/lp/registry/templates/teammembership-index.pt (+1/-1)
lib/lp/registry/templates/timeline-macros.pt (+1/-1)
lib/lp/soyuz/doc/publishing.txt (+50/-11)
lib/lp/soyuz/model/publishing.py (+58/-22)
lib/lp/soyuz/scripts/tests/test_copypackage.py (+16/-1)
lib/lp/soyuz/stories/ppa/xx-copy-packages.txt (+1/-1)
lib/lp/soyuz/stories/ppa/xx-ppa-packages.txt (+32/-10)
lib/lp/soyuz/stories/webservice/xx-source-package-publishing.txt (+5/-3)
lib/lp/soyuz/templates/archive-edit-dependencies.pt (+1/-1)
lib/lp/soyuz/templates/archive-macros.pt (+1/-1)
lib/lp/soyuz/templates/archive-packages.pt (+1/-1)
lib/lp/soyuz/templates/archive-subscribers.pt (+1/-1)
lib/lp/translations/browser/language.py (+8/-0)
lib/lp/translations/stories/distroseries/xx-distroseries-templates.txt (+56/-13)
lib/lp/translations/stories/productseries/xx-productseries-templates.txt (+27/-18)
lib/lp/translations/stories/standalone/xx-language.txt (+68/-7)
lib/lp/translations/templates/language-index.pt (+9/-4)
lib/lp/translations/templates/object-templates.pt (+20/-3)
lib/lp/translations/templates/pofile-export.pt (+1/-1)
lib/lp/translations/templates/pofile-translate.pt (+1/-1)
lib/lp/translations/templates/translation-import-queue-macros.pt (+1/-1)
lib/lp/translations/templates/translationimportqueueentry-index.pt (+1/-1)
lib/lp/translations/templates/translationmessage-translate.pt (+1/-1)
To merge this branch: bzr merge lp:~michael.nelson/launchpad/443353-api-builds-from-private
Reviewer Review Type Date Requested Status
Aaron Bentley (community) Approve
Jonathan Lange (community) Approve
Review via email: mp+14896@code.launchpad.net

Commit message

Ensures that when source+binaries are copied from archive A to B, the corresponding builds will be returned when querying the copied source for its builds (even though they were built in the context of archive A). Fixes bug 443353.

To post a comment you must log in.
Revision history for this message
Michael Nelson (michael.nelson) wrote :

Overview
========

This branch fixes bug 443353 by ensuring that getBuildsForSources() will include builds that were originally built in a different archive context, but have since had binaries copied into the source archive context.

Issues
======

There are two main issues with this branch IMO.

1. Ensuring that the result of the union was ordered correctly is hackish, and dependent on a storm implementation detail (that columns in SQL queries for a certain table are ordered alphabetically).

2. Testing the correct ordering in the doctest isn't so readable. It could be better to print out the results instead, but on the other hand, I didn't want the test to be dependent on database ids. Previously the test simply ensured the last item was the one expected - I've updated this to instead assure that the complete result is sorted as expected.

Any suggestions welcome!

Testing/QA
==========

To test, run:
bin/test -vvt doc/publishing.txt

To QA:

Visit:
https://edge.launchpad.net/ubuntu/+source/openjdk-6

and expand the intrepid 6b12-0ubuntu6.6 security release. Currently this only displays two builds, where as it should display all the builds listed at:

https://edge.launchpad.net/ubuntu/+source/openjdk-6/6b12-0ubuntu6.6

Revision history for this message
Jonathan Lange (jml) wrote :
Download full text (9.7 KiB)

On Sun, Nov 15, 2009 at 2:35 PM, Michael Nelson
<email address hidden> wrote:
> Michael Nelson has proposed merging lp:~michael.nelson/launchpad/443353-api-builds-from-private into lp:launchpad.
>
>    Requested reviews:
>    Canonical Launchpad Engineering (launchpad)
> Related bugs:
>  #443353 API does not include Builds for sources that were sync'd from private PPAs
>  https://bugs.launchpad.net/bugs/443353
>
>
> Overview
> ========
>
> This branch fixes bug 443353 by ensuring that getBuildsForSources() will include builds that were originally built in a different archive context, but have since had binaries copied into the source archive context.
>
> Issues
> ======
>
> There are two main issues with this branch IMO.
>
> 1. Ensuring that the result of the union was ordered correctly is hackish, and dependent on a storm implementation detail (that columns in SQL queries for a certain table are ordered alphabetically).
>
> 2. Testing the correct ordering in the doctest isn't so readable. It could be better to print out the results instead, but on the other hand, I didn't want the test to be dependent on database ids. Previously the test simply ensured the last item was the one expected - I've updated this to instead assure that the complete result is sorted as expected.
>
> Any suggestions welcome!
>

Hi Michael,

Thanks for fixing this -- on a Sunday even!

I'm generally OK with this branch, but would like another opportunity
to have a look at it and maybe to talk with you face-to-face.

jml

> Testing/QA
> ==========
>
> To test, run:
> bin/test -vvt doc/publishing.txt
>
> To QA:
>
> Visit:
> https://edge.launchpad.net/ubuntu/+source/openjdk-6
>
> and expand the intrepid 6b12-0ubuntu6.6 security release. Currently this only displays two builds, where as it should display all the builds listed at:
>
> https://edge.launchpad.net/ubuntu/+source/openjdk-6/6b12-0ubuntu6.6
>
>
>
>
> --
> https://code.launchpad.net/~michael.nelson/launchpad/443353-api-builds-from-private/+merge/14896
> Your team Launchpad code reviewers from Canonical is subscribed to branch lp:launchpad.
>
> === modified file 'lib/lp/soyuz/doc/publishing.txt'
> --- lib/lp/soyuz/doc/publishing.txt     2009-11-05 10:51:36 +0000
> +++ lib/lp/soyuz/doc/publishing.txt     2009-11-15 20:35:29 +0000
> @@ -1055,22 +1055,53 @@
>  each build found.
>
>     >>> cprov_builds.count()
> -    7
> +    8
>
>  The `ResultSet` is ordered by ascending
>  `SourcePackagePublishingHistory.id` and ascending
>  `DistroArchseries.architecturetag` in this order.
>
> -    >>> source_pub, build, arch = cprov_builds.last()
> -
> -    >>> print source_pub.displayname
> -    foo 666 in breezy-autotest
> -
> -    >>> print build.title
> -    i386 build of foo 666 in ubuntutest breezy-autotest RELEASE
> -
> -    >>> print arch.displayname
> -    ubuntutest Breezy Badger Autotest i386
> +    # The easiest thing we can do here (without printing ids)
> +    # is to show that sorting a list of the resulting ids+tags does not
> +    # modify the list.
> +    >>> from copy import copy
> +    >>> ids_and_tags = [(pub.id, arch.architecturetag)
> +    ...     for pub, build, arch in cprov_builds]
> +    >>> ids...

Read more...

Revision history for this message
Jonathan Lange (jml) wrote :

See my email.

review: Needs Fixing
Revision history for this message
Michael Nelson (michael.nelson) wrote :
Download full text (12.0 KiB)

On Sun, Nov 15, 2009 at 3:24 PM, Jonathan Lange <email address hidden> wrote:

> On Sun, Nov 15, 2009 at 2:35 PM, Michael Nelson
> <email address hidden> wrote:
> > Michael Nelson has proposed merging
> lp:~michael.nelson/launchpad/443353-api-builds-from-private into
> lp:launchpad.
> >
> > Requested reviews:
> > Canonical Launchpad Engineering (launchpad)
> > Related bugs:
> > #443353 API does not include Builds for sources that were sync'd from
> private PPAs
> > https://bugs.launchpad.net/bugs/443353
> >
> >
> > Overview
> > ========
> >
> > This branch fixes bug 443353 by ensuring that getBuildsForSources() will
> include builds that were originally built in a different archive context,
> but have since had binaries copied into the source archive context.
> >
> > Issues
> > ======
> >
> > There are two main issues with this branch IMO.
> >
> > 1. Ensuring that the result of the union was ordered correctly is
> hackish, and dependent on a storm implementation detail (that columns in SQL
> queries for a certain table are ordered alphabetically).
> >
> > 2. Testing the correct ordering in the doctest isn't so readable. It
> could be better to print out the results instead, but on the other hand, I
> didn't want the test to be dependent on database ids. Previously the test
> simply ensured the last item was the one expected - I've updated this to
> instead assure that the complete result is sorted as expected.
> >
> > Any suggestions welcome!
> >
>
> Hi Michael,
>
> Thanks for fixing this -- on a Sunday even!
>
>
And thanks for reviewing even on a Sunday :)

> I'm generally OK with this branch, but would like another opportunity
> to have a look at it and maybe to talk with you face-to-face.
>
>
Yes, I was keen for pointers as I wasn't happy with the hack... after
talking with both Jamu and Gustavo, I think we've got a much better solution
(although it still feels it should not be necessary).

> jml
>
> > Testing/QA
> > ==========
> >
> > To test, run:
> > bin/test -vvt doc/publishing.txt
> >
> > To QA:
> >
> > Visit:
> > https://edge.launchpad.net/ubuntu/+source/openjdk-6
> >
> > and expand the intrepid 6b12-0ubuntu6.6 security release. Currently this
> only displays two builds, where as it should display all the builds listed
> at:
> >
> > https://edge.launchpad.net/ubuntu/+source/openjdk-6/6b12-0ubuntu6.6
> >
> >
> >
> >
> > --
> >
> https://code.launchpad.net/~michael.nelson/launchpad/443353-api-builds-from-private/+merge/14896<https://code.launchpad.net/%7Emichael.nelson/launchpad/443353-api-builds-from-private/+merge/14896>
> > Your team Launchpad code reviewers from Canonical is subscribed to branch
> lp:launchpad.
> >
> > === modified file 'lib/lp/soyuz/doc/publishing.txt'
> > --- lib/lp/soyuz/doc/publishing.txt 2009-11-05 10:51:36 +0000
> > +++ lib/lp/soyuz/doc/publishing.txt 2009-11-15 20:35:29 +0000
> > @@ -1055,22 +1055,53 @@
> > each build found.
> >
> > >>> cprov_builds.count()
> > - 7
> > + 8
> >
> > The `ResultSet` is ordered by ascending
> > `SourcePackagePublishingHistory.id` and ascending
> > `DistroArchseries.architecturetag` in this order.
> >
> > - >>> source_pub, build, arch = c...

=== modified file 'lib/lp/soyuz/doc/publishing.txt'
--- lib/lp/soyuz/doc/publishing.txt 2009-11-15 20:13:09 +0000
+++ lib/lp/soyuz/doc/publishing.txt 2009-11-16 03:58:10 +0000
@@ -1064,24 +1064,31 @@
1064 # The easiest thing we can do here (without printing ids)1064 # The easiest thing we can do here (without printing ids)
1065 # is to show that sorting a list of the resulting ids+tags does not1065 # is to show that sorting a list of the resulting ids+tags does not
1066 # modify the list.1066 # modify the list.
1067 >>> from copy import copy
1068 >>> ids_and_tags = [(pub.id, arch.architecturetag)1067 >>> ids_and_tags = [(pub.id, arch.architecturetag)
1069 ... for pub, build, arch in cprov_builds]1068 ... for pub, build, arch in cprov_builds]
1070 >>> ids_and_tags_sorted = copy(ids_and_tags)1069 >>> ids_and_tags == sorted(ids_and_tags)
1071 >>> ids_and_tags_sorted.sort()
1072 >>> ids_and_tags == ids_and_tags_sorted
1073 True1070 True
10741071
1075If a source package is copied from another archive (including the1072If a source package is copied from another archive (including the
1076binaries), then these builds will also be included in the result (even1073binaries), then the related builds for that source package will
1077though they were build in a different archive context).1074also be retrievable via the copied source publication.
1075For example, if a package is built in a private security PPA, and then
1076later copied out into the primary archive, the builds will then
1077be available when looking at the copied source package in the primary
1078archive.
10781079
1079 # Create a new PPA and publish a source with some builds1080 # Create a new PPA and publish a source with some builds
1080 # and binaries.1081 # and binaries.
1081 >>> other_ppa = factory.makeArchive()1082 >>> other_ppa = factory.makeArchive(name="otherppa")
1082 >>> binaries = test_publisher.getPubBinaries(archive=other_ppa)1083 >>> binaries = test_publisher.getPubBinaries(archive=other_ppa)
1084
1085The associated builds and binaries will be created in the context of the
1086other PPA.
1087
1083 >>> build = binaries[0].binarypackagerelease.build1088 >>> build = binaries[0].binarypackagerelease.build
1084 >>> source_pub = build.sourcepackagerelease.publishings[0]1089 >>> source_pub = build.sourcepackagerelease.publishings[0]
1090 >>> print build.archive.name
1091 otherppa
10851092
1086 # Copy the source into Celso's PPA, ensuring that the binaries1093 # Copy the source into Celso's PPA, ensuring that the binaries
1087 # are alse published there.1094 # are alse published there.
@@ -1092,7 +1099,8 @@
1092 ... binaries[0].binarypackagerelease, cprov.archive)1099 ... binaries[0].binarypackagerelease, cprov.archive)
10931100
1094Now we will see an extra source in Celso's PPA as well as an extra1101Now we will see an extra source in Celso's PPA as well as an extra
1095build - even though the build's context is not Celso's PPA.1102build - even though the build's context is not Celso's PPA. Previously
1103there were 8 sources and builds.
10961104
1097 >>> cprov_sources_new = cprov.archive.getPublishedSources()1105 >>> cprov_sources_new = cprov.archive.getPublishedSources()
1098 >>> cprov_sources_new.count()1106 >>> cprov_sources_new.count()
10991107
=== modified file 'lib/lp/soyuz/model/publishing.py'
--- lib/lp/soyuz/model/publishing.py 2009-11-15 20:41:46 +0000
+++ lib/lp/soyuz/model/publishing.py 2009-11-16 05:45:03 +0000
@@ -1234,8 +1234,6 @@
1234 Build.buildstate.is_in(build_states))1234 Build.buildstate.is_in(build_states))
12351235
1236 store = getUtility(IStoreSelector).get(MAIN_STORE, DEFAULT_FLAVOR)1236 store = getUtility(IStoreSelector).get(MAIN_STORE, DEFAULT_FLAVOR)
1237 find_spec = (
1238 SourcePackagePublishingHistory, Build, DistroArchSeries)
12391237
1240 # We'll be looking for builds in the same distroseries as the1238 # We'll be looking for builds in the same distroseries as the
1241 # SPPH for the same release.1239 # SPPH for the same release.
@@ -1251,7 +1249,7 @@
1251 # First, we'll find the builds that were built in the same1249 # First, we'll find the builds that were built in the same
1252 # archive context as the published sources.1250 # archive context as the published sources.
1253 builds_in_same_archive = store.find(1251 builds_in_same_archive = store.find(
1254 find_spec,1252 Build,
1255 builds_for_distroseries_expr,1253 builds_for_distroseries_expr,
1256 SourcePackagePublishingHistory.archiveID == Build.archiveID,1254 SourcePackagePublishingHistory.archiveID == Build.archiveID,
1257 *extra_exprs)1255 *extra_exprs)
@@ -1260,7 +1258,7 @@
1260 # same archive... even though the build was not built in1258 # same archive... even though the build was not built in
1261 # the same context archive.1259 # the same context archive.
1262 builds_copied_into_archive = store.find(1260 builds_copied_into_archive = store.find(
1263 find_spec,1261 Build,
1264 builds_for_distroseries_expr,1262 builds_for_distroseries_expr,
1265 SourcePackagePublishingHistory.archiveID != Build.archiveID,1263 SourcePackagePublishingHistory.archiveID != Build.archiveID,
1266 BinaryPackagePublishingHistory.archive == Build.archiveID,1264 BinaryPackagePublishingHistory.archive == Build.archiveID,
@@ -1269,26 +1267,29 @@
1269 BinaryPackageRelease.build == Build.id,1267 BinaryPackageRelease.build == Build.id,
1270 *extra_exprs)1268 *extra_exprs)
12711269
1272 result_set = builds_copied_into_archive.union(1270 builds_union = builds_copied_into_archive.union(
1273 builds_in_same_archive).config(distinct=True)1271 builds_in_same_archive).config(distinct=True)
12741272
1275 # XXX 2009-11-15 Michael Nelson bug=366043. It is not possible1273 # Now that we have a result_set of all the builds, we'll use it
1276 # to sort by the name `SourcePackagePublishingHistory.id` as after1274 # as a subquery to get the required publishing and arch to do
1277 # the union there are no tables. Nor can we sort by ambiguous `id`1275 # the ordering. We do this in this round-about way because we
1278 # as in this case there are 3 id columns in the result. Specifying1276 # can't sort on SourcePackagePublishingHistory.id after the
1279 # the column index is the only option that I can find. So we're1277 # union. See bug 443353 for details.
1280 # relying on an implementation detail of Storm that it lists1278 find_spec = (
1281 # columns in alphabetical order in sql queries.1279 SourcePackagePublishingHistory, Build, DistroArchSeries)
1282 sql_columns = SourcePackagePublishingHistory._storm_columns.values()1280
1283 sql_column_names = [column.name for column in sql_columns]1281 # Storm doesn't let us do builds_union.values('id') -
1284 sql_column_names.sort()1282 # ('Union' object has no attribute 'columns'). So instead
12851283 # we have to instantiate the objects just to get the id.
1286 # SQL order by uses 1-based column numbers.1284 build_ids = [build.id for build in builds_union]
1287 source_pub_id_col_number = sql_column_names.index('id') + 11285
1288 result_set.order_by(1286 result_set = store.find(
1289 source_pub_id_col_number, DistroArchSeries.architecturetag)1287 find_spec, builds_for_distroseries_expr,
12901288 Build.id.is_in(build_ids))
1291 return result_set1289
1290 return result_set.order_by(
1291 SourcePackagePublishingHistory.id,
1292 DistroArchSeries.architecturetag)
12921293
1293 def getByIdAndArchive(self, id, archive, source=True):1294 def getByIdAndArchive(self, id, archive, source=True):
1294 """See `IPublishingSet`."""1295 """See `IPublishingSet`."""
Revision history for this message
Jonathan Lange (jml) wrote :

Thanks for fixing this, Michael. Land away.

review: Approve
Revision history for this message
Michael Nelson (michael.nelson) wrote :
Download full text (9.9 KiB)

I've just gotten back to this now - when I originally tried to land this while at UDS there were a bunch of ec2 errors - one of which pointed out an error in the query itself.

There are two parts the failures fixed by this incremental.

* First, there was an actual error in the query (details below),
* second, a number of tests were affected by the change as we now return
  builds from other archive contexts if the build has binaries published in
  the current archive context (ie. by a copy)
* third, we have some bogus sample data (effectively two i386 builds for
  ice-weasel 1.0 in cprov's ppa - one built in that context but without any
  corresponding bpr's or bpph (so pending, buildid=25), the other copied and
  published there with a new bpph (buildid=23). As this branch exposed this
  data, I modified two tests to use a different package instead (yes, I
  would like to have re-written the test to use STP etc. etc., but).

So, annotated diff below, raw diff at: http://pastebin.ubuntu.com/336595/ (-r 9889..9892)

=== modified file 'lib/lp/soyuz/model/publishing.py'
--- lib/lp/soyuz/model/publishing.py 2009-12-04 13:46:43 +0000
+++ lib/lp/soyuz/model/publishing.py 2009-12-07 11:11:28 +0000
@@ -594,7 +594,7 @@
             # not blow up because of bad data.
             return None
         source, packageupload, spr, changesfile, lfc = result
-
+
         # Return a webapp-proxied LibraryFileAlias so that restricted
         # librarian files are accessible. Non-restricted files will get
         # a 302 so that webapp threads are not tied up.
@@ -1290,7 +1290,8 @@
             Build,
             builds_for_distroseries_expr,
             SourcePackagePublishingHistory.archiveID != Build.archiveID,
- BinaryPackagePublishingHistory.archive == Build.archiveID,
+ BinaryPackagePublishingHistory.archive ==
+ SourcePackagePublishingHistory.archiveID,

### So this was the error in the original MP - we're looking for builds that
originated in other contexts that have binaries published in the SPPH
archive context - not the Build's archive context :/

             BinaryPackagePublishingHistory.binarypackagerelease ==
                 BinaryPackageRelease.id,
             BinaryPackageRelease.build == Build.id,

=== modified file 'lib/lp/soyuz/scripts/tests/test_copypackage.py'
--- lib/lp/soyuz/scripts/tests/test_copypackage.py 2009-10-17 00:58:51 +0000
+++ lib/lp/soyuz/scripts/tests/test_copypackage.py 2009-12-07 11:15:16 +0000
@@ -1340,6 +1340,21 @@
         target_archive = copy_helper.destination.archive
         self.checkCopies(copied, target_archive, 3)

+ # The second copy will fail explicitly because the new BPPH
+ # records are not yet published.
+ nothing_copied = copy_helper.mainTask()
+ self.assertEqual(len(nothing_copied), 0)
+ self.assertEqual(
+ copy_helper.logger.buffer.getvalue().splitlines()[-1],
+ 'ERROR: foo 666 in hoary (same version has unpublished binaries '
+ 'in the destination archive for Hoary, please wait for them to '
+ 'be published before copying)')
+
+ # If we ensure that the copied b...

Revision history for this message
Aaron Bentley (abentley) wrote :

I approve the incremental change. As discussed on IRC, I think it may be possible to remove the first find and use the second query to find cases where SourcePackagePublishingHistory.archiveID == Build.archiveID as well as cases where SourcePackagePublishingHistory.archiveID != Build.archiveID. But if not, it's fine to land as-is.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'lib/lp/archiveuploader/nascentuploadfile.py'
--- lib/lp/archiveuploader/nascentuploadfile.py 2009-11-10 13:09:26 +0000
+++ lib/lp/archiveuploader/nascentuploadfile.py 2009-12-07 15:21:15 +0000
@@ -690,7 +690,7 @@
690 tar_checker.ancient_files[first_file])690 tar_checker.ancient_files[first_file])
691 yield UploadError(691 yield UploadError(
692 "%s: has %s file(s) with a time stamp too "692 "%s: has %s file(s) with a time stamp too "
693 "far into the future (e.g. %s [%s])."693 "far in the past (e.g. %s [%s])."
694 % (self.filename, len(ancient_files), first_file,694 % (self.filename, len(ancient_files), first_file,
695 timestamp))695 timestamp))
696 return696 return
697697
=== modified file 'lib/lp/archiveuploader/tests/nascentuploadfile.txt'
--- lib/lp/archiveuploader/tests/nascentuploadfile.txt 2009-07-08 08:38:05 +0000
+++ lib/lp/archiveuploader/tests/nascentuploadfile.txt 2009-12-07 15:21:15 +0000
@@ -539,6 +539,77 @@
539539
540== DebBinaryUploadFile ==540== DebBinaryUploadFile ==
541541
542DebBinaryUploadFile models a binary .deb file.
543
544 >>> from lp.archiveuploader.nascentuploadfile import (
545 ... DebBinaryUploadFile)
546 >>> ed_deb_path = datadir('ed_0.2-20_i386.deb')
547 >>> ed_binary_deb = DebBinaryUploadFile(ed_deb_path,
548 ... 'e31eeb0b6b3b87e1ea79378df864ffff',
549 ... 15, 'main/editors', 'important', 'foo', '1.2',
550 ... ed_mixed_changes, modified_insecure_policy,
551 ... mock_logger_quiet)
552
553Like the other files it can be verified:
554
555 >>> list(ed_binary_deb.verify())
556 []
557
558Verification checks that the specified section matches the section in the
559changes file:
560
561 >>> ed_binary_deb = DebBinaryUploadFile(ed_deb_path,
562 ... 'e31eeb0b6b3b87e1ea79378df864ffff',
563 ... 15, 'main/net', 'important', 'foo', '1.2',
564 ... ed_mixed_changes, modified_insecure_policy,
565 ... mock_logger_quiet)
566 >>> list(ed_binary_deb.verify())
567 [UploadError('ed_0.2-20_i386.deb control file lists section as
568 main/editors but changes file has main/net.',)]
569
570It also checks the priority against the changes file:
571
572 >>> ed_binary_deb = DebBinaryUploadFile(ed_deb_path,
573 ... 'e31eeb0b6b3b87e1ea79378df864ffff',
574 ... 15, 'main/editors', 'extra', 'foo', '1.2',
575 ... ed_mixed_changes, modified_insecure_policy,
576 ... mock_logger_quiet)
577 >>> list(ed_binary_deb.verify())
578 [UploadError('ed_0.2-20_i386.deb control file lists priority as important
579 but changes file has extra.',)]
580
581The timestamp of the files in the .deb are tested against the policy for being
582too new:
583
584 >>> old_only_policy = getPolicy(
585 ... name='insecure', distro='ubuntu', distroseries='hoary')
586 >>> old_only_policy.can_upload_binaries = True
587 >>> old_only_policy.future_time_grace = -5 * 365 * 24 * 60 * 60
588
589 >>> ed_binary_deb = DebBinaryUploadFile(ed_deb_path,
590 ... 'e31eeb0b6b3b87e1ea79378df864ffff',
591 ... 15, 'main/editors', 'important', 'foo', '1.2',
592 ... ed_mixed_changes, old_only_policy,
593 ... mock_logger_quiet)
594 >>> list(ed_binary_deb.verifyDebTimestamp())
595 [UploadError('ed_0.2-20_i386.deb: has 26 file(s) with a time stamp too
596 far into the future (e.g. control [Thu Jan 3 19:29:01 2008]).',)]
597
598... as well as for being too old:
599
600 >>> new_only_policy = getPolicy(
601 ... name='insecure', distro='ubuntu', distroseries='hoary')
602 >>> new_only_policy.can_upload_binaries = True
603 >>> new_only_policy.earliest_year = 2010
604 >>> ed_binary_deb = DebBinaryUploadFile(ed_deb_path,
605 ... 'e31eeb0b6b3b87e1ea79378df864ffff',
606 ... 15, 'main/editors', 'important', 'foo', '1.2',
607 ... ed_mixed_changes, new_only_policy,
608 ... mock_logger_quiet)
609 >>> list(ed_binary_deb.verify())
610 [UploadError('ed_0.2-20_i386.deb: has 26 file(s) with a time stamp too
611 far in the past (e.g. control [Thu Jan 3 19:29:01 2008]).',)]
612
542613
543== UDebBinaryUploadFile ==614== UDebBinaryUploadFile ==
544615
545616
=== modified file 'lib/lp/bugs/templates/bug-portlet-subscribers.pt'
--- lib/lp/bugs/templates/bug-portlet-subscribers.pt 2009-11-26 03:13:32 +0000
+++ lib/lp/bugs/templates/bug-portlet-subscribers.pt 2009-12-07 15:21:15 +0000
@@ -25,7 +25,7 @@
25 <img src="/@@/spinner" />25 <img src="/@@/spinner" />
26 </div>26 </div>
27 <script type="text/javascript">27 <script type="text/javascript">
28 YUI().use('io-base', 'node', 'bugs.bugtask_index', function(Y) {28 LPS.use('io-base', 'node', 'bugs.bugtask_index', function(Y) {
29 // Must be done inline here to ensure the load event fires.29 // Must be done inline here to ensure the load event fires.
30 // This is a work around for a YUI3 issue with event handling.30 // This is a work around for a YUI3 issue with event handling.
31 var subscription_link = Y.one('.menu-link-subscription');31 var subscription_link = Y.one('.menu-link-subscription');
3232
=== modified file 'lib/lp/bugs/templates/bugtarget-filebug-submit-bug.pt'
--- lib/lp/bugs/templates/bugtarget-filebug-submit-bug.pt 2009-10-01 12:09:37 +0000
+++ lib/lp/bugs/templates/bugtarget-filebug-submit-bug.pt 2009-12-07 15:21:15 +0000
@@ -14,7 +14,7 @@
14 tal:define="lp_js string:${icingroot}/build"14 tal:define="lp_js string:${icingroot}/build"
15 tal:attributes="src string:${lp_js}/bugs/filebug-dupefinder.js"></script>15 tal:attributes="src string:${lp_js}/bugs/filebug-dupefinder.js"></script>
16 <script type="text/javascript">16 <script type="text/javascript">
17 YUI().use('base', 'node', 'oop', 'event', 'bugs.dupe_finder', function(Y) {17 LPS.use('base', 'node', 'oop', 'event', 'bugs.dupe_finder', function(Y) {
18 Y.bugs.setup_dupe_finder();18 Y.bugs.setup_dupe_finder();
19 });19 });
20 </script>20 </script>
2121
=== modified file 'lib/lp/bugs/templates/bugtarget-portlet-bugfilters.pt'
--- lib/lp/bugs/templates/bugtarget-portlet-bugfilters.pt 2009-11-04 13:56:17 +0000
+++ lib/lp/bugs/templates/bugtarget-portlet-bugfilters.pt 2009-12-07 15:21:15 +0000
@@ -12,7 +12,7 @@
12 <img src="/@@/spinner" />12 <img src="/@@/spinner" />
13 </div>13 </div>
14 <script type="text/javascript">14 <script type="text/javascript">
15 YUI().use('io-base', 'node', function(Y) {15 LPS.use('io-base', 'node', function(Y) {
16 Y.on('domready', function() {16 Y.on('domready', function() {
17 var portlet = Y.one('#portlet-bugfilters');17 var portlet = Y.one('#portlet-bugfilters');
18 Y.one('#bugfilters-portlet-spinner').setStyle('display', 'block');18 Y.one('#bugfilters-portlet-spinner').setStyle('display', 'block');
1919
=== modified file 'lib/lp/bugs/templates/bugtarget-portlet-bugtags.pt'
--- lib/lp/bugs/templates/bugtarget-portlet-bugtags.pt 2009-11-04 13:56:17 +0000
+++ lib/lp/bugs/templates/bugtarget-portlet-bugtags.pt 2009-12-07 15:21:15 +0000
@@ -9,7 +9,7 @@
9 <a id="tags-content-link"9 <a id="tags-content-link"
10 tal:attributes="href context/fmt:url/+bugtarget-portlet-tags-content"></a>10 tal:attributes="href context/fmt:url/+bugtarget-portlet-tags-content"></a>
11 <script type="text/javascript">11 <script type="text/javascript">
12 YUI().use('io-base', 'node', function(Y) {12 LPS.use('io-base', 'node', function(Y) {
13 Y.on('domready', function() {13 Y.on('domready', function() {
14 Y.one('#tags-portlet-spinner').setStyle('display', 'block');14 Y.one('#tags-portlet-spinner').setStyle('display', 'block');
1515
1616
=== modified file 'lib/lp/bugs/templates/bugtask-index.pt'
--- lib/lp/bugs/templates/bugtask-index.pt 2009-11-30 17:57:15 +0000
+++ lib/lp/bugs/templates/bugtask-index.pt 2009-12-07 15:21:15 +0000
@@ -37,7 +37,7 @@
37 </script>37 </script>
38 </tal:devmode>38 </tal:devmode>
39 <script type="text/javascript">39 <script type="text/javascript">
40 YUI().use('base', 'node', 'oop', 'event', 'bugs.bugtask_index',40 LPS.use('base', 'node', 'oop', 'event', 'bugs.bugtask_index',
41 'code.branchmergeproposal.popupdiff', function(Y) {41 'code.branchmergeproposal.popupdiff', function(Y) {
42 Y.bugs.setup_bugtask_index();42 Y.bugs.setup_bugtask_index();
43 Y.on('load', function(e) {43 Y.on('load', function(e) {
@@ -155,7 +155,7 @@
155 <img src="/@@/spinner" id="tags-edit-spinner" style="display: none" />155 <img src="/@@/spinner" id="tags-edit-spinner" style="display: none" />
156 <a href="+edit" title="Edit tags" id="edit-tags-trigger" class="sprite edit"></a>156 <a href="+edit" title="Edit tags" id="edit-tags-trigger" class="sprite edit"></a>
157 <script type="text/javascript">157 <script type="text/javascript">
158 YUI().use('event', 'node', 'bugs.bug_tags_entry', function(Y) {158 LPS.use('event', 'node', 'bugs.bug_tags_entry', function(Y) {
159 // XXX intellectronica 2009-04-16 bug #362309:159 // XXX intellectronica 2009-04-16 bug #362309:
160 // The load event fires very late on bug pages that take a160 // The load event fires very late on bug pages that take a
161 // long time to render, but we prefer to use it since the161 // long time to render, but we prefer to use it since the
@@ -295,7 +295,7 @@
295 button.style.display = 'none';295 button.style.display = 'none';
296 </script>296 </script>
297 <script type="text/javascript">297 <script type="text/javascript">
298 YUI().use('lp.comment', function(Y) {298 LPS.use('lp.comment', function(Y) {
299 var comment = new Y.lp.Comment();299 var comment = new Y.lp.Comment();
300 comment.render();300 comment.render();
301 });301 });
302302
=== modified file 'lib/lp/bugs/templates/bugtask-tasks-and-nominations-table-row.pt'
--- lib/lp/bugs/templates/bugtask-tasks-and-nominations-table-row.pt 2009-11-03 15:32:31 +0000
+++ lib/lp/bugs/templates/bugtask-tasks-and-nominations-table-row.pt 2009-12-07 15:21:15 +0000
@@ -185,7 +185,7 @@
185 class="bugtasks-table-row-init-script"185 class="bugtasks-table-row-init-script"
186 tal:condition="not:view/many_bugtasks"186 tal:condition="not:view/many_bugtasks"
187 tal:content="string:187 tal:content="string:
188 YUI().use('event', 'bugs.bugtask_index', function(Y) {188 LPS.use('event', 'bugs.bugtask_index', function(Y) {
189 Y.on('load',189 Y.on('load',
190 function(e) {190 function(e) {
191 Y.bugs.setup_bugtask_row(${view/js_config});191 Y.bugs.setup_bugtask_row(${view/js_config});
192192
=== modified file 'lib/lp/bugs/templates/bugtasks-and-nominations-table.pt'
--- lib/lp/bugs/templates/bugtasks-and-nominations-table.pt 2009-09-02 22:13:06 +0000
+++ lib/lp/bugs/templates/bugtasks-and-nominations-table.pt 2009-12-07 15:21:15 +0000
@@ -88,7 +88,7 @@
88 </span>88 </span>
8989
90 <script type="text/javascript" tal:content="string:90 <script type="text/javascript" tal:content="string:
91 YUI().use('event', 'bugs.bugtask_index', function(Y) {91 LPS.use('event', 'bugs.bugtask_index', function(Y) {
92 Y.on('load', function(e) {92 Y.on('load', function(e) {
93 Y.bugs.setup_me_too(${view/current_user_affected_js_status});93 Y.bugs.setup_me_too(${view/current_user_affected_js_status});
94 }, window);94 }, window);
9595
=== modified file 'lib/lp/bugs/templates/official-bug-target-manage-tags.pt'
--- lib/lp/bugs/templates/official-bug-target-manage-tags.pt 2009-09-04 17:03:00 +0000
+++ lib/lp/bugs/templates/official-bug-target-manage-tags.pt 2009-12-07 15:21:15 +0000
@@ -31,7 +31,7 @@
31 </script>31 </script>
32 <script tal:replace="structure view/tags_js_data" />32 <script tal:replace="structure view/tags_js_data" />
33 <script type="text/javascript">33 <script type="text/javascript">
34 YUI().use('event', 'bugs.official_bug_tag_management', function(Y) {34 LPS.use('event', 'bugs.official_bug_tag_management', function(Y) {
35 Y.on('domready', function(e) {35 Y.on('domready', function(e) {
36 Y.bugs.setup_official_bug_tag_management();36 Y.bugs.setup_official_bug_tag_management();
37 });37 });
3838
=== modified file 'lib/lp/code/templates/branch-import-details.pt'
--- lib/lp/code/templates/branch-import-details.pt 2009-11-04 13:56:17 +0000
+++ lib/lp/code/templates/branch-import-details.pt 2009-12-07 15:21:15 +0000
@@ -32,7 +32,7 @@
32 Try again32 Try again
33 </a>33 </a>
34 <script type="text/javascript">34 <script type="text/javascript">
35 YUI().use('event', 'node', function(Y) {35 LPS.use('event', 'node', function(Y) {
36 Y.on("domready", function () { Y.one('#tryagainlink').setStyle('display', 'inline') });36 Y.on("domready", function () { Y.one('#tryagainlink').setStyle('display', 'inline') });
37 });37 });
38 </script>38 </script>
3939
=== modified file 'lib/lp/code/templates/branch-index.pt'
--- lib/lp/code/templates/branch-index.pt 2009-11-17 05:07:41 +0000
+++ lib/lp/code/templates/branch-index.pt 2009-12-07 15:21:15 +0000
@@ -47,7 +47,7 @@
47 </tal:devmode>47 </tal:devmode>
48 <script type="text/javascript"48 <script type="text/javascript"
49 tal:content="string:49 tal:content="string:
50 YUI().use('node', 'event', 'widget', 'plugin', 'overlay',50 LPS.use('node', 'event', 'widget', 'plugin', 'overlay',
51 'lazr.choiceedit', 'code.branchstatus',51 'lazr.choiceedit', 'code.branchstatus',
52 'code.branchmergeproposal.popupdiff',52 'code.branchmergeproposal.popupdiff',
53 function(Y) {53 function(Y) {
5454
=== modified file 'lib/lp/code/templates/branch-listing.pt'
--- lib/lp/code/templates/branch-listing.pt 2009-11-04 13:56:17 +0000
+++ lib/lp/code/templates/branch-listing.pt 2009-12-07 15:21:15 +0000
@@ -41,7 +41,7 @@
41}41}
42registerLaunchpadFunction(hookUpFilterSubmission);42registerLaunchpadFunction(hookUpFilterSubmission);
4343
44YUI().use('io-base', 'node', 'json-parse', function(Y) {44LPS.use('io-base', 'node', 'json-parse', function(Y) {
4545
46function doUpdate(transaction_id, response, args) {46function doUpdate(transaction_id, response, args) {
47 json_values = Y.JSON.parse(response.responseText);47 json_values = Y.JSON.parse(response.responseText);
4848
=== modified file 'lib/lp/code/templates/branch-portlet-subscribers.pt'
--- lib/lp/code/templates/branch-portlet-subscribers.pt 2009-11-04 13:56:17 +0000
+++ lib/lp/code/templates/branch-portlet-subscribers.pt 2009-12-07 15:21:15 +0000
@@ -41,7 +41,7 @@
41 string:&lt;script id='milestone-script' type='text/javascript'&gt;" />41 string:&lt;script id='milestone-script' type='text/javascript'&gt;" />
42 <!--42 <!--
4343
44 YUI().use('io-base', 'node', 'code.branchsubscription', function(Y) {44 LPS.use('io-base', 'node', 'code.branchsubscription', function(Y) {
4545
46 if(Y.UA.ie) {46 if(Y.UA.ie) {
47 Y.one('#subscriber-list').set('innerHTML',47 Y.one('#subscriber-list').set('innerHTML',
4848
=== modified file 'lib/lp/code/templates/branch-related-bugs-specs.pt'
--- lib/lp/code/templates/branch-related-bugs-specs.pt 2009-09-08 21:42:45 +0000
+++ lib/lp/code/templates/branch-related-bugs-specs.pt 2009-12-07 15:21:15 +0000
@@ -42,7 +42,7 @@
42 string:&lt;script id='branchlink-script' type='text/javascript'&gt;" />42 string:&lt;script id='branchlink-script' type='text/javascript'&gt;" />
43 <!--43 <!--
4444
45 YUI().use('io-base', 'code.branchlinks', function(Y) {45 LPS.use('io-base', 'code.branchlinks', function(Y) {
4646
47 if(Y.UA.ie) {47 if(Y.UA.ie) {
48 return;48 return;
4949
=== modified file 'lib/lp/code/templates/branchmergeproposal-generic-listing.pt'
--- lib/lp/code/templates/branchmergeproposal-generic-listing.pt 2009-11-04 13:56:17 +0000
+++ lib/lp/code/templates/branchmergeproposal-generic-listing.pt 2009-12-07 15:21:15 +0000
@@ -24,7 +24,7 @@
24 </form>24 </form>
25<script type="text/javascript">25<script type="text/javascript">
2626
27YUI().use('node', function(Y) {27LPS.use('node', function(Y) {
2828
29 function submit_filter() {29 function submit_filter() {
30 Y.one('#filter_form').submit();30 Y.one('#filter_form').submit();
3131
=== modified file 'lib/lp/registry/templates/object-timeline-graph.pt'
--- lib/lp/registry/templates/object-timeline-graph.pt 2009-11-24 09:30:01 +0000
+++ lib/lp/registry/templates/object-timeline-graph.pt 2009-12-07 15:21:15 +0000
@@ -32,7 +32,7 @@
32 include_inactive = false;32 include_inactive = false;
33 }33 }
3434
35 YUI().use('registry.timeline', 'node', function(Y) {35 LPS.use('registry.timeline', 'node', function(Y) {
36 Y.on('domready', function(e) {36 Y.on('domready', function(e) {
37 if (Y.UA.ie) {37 if (Y.UA.ie) {
38 return;38 return;
3939
=== modified file 'lib/lp/registry/templates/person-macros.pt'
--- lib/lp/registry/templates/person-macros.pt 2009-11-04 13:56:17 +0000
+++ lib/lp/registry/templates/person-macros.pt 2009-12-07 15:21:15 +0000
@@ -190,7 +190,7 @@
190 condition="private_prefix">190 condition="private_prefix">
191 <script type="text/javascript"191 <script type="text/javascript"
192 tal:content="string:192 tal:content="string:
193 YUI().use('node', 'event', function(Y) {193 LPS.use('node', 'event', function(Y) {
194 // Prepend/remove 'private-' from team name based on visibility194 // Prepend/remove 'private-' from team name based on visibility
195 // setting. User can choose to edit it back out, if they wish.195 // setting. User can choose to edit it back out, if they wish.
196 function visibility_on_change(e) {196 function visibility_on_change(e) {
197197
=== modified file 'lib/lp/registry/templates/product-new.pt'
--- lib/lp/registry/templates/product-new.pt 2009-11-04 13:56:17 +0000
+++ lib/lp/registry/templates/product-new.pt 2009-12-07 15:21:15 +0000
@@ -14,7 +14,7 @@
14 * details widgets until the user states that the project they are14 * details widgets until the user states that the project they are
15 * registering is not a duplicate.15 * registering is not a duplicate.
16 */16 */
17YUI().use('node', 'lazr.effects', function(Y) {17LPS.use('node', 'lazr.effects', function(Y) {
18 Y.on('domready', function() {18 Y.on('domready', function() {
19 /* These two regexps serve slightly different purposes. The first19 /* These two regexps serve slightly different purposes. The first
20 * finds the leftmost run of valid url characters for the autofill20 * finds the leftmost run of valid url characters for the autofill
2121
=== modified file 'lib/lp/registry/templates/productrelease-add-from-series.pt'
--- lib/lp/registry/templates/productrelease-add-from-series.pt 2009-11-04 13:56:17 +0000
+++ lib/lp/registry/templates/productrelease-add-from-series.pt 2009-12-07 15:21:15 +0000
@@ -14,7 +14,7 @@
14 <tal:script14 <tal:script
15 replace="structure15 replace="structure
16 string:&lt;script id='milestone-script' type='text/javascript'&gt;" />16 string:&lt;script id='milestone-script' type='text/javascript'&gt;" />
17 YUI().use('node', 'lp.milestoneoverlay', function (Y) {17 LPS.use('node', 'lp.milestoneoverlay', function (Y) {
1818
19 // This is a value for the SELECT OPTION which is passed with19 // This is a value for the SELECT OPTION which is passed with
20 // the SELECT's "change" event. It includes some symbols that are not20 // the SELECT's "change" event. It includes some symbols that are not
2121
=== modified file 'lib/lp/registry/templates/teammembership-index.pt'
--- lib/lp/registry/templates/teammembership-index.pt 2009-11-04 13:56:17 +0000
+++ lib/lp/registry/templates/teammembership-index.pt 2009-12-07 15:21:15 +0000
@@ -20,7 +20,7 @@
20 use-macro="context/@@launchpad_widget_macros/yui2calendar-dependencies" />20 use-macro="context/@@launchpad_widget_macros/yui2calendar-dependencies" />
2121
22 <script type="text/javascript">22 <script type="text/javascript">
23 YUI().use('node', 'lp.calendar', function(Y) {23 LPS.use('node', 'lp.calendar', function(Y) {
24 // Ensure that when the picker is used the radio button switches24 // Ensure that when the picker is used the radio button switches
25 // from 'Never' to 'On' and the expiry field is enabled.25 // from 'Never' to 'On' and the expiry field is enabled.
26 Y.on("available", function(e) {26 Y.on("available", function(e) {
2727
=== modified file 'lib/lp/registry/templates/timeline-macros.pt'
--- lib/lp/registry/templates/timeline-macros.pt 2009-11-04 13:56:17 +0000
+++ lib/lp/registry/templates/timeline-macros.pt 2009-12-07 15:21:15 +0000
@@ -35,7 +35,7 @@
35 if (auto_resize == 'true') {35 if (auto_resize == 'true') {
36 timeline_url += 'resize_frame=timeline-iframe&';36 timeline_url += 'resize_frame=timeline-iframe&';
37 }37 }
38 YUI().use('node', function(Y) {38 LPS.use('node', function(Y) {
39 if (Y.UA.ie) {39 if (Y.UA.ie) {
40 return;40 return;
41 }41 }
4242
=== modified file 'lib/lp/soyuz/doc/publishing.txt'
--- lib/lp/soyuz/doc/publishing.txt 2009-11-18 23:56:26 +0000
+++ lib/lp/soyuz/doc/publishing.txt 2009-12-07 15:21:15 +0000
@@ -1055,22 +1055,61 @@
1055each build found.1055each build found.
10561056
1057 >>> cprov_builds.count()1057 >>> cprov_builds.count()
1058 71058 8
10591059
1060The `ResultSet` is ordered by ascending1060The `ResultSet` is ordered by ascending
1061`SourcePackagePublishingHistory.id` and ascending1061`SourcePackagePublishingHistory.id` and ascending
1062`DistroArchseries.architecturetag` in this order.1062`DistroArchseries.architecturetag` in this order.
10631063
1064 >>> source_pub, build, arch = cprov_builds.last()1064 # The easiest thing we can do here (without printing ids)
10651065 # is to show that sorting a list of the resulting ids+tags does not
1066 >>> print source_pub.displayname1066 # modify the list.
1067 foo 666 in breezy-autotest1067 >>> ids_and_tags = [(pub.id, arch.architecturetag)
10681068 ... for pub, build, arch in cprov_builds]
1069 >>> print build.title1069 >>> ids_and_tags == sorted(ids_and_tags)
1070 i386 build of foo 666 in ubuntutest breezy-autotest RELEASE1070 True
10711071
1072 >>> print arch.displayname1072If a source package is copied from another archive (including the
1073 ubuntutest Breezy Badger Autotest i3861073binaries), then the related builds for that source package will
1074also be retrievable via the copied source publication.
1075For example, if a package is built in a private security PPA, and then
1076later copied out into the primary archive, the builds will then
1077be available when looking at the copied source package in the primary
1078archive.
1079
1080 # Create a new PPA and publish a source with some builds
1081 # and binaries.
1082 >>> other_ppa = factory.makeArchive(name="otherppa")
1083 >>> binaries = test_publisher.getPubBinaries(archive=other_ppa)
1084
1085The associated builds and binaries will be created in the context of the
1086other PPA.
1087
1088 >>> build = binaries[0].binarypackagerelease.build
1089 >>> source_pub = build.sourcepackagerelease.publishings[0]
1090 >>> print build.archive.name
1091 otherppa
1092
1093 # Copy the source into Celso's PPA, ensuring that the binaries
1094 # are alse published there.
1095 >>> source_pub_cprov = source_pub.copyTo(
1096 ... source_pub.distroseries, source_pub.pocket,
1097 ... cprov.archive)
1098 >>> binaries_cprov = test_publisher.publishBinaryInArchive(
1099 ... binaries[0].binarypackagerelease, cprov.archive)
1100
1101Now we will see an extra source in Celso's PPA as well as an extra
1102build - even though the build's context is not Celso's PPA. Previously
1103there were 8 sources and builds.
1104
1105 >>> cprov_sources_new = cprov.archive.getPublishedSources()
1106 >>> cprov_sources_new.count()
1107 9
1108
1109 >>> cprov_builds_new = publishing_set.getBuildsForSources(
1110 ... cprov_sources_new)
1111 >>> cprov_builds_new.count()
1112 9
10741113
1075Next we'll create two sources with two builds each (the SoyuzTestPublisher1114Next we'll create two sources with two builds each (the SoyuzTestPublisher
1076default) and show that the number of unpublished builds for these sources1115default) and show that the number of unpublished builds for these sources
10771116
=== modified file 'lib/lp/soyuz/model/publishing.py'
--- lib/lp/soyuz/model/publishing.py 2009-11-19 00:26:13 +0000
+++ lib/lp/soyuz/model/publishing.py 2009-12-07 15:21:15 +0000
@@ -40,6 +40,7 @@
40from canonical.database.enumcol import EnumCol40from canonical.database.enumcol import EnumCol
41from lp.registry.interfaces.pocket import PackagePublishingPocket41from lp.registry.interfaces.pocket import PackagePublishingPocket
42from lp.soyuz.model.binarypackagename import BinaryPackageName42from lp.soyuz.model.binarypackagename import BinaryPackageName
43from lp.soyuz.model.binarypackagerelease import BinaryPackageRelease
43from lp.soyuz.model.files import (44from lp.soyuz.model.files import (
44 BinaryPackageFile, SourcePackageReleaseFile)45 BinaryPackageFile, SourcePackageReleaseFile)
45from canonical.launchpad.database.librarian import (46from canonical.launchpad.database.librarian import (
@@ -593,7 +594,7 @@
593 # not blow up because of bad data.594 # not blow up because of bad data.
594 return None595 return None
595 source, packageupload, spr, changesfile, lfc = result596 source, packageupload, spr, changesfile, lfc = result
596 597
597 # Return a webapp-proxied LibraryFileAlias so that restricted598 # Return a webapp-proxied LibraryFileAlias so that restricted
598 # librarian files are accessible. Non-restricted files will get599 # librarian files are accessible. Non-restricted files will get
599 # a 302 so that webapp threads are not tied up.600 # a 302 so that webapp threads are not tied up.
@@ -1262,23 +1263,64 @@
1262 Build.buildstate.is_in(build_states))1263 Build.buildstate.is_in(build_states))
12631264
1264 store = getUtility(IStoreSelector).get(MAIN_STORE, DEFAULT_FLAVOR)1265 store = getUtility(IStoreSelector).get(MAIN_STORE, DEFAULT_FLAVOR)
1265 result_set = store.find(1266
1266 (SourcePackagePublishingHistory, Build, DistroArchSeries),1267 # We'll be looking for builds in the same distroseries as the
1268 # SPPH for the same release.
1269 builds_for_distroseries_expr = (
1267 Build.distroarchseriesID == DistroArchSeries.id,1270 Build.distroarchseriesID == DistroArchSeries.id,
1271 SourcePackagePublishingHistory.distroseriesID ==
1272 DistroArchSeries.distroseriesID,
1273 SourcePackagePublishingHistory.sourcepackagereleaseID ==
1274 Build.sourcepackagereleaseID,
1275 In(SourcePackagePublishingHistory.id, source_publication_ids)
1276 )
1277
1278 # First, we'll find the builds that were built in the same
1279 # archive context as the published sources.
1280 builds_in_same_archive = store.find(
1281 Build,
1282 builds_for_distroseries_expr,
1268 SourcePackagePublishingHistory.archiveID == Build.archiveID,1283 SourcePackagePublishingHistory.archiveID == Build.archiveID,
1269 SourcePackagePublishingHistory.distroseriesID ==1284 *extra_exprs)
1270 DistroArchSeries.distroseriesID,1285
1271 SourcePackagePublishingHistory.sourcepackagereleaseID ==1286 # Next get all the builds that have a binary published in the
1272 Build.sourcepackagereleaseID,1287 # same archive... even though the build was not built in
1273 In(SourcePackagePublishingHistory.id, source_publication_ids),1288 # the same context archive.
1274 *extra_exprs)1289 builds_copied_into_archive = store.find(
12751290 Build,
1276 result_set.order_by(1291 builds_for_distroseries_expr,
1292 SourcePackagePublishingHistory.archiveID != Build.archiveID,
1293 BinaryPackagePublishingHistory.archive ==
1294 SourcePackagePublishingHistory.archiveID,
1295 BinaryPackagePublishingHistory.binarypackagerelease ==
1296 BinaryPackageRelease.id,
1297 BinaryPackageRelease.build == Build.id,
1298 *extra_exprs)
1299
1300 builds_union = builds_copied_into_archive.union(
1301 builds_in_same_archive).config(distinct=True)
1302
1303 # Now that we have a result_set of all the builds, we'll use it
1304 # as a subquery to get the required publishing and arch to do
1305 # the ordering. We do this in this round-about way because we
1306 # can't sort on SourcePackagePublishingHistory.id after the
1307 # union. See bug 443353 for details.
1308 find_spec = (
1309 SourcePackagePublishingHistory, Build, DistroArchSeries)
1310
1311 # Storm doesn't let us do builds_union.values('id') -
1312 # ('Union' object has no attribute 'columns'). So instead
1313 # we have to instantiate the objects just to get the id.
1314 build_ids = [build.id for build in builds_union]
1315
1316 result_set = store.find(
1317 find_spec, builds_for_distroseries_expr,
1318 Build.id.is_in(build_ids))
1319
1320 return result_set.order_by(
1277 SourcePackagePublishingHistory.id,1321 SourcePackagePublishingHistory.id,
1278 DistroArchSeries.architecturetag)1322 DistroArchSeries.architecturetag)
12791323
1280 return result_set
1281
1282 def getByIdAndArchive(self, id, archive, source=True):1324 def getByIdAndArchive(self, id, archive, source=True):
1283 """See `IPublishingSet`."""1325 """See `IPublishingSet`."""
1284 if source:1326 if source:
@@ -1317,12 +1359,10 @@
1317 def _getSourceBinaryJoinForSources(self, source_publication_ids,1359 def _getSourceBinaryJoinForSources(self, source_publication_ids,
1318 active_binaries_only=True):1360 active_binaries_only=True):
1319 """Return the join linking sources with binaries."""1361 """Return the join linking sources with binaries."""
1320 # Import Build, BinaryPackageRelease and DistroArchSeries locally1362 # Import Build and DistroArchSeries locally
1321 # to avoid circular imports, since Build uses1363 # to avoid circular imports, since Build uses
1322 # SourcePackagePublishingHistory, BinaryPackageRelease uses Build1364 # SourcePackagePublishingHistory, BinaryPackageRelease uses Build
1323 # and DistroArchSeries uses BinaryPackagePublishingHistory.1365 # and DistroArchSeries uses BinaryPackagePublishingHistory.
1324 from lp.soyuz.model.binarypackagerelease import (
1325 BinaryPackageRelease)
1326 from lp.soyuz.model.build import Build1366 from lp.soyuz.model.build import Build
1327 from lp.soyuz.model.distroarchseries import (1367 from lp.soyuz.model.distroarchseries import (
1328 DistroArchSeries)1368 DistroArchSeries)
@@ -1397,12 +1437,8 @@
13971437
1398 def getBinaryFilesForSources(self, one_or_more_source_publications):1438 def getBinaryFilesForSources(self, one_or_more_source_publications):
1399 """See `IPublishingSet`."""1439 """See `IPublishingSet`."""
1400 # Import Build and BinaryPackageRelease locally to avoid circular1440 # Import Build locally to avoid circular imports, since that
1401 # imports, since that Build already imports1441 # Build already imports SourcePackagePublishingHistory.
1402 # SourcePackagePublishingHistory and BinaryPackageRelease imports
1403 # Build.
1404 from lp.soyuz.model.binarypackagerelease import (
1405 BinaryPackageRelease)
1406 from lp.soyuz.model.build import Build1442 from lp.soyuz.model.build import Build
14071443
1408 source_publication_ids = self._extractIDs(1444 source_publication_ids = self._extractIDs(
14091445
=== modified file 'lib/lp/soyuz/scripts/tests/test_copypackage.py'
--- lib/lp/soyuz/scripts/tests/test_copypackage.py 2009-11-17 21:38:28 +0000
+++ lib/lp/soyuz/scripts/tests/test_copypackage.py 2009-12-07 15:21:15 +0000
@@ -1368,6 +1368,21 @@
1368 target_archive = copy_helper.destination.archive1368 target_archive = copy_helper.destination.archive
1369 self.checkCopies(copied, target_archive, 3)1369 self.checkCopies(copied, target_archive, 3)
13701370
1371 # The second copy will fail explicitly because the new BPPH
1372 # records are not yet published.
1373 nothing_copied = copy_helper.mainTask()
1374 self.assertEqual(len(nothing_copied), 0)
1375 self.assertEqual(
1376 copy_helper.logger.buffer.getvalue().splitlines()[-1],
1377 'ERROR: foo 666 in hoary (same version has unpublished binaries '
1378 'in the destination archive for Hoary, please wait for them to '
1379 'be published before copying)')
1380
1381 # If we ensure that the copied binaries are published, the
1382 # copy won't fail but will simply not copy anything.
1383 for bin_pub in copied[1:3]:
1384 bin_pub.secure_record.setPublished()
1385
1371 nothing_copied = copy_helper.mainTask()1386 nothing_copied = copy_helper.mainTask()
1372 self.assertEqual(len(nothing_copied), 0)1387 self.assertEqual(len(nothing_copied), 0)
1373 self.assertEqual(1388 self.assertEqual(
@@ -1504,7 +1519,7 @@
1504 name='boing')1519 name='boing')
1505 self.assertEqual(copied_source.displayname, 'boing 1.0 in hoary')1520 self.assertEqual(copied_source.displayname, 'boing 1.0 in hoary')
1506 self.assertEqual(len(copied_source.getPublishedBinaries()), 2)1521 self.assertEqual(len(copied_source.getPublishedBinaries()), 2)
1507 self.assertEqual(len(copied_source.getBuilds()), 0)1522 self.assertEqual(len(copied_source.getBuilds()), 1)
15081523
1509 def _setupArchitectureGrowingScenario(self, architecturehintlist="all"):1524 def _setupArchitectureGrowingScenario(self, architecturehintlist="all"):
1510 """Prepare distroseries with different sets of architectures.1525 """Prepare distroseries with different sets of architectures.
15111526
=== modified file 'lib/lp/soyuz/stories/ppa/xx-copy-packages.txt'
--- lib/lp/soyuz/stories/ppa/xx-copy-packages.txt 2009-10-13 10:05:58 +0000
+++ lib/lp/soyuz/stories/ppa/xx-copy-packages.txt 2009-12-07 15:21:15 +0000
@@ -1062,7 +1062,7 @@
1062 >>> print_ppa_packages(jblack_browser.contents)1062 >>> print_ppa_packages(jblack_browser.contents)
1063 Source Published Status Series Section Build1063 Source Published Status Series Section Build
1064 Status1064 Status
1065 foo - 2.0 (changesfile) Pending Hoary Base1065 foo - 2.0 (changesfile) Pending Hoary Base i386
1066 foo - 1.1 (changesfile) Pending Warty Base1066 foo - 1.1 (changesfile) Pending Warty Base
1067 pmount - 0.1-1 Pending Hoary Editors1067 pmount - 0.1-1 Pending Hoary Editors
1068 pmount - 0.1-1 Pending Warty Editors1068 pmount - 0.1-1 Pending Warty Editors
10691069
=== modified file 'lib/lp/soyuz/stories/ppa/xx-ppa-packages.txt'
--- lib/lp/soyuz/stories/ppa/xx-ppa-packages.txt 2009-11-05 10:51:36 +0000
+++ lib/lp/soyuz/stories/ppa/xx-ppa-packages.txt 2009-12-07 15:21:15 +0000
@@ -129,29 +129,51 @@
129If a the binaries for a package are fully built, but have not yet been129If a the binaries for a package are fully built, but have not yet been
130published, this will be indicated to the viewer:130published, this will be indicated to the viewer:
131131
132 >>> anon_browser.open(132 # First, we'll update the binary publishing history for the i386
133 ... "http://launchpad.dev/~cprov/+archive/ppa/+packages")133 # record so that it is pending publication.
134 >>> expander_url = anon_browser.getLink(id='pub28-expander').url134 >>> login('foo.bar@canonical.com')
135 >>> from zope.component import getUtility
136 >>> from lp.registry.interfaces.person import IPersonSet
137 >>> cprov_ppa = getUtility(IPersonSet).getByName('cprov').archive
138 >>> pmount_i386_pub = cprov_ppa.getAllPublishedBinaries(
139 ... name='pmount', version='0.1-1')[1]
140 >>> print pmount_i386_pub.displayname
141 pmount 0.1-1 in warty i386
142 >>> from lp.soyuz.interfaces.publishing import PackagePublishingStatus
143 >>> pmount_i386_pub.secure_record.status = PackagePublishingStatus.PENDING
144 >>> pmount_i386_pub.secure_record.datepublished = None
145 >>> transaction.commit()
146 >>> logout()
147
148 # Now, to re-display the pmount expanded section:
135 >>> anon_browser.open(expander_url)149 >>> anon_browser.open(expander_url)
136 >>> print extract_text(anon_browser.contents)150 >>> print extract_text(anon_browser.contents)
137 Note: Some binary packages for this source are not yet published in the151 Note: Some binary packages for this source are not yet published in the
138 repository.152 repository.
139 Publishing details153 Publishing details
140 Published on 2007-07-09154 Published on 2007-07-09
141 Copied from ubuntu warty in PPA for Mark Shuttleworth155 Copied from ubuntu hoary in Primary Archive for Ubuntu Linux
142 Changelog156 Changelog
157 pmount (0.1-1) hoary; urgency=low
158 * Fix description (Malone #1)
159 * Fix debian (Debian #2000)
160 * Fix warty (Warty Ubuntu #1)
161 -- Sample Person...
143 Builds162 Builds
144 i386 - Pending publication163 i386 - Pending publication
145 Built packages164 Built packages
146 mozilla-firefox ff from iceweasel165 pmount
166 pmount shortdesc
147 Package files167 Package files
148 firefox_0.9.2.orig.tar.gz (9.5 MiB)168 No files published for this package.
149 iceweasel-1.0.dsc (123 bytes)
150 mozilla-firefox_0.9_i386.deb (3 bytes)
151169
152The package was copied from a PPA. The archive title will hence link170When the package is copied from a PPA, the archive title will link
153back to the source PPA.171back to the source PPA.
154172
173 >>> anon_browser.open(
174 ... "http://launchpad.dev/~cprov/+archive/ppa/+packages")
175 >>> expander_url = anon_browser.getLink(id='pub28-expander').url
176 >>> anon_browser.open(expander_url)
155 >>> anon_browser.getLink("PPA for Mark Shuttleworth").url177 >>> anon_browser.getLink("PPA for Mark Shuttleworth").url
156 'http://launchpad.dev/~mark/+archive/ppa'178 'http://launchpad.dev/~mark/+archive/ppa'
157179
@@ -164,7 +186,7 @@
164 >>> admin_browser.getControl(name="field.buildd_secret").value = "secret"186 >>> admin_browser.getControl(name="field.buildd_secret").value = "secret"
165 >>> admin_browser.getControl("Save").click()187 >>> admin_browser.getControl("Save").click()
166188
167 >>> anon_browser.open("http://launchpad.dev/~cprov/+archive/ppa")189 >>> anon_browser.open(expander_url)
168 >>> anon_browser.getLink("PPA for Mark Shuttleworth")190 >>> anon_browser.getLink("PPA for Mark Shuttleworth")
169 Traceback (most recent call last):191 Traceback (most recent call last):
170 ...192 ...
171193
=== modified file 'lib/lp/soyuz/stories/webservice/xx-source-package-publishing.txt'
--- lib/lp/soyuz/stories/webservice/xx-source-package-publishing.txt 2009-11-18 23:56:26 +0000
+++ lib/lp/soyuz/stories/webservice/xx-source-package-publishing.txt 2009-12-07 15:21:15 +0000
@@ -207,18 +207,20 @@
207======================207======================
208208
209The source publication object has a custom operation called 'getBuilds' and209The source publication object has a custom operation called 'getBuilds' and
210it returns the build records in the context of that publication.210it returns the build records for builds that were built in the same context
211archive as the publication, or builds from other archives but where the
212binaries have been copied and published in the same context archive.
211213
212 >>> pubs = webservice.named_get(214 >>> pubs = webservice.named_get(
213 ... cprov_archive['self_link'], 'getPublishedSources',215 ... cprov_archive['self_link'], 'getPublishedSources',
214 ... source_name="iceweasel", version="1.0",216 ... source_name="pmount", version="0.1-1",
215 ... exact_match=True).jsonBody()217 ... exact_match=True).jsonBody()
216 >>> source_pub = pubs['entries'][0]218 >>> source_pub = pubs['entries'][0]
217 >>> builds = webservice.named_get(219 >>> builds = webservice.named_get(
218 ... source_pub['self_link'], 'getBuilds').jsonBody()220 ... source_pub['self_link'], 'getBuilds').jsonBody()
219 >>> for entry in sorted(builds['entries']):221 >>> for entry in sorted(builds['entries']):
220 ... print entry['title']222 ... print entry['title']
221 i386 build of iceweasel 1.0 in ubuntu warty RELEASE223 i386 build of pmount 0.1-1 in ubuntu warty RELEASE
222224
223225
224Finding related Binary publications226Finding related Binary publications
225227
=== modified file 'lib/lp/soyuz/templates/archive-edit-dependencies.pt'
--- lib/lp/soyuz/templates/archive-edit-dependencies.pt 2009-11-12 17:26:17 +0000
+++ lib/lp/soyuz/templates/archive-edit-dependencies.pt 2009-12-07 15:21:15 +0000
@@ -62,7 +62,7 @@
62 </div> <!-- launchpad_form -->62 </div> <!-- launchpad_form -->
6363
64<script type="text/javascript">64<script type="text/javascript">
65 YUI().use("node", function(Y) {65 LPS.use("node", function(Y) {
6666
67 // Highlight (setting bold font-weight) the label for the67 // Highlight (setting bold font-weight) the label for the
68 // selected option in a given NodesList. Assumes the input is68 // selected option in a given NodesList. Assumes the input is
6969
=== modified file 'lib/lp/soyuz/templates/archive-macros.pt'
--- lib/lp/soyuz/templates/archive-macros.pt 2009-11-04 19:59:16 +0000
+++ lib/lp/soyuz/templates/archive-macros.pt 2009-12-07 15:21:15 +0000
@@ -10,7 +10,7 @@
10 </tal:comment>10 </tal:comment>
1111
12<script type="text/javascript">12<script type="text/javascript">
13YUI().use('node', 'io-base', 'lazr.anim', 'soyuz-base', function(Y) {13LPS.use('node', 'io-base', 'lazr.anim', 'soyuz-base', function(Y) {
1414
1515
16/*16/*
1717
=== modified file 'lib/lp/soyuz/templates/archive-packages.pt'
--- lib/lp/soyuz/templates/archive-packages.pt 2009-11-04 13:56:17 +0000
+++ lib/lp/soyuz/templates/archive-packages.pt 2009-12-07 15:21:15 +0000
@@ -23,7 +23,7 @@
23 </tal:devmode>23 </tal:devmode>
24 <script type="text/javascript" id="repository-size-update"24 <script type="text/javascript" id="repository-size-update"
25 tal:condition="view/archive_url">25 tal:condition="view/archive_url">
26YUI().use('io-base', 'lazr.anim', 'node', 'soyuz-base',26LPS.use('io-base', 'lazr.anim', 'node', 'soyuz-base',
27 'soyuz.update_archive_build_statuses', function(Y) {27 'soyuz.update_archive_build_statuses', function(Y) {
2828
2929
3030
=== modified file 'lib/lp/soyuz/templates/archive-subscribers.pt'
--- lib/lp/soyuz/templates/archive-subscribers.pt 2009-09-29 07:21:40 +0000
+++ lib/lp/soyuz/templates/archive-subscribers.pt 2009-12-07 15:21:15 +0000
@@ -98,7 +98,7 @@
98 </form>98 </form>
99 </div><!-- class="portlet" -->99 </div><!-- class="portlet" -->
100 <script type="text/javascript" id="setup-archivesubscribers-index">100 <script type="text/javascript" id="setup-archivesubscribers-index">
101 YUI().use('soyuz.archivesubscribers_index', function(Y) {101 LPS.use('soyuz.archivesubscribers_index', function(Y) {
102 Y.soyuz.setup_archivesubscribers_index();102 Y.soyuz.setup_archivesubscribers_index();
103 });103 });
104 </script>104 </script>
105105
=== modified file 'lib/lp/translations/browser/language.py'
--- lib/lp/translations/browser/language.py 2009-10-31 11:06:44 +0000
+++ lib/lp/translations/browser/language.py 2009-12-07 15:21:15 +0000
@@ -29,6 +29,7 @@
29 enabled_with_permission, GetitemNavigation, LaunchpadEditFormView,29 enabled_with_permission, GetitemNavigation, LaunchpadEditFormView,
30 LaunchpadFormView, LaunchpadView, Link, NavigationMenu)30 LaunchpadFormView, LaunchpadView, Link, NavigationMenu)
31from lp.translations.utilities.pluralforms import make_friendly_plural_forms31from lp.translations.utilities.pluralforms import make_friendly_plural_forms
32from canonical.launchpad.interfaces.launchpad import ILaunchpadCelebrities
3233
33from canonical.widgets import LabeledMultiCheckBoxWidget34from canonical.widgets import LabeledMultiCheckBoxWidget
3435
@@ -202,6 +203,13 @@
202203
203 return pluralforms_list204 return pluralforms_list
204205
206 @property
207 def add_question_url(self):
208 rosetta = getUtility(ILaunchpadCelebrities).lp_translations
209 return canonical_url(
210 rosetta,
211 view_name='+addquestion',
212 rootsite='answers')
205213
206class LanguageAdminView(LaunchpadEditFormView):214class LanguageAdminView(LaunchpadEditFormView):
207 """Handle an admin form submission."""215 """Handle an admin form submission."""
208216
=== modified file 'lib/lp/translations/stories/distroseries/xx-distroseries-templates.txt'
--- lib/lp/translations/stories/distroseries/xx-distroseries-templates.txt 2009-10-30 10:09:17 +0000
+++ lib/lp/translations/stories/distroseries/xx-distroseries-templates.txt 2009-12-07 15:21:15 +0000
@@ -1,11 +1,15 @@
1= Templates view for DistroSeries =1
2
3Templates view for DistroSeries
4===============================
25
3The +templates view for DistroSeries gives an overview of the translation6The +templates view for DistroSeries gives an overview of the translation
4templates in this series and provides easy access to the various subpages of7templates in this series and provides easy access to the various subpages of
5each template.8each template.
69
710
8== Getting there ==11Getting there
12-------------
913
10To get to the listing of all templates, one needs to use the link14To get to the listing of all templates, one needs to use the link
11from the distribution series translations page.15from the distribution series translations page.
@@ -16,7 +20,45 @@
16 >>> print user_browser.url20 >>> print user_browser.url
17 http://translations.launchpad.dev/ubuntu/hoary/+templates21 http://translations.launchpad.dev/ubuntu/hoary/+templates
1822
19== The templates table ==23The templates table
24-------------------
25
26Full template listing for a distribution series is reached by following
27a link from the distribution series translations page.
28
29 >>> anon_browser.open(
30 ... 'http://translations.launchpad.dev/ubuntu/hoary')
31 >>> anon_browser.getLink('full list of templates').click()
32
33Full listing of templates shows source package name, template name and
34the date of last update for this distribution series.
35
36 >>> table = find_tag_by_id(anon_browser.contents, 'templates_table')
37 >>> print extract_text(table)
38 Source package Template name Last update
39 evolution disabled-template 2007-01-05
40 evolution evolution-2.2 2005-05-06
41 evolution man 2006-08-14
42 mozilla pkgconf-mozilla 2005-05-06
43 pmount man 2006-08-14
44 pmount pmount 2005-05-06
45
46
47Logged-in users will see a link from distro series
48 >>> user_browser.open(
49 ... 'http://translations.launchpad.dev/ubuntu/hoary')
50 >>> user_browser.getLink('full list of templates').click()
51
52Logged-in users can also choose to download all translations for each
53of the templates.
54
55 >>> table = find_tag_by_id(user_browser.contents, 'templates_table')
56 >>> print extract_text(table)
57 Source package Template name Last update Actions
58 evolution disabled-template 2007-01-05 Download
59 ...
60 mozilla pkgconf-mozilla 2005-05-06 Download
61 ...
2062
21Administrator can see all editing options.63Administrator can see all editing options.
2264
@@ -28,16 +70,17 @@
2870
29 >>> table = find_tag_by_id(admin_browser.contents, 'templates_table')71 >>> table = find_tag_by_id(admin_browser.contents, 'templates_table')
30 >>> print extract_text(table)72 >>> print extract_text(table)
31 Source package Template name Actions73 Source package Template name Last update Actions
32 evolution disabled-template Edit Upload Download Administer74 evolution disabled-template 2007-01-05 Edit Upload Download Administer
33 evolution evolution-2.2 Edit Upload Download Administer75 evolution evolution-2.2 2005-05-06 Edit Upload Download Administer
34 evolution man Edit Upload Download Administer76 evolution man 2006-08-14 Edit Upload Download Administer
35 mozilla pkgconf-mozilla Edit Upload Download Administer77 mozilla pkgconf-mozilla 2005-05-06 Edit Upload Download Administer
36 pmount man Edit Upload Download Administer78 pmount man 2006-08-14 Edit Upload Download Administer
37 pmount pmount Edit Upload Download Administer79 pmount pmount 2005-05-06 Edit Upload Download Administer
3880
3981
40== Links to the templates ==82Links to the templates
83----------------------
4184
42Clicking on a template name will take the user to that template's overview85Clicking on a template name will take the user to that template's overview
43page.86page.
4487
=== modified file 'lib/lp/translations/stories/productseries/xx-productseries-templates.txt'
--- lib/lp/translations/stories/productseries/xx-productseries-templates.txt 2009-10-30 10:09:17 +0000
+++ lib/lp/translations/stories/productseries/xx-productseries-templates.txt 2009-12-07 15:21:15 +0000
@@ -1,13 +1,18 @@
1= Templates view for ProductSeries =1
2
3Templates view for ProductSeries
4================================
25
3The +templates view for ProductSeries gives an overview of the translation6The +templates view for ProductSeries gives an overview of the translation
4templates in this series and provides easy access to the various subpages of7templates in this series and provides easy access to the various subpages of
5each template.8each template.
69
7== Preparation ==10
811Preparation
9To test the ordering of templates in the listing, we need another template12-----------
10that is new but must appear at the top of the list.13
14To test the ordering of templates in the listing, we need another
15template that is new but must appear at the top of the list.
1116
12 >>> login('foo.bar@canonical.com')17 >>> login('foo.bar@canonical.com')
13 >>> from zope.component import getUtility18 >>> from zope.component import getUtility
@@ -18,7 +23,9 @@
18 ... name='at-the-top')23 ... name='at-the-top')
19 >>> logout()24 >>> logout()
2025
21== Getting there ==26
27Getting there
28-------------
2229
23To get to the listing of all templates, one needs to use the link30To get to the listing of all templates, one needs to use the link
24from the product series translations page.31from the product series translations page.
@@ -30,16 +37,17 @@
30 http://translations.launchpad.dev/evolution/trunk/+templates37 http://translations.launchpad.dev/evolution/trunk/+templates
3138
3239
33== The templates table ==40The templates table
41-------------------
3442
35The page shows a table of all templates and links to their subpages.43The page shows a table of all templates and links to their subpages.
3644
37 >>> table = find_tag_by_id(user_browser.contents, 'templates_table')45 >>> table = find_tag_by_id(user_browser.contents, 'templates_table')
38 >>> print extract_text(table)46 >>> print extract_text(table)
39 Template name Actions47 Template name Last update Actions
40 at-the-top Download48 at-the-top ... Download
41 evolution-2.2 Download49 evolution-2.2 2005-08-25 Download
42 evolution-2.2-test Download50 evolution-2.2-test 2006-12-13 Download
4351
44If an administrator views this page, links to the templates admin page are52If an administrator views this page, links to the templates admin page are
45shown, too.53shown, too.
@@ -48,13 +56,14 @@
48 ... 'http://translations.launchpad.dev/evolution/trunk/+templates')56 ... 'http://translations.launchpad.dev/evolution/trunk/+templates')
49 >>> table = find_tag_by_id(admin_browser.contents, 'templates_table')57 >>> table = find_tag_by_id(admin_browser.contents, 'templates_table')
50 >>> print extract_text(table)58 >>> print extract_text(table)
51 Template name Actions59 Template name Last update Actions
52 at-the-top Edit Upload Download Administer60 at-the-top ... Edit Upload Download Administer
53 evolution-2.2 Edit Upload Download Administer61 evolution-2.2 2005-08-25 Edit Upload Download Administer
54 evolution-2.2-test Edit Upload Download Administer62 evolution-2.2-test 2006-12-13 Edit Upload Download Administer
5563
5664
57== Links to the templates ==65Links to the templates
66----------------------
5867
59Clicking on a template name will take the user to that template's overview68Clicking on a template name will take the user to that template's overview
60page.69page.
6170
=== modified file 'lib/lp/translations/stories/standalone/xx-language.txt'
--- lib/lp/translations/stories/standalone/xx-language.txt 2009-10-31 11:06:44 +0000
+++ lib/lp/translations/stories/standalone/xx-language.txt 2009-12-07 15:21:15 +0000
@@ -1,6 +1,15 @@
1
2
3Languages view
4==============
5
1Here is the tale of languages. We will see how to create, find and edit6Here is the tale of languages. We will see how to create, find and edit
2them.7them.
38
9
10Getting there
11-------------
12
4Launchpad Translations has a main page.13Launchpad Translations has a main page.
514
6 >>> admin_browser.open('http://translations.launchpad.dev/')15 >>> admin_browser.open('http://translations.launchpad.dev/')
@@ -11,7 +20,12 @@
11 >>> print admin_browser.url20 >>> print admin_browser.url
12 http://translations.launchpad.dev/+languages21 http://translations.launchpad.dev/+languages
1322
14Following the link, there is a form to add new languages.23
24Adding new languages
25--------------------
26
27Following the link from the translations main page, there is a form to
28add new languages.
1529
16 >>> admin_browser.getLink('Add new language').click()30 >>> admin_browser.getLink('Add new language').click()
17 >>> print admin_browser.url31 >>> print admin_browser.url
@@ -65,11 +79,16 @@
65 ...79 ...
66 LinkNotFoundError80 LinkNotFoundError
6781
68 >>> user_browser.open('http://translations.launchpad.dev/+languages/+add')82 >>> user_browser.open(
83 ... 'http://translations.launchpad.dev/+languages/+add')
69 Traceback (most recent call last):84 Traceback (most recent call last):
70 ...85 ...
71 Unauthorized:...86 Unauthorized:...
7287
88
89Searching for a language
90------------------------
91
73From the top languages page, anyone can find languages.92From the top languages page, anyone can find languages.
7493
75 >>> browser.open('http://translations.launchpad.dev/+languages')94 >>> browser.open('http://translations.launchpad.dev/+languages')
@@ -82,7 +101,11 @@
82 >>> print browser.url101 >>> print browser.url
83 http://translations.launchpad.dev/+languages/+index?find=Spanish102 http://translations.launchpad.dev/+languages/+index?find=Spanish
84103
85And following one of the found languages, we can see a brief information104
105Read language information
106-------------------------
107
108Following one of the found languages, we can see a brief information
86about the selected language.109about the selected language.
87110
88 >>> browser.getLink('Spanish').click()111 >>> browser.getLink('Spanish').click()
@@ -128,14 +151,50 @@
128 ...Uruguay...151 ...Uruguay...
129 ...Venezuela...152 ...Venezuela...
130153
131 >>> topcontributors_portlet = find_portlet(browser.contents, 'Top contributors')154 >>> topcontributors_portlet = find_portlet(
155 ... browser.contents, 'Top contributors')
132 >>> print topcontributors_portlet156 >>> print topcontributors_portlet
133 <...157 <...
134 ...Carlos Perelló Marín...158 ...Carlos Perelló Marín...
135159
160Our test sample data does not know about plural forms of
161Abkhazian and about countries where this language is spoken.
162
163We will see a note about missing plural forms and a link to Rosetta
164add question page for informing Rosetta admin about the right plural
165form.
166
167 >>> browser.open('http://translations.launchpad.dev/+languages/ab')
168 >>> print extract_text(find_portlet(browser.contents, 'Plural forms'
169 ... ).renderContents())
170 Plural forms
171 Unfortunately, Launchpad doesn't know the plural
172 form information for this language...
173
174 >>> print browser.getLink(id='plural_question').url
175 http://answers.launchpad.dev/rosetta/+addquestion
176
177We will see a note that Launchpad does not know in which countries
178this language is spoken and a link to add question page for informing
179Rosetta admin about the countries where this page is officially spoken.
180
181 >>> countries_portlet = find_portlet(browser.contents, 'Countries')
182 >>> print countries_portlet
183 <...
184 Abkhazian is not registered as being spoken in any
185 country...
186
187 >>> print browser.getLink(id='country_question').url
188 http://answers.launchpad.dev/rosetta/+addquestion
189
190
191Edit language information
192-------------------------
193
136Finally, there is the edit form to change language basic information.194Finally, there is the edit form to change language basic information.
137195
138 >>> user_browser.open('http://translations.launchpad.dev/+languages/es')196 >>> user_browser.open(
197 ... 'http://translations.launchpad.dev/+languages/es')
139 >>> print user_browser.url198 >>> print user_browser.url
140 http://translations.launchpad.dev/+languages/es199 http://translations.launchpad.dev/+languages/es
141200
@@ -146,7 +205,8 @@
146 ...205 ...
147 LinkNotFoundError206 LinkNotFoundError
148207
149 >>> user_browser.open('http://translations.launchpad.dev/+languages/es/+admin')208 >>> user_browser.open(
209 ... 'http://translations.launchpad.dev/+languages/es/+admin')
150 Traceback (most recent call last):210 Traceback (most recent call last):
151 ...211 ...
152 Unauthorized:...212 Unauthorized:...
@@ -155,7 +215,8 @@
155215
156 >>> from canonical.launchpad.testing.pages import strip_label216 >>> from canonical.launchpad.testing.pages import strip_label
157217
158 >>> admin_browser.open('http://translations.launchpad.dev/+languages/es')218 >>> admin_browser.open(
219 ... 'http://translations.launchpad.dev/+languages/es')
159 >>> print admin_browser.url220 >>> print admin_browser.url
160 http://translations.launchpad.dev/+languages/es221 http://translations.launchpad.dev/+languages/es
161222
162223
=== modified file 'lib/lp/translations/templates/language-index.pt'
--- lib/lp/translations/templates/language-index.pt 2009-09-17 14:45:59 +0000
+++ lib/lp/translations/templates/language-index.pt 2009-12-07 15:21:15 +0000
@@ -43,8 +43,10 @@
43 <p class="helpwanted">43 <p class="helpwanted">
44 Unfortunately, Launchpad doesn't know the plural form44 Unfortunately, Launchpad doesn't know the plural form
45 information for this language. If you know it, please open a45 information for this language. If you know it, please open a
46 <a href="/rosetta/+addticket">ticket</a> with that information,46 <a id='plural_question'
47 so we can add it to Launchpad.47 tal:attributes="href view/add_question_url"
48 >question</a>
49 with that information, so we can add it to Launchpad.
48 </p>50 </p>
49 </tal:has_not_pluralforms>51 </tal:has_not_pluralforms>
50 </div>52 </div>
@@ -124,8 +126,11 @@
124 </tal:language>126 </tal:language>
125 is not registered as being spoken in any country. If you know127 is not registered as being spoken in any country. If you know
126 about a country that officially speaks this language, please128 about a country that officially speaks this language, please
127 open a <a href="/rosetta/+addticket">ticket</a> with that129 open a
128 information, so we can add it to Launchpad.130 <a id='country_question'
131 tal:attributes="href view/add_question_url"
132 >question</a>
133 with that information, so we can add it to Launchpad.
129 </p>134 </p>
130 </tal:has_not_countries>135 </tal:has_not_countries>
131 </div>136 </div>
132137
=== modified file 'lib/lp/translations/templates/object-templates.pt'
--- lib/lp/translations/templates/object-templates.pt 2009-11-24 19:23:52 +0000
+++ lib/lp/translations/templates/object-templates.pt 2009-12-07 15:21:15 +0000
@@ -26,16 +26,16 @@
26 </style>26 </style>
27 <style tal:condition="view/is_distroseries" type="text/css">27 <style tal:condition="view/is_distroseries" type="text/css">
28 #templates_table {28 #templates_table {
29 width: 72em;29 width: 79em;
30 }30 }
31 </style>31 </style>
32 <style tal:condition="not:view/is_distroseries" type="text/css">32 <style tal:condition="not:view/is_distroseries" type="text/css">
33 #templates_table {33 #templates_table {
34 width: 50em;34 width: 58em;
35 }35 }
36 </style>36 </style>
37 <script language="JavaScript" type="text/javascript">37 <script language="JavaScript" type="text/javascript">
38 YUI().use('node-base', 'event-delegate', function(Y) {38 LPS.use('node-base', 'event-delegate', function(Y) {
39 Y.on('domready', function(e) {39 Y.on('domready', function(e) {
40 Y.all('#templates_table .template_links').addClass(40 Y.all('#templates_table .template_links').addClass(
41 'inactive_links');41 'inactive_links');
@@ -75,6 +75,7 @@
75 <th tal:condition="view/is_distroseries"75 <th tal:condition="view/is_distroseries"
76 class="sourcepackage_column">Source package</th>76 class="sourcepackage_column">Source package</th>
77 <th class="template_column">Template name</th>77 <th class="template_column">Template name</th>
78 <th class="lastupdate_column">Last update</th>
78 <th class="actions_column"79 <th class="actions_column"
79 tal:condition="context/required:launchpad.AnyPerson">80 tal:condition="context/required:launchpad.AnyPerson">
80 Actions</th>81 Actions</th>
@@ -88,6 +89,22 @@
88 </td>89 </td>
89 <td class="template_column"><a tal:attributes="href template/fmt:url"90 <td class="template_column"><a tal:attributes="href template/fmt:url"
90 tal:content="template/name">Template name</a></td>91 tal:content="template/name">Template name</a></td>
92 <td class="lastupdate_column">
93 <span class="sortkey"
94 tal:condition="template/date_last_updated"
95 tal:content="template/date_last_updated/fmt:datetime">
96 time sort key
97 </span>
98 <span class="lastupdate_column"
99 tal:condition="template/date_last_updated"
100 tal:attributes="
101 title template/date_last_updated/fmt:datetime"
102 tal:content="
103 template/date_last_updated/fmt:approximatedate"
104 >
105 2009-09-23
106 </span>
107 </td>
91 <td class="actions_column"108 <td class="actions_column"
92 tal:condition="context/required:launchpad.AnyPerson">109 tal:condition="context/required:launchpad.AnyPerson">
93 <div class="template_links">110 <div class="template_links">
94111
=== modified file 'lib/lp/translations/templates/pofile-export.pt'
--- lib/lp/translations/templates/pofile-export.pt 2009-11-10 21:04:19 +0000
+++ lib/lp/translations/templates/pofile-export.pt 2009-12-07 15:21:15 +0000
@@ -13,7 +13,7 @@
13 }13 }
14 </style>14 </style>
15 <script type="text/javascript">15 <script type="text/javascript">
16 YUI().use('node', 'event', function(Y){16 LPS.use('node', 'event', function(Y){
17 Y.on('domready', function(){17 Y.on('domready', function(){
18 // The pochanged option is only available for the PO format.18 // The pochanged option is only available for the PO format.
19 var formatlist = Y.one('#div_format select');19 var formatlist = Y.one('#div_format select');
2020
=== modified file 'lib/lp/translations/templates/pofile-translate.pt'
--- lib/lp/translations/templates/pofile-translate.pt 2009-11-04 19:59:16 +0000
+++ lib/lp/translations/templates/pofile-translate.pt 2009-12-07 15:21:15 +0000
@@ -20,7 +20,7 @@
20 <script type="text/javascript">20 <script type="text/javascript">
21 registerLaunchpadFunction(insertAllExpansionButtons);21 registerLaunchpadFunction(insertAllExpansionButtons);
2222
23 YUI().use('node', 'cookie', 'anim', 'lp.pofile', function(Y) {23 LPS.use('node', 'cookie', 'anim', 'lp.pofile', function(Y) {
2424
25 var hide_notification = function(node) {25 var hide_notification = function(node) {
26 var hide_anim = new Y.Anim({26 var hide_anim = new Y.Anim({
2727
=== modified file 'lib/lp/translations/templates/translation-import-queue-macros.pt'
--- lib/lp/translations/templates/translation-import-queue-macros.pt 2009-11-20 14:15:34 +0000
+++ lib/lp/translations/templates/translation-import-queue-macros.pt 2009-12-07 15:21:15 +0000
@@ -18,7 +18,7 @@
18 </script>18 </script>
1919
20 <script type="text/javascript">20 <script type="text/javascript">
21 YUI().use( 'translations', 'event', function(Y) {21 LPS.use( 'translations', 'event', function(Y) {
22 Y.on('domready', function(e) {22 Y.on('domready', function(e) {
23 Y.translations.initialize_import_queue_page(Y);23 Y.translations.initialize_import_queue_page(Y);
24 });24 });
2525
=== modified file 'lib/lp/translations/templates/translationimportqueueentry-index.pt'
--- lib/lp/translations/templates/translationimportqueueentry-index.pt 2009-11-04 13:56:17 +0000
+++ lib/lp/translations/templates/translationimportqueueentry-index.pt 2009-12-07 15:21:15 +0000
@@ -14,7 +14,7 @@
14 }14 }
15 </style>15 </style>
16 <script type="text/javascript">16 <script type="text/javascript">
17 YUI().use('node', 'lazr.anim', function(Y) {17 LPS.use('node', 'lazr.anim', function(Y) {
18 var fields = {'POT':18 var fields = {'POT':
19 ['field.name', 'field.translation_domain',19 ['field.name', 'field.translation_domain',
20 'field.languagepack'],20 'field.languagepack'],
2121
=== modified file 'lib/lp/translations/templates/translationmessage-translate.pt'
--- lib/lp/translations/templates/translationmessage-translate.pt 2009-09-17 07:28:30 +0000
+++ lib/lp/translations/templates/translationmessage-translate.pt 2009-12-07 15:21:15 +0000
@@ -18,7 +18,7 @@
18 tal:define="lp_js string:${icingroot}/build"18 tal:define="lp_js string:${icingroot}/build"
19 tal:attributes="src string:${lp_js}/translations/pofile.js"></script>19 tal:attributes="src string:${lp_js}/translations/pofile.js"></script>
20 <script type="text/javascript">20 <script type="text/javascript">
21 YUI().use('node', 'lp.pofile', function(Y) {21 LPS.use('node', 'lp.pofile', function(Y) {
22 Y.on('domready', Y.lp.pofile.setupSuggestionDismissal);22 Y.on('domready', Y.lp.pofile.setupSuggestionDismissal);
23 });23 });
24 </script>24 </script>

Subscribers

People subscribed via source and target branches

to status/vote changes: