Merge lp:~wgrant/launchpad/gina-3.0-support into lp:launchpad/db-devel
- gina-3.0-support
- Merge into db-devel
Status: | Merged |
---|---|
Approved by: | Julian Edwards |
Approved revision: | no longer in the source branch. |
Merged at revision: | not available |
Proposed branch: | lp:~wgrant/launchpad/gina-3.0-support |
Merge into: | lp:launchpad/db-devel |
Prerequisite: | lp:~wgrant/launchpad/distroseries-source-format-selection |
Diff against target: |
1838 lines (+1124/-159) 25 files modified
lib/canonical/launchpad/fields/__init__.py (+61/-1) lib/canonical/launchpad/helpers.py (+1/-64) lib/canonical/launchpad/javascript/bugs/filebug-dupefinder.js (+257/-0) lib/lp/archiveuploader/tests/test_utils.py (+18/-0) lib/lp/archiveuploader/utils.py (+14/-0) lib/lp/bugs/browser/bugtarget.py (+28/-0) lib/lp/bugs/browser/tests/bugtarget-filebug-views.txt (+22/-0) lib/lp/bugs/stories/bugattachments/20-edit-bug-attachment.txt (+38/-0) lib/lp/bugs/templates/bug-portlet-attachments.pt (+49/-0) lib/lp/bugs/templates/bugtarget-filebug-search.pt (+45/-0) lib/lp/bugs/templates/bugtasks-and-nominations-table.pt (+47/-0) lib/lp/code/browser/branch.py (+8/-2) lib/lp/code/templates/branchmergeproposal-index.pt (+25/-0) lib/lp/registry/browser/distroseries.py (+56/-24) lib/lp/registry/browser/tests/packaging-views.txt (+58/-0) lib/lp/registry/interfaces/person.py (+6/-0) lib/lp/registry/stories/distroseries/xx-show-distroseries-packaging.txt (+98/-48) lib/lp/registry/tests/test_productseries_vocabularies.py (+75/-0) lib/lp/soyuz/doc/gina.txt (+11/-11) lib/lp/soyuz/scripts/gina/handlers.py (+44/-7) lib/lp/soyuz/scripts/tests/gina_test_archive/dists/breezy/main/source/Sources (+17/-0) lib/lp/soyuz/scripts/tests/gina_test_archive/pool/main/b/bar/bar_1.0-1.dsc (+22/-0) lib/lp/soyuz/scripts/tests/test_gina.py (+15/-0) lib/lp/translations/stories/distroseries/xx-distroseries-templates.txt (+65/-2) lib/lp/translations/templates/object-templates.pt (+44/-0) |
To merge this branch: | bzr merge lp:~wgrant/launchpad/gina-3.0-support |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Данило Шеган (community) | release-critical | Approve | |
Julian Edwards (community) | Approve | ||
Review via email: mp+15478@code.launchpad.net |
Commit message
Description of the change
William Grant (wgrant) wrote : | # |
Julian Edwards (julian-edwards) wrote : | # |
review approve
merge approve
> gina needs to support 3.0 (quilt) and 3.0 (native) sources. To do this, it
> just needs to identify files as the correct types. Since archiveuploader
> already has a function to do this, I've altered gina to use that rather
> than the duplicated canonical.
> the final callsite of getFileType, I've removed that.
>
> Since determine_
> determine_
> determine_
> sure.
I think it should go there to be consistent.
>
> For testing, I've added a 3.0 (quilt) source to the test archive.
>
Great, thanks for making this change William! It looks good to me so I
approved it. There's just a couple of minor comments inline.
[snip]
>=== modified file 'lib/lp/
>--- lib/lp/
>+++ lib/lp/
>@@ -29,6 +29,7 @@
>
> from lp.archivepubli
> from lp.archiveuploa
>+from lp.archiveuploa
>
> from canonical.
>
>@@ -46,10 +47,22 @@
>
> from lp.registry.
> PersonCreationR
> SourcePackageType +from lp.soyuz.
> BinaryPackageFi
> IBinaryPackageN
> from lp.soyuz.
>-from canonical.
>+from canonical.
I think Gina is the only thing using getBinaryPackag
worth de-cluttering helpers.py and moving it to the gina module.
>+
>+
>+def determine_
>+ """Determine the BinaryPackageFi
>+
>+ if filename.
>+ return BinaryPackageFi
>+ elif filename.
>+ return BinaryPackageFi
This should be UDEB I think?
Everything else looks good! Remind me to land this and the other branch when
PQM opens.
Cheers
J
William Grant (wgrant) wrote : | # |
Hi Julian,
Thanks for the review.
On Tue, 2009-12-01 at 16:33 +0000, Julian Edwards wrote:
> Review: Approve
> review approve
> merge approve
>
> > gina needs to support 3.0 (quilt) and 3.0 (native) sources. To do this, it
> > just needs to identify files as the correct types. Since archiveuploader
> > already has a function to do this, I've altered gina to use that rather
> > than the duplicated canonical.
> > the final callsite of getFileType, I've removed that.
> >
> > Since determine_
> > determine_
> > determine_
> > sure.
>
> I think it should go there to be consistent.
Moved.
> >
> > For testing, I've added a 3.0 (quilt) source to the test archive.
> >
>
> Great, thanks for making this change William! It looks good to me so I
> approved it. There's just a couple of minor comments inline.
>
> [snip]
>
> >=== modified file 'lib/lp/
> >--- lib/lp/
> >+++ lib/lp/
> >@@ -29,6 +29,7 @@
> >
> > from lp.archivepubli
> > from lp.archiveuploa
> >+from lp.archiveuploa
> >
> > from canonical.
> >
> >@@ -46,10 +47,22 @@
> >
> > from lp.registry.
> > PersonCreationR
> > SourcePackageType +from lp.soyuz.
> > BinaryPackageFi
> > IBinaryPackageN
> > from lp.soyuz.
> >-from canonical.
> >+from canonical.
>
> I think Gina is the only thing using getBinaryPackag
> worth de-cluttering helpers.py and moving it to the gina module.
Done. I also removed getBinaryPackag
callsites.
> >+
> >+
> >+def determine_
> >+ """Determine the BinaryPackageFi
> >+
> >+ if filename.
> >+ return BinaryPackageFi
> >+ elif filename.
> >+ return BinaryPackageFi
>
> This should be UDEB I think?
Oops, yes. I've added a test for determine_
> Everything else looks good! Remind me to land this and the other branch when
> PQM opens.
Both are still blocked on an updated buildbot AMI, but that should
appear on Monday.
The diff on LP is now insanely huge (it looks like it might not have
taken into account the prerequisite branch), but the correct
intermediate diff is attached.
1 | === modified file 'lib/canonical/launchpad/helpers.py' |
2 | --- lib/canonical/launchpad/helpers.py 2009-11-25 10:26:03 +0000 |
3 | +++ lib/canonical/launchpad/helpers.py 2009-12-10 12:14:13 +0000 |
4 | @@ -26,8 +26,7 @@ |
5 | |
6 | import canonical |
7 | from canonical.launchpad.interfaces import ( |
8 | - BinaryPackageFormat, ILaunchBag, IRequestPreferredLanguages, |
9 | - IRequestLocalLanguages) |
10 | + ILaunchBag, IRequestPreferredLanguages, IRequestLocalLanguages) |
11 | |
12 | |
13 | # pylint: disable-msg=W0102 |
14 | @@ -466,52 +465,6 @@ |
15 | long(sha.new(message_id).hexdigest(), 16), 62)) |
16 | |
17 | |
18 | -BINARYPACKAGE_EXTENSIONS = { |
19 | - BinaryPackageFormat.DEB: '.deb', |
20 | - BinaryPackageFormat.UDEB: '.udeb', |
21 | - BinaryPackageFormat.RPM: '.rpm'} |
22 | - |
23 | - |
24 | -class UnrecognizedBinaryFormat(Exception): |
25 | - |
26 | - def __init__(self, fname, *args): |
27 | - Exception.__init__(self, *args) |
28 | - self.fname = fname |
29 | - |
30 | - def __str__(self): |
31 | - return '%s is not recognized as a binary file.' % self.fname |
32 | - |
33 | - |
34 | -def getBinaryPackageFormat(fname): |
35 | - """Return the BinaryPackageFormat for the given filename. |
36 | - |
37 | - >>> getBinaryPackageFormat('mozilla-firefox_0.9_i386.deb').name |
38 | - 'DEB' |
39 | - >>> getBinaryPackageFormat('debian-installer.9_all.udeb').name |
40 | - 'UDEB' |
41 | - >>> getBinaryPackageFormat('network-manager.9_i386.rpm').name |
42 | - 'RPM' |
43 | - """ |
44 | - for key, value in BINARYPACKAGE_EXTENSIONS.items(): |
45 | - if fname.endswith(value): |
46 | - return key |
47 | - |
48 | - raise UnrecognizedBinaryFormat(fname) |
49 | - |
50 | - |
51 | -def getBinaryPackageExtension(format): |
52 | - """Return the file extension for the given BinaryPackageFormat. |
53 | - |
54 | - >>> getBinaryPackageExtension(BinaryPackageFormat.DEB) |
55 | - '.deb' |
56 | - >>> getBinaryPackageExtension(BinaryPackageFormat.UDEB) |
57 | - '.udeb' |
58 | - >>> getBinaryPackageExtension(BinaryPackageFormat.RPM) |
59 | - '.rpm' |
60 | - """ |
61 | - return BINARYPACKAGE_EXTENSIONS[format] |
62 | - |
63 | - |
64 | def intOrZero(value): |
65 | """Return int(value) or 0 if the conversion fails. |
66 | |
67 | |
68 | === modified file 'lib/lp/archiveuploader/tests/test_utils.py' |
69 | --- lib/lp/archiveuploader/tests/test_utils.py 2009-11-18 02:58:23 +0000 |
70 | +++ lib/lp/archiveuploader/tests/test_utils.py 2009-12-10 13:32:27 +0000 |
71 | @@ -10,6 +10,7 @@ |
72 | import shutil |
73 | |
74 | from lp.registry.interfaces.sourcepackage import SourcePackageFileType |
75 | +from lp.soyuz.interfaces.binarypackagerelease import BinaryPackageFileType |
76 | from lp.archiveuploader.tests import datadir |
77 | |
78 | |
79 | @@ -72,6 +73,23 @@ |
80 | self.assertEquals(None, determine_source_file_type('foo_1.0')) |
81 | self.assertEquals(None, determine_source_file_type('foo_1.0.blah.gz')) |
82 | |
83 | + def test_determine_binary_file_type(self): |
84 | + """lp.archiveuploader.utils.determine_binary_file_type should work.""" |
85 | + from lp.archiveuploader.utils import determine_binary_file_type |
86 | + |
87 | + # .deb -> DEB |
88 | + self.assertEquals( |
89 | + determine_binary_file_type('foo_1.0-1_all.deb'), |
90 | + BinaryPackageFileType.DEB) |
91 | + |
92 | + # .udeb -> UDEB |
93 | + self.assertEquals( |
94 | + determine_binary_file_type('foo_1.0-1_all.udeb'), |
95 | + BinaryPackageFileType.UDEB) |
96 | + |
97 | + self.assertEquals(determine_binary_file_type('foo_1.0'), None) |
98 | + self.assertEquals(determine_binary_file_type('foo_1.0.notdeb'), None) |
99 | + |
100 | def testPrefixMultilineString(self): |
101 | """lp.archiveuploader.utils.prefix_multi_line_string should work""" |
102 | from lp.archiveuploader.utils import prefix_multi_line_string |
103 | |
104 | === modified file 'lib/lp/archiveuploader/utils.py' |
105 | --- lib/lp/archiveuploader/utils.py 2009-11-14 02:59:34 +0000 |
106 | +++ lib/lp/archiveuploader/utils.py 2009-12-10 13:34:56 +0000 |
107 | @@ -17,6 +17,7 @@ |
108 | 're_changes_file_name', |
109 | 're_extract_src_version', |
110 | 'get_source_file_extension', |
111 | + 'determine_binary_file_type', |
112 | 'determine_source_file_type', |
113 | 'prefix_multi_line_string', |
114 | 'safe_fix_maintainer', |
115 | @@ -88,6 +89,19 @@ |
116 | return None |
117 | |
118 | |
119 | +def determine_binary_file_type(filename): |
120 | + """Determine the BinaryPackageFileType of the given filename.""" |
121 | + # Avoid circular imports. |
122 | + from lp.soyuz.interfaces.binarypackagerelease import BinaryPackageFileType |
123 | + |
124 | + if filename.endswith(".deb"): |
125 | + return BinaryPackageFileType.DEB |
126 | + elif filename.endswith(".udeb"): |
127 | + return BinaryPackageFileType.UDEB |
128 | + else: |
129 | + return None |
130 | + |
131 | + |
132 | def prefix_multi_line_string(str, prefix, include_blank_lines=0): |
133 | """Utility function to split an input string and prefix, |
134 | |
135 | |
136 | === modified file 'lib/lp/soyuz/scripts/gina/handlers.py' |
137 | --- lib/lp/soyuz/scripts/gina/handlers.py 2009-11-25 10:26:03 +0000 |
138 | +++ lib/lp/soyuz/scripts/gina/handlers.py 2009-12-10 12:15:49 +0000 |
139 | @@ -29,7 +29,8 @@ |
140 | |
141 | from lp.archivepublisher.diskpool import poolify |
142 | from lp.archiveuploader.tagfiles import parse_tagfile |
143 | -from lp.archiveuploader.utils import determine_source_file_type |
144 | +from lp.archiveuploader.utils import (determine_binary_file_type, |
145 | + determine_source_file_type) |
146 | |
147 | from canonical.database.sqlbase import sqlvalues |
148 | |
149 | @@ -47,22 +48,10 @@ |
150 | |
151 | from lp.registry.interfaces.person import IPersonSet, PersonCreationRationale |
152 | from lp.registry.interfaces.sourcepackage import SourcePackageType |
153 | -from lp.soyuz.interfaces.binarypackagerelease import BinaryPackageFileType |
154 | from lp.soyuz.interfaces.binarypackagename import IBinaryPackageNameSet |
155 | +from lp.soyuz.interfaces.binarypackagerelease import BinaryPackageFormat |
156 | from lp.soyuz.interfaces.build import BuildStatus |
157 | from lp.soyuz.interfaces.publishing import PackagePublishingStatus |
158 | -from canonical.launchpad.helpers import getBinaryPackageFormat |
159 | - |
160 | - |
161 | -def determine_binary_file_type(filename): |
162 | - """Determine the BinaryPackageFileType of the given filename.""" |
163 | - |
164 | - if filename.endswith(".deb"): |
165 | - return BinaryPackageFileType.DEB |
166 | - elif filename.endswith(".udeb"): |
167 | - return BinaryPackageFileType.DEB |
168 | - else: |
169 | - return None |
170 | |
171 | |
172 | def check_not_in_librarian(files, archive_root, directory): |
173 | @@ -91,6 +80,39 @@ |
174 | return to_upload |
175 | |
176 | |
177 | +BINARYPACKAGE_EXTENSIONS = { |
178 | + BinaryPackageFormat.DEB: '.deb', |
179 | + BinaryPackageFormat.UDEB: '.udeb', |
180 | + BinaryPackageFormat.RPM: '.rpm'} |
181 | + |
182 | + |
183 | +class UnrecognizedBinaryFormat(Exception): |
184 | + |
185 | + def __init__(self, fname, *args): |
186 | + Exception.__init__(self, *args) |
187 | + self.fname = fname |
188 | + |
189 | + def __str__(self): |
190 | + return '%s is not recognized as a binary file.' % self.fname |
191 | + |
192 | + |
193 | +def getBinaryPackageFormat(fname): |
194 | + """Return the BinaryPackageFormat for the given filename. |
195 | + |
196 | + >>> getBinaryPackageFormat('mozilla-firefox_0.9_i386.deb').name |
197 | + 'DEB' |
198 | + >>> getBinaryPackageFormat('debian-installer.9_all.udeb').name |
199 | + 'UDEB' |
200 | + >>> getBinaryPackageFormat('network-manager.9_i386.rpm').name |
201 | + 'RPM' |
202 | + """ |
203 | + for key, value in BINARYPACKAGE_EXTENSIONS.items(): |
204 | + if fname.endswith(value): |
205 | + return key |
206 | + |
207 | + raise UnrecognizedBinaryFormat(fname) |
208 | + |
209 | + |
210 | class DataSetupError(Exception): |
211 | """Raised when required data is found to be missing in the database""" |
212 | |
213 | |
214 | === added file 'lib/lp/soyuz/scripts/tests/test_gina.py' |
215 | --- lib/lp/soyuz/scripts/tests/test_gina.py 1970-01-01 00:00:00 +0000 |
216 | +++ lib/lp/soyuz/scripts/tests/test_gina.py 2009-12-10 12:19:14 +0000 |
217 | @@ -0,0 +1,15 @@ |
218 | +# Copyright 2009 Canonical Ltd. This software is licensed under the |
219 | +# GNU Affero General Public License version 3 (see the file LICENSE). |
220 | + |
221 | +import unittest |
222 | + |
223 | +from zope.testing.doctest import DocTestSuite |
224 | + |
225 | +import lp.soyuz.scripts.gina.handlers |
226 | + |
227 | + |
228 | +def test_suite(): |
229 | + suite = unittest.TestSuite() |
230 | + suite.addTest(DocTestSuite(lp.soyuz.scripts.gina.handlers)) |
231 | + return suite |
232 | + |
Данило Шеган (danilo) wrote : | # |
Provided dogfood testing proves OK, looks good. Though, I'd prefer refactoring to be left for when we are outside RC mode.
Preview Diff
1 | === modified file 'lib/canonical/launchpad/fields/__init__.py' |
2 | --- lib/canonical/launchpad/fields/__init__.py 2009-12-09 23:11:31 +0000 |
3 | +++ lib/canonical/launchpad/fields/__init__.py 2009-12-14 08:43:38 +0000 |
4 | @@ -760,6 +760,14 @@ |
5 | """Return True if the person is public.""" |
6 | from canonical.launchpad.interfaces import IPerson, PersonVisibility |
7 | if not IPerson.providedBy(person): |
8 | +<<<<<<< TREE |
9 | +======= |
10 | + return False |
11 | + if person.visibility == PersonVisibility.PUBLIC: |
12 | + return True |
13 | + else: |
14 | + # PRIVATE_MEMBERSHIP or PRIVATE. |
15 | +>>>>>>> MERGE-SOURCE |
16 | return False |
17 | return person.visibility == PersonVisibility.PUBLIC |
18 | |
19 | @@ -768,7 +776,17 @@ |
20 | """True if the person/team has private membership visibility.""" |
21 | from canonical.launchpad.interfaces import IPerson, PersonVisibility |
22 | if not IPerson.providedBy(person): |
23 | - return False |
24 | +<<<<<<< TREE |
25 | +======= |
26 | + return False |
27 | + if person.visibility == PersonVisibility.PRIVATE_MEMBERSHIP: |
28 | + # PRIVATE_MEMBERSHIP. |
29 | + return True |
30 | + else: |
31 | + # PUBLIC or PRIVATE. |
32 | +>>>>>>> MERGE-SOURCE |
33 | + return False |
34 | +<<<<<<< TREE |
35 | return person.visibility == PersonVisibility.PRIVATE_MEMBERSHIP |
36 | |
37 | |
38 | @@ -791,9 +809,33 @@ |
39 | |
40 | |
41 | class PublicPersonChoice(PersonChoice): |
42 | +======= |
43 | + |
44 | + |
45 | +class PrivateTeamNotAllowed(ConstraintNotSatisfied): |
46 | + __doc__ = _("A private team is not allowed.") |
47 | + |
48 | + |
49 | +class PrivateMembershipTeamNotAllowed(ConstraintNotSatisfied): |
50 | + __doc__ = _("A private-membership team is not allowed.") |
51 | + |
52 | + |
53 | +class PersonChoice(Choice): |
54 | + """A person or team. |
55 | + |
56 | + This is useful as a superclass and provides a clearer error message than |
57 | + "Constraint not satisfied". |
58 | + """ |
59 | + implements(IReferenceChoice) |
60 | + schema = IObject # Will be set to IPerson once IPerson is defined. |
61 | + |
62 | + |
63 | +class PublicPersonChoice(PersonChoice): |
64 | +>>>>>>> MERGE-SOURCE |
65 | """A person or team who is public.""" |
66 | |
67 | def constraint(self, value): |
68 | +<<<<<<< TREE |
69 | if is_public_person(value): |
70 | return True |
71 | else: |
72 | @@ -802,6 +844,16 @@ |
73 | |
74 | |
75 | class ParticipatingPersonChoice(PersonChoice): |
76 | +======= |
77 | + if is_valid_public_person(value): |
78 | + return True |
79 | + else: |
80 | + # The vocabulary prevents the revealing of private team names. |
81 | + raise PrivateTeamNotAllowed(value) |
82 | + |
83 | + |
84 | +class ParticipatingPersonChoice(PersonChoice): |
85 | +>>>>>>> MERGE-SOURCE |
86 | """A person or team who is not a private membership team. |
87 | |
88 | A person can participate in all contexts. A PRIVATE team can participate |
89 | @@ -811,8 +863,16 @@ |
90 | """ |
91 | |
92 | def constraint(self, value): |
93 | +<<<<<<< TREE |
94 | if not is_private_membership_person(value): |
95 | return True |
96 | else: |
97 | # The vocabulary prevents the revealing of private team names. |
98 | raise PrivateMembershipTeamNotAllowed(value) |
99 | +======= |
100 | + if not is_private_membership(value): |
101 | + return True |
102 | + else: |
103 | + # The vocabulary prevents the revealing of private team names. |
104 | + raise PrivateMembershipTeamNotAllowed(value) |
105 | +>>>>>>> MERGE-SOURCE |
106 | |
107 | === modified file 'lib/canonical/launchpad/helpers.py' |
108 | --- lib/canonical/launchpad/helpers.py 2009-11-14 02:55:15 +0000 |
109 | +++ lib/canonical/launchpad/helpers.py 2009-12-14 08:43:38 +0000 |
110 | @@ -26,9 +26,7 @@ |
111 | |
112 | import canonical |
113 | from canonical.launchpad.interfaces import ( |
114 | - BinaryPackageFormat, BinaryPackageFileType, ILaunchBag, |
115 | - IRequestPreferredLanguages, IRequestLocalLanguages, |
116 | - SourcePackageFileType) |
117 | + ILaunchBag, IRequestPreferredLanguages, IRequestLocalLanguages) |
118 | |
119 | |
120 | # pylint: disable-msg=W0102 |
121 | @@ -467,67 +465,6 @@ |
122 | long(sha.new(message_id).hexdigest(), 16), 62)) |
123 | |
124 | |
125 | -def getFileType(fname): |
126 | - if fname.endswith(".deb"): |
127 | - return BinaryPackageFileType.DEB |
128 | - if fname.endswith(".udeb"): |
129 | - return BinaryPackageFileType.DEB |
130 | - if fname.endswith(".dsc"): |
131 | - return SourcePackageFileType.DSC |
132 | - if fname.endswith(".diff.gz"): |
133 | - return SourcePackageFileType.DIFF |
134 | - if fname.endswith(".orig.tar.gz"): |
135 | - return SourcePackageFileType.ORIG_TARBALL |
136 | - if fname.endswith(".tar.gz"): |
137 | - return SourcePackageFileType.NATIVE_TARBALL |
138 | - |
139 | - |
140 | -BINARYPACKAGE_EXTENSIONS = { |
141 | - BinaryPackageFormat.DEB: '.deb', |
142 | - BinaryPackageFormat.UDEB: '.udeb', |
143 | - BinaryPackageFormat.RPM: '.rpm'} |
144 | - |
145 | - |
146 | -class UnrecognizedBinaryFormat(Exception): |
147 | - |
148 | - def __init__(self, fname, *args): |
149 | - Exception.__init__(self, *args) |
150 | - self.fname = fname |
151 | - |
152 | - def __str__(self): |
153 | - return '%s is not recognized as a binary file.' % self.fname |
154 | - |
155 | - |
156 | -def getBinaryPackageFormat(fname): |
157 | - """Return the BinaryPackageFormat for the given filename. |
158 | - |
159 | - >>> getBinaryPackageFormat('mozilla-firefox_0.9_i386.deb').name |
160 | - 'DEB' |
161 | - >>> getBinaryPackageFormat('debian-installer.9_all.udeb').name |
162 | - 'UDEB' |
163 | - >>> getBinaryPackageFormat('network-manager.9_i386.rpm').name |
164 | - 'RPM' |
165 | - """ |
166 | - for key, value in BINARYPACKAGE_EXTENSIONS.items(): |
167 | - if fname.endswith(value): |
168 | - return key |
169 | - |
170 | - raise UnrecognizedBinaryFormat(fname) |
171 | - |
172 | - |
173 | -def getBinaryPackageExtension(format): |
174 | - """Return the file extension for the given BinaryPackageFormat. |
175 | - |
176 | - >>> getBinaryPackageExtension(BinaryPackageFormat.DEB) |
177 | - '.deb' |
178 | - >>> getBinaryPackageExtension(BinaryPackageFormat.UDEB) |
179 | - '.udeb' |
180 | - >>> getBinaryPackageExtension(BinaryPackageFormat.RPM) |
181 | - '.rpm' |
182 | - """ |
183 | - return BINARYPACKAGE_EXTENSIONS[format] |
184 | - |
185 | - |
186 | def intOrZero(value): |
187 | """Return int(value) or 0 if the conversion fails. |
188 | |
189 | |
190 | === modified file 'lib/canonical/launchpad/javascript/bugs/filebug-dupefinder.js' |
191 | --- lib/canonical/launchpad/javascript/bugs/filebug-dupefinder.js 2009-12-11 11:09:35 +0000 |
192 | +++ lib/canonical/launchpad/javascript/bugs/filebug-dupefinder.js 2009-12-14 08:43:37 +0000 |
193 | @@ -25,6 +25,7 @@ |
194 | * The NodeList of possible duplicates. |
195 | */ |
196 | var bug_already_reported_expanders; |
197 | +<<<<<<< TREE |
198 | /* |
199 | * The search field on the +filebug form |
200 | */ |
201 | @@ -45,6 +46,16 @@ |
202 | * The URL of the inline +filebug form. |
203 | */ |
204 | var filebug_form_url; |
205 | +======= |
206 | +/* |
207 | + * The search field on the +filebug form |
208 | + */ |
209 | +var search_field; |
210 | +/* |
211 | + * The search button on the +filebug form |
212 | + */ |
213 | +var search_button; |
214 | +>>>>>>> MERGE-SOURCE |
215 | /* |
216 | * The boilerplate elements for the do-you-want-to-subscribe |
217 | * FormOverlay. |
218 | @@ -119,6 +130,7 @@ |
219 | } |
220 | |
221 | /** |
222 | +<<<<<<< TREE |
223 | * Search for bugs that may match the text that the user has entered and |
224 | * display them in-line. |
225 | */ |
226 | @@ -203,6 +215,93 @@ |
227 | } |
228 | |
229 | /* |
230 | +======= |
231 | + * Search for bugs that may match the text that the user has entered and |
232 | + * display them in-line. |
233 | + */ |
234 | +function search_for_and_display_dupes() { |
235 | + function show_failure_message(transaction_id, response, args) { |
236 | + // If the request failed due to a timeout, display a message |
237 | + // explaining how the user may be able to work around it. |
238 | + var error_message = ''; |
239 | + if (response.status == 503) { |
240 | + // We treat 503 (service unavailable) as a timeout because |
241 | + // that's what timeouts in LP return. |
242 | + error_message = |
243 | + "Searching for your bug in Launchpad took too long. " + |
244 | + "Try reducing the number of words in the summary " + |
245 | + "field and click \"Check again\" to retry your search. " + |
246 | + "Alternatively, you can enter the details of your bug " + |
247 | + "below."; |
248 | + } else { |
249 | + // Any other error code gets a generic message. |
250 | + error_message = |
251 | + "An error occured whilst trying to find bugs matching " + |
252 | + "the summary you entered. Click \"Check again\" to retry " + |
253 | + "your search. Alternatively, you can enter the " + |
254 | + "details of your bug below."; |
255 | + } |
256 | + |
257 | + var error_node = Y.Node.create('<p></p>'); |
258 | + error_node.set('text', error_message); |
259 | + Y.one('#possible-duplicates').appendChild(error_node); |
260 | + |
261 | + Y.one('#spinner').addClass(UNSEEN); |
262 | + show_bug_reporting_form(); |
263 | + |
264 | + Y.one(Y.DOM.byId('field.title')).set( |
265 | + 'value', search_field.get('value')); |
266 | + search_button.set('value', 'Check again'); |
267 | + search_button.removeClass(UNSEEN); |
268 | + } |
269 | + |
270 | + function on_success(transaction_id, response, args) { |
271 | + // Hide the spinner and show the duplicates. |
272 | + Y.one('#spinner').addClass(UNSEEN); |
273 | + |
274 | + var duplicate_div = Y.one('#possible-duplicates'); |
275 | + duplicate_div.set(INNER_HTML, response.responseText); |
276 | + |
277 | + bug_already_reported_expanders = Y.all( |
278 | + 'img.bug-already-reported-expander'); |
279 | + if (Y.Lang.isValue(bug_already_reported_expanders)) { |
280 | + // If there are duplicates shown, set up the JavaScript of |
281 | + // the duplicates that have been returned. |
282 | + Y.bugs.setup_dupes(); |
283 | + } else { |
284 | + // Otherwise, show the bug reporting form. |
285 | + show_bug_reporting_form(); |
286 | + } |
287 | + |
288 | + // Copy the value from the search field into the title field |
289 | + // on the filebug form. |
290 | + Y.one('#bug_reporting_form input[name=field.title]').set( |
291 | + 'value', search_field.get('value')); |
292 | + |
293 | + // Finally, change the label on the search button and show it |
294 | + // again. |
295 | + search_button.set('value', 'Check again'); |
296 | + search_button.removeClass(UNSEEN); |
297 | + } |
298 | + |
299 | + var search_term = encodeURI(search_field.get('value')); |
300 | + var search_url_base = Y.one( |
301 | + '#duplicate-search-url').getAttribute('href'); |
302 | + var search_url = search_url_base + '?title=' + search_term; |
303 | + |
304 | + // Hide the button, show the spinner and clear the contents of the |
305 | + // possible duplicates div. |
306 | + search_button.addClass(UNSEEN); |
307 | + Y.one('#spinner').removeClass(UNSEEN); |
308 | + Y.one('#possible-duplicates').set(INNER_HTML, ''); |
309 | + |
310 | + config = {on: {success: on_success, |
311 | + failure: show_failure_message}}; |
312 | + Y.io(search_url, config); |
313 | +} |
314 | + |
315 | +/* |
316 | +>>>>>>> MERGE-SOURCE |
317 | * Create the overlay for a user to optionally subscribe to a bug that |
318 | * affects them. |
319 | * @param form The form to which the FormOverlay is going to be |
320 | @@ -265,11 +364,21 @@ |
321 | |
322 | // Add an on-click handler to the radio buttons to ensure that their |
323 | // labels' styles are set correctly when they're selected. |
324 | +<<<<<<< TREE |
325 | var radio_buttons = form.queryAll('input.subscribe-option'); |
326 | Y.each(radio_buttons, function(radio_button) { |
327 | var weight = radio_button.get('checked') ? 'bold' : 'normal'; |
328 | radio_button.get('parentNode').setStyle('fontWeight', weight); |
329 | }); |
330 | +======= |
331 | + var radio_buttons = form.queryAll('input.subscribe-option'); |
332 | + if (Y.Lang.isValue(radio_buttons)) { |
333 | + Y.each(radio_buttons, function(radio_button) { |
334 | + var weight = radio_button.get('checked') ? 'bold' : 'normal'; |
335 | + radio_button.get('parentNode').setStyle('fontWeight', weight); |
336 | + }); |
337 | + } |
338 | +>>>>>>> MERGE-SOURCE |
339 | |
340 | return subscribe_form_overlay; |
341 | } |
342 | @@ -465,9 +574,142 @@ |
343 | }); |
344 | }; |
345 | |
346 | +/** |
347 | + * Set up the dupe finder, overriding the default behaviour of the |
348 | + * +filebug search form. |
349 | + */ |
350 | +function set_up_dupe_finder(transaction_id, response, args) { |
351 | + var filebug_form_container = Y.one('#filebug-form-container'); |
352 | + filebug_form_container.set(INNER_HTML, response.responseText); |
353 | + |
354 | + // Activate the extra options collapsible section on the bug |
355 | + // reporting form. |
356 | + var bug_reporting_form = Y.one('#bug_reporting_form'); |
357 | + if (Y.Lang.isValue(bug_reporting_form)) { |
358 | + activateCollapsibles(); |
359 | + } |
360 | + |
361 | + search_button = Y.one(Y.DOM.byId('field.actions.search')); |
362 | + |
363 | + // Change the name and id of the search field so that it doesn't |
364 | + // confuse the view when we submit a bug report. |
365 | + search_field = Y.one(Y.DOM.byId('field.title')); |
366 | + search_field.set('name', 'field.search'); |
367 | + search_field.set('id', 'field.search'); |
368 | + |
369 | + // Update the label on the search button so that it no longer |
370 | + // says "Continue". |
371 | + search_button.set('value', 'Next'); |
372 | + |
373 | + // Set up the handler for the search form. |
374 | + search_form = Y.one('#filebug-search-form'); |
375 | + search_form.on('submit', function(e) { |
376 | + // Prevent the event from propagating; we don't want to reload |
377 | + // the page. |
378 | + e.halt(); |
379 | + search_for_and_display_dupes(); |
380 | + }); |
381 | +} |
382 | + |
383 | +Y.bugs.setup_dupes = function() { |
384 | + bug_already_reported_expanders = Y.all( |
385 | + 'img.bug-already-reported-expander'); |
386 | + bug_reporting_form = Y.one('#bug_reporting_form'); |
387 | + |
388 | + if (Y.Lang.isValue(bug_already_reported_expanders)) { |
389 | + // Collapse all the details divs, since we don't want them |
390 | + // expanded first up. |
391 | + Y.each(Y.all('div.duplicate-details'), function(div) { |
392 | + collapse_bug_details(div); |
393 | + }); |
394 | + |
395 | + // Set up the onclick handlers for the expanders. |
396 | + Y.each(Y.all('.similar-bug'), function(row) { |
397 | + var bug_details_div = row.query('div.duplicate-details'); |
398 | + var image = row.query('img.bug-already-reported-expander'); |
399 | + var bug_title_link = row.query('.duplicate-bug-link'); |
400 | + var view_bug_link = row.query('.view-bug-link'); |
401 | + |
402 | + // Shut down the default action for the link and mark it |
403 | + // as a JS'd link. We do this as it's simpler than |
404 | + // trying to find all the bits of the row that we want |
405 | + // to make clickable. |
406 | + bug_title_link.addClass('js-action'); |
407 | + bug_title_link.on('click', function(e) { |
408 | + e.preventDefault(); |
409 | + }); |
410 | + |
411 | + // The "view this bug" link shouldn't trigger the |
412 | + // collapsible, so we stop the event from propagating. |
413 | + view_bug_link.on('click', function(e) { |
414 | + e.stopPropagation(); |
415 | + }); |
416 | + |
417 | + // The same is true for the collapsible section. People |
418 | + // may want to copy and paste this, which involves |
419 | + // clicking, so we stop the onclick event from |
420 | + // propagating here, too. |
421 | + bug_details_div.on('click', function(e) { |
422 | + e.stopPropagation(); |
423 | + }); |
424 | + |
425 | + // Set up the on focus handler for the link so that |
426 | + // tabbing will expand the different bugs. |
427 | + bug_title_link.on('focus', function(e) { |
428 | + if (!bug_details_div.hasClass('lazr-opened')) { |
429 | + var anim = Y.lazr.effects.slide_out(bug_details_div); |
430 | + anim.run(); |
431 | + |
432 | + image.set(SRC, EXPANDER_EXPANDED); |
433 | + |
434 | + // If the bug reporting form is shown, hide it. |
435 | + if (bug_reporting_form.getStyle(DISPLAY) == BLOCK) { |
436 | + bug_reporting_form.addClass(UNSEEN); |
437 | + } |
438 | + } |
439 | + }); |
440 | + |
441 | + row.on('click', function(e) { |
442 | + if (bug_details_div.hasClass('lazr-opened')) { |
443 | + collapse_bug_details(image); |
444 | + } else { |
445 | + var anim = Y.lazr.effects.slide_out(bug_details_div); |
446 | + anim.run(); |
447 | + |
448 | + image.set(SRC, EXPANDER_EXPANDED); |
449 | + } |
450 | + }); |
451 | + }); |
452 | + |
453 | + // Hide the bug reporting form. |
454 | + bug_reporting_form.addClass(UNSEEN); |
455 | + } |
456 | + |
457 | + bug_not_reported_button = Y.one('#bug-not-already-reported'); |
458 | + if (Y.Lang.isValue(bug_not_reported_button)) { |
459 | + // The bug_not_reported_button won't show up if there aren't any |
460 | + // possible duplicates. |
461 | + bug_not_reported_button.on('click', show_bug_reporting_form); |
462 | + } |
463 | + |
464 | + // Attach the form overlay to the "Yes, this is my bug" forms. |
465 | + var this_is_my_bug_forms = Y.all('form.this-is-my-bug-form'); |
466 | + Y.each(this_is_my_bug_forms, function(form) { |
467 | + var subscribe_form_overlay = create_subscribe_overlay(form); |
468 | + |
469 | + form.on('submit', function(e) { |
470 | + // We don't care about the original event, so stop it |
471 | + // and show the form overlay that we just created. |
472 | + e.halt(); |
473 | + subscribe_form_overlay.show(); |
474 | + }); |
475 | + }); |
476 | +}; |
477 | + |
478 | Y.bugs.setup_dupe_finder = function() { |
479 | Y.log("In setup_dupe_finder"); |
480 | Y.on('domready', function() { |
481 | +<<<<<<< TREE |
482 | config = {on: {success: set_up_dupe_finder, |
483 | failure: function() {}}}; |
484 | |
485 | @@ -481,6 +723,21 @@ |
486 | 'href'); |
487 | Y.io(filebug_form_url, config); |
488 | } |
489 | +======= |
490 | + config = {on: {success: set_up_dupe_finder, |
491 | + failure: function() {}}}; |
492 | + |
493 | + // Load the filebug form asynchronously. If this fails we |
494 | + // degrade to the standard mode for bug filing, clicking through |
495 | + // to the second part of the bug filing form. |
496 | + var filebug_form_url_element = Y.one( |
497 | + '#filebug-form-url'); |
498 | + if (Y.Lang.isValue(filebug_form_url_element)) { |
499 | + var filebug_form_url = filebug_form_url_element.getAttribute( |
500 | + 'href'); |
501 | + Y.io(filebug_form_url, config); |
502 | + } |
503 | +>>>>>>> MERGE-SOURCE |
504 | }); |
505 | }; |
506 | |
507 | |
508 | === modified file 'lib/lp/archiveuploader/tests/test_utils.py' |
509 | --- lib/lp/archiveuploader/tests/test_utils.py 2009-11-18 02:58:23 +0000 |
510 | +++ lib/lp/archiveuploader/tests/test_utils.py 2009-12-14 08:43:38 +0000 |
511 | @@ -10,6 +10,7 @@ |
512 | import shutil |
513 | |
514 | from lp.registry.interfaces.sourcepackage import SourcePackageFileType |
515 | +from lp.soyuz.interfaces.binarypackagerelease import BinaryPackageFileType |
516 | from lp.archiveuploader.tests import datadir |
517 | |
518 | |
519 | @@ -72,6 +73,23 @@ |
520 | self.assertEquals(None, determine_source_file_type('foo_1.0')) |
521 | self.assertEquals(None, determine_source_file_type('foo_1.0.blah.gz')) |
522 | |
523 | + def test_determine_binary_file_type(self): |
524 | + """lp.archiveuploader.utils.determine_binary_file_type should work.""" |
525 | + from lp.archiveuploader.utils import determine_binary_file_type |
526 | + |
527 | + # .deb -> DEB |
528 | + self.assertEquals( |
529 | + determine_binary_file_type('foo_1.0-1_all.deb'), |
530 | + BinaryPackageFileType.DEB) |
531 | + |
532 | + # .udeb -> UDEB |
533 | + self.assertEquals( |
534 | + determine_binary_file_type('foo_1.0-1_all.udeb'), |
535 | + BinaryPackageFileType.UDEB) |
536 | + |
537 | + self.assertEquals(determine_binary_file_type('foo_1.0'), None) |
538 | + self.assertEquals(determine_binary_file_type('foo_1.0.notdeb'), None) |
539 | + |
540 | def testPrefixMultilineString(self): |
541 | """lp.archiveuploader.utils.prefix_multi_line_string should work""" |
542 | from lp.archiveuploader.utils import prefix_multi_line_string |
543 | |
544 | === modified file 'lib/lp/archiveuploader/utils.py' |
545 | --- lib/lp/archiveuploader/utils.py 2009-11-14 02:59:34 +0000 |
546 | +++ lib/lp/archiveuploader/utils.py 2009-12-14 08:43:37 +0000 |
547 | @@ -17,6 +17,7 @@ |
548 | 're_changes_file_name', |
549 | 're_extract_src_version', |
550 | 'get_source_file_extension', |
551 | + 'determine_binary_file_type', |
552 | 'determine_source_file_type', |
553 | 'prefix_multi_line_string', |
554 | 'safe_fix_maintainer', |
555 | @@ -88,6 +89,19 @@ |
556 | return None |
557 | |
558 | |
559 | +def determine_binary_file_type(filename): |
560 | + """Determine the BinaryPackageFileType of the given filename.""" |
561 | + # Avoid circular imports. |
562 | + from lp.soyuz.interfaces.binarypackagerelease import BinaryPackageFileType |
563 | + |
564 | + if filename.endswith(".deb"): |
565 | + return BinaryPackageFileType.DEB |
566 | + elif filename.endswith(".udeb"): |
567 | + return BinaryPackageFileType.UDEB |
568 | + else: |
569 | + return None |
570 | + |
571 | + |
572 | def prefix_multi_line_string(str, prefix, include_blank_lines=0): |
573 | """Utility function to split an input string and prefix, |
574 | |
575 | |
576 | === modified file 'lib/lp/bugs/browser/bugtarget.py' |
577 | --- lib/lp/bugs/browser/bugtarget.py 2009-12-11 10:58:46 +0000 |
578 | +++ lib/lp/bugs/browser/bugtarget.py 2009-12-14 08:43:37 +0000 |
579 | @@ -360,6 +360,11 @@ |
580 | if 'field.actions' in key] != [] or |
581 | self.user.inTeam(bug_supervisor)) |
582 | |
583 | + @property |
584 | + def use_asynchronous_dupefinder(self): |
585 | + """Return True if the asynchronous dupe finder can be used.""" |
586 | + return IProduct.providedBy(self.context) |
587 | + |
588 | def getPackageNameFieldCSSClass(self): |
589 | """Return the CSS class for the packagename field.""" |
590 | if self.widget_errors.get("packagename"): |
591 | @@ -700,6 +705,7 @@ |
592 | """Override this method in base classes to show the filebug form.""" |
593 | raise NotImplementedError |
594 | |
595 | +<<<<<<< TREE |
596 | @property |
597 | def inline_filebug_base_url(self): |
598 | """Return the base URL for the current request. |
599 | @@ -729,6 +735,28 @@ |
600 | url = urlappend(url, self.extra_data_token) |
601 | return url |
602 | |
603 | +======= |
604 | + @property |
605 | + def inline_filebug_form_url(self): |
606 | + """The URL to the inline filebug form. |
607 | + |
608 | + If a token was passed to this view, it will be be passed through |
609 | + to the inline bug filing form via the returned URL. |
610 | + """ |
611 | + url = canonical_url(self.context, view_name='+filebug-inline-form') |
612 | + if self.extra_data_token is not None: |
613 | + url = urlappend(url, self.extra_data_token) |
614 | + return url |
615 | + |
616 | + @property |
617 | + def duplicate_search_url(self): |
618 | + """The URL to the inline duplicate search view.""" |
619 | + url = canonical_url(self.context, view_name='+filebug-show-similar') |
620 | + if self.extra_data_token is not None: |
621 | + url = urlappend(url, self.extra_data_token) |
622 | + return url |
623 | + |
624 | +>>>>>>> MERGE-SOURCE |
625 | def publishTraverse(self, request, name): |
626 | """See IBrowserPublisher.""" |
627 | if self.extra_data_token is not None: |
628 | |
629 | === modified file 'lib/lp/bugs/browser/tests/bugtarget-filebug-views.txt' |
630 | --- lib/lp/bugs/browser/tests/bugtarget-filebug-views.txt 2009-12-10 17:29:26 +0000 |
631 | +++ lib/lp/bugs/browser/tests/bugtarget-filebug-views.txt 2009-12-14 08:43:38 +0000 |
632 | @@ -43,6 +43,7 @@ |
633 | u'Test description.' |
634 | |
635 | |
636 | +<<<<<<< TREE |
637 | == URLs to additional FileBug elements == |
638 | |
639 | FileBugViewBase's inline_filebug_base_url returns the base URL for all |
640 | @@ -90,6 +91,27 @@ |
641 | http://launchpad.dev/evolution/+filebug-show-similar |
642 | |
643 | |
644 | +======= |
645 | +== URLs to additional FileBug elements == |
646 | + |
647 | +FileBugViewBase provides properties that return the URLs of further |
648 | +useful parts of the +filebug process. |
649 | + |
650 | +The inline_filebug_form_url property returns the URL of the inline |
651 | +filebug form so that it may be loaded asynchronously. |
652 | + |
653 | + >>> print filebug_view.inline_filebug_form_url |
654 | + http://launchpad.dev/ubuntu/+source/mozilla-firefox/+filebug-inline-form |
655 | + |
656 | +Similarly, the duplicate_search_url property returns the base URL for |
657 | +the duplicate search view, which can be used to load the list of |
658 | +possible duplicates for a bug asynchronously. |
659 | + |
660 | + >>> print filebug_view.duplicate_search_url |
661 | + http://launchpad.dev/ubuntu/+source/mozilla-firefox/+filebug-show-similar |
662 | + |
663 | + |
664 | +>>>>>>> MERGE-SOURCE |
665 | == Adding extra info to filed bugs == |
666 | |
667 | It's possible for bug reporting tools to upload a file with debug |
668 | |
669 | === modified file 'lib/lp/bugs/stories/bugattachments/20-edit-bug-attachment.txt' |
670 | --- lib/lp/bugs/stories/bugattachments/20-edit-bug-attachment.txt 2009-12-10 15:12:22 +0000 |
671 | +++ lib/lp/bugs/stories/bugattachments/20-edit-bug-attachment.txt 2009-12-14 08:43:38 +0000 |
672 | @@ -23,6 +23,7 @@ |
673 | |
674 | ...we're redirected to the bug page |
675 | |
676 | +<<<<<<< TREE |
677 | >>> user_browser.url |
678 | 'http://bugs.launchpad.dev/firefox/+bug/1' |
679 | |
680 | @@ -67,3 +68,40 @@ |
681 | >>> patch_checkbox = user_browser.getControl('This attachment is a patch') |
682 | >>> patch_checkbox.selected |
683 | True |
684 | +======= |
685 | + >>> user_browser.url |
686 | + 'http://bugs.launchpad.dev/firefox/+bug/1' |
687 | + |
688 | + >>> 'Another title' in user_browser.contents |
689 | + True |
690 | + |
691 | +We can edit the attachment to be a patch. |
692 | + |
693 | + >>> user_browser.getLink(url='+attachment/1').click() |
694 | + >>> user_browser.getControl('This attachment is a patch').selected = True |
695 | + >>> user_browser.getControl('Change').click() |
696 | + |
697 | + >>> user_browser.url |
698 | + 'http://bugs.launchpad.dev/firefox/+bug/1' |
699 | + |
700 | +The attachment that became a patch is now shown in the portlet "Patches"... |
701 | + |
702 | + >>> patches = find_portlet(user_browser.contents, 'Patches') |
703 | + >>> for li_tag in patches.findAll('li', 'download-attachment'): |
704 | + ... print li_tag.a.renderContents() |
705 | + Another title |
706 | + |
707 | +...while it is gone from the portlet "Bug attachments". |
708 | + |
709 | + >>> attachments = find_portlet(user_browser.contents, 'Bug attachments') |
710 | + >>> for li_tag in attachments.findAll('li', 'download-attachment'): |
711 | + ... print li_tag.a.renderContents() |
712 | + bar.txt |
713 | + |
714 | +The content type of a patch is automatically changed to text/plain. |
715 | + |
716 | + >>> user_browser.getLink(url='+attachment/1').click() |
717 | + >>> user_browser.getControl('Content Type').value |
718 | + 'text/plain' |
719 | + |
720 | +>>>>>>> MERGE-SOURCE |
721 | |
722 | === modified file 'lib/lp/bugs/templates/bug-portlet-attachments.pt' |
723 | --- lib/lp/bugs/templates/bug-portlet-attachments.pt 2009-12-10 15:07:18 +0000 |
724 | +++ lib/lp/bugs/templates/bug-portlet-attachments.pt 2009-12-14 08:43:39 +0000 |
725 | @@ -2,6 +2,7 @@ |
726 | xmlns:tal="http://xml.zope.org/namespaces/tal" |
727 | xmlns:metal="http://xml.zope.org/namespaces/metal" |
728 | xmlns:i18n="http://xml.zope.org/namespaces/i18n" |
729 | +<<<<<<< TREE |
730 | tal:omit-tag=""> |
731 | <div tal:condition="view/regular_attachments" class="portlet" |
732 | id="portlet-attachments"> |
733 | @@ -48,4 +49,52 @@ |
734 | </li> |
735 | </ul> |
736 | </div> |
737 | +======= |
738 | + tal:omit-tag=""> |
739 | + <div tal:condition="view/regular_attachments" class="portlet" |
740 | + id="portlet-attachments"> |
741 | + <h2>Bug attachments</h2> |
742 | + <ul> |
743 | + <li class="download-attachment" |
744 | + tal:repeat="attachment view/regular_attachments"> |
745 | + <a tal:attributes="href attachment/libraryfile/http_url" |
746 | + tal:content="attachment/title" |
747 | + class="sprite download-icon"> |
748 | + Attachment Title |
749 | + </a> |
750 | + <small> |
751 | + (<a tal:attributes="href attachment/fmt:url">edit</a>) |
752 | + </small> |
753 | + </li> |
754 | + </ul> |
755 | + <ul> |
756 | + <li> |
757 | + <a tal:attributes="href view/current_bugtask/fmt:url/+addcomment" |
758 | + class="sprite add">Add attachment</a> |
759 | + </li> |
760 | + </ul> |
761 | + </div> |
762 | + <div tal:condition="view/patches" class="portlet" id="portlet-patches"> |
763 | + <h2>Patches</h2> |
764 | + <ul> |
765 | + <li class="download-attachment" |
766 | + tal:repeat="attachment view/patches"> |
767 | + <a tal:attributes="href attachment/libraryfile/http_url" |
768 | + tal:content="attachment/title" |
769 | + class="sprite download-icon"> |
770 | + Attachment Title |
771 | + </a> |
772 | + <small> |
773 | + (<a tal:attributes="href attachment/fmt:url">edit</a>) |
774 | + </small> |
775 | + </li> |
776 | + </ul> |
777 | + <ul> |
778 | + <li> |
779 | + <a tal:attributes="href view/current_bugtask/fmt:url/+addcomment" |
780 | + class="sprite add">Add patch</a> |
781 | + </li> |
782 | + </ul> |
783 | + </div> |
784 | +>>>>>>> MERGE-SOURCE |
785 | </div> |
786 | |
787 | === modified file 'lib/lp/bugs/templates/bugtarget-filebug-search.pt' |
788 | --- lib/lp/bugs/templates/bugtarget-filebug-search.pt 2009-12-11 10:58:46 +0000 |
789 | +++ lib/lp/bugs/templates/bugtarget-filebug-search.pt 2009-12-14 08:43:38 +0000 |
790 | @@ -5,6 +5,7 @@ |
791 | xmlns:i18n="http://xml.zope.org/namespaces/i18n" |
792 | metal:use-macro="view/macro:page/main_only"> |
793 | |
794 | +<<<<<<< TREE |
795 | <metal:block fill-slot="head_epilogue"> |
796 | <script type="text/javascript" |
797 | tal:condition="devmode" |
798 | @@ -22,6 +23,27 @@ |
799 | </script> |
800 | </metal:block> |
801 | |
802 | +======= |
803 | + <metal:block fill-slot="head_epilogue"> |
804 | + <script type="text/javascript" |
805 | + tal:condition="devmode" |
806 | + tal:content="string:var yui_base='${yui}';"></script> |
807 | + <script type="text/javascript" |
808 | + tal:condition="devmode" |
809 | + tal:define="lp_js string:${icingroot}/build" |
810 | + tal:attributes="src string:${lp_js}/bugs/filebug-dupefinder.js"></script> |
811 | + |
812 | + <tal:dupe-finder-js condition="view/use_asynchronous_dupefinder"> |
813 | + <script type="text/javascript"> |
814 | + LPS.use( |
815 | + 'base', 'node', 'oop', 'event', 'bugs.dupe_finder', function(Y) { |
816 | + Y.bugs.setup_dupe_finder(); |
817 | + }); |
818 | + </script> |
819 | + </tal:dupe-finder-js> |
820 | + </metal:block> |
821 | + |
822 | +>>>>>>> MERGE-SOURCE |
823 | <div metal:fill-slot="heading"> |
824 | <div tal:condition="view/isPrivate" id="privacy" class="aside private"> |
825 | This report will be private, though you can disclose it later. |
826 | @@ -106,6 +128,7 @@ |
827 | We add this to hide the standard action buttons. |
828 | </tal:comment> |
829 | </div> |
830 | +<<<<<<< TREE |
831 | </div> |
832 | </div> |
833 | |
834 | @@ -128,3 +151,25 @@ |
835 | </div> |
836 | |
837 | </html> |
838 | +======= |
839 | + </div> |
840 | + </div> |
841 | + </tal:uses-malone> |
842 | + </div> |
843 | + |
844 | + <div id="possible-duplicates" style="text-align: left;"> |
845 | + </div> |
846 | + <div id="filebug-form-container" style="display: none;"> |
847 | + </div> |
848 | + |
849 | + <p style="display: none" tal:condition="view/use_asynchronous_dupefinder"> |
850 | + <a id="filebug-form-url" |
851 | + tal:attributes="href view/inline_filebug_form_url"></a> |
852 | + <a id="duplicate-search-url" |
853 | + tal:attributes="href view/duplicate_search_url"></a> |
854 | + </p> |
855 | + |
856 | + </div> |
857 | + |
858 | +</html> |
859 | +>>>>>>> MERGE-SOURCE |
860 | |
861 | === modified file 'lib/lp/bugs/templates/bugtasks-and-nominations-table.pt' |
862 | --- lib/lp/bugs/templates/bugtasks-and-nominations-table.pt 2009-12-11 14:00:13 +0000 |
863 | +++ lib/lp/bugs/templates/bugtasks-and-nominations-table.pt 2009-12-14 08:43:38 +0000 |
864 | @@ -112,7 +112,54 @@ |
865 | define="link context_menu/nominate" |
866 | condition="link/enabled" |
867 | replace="structure link/render" /> |
868 | +<<<<<<< TREE |
869 | </tal:also-affects-links> |
870 | +======= |
871 | + <span id="affectsmetoo" style="display: inline" |
872 | + tal:condition="link/enabled" |
873 | + tal:define="link context_menu/affectsmetoo; |
874 | + affected view/current_user_affected_status"> |
875 | + |
876 | + <tal:comment condition="nothing"> |
877 | + This .static section is shown in browsers with javascript |
878 | + enabled, and before setup_me_too is run. |
879 | + </tal:comment> |
880 | + <span class="static"> |
881 | + <tal:affected condition="affected"> |
882 | + <img width="14" height="14" src="/@@/flame-icon" alt="" /> |
883 | + This bug affects me too |
884 | + </tal:affected> |
885 | + <tal:not-affected condition="not:affected"> |
886 | + This bug doesn't affect me |
887 | + </tal:not-affected> |
888 | + <a href="+affectsmetoo"> |
889 | + <img class="editicon" src="/@@/edit" alt="Edit" /> |
890 | + </a> |
891 | + </span> |
892 | + |
893 | + <tal:comment condition="nothing"> |
894 | + This .dynamic section is used by setup_me_too to display |
895 | + controls and information in the correct places. |
896 | + </tal:comment> |
897 | + <span class="dynamic unseen"> |
898 | + <img src="/@@/flame-icon" alt=""/> |
899 | + <a href="+affectsmetoo" class="js-action" |
900 | + ><span class="value">Does this bug affect you?</span></a> |
901 | + <img class="editicon" src="/@@/edit" alt="Edit" /> |
902 | + </span> |
903 | + |
904 | + <script type="text/javascript" tal:content="string: |
905 | + LPS.use('event', 'bugs.bugtask_index', function(Y) { |
906 | + Y.on('load', function(e) { |
907 | + Y.bugs.setup_me_too(${view/current_user_affected_js_status}); |
908 | + }, window); |
909 | + }); |
910 | + "> |
911 | + </script> |
912 | + |
913 | + </span> |
914 | + </tal:also-affects-links> |
915 | +>>>>>>> MERGE-SOURCE |
916 | </div> |
917 | |
918 | </tal:root> |
919 | |
920 | === modified file 'lib/lp/code/browser/branch.py' |
921 | --- lib/lp/code/browser/branch.py 2009-12-11 00:56:16 +0000 |
922 | +++ lib/lp/code/browser/branch.py 2009-12-14 08:43:37 +0000 |
923 | @@ -83,8 +83,14 @@ |
924 | UICreatableBranchType) |
925 | from lp.code.errors import InvalidBranchMergeProposal |
926 | from lp.code.interfaces.branch import ( |
927 | - BranchCreationForbidden, BranchExists, IBranch, |
928 | - user_has_special_branch_access) |
929 | +<<<<<<< TREE |
930 | + BranchCreationForbidden, BranchExists, IBranch, |
931 | + user_has_special_branch_access) |
932 | +======= |
933 | + BranchCreationForbidden, BranchExists, IBranch, |
934 | + user_has_special_branch_access) |
935 | +from lp.code.interfaces.branchmergeproposal import InvalidBranchMergeProposal |
936 | +>>>>>>> MERGE-SOURCE |
937 | from lp.code.interfaces.branchtarget import IBranchTarget |
938 | from lp.code.interfaces.codeimport import CodeImportReviewStatus |
939 | from lp.code.interfaces.codeimportjob import ( |
940 | |
941 | === modified file 'lib/lp/code/templates/branchmergeproposal-index.pt' |
942 | --- lib/lp/code/templates/branchmergeproposal-index.pt 2009-12-11 05:07:57 +0000 |
943 | +++ lib/lp/code/templates/branchmergeproposal-index.pt 2009-12-14 08:43:37 +0000 |
944 | @@ -110,6 +110,7 @@ |
945 | </div> |
946 | |
947 | <div class="yui-g"> |
948 | +<<<<<<< TREE |
949 | <tal:not-logged-in condition="not: view/user"> |
950 | <div align="center" id="add-comment-login-first"> |
951 | To post a comment you must <a href="+login">log in</a>. |
952 | @@ -117,6 +118,9 @@ |
953 | </tal:not-logged-in> |
954 | |
955 | <div tal:define="link menu/add_comment" |
956 | +======= |
957 | + <div tal:define="link menu/add_comment" |
958 | +>>>>>>> MERGE-SOURCE |
959 | tal:condition="link/enabled" |
960 | tal:content="structure link/render"> |
961 | Add comment |
962 | @@ -125,6 +129,7 @@ |
963 | <div id="conversation" |
964 | tal:content="structure view/conversation/@@+render"/> |
965 | </div> |
966 | +<<<<<<< TREE |
967 | |
968 | <tal:logged-in condition="view/user"> |
969 | <div tal:define="comment_form nocall:context/@@+comment; |
970 | @@ -146,6 +151,22 @@ |
971 | </div> |
972 | </tal:logged-in> |
973 | |
974 | +======= |
975 | + <!-- Hide inline commenting if YUI isn't used. --> |
976 | + <div id="inline-add-comment" style="display: none"> |
977 | + <tal:comment replace="structure context/@@+comment/++form++" /> |
978 | + <div class="actions" id="launchpad-form-actions"> |
979 | + <input type="submit" id="field.actions.add" name="field.actions.add" value="Save Comment" class="button" /> |
980 | + </div> |
981 | + </div> |
982 | + |
983 | + <script type="text/javascript"> |
984 | + LPS.use('lp.comment', function(Y) { |
985 | + var comment = new Y.lp.CodeReviewComment(); |
986 | + comment.render(); |
987 | + }) |
988 | + </script> |
989 | +>>>>>>> MERGE-SOURCE |
990 | <div class="yui-g"> |
991 | <div class="yui-u first"> |
992 | <div id="source-revisions" |
993 | @@ -190,7 +211,11 @@ |
994 | string:<script id='codereview-script' type='text/javascript'>" /> |
995 | conf = <tal:status-config replace="view/status_config" /> |
996 | <!-- |
997 | +<<<<<<< TREE |
998 | LPS.use('io-base', 'code.codereview', 'code.branchmergeproposal', 'lp.comment', |
999 | +======= |
1000 | + LPS.use('io-base', 'code.codereview', 'code.branchmergeproposal', |
1001 | +>>>>>>> MERGE-SOURCE |
1002 | function(Y) { |
1003 | |
1004 | Y.on('load', function() { |
1005 | |
1006 | === modified file 'lib/lp/registry/browser/distroseries.py' |
1007 | --- lib/lp/registry/browser/distroseries.py 2009-12-09 19:47:23 +0000 |
1008 | +++ lib/lp/registry/browser/distroseries.py 2009-12-14 08:43:39 +0000 |
1009 | @@ -462,27 +462,59 @@ |
1010 | """A View to show series package to upstream package relationships.""" |
1011 | |
1012 | label = 'Mapping series packages to upstream project series' |
1013 | - page_title = 'Upstream packaging links' |
1014 | - |
1015 | - @cachedproperty |
1016 | - def unlinked_translatables(self): |
1017 | - """The sourcepackages that lack a link to a productseries.""" |
1018 | - packages = self.context.getUnlinkedTranslatableSourcePackages() |
1019 | - if self.context.distribution.full_functionality: |
1020 | - # Launchpad knows exactly what is published in the series. |
1021 | - packages = [package for package in packages |
1022 | - if package.currentrelease is not None] |
1023 | - return packages |
1024 | - |
1025 | - @cachedproperty |
1026 | - def show_unlinked_translatables(self): |
1027 | - """Are there unlinked translatables and should they be shown.""" |
1028 | - return ( |
1029 | - len(self.unlinked_translatables) > 0 |
1030 | - and self.cached_packagings.start == 0) |
1031 | - |
1032 | - @cachedproperty |
1033 | - def cached_packagings(self): |
1034 | - """The batched upstream packaging links.""" |
1035 | - packagings = self.context.packagings |
1036 | - return BatchNavigator(packagings, self.request, size=200) |
1037 | +<<<<<<< TREE |
1038 | + page_title = 'Upstream packaging links' |
1039 | + |
1040 | + @cachedproperty |
1041 | + def unlinked_translatables(self): |
1042 | + """The sourcepackages that lack a link to a productseries.""" |
1043 | + packages = self.context.getUnlinkedTranslatableSourcePackages() |
1044 | + if self.context.distribution.full_functionality: |
1045 | + # Launchpad knows exactly what is published in the series. |
1046 | + packages = [package for package in packages |
1047 | + if package.currentrelease is not None] |
1048 | + return packages |
1049 | + |
1050 | + @cachedproperty |
1051 | + def show_unlinked_translatables(self): |
1052 | + """Are there unlinked translatables and should they be shown.""" |
1053 | + return ( |
1054 | + len(self.unlinked_translatables) > 0 |
1055 | + and self.cached_packagings.start == 0) |
1056 | + |
1057 | + @cachedproperty |
1058 | + def cached_packagings(self): |
1059 | + """The batched upstream packaging links.""" |
1060 | + packagings = self.context.packagings |
1061 | + return BatchNavigator(packagings, self.request, size=200) |
1062 | +======= |
1063 | + page_title = 'Upstream packaging links' |
1064 | + |
1065 | + @cachedproperty |
1066 | + def unlinked_translatables(self): |
1067 | + """The sourcepackages that lack a link to a productseries.""" |
1068 | + packages = self.context.getUnlinkedTranslatableSourcePackages() |
1069 | + if self.context.distribution.full_functionality: |
1070 | + # Launchpad knows exactly what is published in the series. |
1071 | + packages = [package for package in packages |
1072 | + if package.currentrelease is not None] |
1073 | + return packages |
1074 | + |
1075 | + @cachedproperty |
1076 | + def show_unlinked_translatables(self): |
1077 | + """Are there unlinked translatables and should they be shown.""" |
1078 | + return ( |
1079 | + len(self.unlinked_translatables) > 0 |
1080 | + and self.cached_packagings.start == 0) |
1081 | + |
1082 | + @cachedproperty |
1083 | + def cached_packagings(self): |
1084 | + """The batched upstream packaging links.""" |
1085 | + packagings = self.context.packagings |
1086 | + if self.context.distribution.full_functionality: |
1087 | + # Launchpad knows exactly what is published in the series. |
1088 | + packagings = [ |
1089 | + packaging for packaging in packagings |
1090 | + if packaging.sourcepackage.currentrelease is not None] |
1091 | + return BatchNavigator(packagings, self.request, size=200) |
1092 | +>>>>>>> MERGE-SOURCE |
1093 | |
1094 | === modified file 'lib/lp/registry/browser/tests/packaging-views.txt' |
1095 | --- lib/lp/registry/browser/tests/packaging-views.txt 2009-12-10 20:03:11 +0000 |
1096 | +++ lib/lp/registry/browser/tests/packaging-views.txt 2009-12-14 08:43:38 +0000 |
1097 | @@ -341,6 +341,7 @@ |
1098 | sarge hotter |
1099 | 7.0 hotter |
1100 | grumpy hotter |
1101 | +<<<<<<< TREE |
1102 | |
1103 | |
1104 | Distro series +packaging view |
1105 | @@ -390,3 +391,60 @@ |
1106 | ... hoary, name='+packaging', query_string='start=2') |
1107 | >>> view.show_unlinked_translatables |
1108 | False |
1109 | +======= |
1110 | + |
1111 | + |
1112 | +Distro series +packaging view |
1113 | +----------------------------- |
1114 | + |
1115 | +The DistroSeriesPackagesView shows the packages in a distro series that |
1116 | +are linked to upstream projects. |
1117 | + |
1118 | + >>> view = create_initialized_view(hoary, name='+packaging') |
1119 | + >>> print view.label |
1120 | + Mapping series packages to upstream project series |
1121 | + |
1122 | + >>> print view.page_title |
1123 | + Upstream packaging links |
1124 | + |
1125 | +The view provides a property to get the source packages that have |
1126 | +translations, but are not linked to an upstream project. The view filters |
1127 | +unpublished versions from full functionality distributions like Ubuntu. |
1128 | + |
1129 | + >>> hoary.getUnlinkedTranslatableSourcePackages() |
1130 | + [<SourcePackage .../hoary/pmount>, <SourcePackage .../hoary/mozilla>] |
1131 | + |
1132 | + >>> view.show_unlinked_translatables |
1133 | + True |
1134 | + |
1135 | + >>> view.unlinked_translatables |
1136 | + [<SourcePackage ubuntu/hoary/pmount>] |
1137 | + |
1138 | +A distro series can have thousands of upstream packaging links. The view |
1139 | +provides a batch navigator to access the packagings. The default batch size |
1140 | +is 200. The view filters unpublished versions from full functionality |
1141 | +distributions like Ubuntu. |
1142 | + |
1143 | + >>> for packaging in hoary.packagings: |
1144 | + ... print packaging.sourcepackagename.name |
1145 | + evolution |
1146 | + mozilla-firefox |
1147 | + netapplet |
1148 | + |
1149 | + >>> batch_navigator = view.cached_packagings |
1150 | + >>> batch_navigator.default_size |
1151 | + 200 |
1152 | + |
1153 | + >>> for packaging in batch_navigator.batch: |
1154 | + ... print packaging.sourcepackagename.name |
1155 | + evolution |
1156 | + netapplet |
1157 | + |
1158 | +The show_unlinked_translatables property is False when the batch is after the |
1159 | +first batch. |
1160 | + |
1161 | + >>> view = create_initialized_view( |
1162 | + ... hoary, name='+packaging', query_string='start=2') |
1163 | + >>> view.show_unlinked_translatables |
1164 | + False |
1165 | +>>>>>>> MERGE-SOURCE |
1166 | |
1167 | === modified file 'lib/lp/registry/interfaces/person.py' |
1168 | --- lib/lp/registry/interfaces/person.py 2009-12-09 23:11:31 +0000 |
1169 | +++ lib/lp/registry/interfaces/person.py 2009-12-14 08:43:39 +0000 |
1170 | @@ -65,10 +65,16 @@ |
1171 | |
1172 | from canonical.database.sqlbase import block_implicit_flushes |
1173 | from canonical.launchpad.fields import ( |
1174 | +<<<<<<< TREE |
1175 | BlacklistableContentNameField, IconImageUpload, |
1176 | is_private_membership_person, is_public_person, LogoImageUpload, |
1177 | MugshotImageUpload, PasswordField, PersonChoice, PublicPersonChoice, |
1178 | StrippedTextLine) |
1179 | +======= |
1180 | + BlacklistableContentNameField, IconImageUpload, is_private_membership, |
1181 | + is_valid_public_person, LogoImageUpload, MugshotImageUpload, |
1182 | + PasswordField, PersonChoice, PublicPersonChoice, StrippedTextLine) |
1183 | +>>>>>>> MERGE-SOURCE |
1184 | from canonical.launchpad.interfaces.account import AccountStatus, IAccount |
1185 | from canonical.launchpad.interfaces.emailaddress import IEmailAddress |
1186 | from lp.app.interfaces.headings import IRootContext |
1187 | |
1188 | === modified file 'lib/lp/registry/stories/distroseries/xx-show-distroseries-packaging.txt' |
1189 | --- lib/lp/registry/stories/distroseries/xx-show-distroseries-packaging.txt 2009-12-10 19:58:31 +0000 |
1190 | +++ lib/lp/registry/stories/distroseries/xx-show-distroseries-packaging.txt 2009-12-14 08:43:38 +0000 |
1191 | @@ -1,48 +1,98 @@ |
1192 | -Distro series packaging |
1193 | -======================= |
1194 | - |
1195 | -The distro series packaging page is accssible to any user from the distro |
1196 | -series +index page. |
1197 | - |
1198 | - >>> anon_browser.open('http://launchpad.dev/ubuntu/hoary') |
1199 | - >>> anon_browser.getLink('Upstream links').click() |
1200 | - >>> print anon_browser.title |
1201 | - Upstream packaging links : ... |
1202 | - |
1203 | -The page lists the the source packages that have translations, but are |
1204 | -not linked to an upstream project to sync them to. |
1205 | - |
1206 | - >>> content = find_main_content(anon_browser.contents) |
1207 | - >>> print extract_text(find_tag_by_id(content, 'unlinked-translatables')) |
1208 | - Unlinked translatable packages |
1209 | - pmount |
1210 | - |
1211 | -The page lists the upstream packaging links. |
1212 | - |
1213 | - >>> print extract_text(find_tag_by_id(content, 'packagings')) |
1214 | - Source Package Upstream Project Series |
1215 | - evolution Evolution trunk series |
1216 | - mozilla-firefox Mozilla Firefox 1.0 series |
1217 | - netapplet NetApplet trunk series |
1218 | - |
1219 | -The packaging links are batched so that users can view the thousands of |
1220 | -links packages. Users can also hack the URL to set their own batch size. |
1221 | - |
1222 | - >>> anon_browser.open( |
1223 | - ... 'http://launchpad.dev/ubuntu/hoary/+packaging?start=0&batch=1') |
1224 | - >>> print extract_text(find_tag_by_id( |
1225 | - ... anon_browser.contents, 'packagings')) |
1226 | - Source Package Upstream Project Series |
1227 | - evolution Evolution trunk series |
1228 | - |
1229 | - >>> anon_browser.getLink('Next', index=0).click() |
1230 | - >>> content = find_main_content(anon_browser.contents) |
1231 | - >>> print extract_text(find_tag_by_id(content, 'packagings')) |
1232 | - Source Package Upstream Project Series |
1233 | - mozilla-firefox Mozilla Firefox 1.0 series |
1234 | - |
1235 | -The unlinked translatable source packages is not displayed on pages after |
1236 | -the first page. |
1237 | - |
1238 | - >>> print find_tag_by_id(content, 'unlinked_translatables') |
1239 | - None |
1240 | +<<<<<<< TREE |
1241 | +Distro series packaging |
1242 | +======================= |
1243 | + |
1244 | +The distro series packaging page is accssible to any user from the distro |
1245 | +series +index page. |
1246 | + |
1247 | + >>> anon_browser.open('http://launchpad.dev/ubuntu/hoary') |
1248 | + >>> anon_browser.getLink('Upstream links').click() |
1249 | + >>> print anon_browser.title |
1250 | + Upstream packaging links : ... |
1251 | + |
1252 | +The page lists the the source packages that have translations, but are |
1253 | +not linked to an upstream project to sync them to. |
1254 | + |
1255 | + >>> content = find_main_content(anon_browser.contents) |
1256 | + >>> print extract_text(find_tag_by_id(content, 'unlinked-translatables')) |
1257 | + Unlinked translatable packages |
1258 | + pmount |
1259 | + |
1260 | +The page lists the upstream packaging links. |
1261 | + |
1262 | + >>> print extract_text(find_tag_by_id(content, 'packagings')) |
1263 | + Source Package Upstream Project Series |
1264 | + evolution Evolution trunk series |
1265 | + mozilla-firefox Mozilla Firefox 1.0 series |
1266 | + netapplet NetApplet trunk series |
1267 | + |
1268 | +The packaging links are batched so that users can view the thousands of |
1269 | +links packages. Users can also hack the URL to set their own batch size. |
1270 | + |
1271 | + >>> anon_browser.open( |
1272 | + ... 'http://launchpad.dev/ubuntu/hoary/+packaging?start=0&batch=1') |
1273 | + >>> print extract_text(find_tag_by_id( |
1274 | + ... anon_browser.contents, 'packagings')) |
1275 | + Source Package Upstream Project Series |
1276 | + evolution Evolution trunk series |
1277 | + |
1278 | + >>> anon_browser.getLink('Next', index=0).click() |
1279 | + >>> content = find_main_content(anon_browser.contents) |
1280 | + >>> print extract_text(find_tag_by_id(content, 'packagings')) |
1281 | + Source Package Upstream Project Series |
1282 | + mozilla-firefox Mozilla Firefox 1.0 series |
1283 | + |
1284 | +The unlinked translatable source packages is not displayed on pages after |
1285 | +the first page. |
1286 | + |
1287 | + >>> print find_tag_by_id(content, 'unlinked_translatables') |
1288 | + None |
1289 | +======= |
1290 | +Distro series packaging |
1291 | +======================= |
1292 | + |
1293 | +The distro series packaging page is accssible to any user from the distro |
1294 | +series +index page. |
1295 | + |
1296 | + >>> anon_browser.open('http://launchpad.dev/ubuntu/hoary') |
1297 | + >>> anon_browser.getLink('Upstream links').click() |
1298 | + >>> print anon_browser.title |
1299 | + Upstream packaging links : ... |
1300 | + |
1301 | +The page lists the the source packages that have translations, but are |
1302 | +not linked to an upstream project to sync them to. |
1303 | + |
1304 | + >>> content = find_main_content(anon_browser.contents) |
1305 | + >>> print extract_text(find_tag_by_id(content, 'unlinked-translatables')) |
1306 | + Unlinked translatable packages |
1307 | + pmount |
1308 | + |
1309 | +The page lists the upstream packaging links. |
1310 | + |
1311 | + >>> print extract_text(find_tag_by_id(content, 'packagings')) |
1312 | + Source Package Upstream Project Series |
1313 | + evolution Evolution trunk series |
1314 | + netapplet NetApplet trunk series |
1315 | + |
1316 | +The packaging links are batched so that users can view the thousands of |
1317 | +links packages. Users can also hack the URL to set their own batch size. |
1318 | + |
1319 | + >>> anon_browser.open( |
1320 | + ... 'http://launchpad.dev/ubuntu/hoary/+packaging?start=0&batch=1') |
1321 | + >>> print extract_text(find_tag_by_id( |
1322 | + ... anon_browser.contents, 'packagings')) |
1323 | + Source Package Upstream Project Series |
1324 | + evolution Evolution trunk series |
1325 | + |
1326 | + >>> anon_browser.getLink('Next', index=0).click() |
1327 | + >>> content = find_main_content(anon_browser.contents) |
1328 | + >>> print extract_text(find_tag_by_id(content, 'packagings')) |
1329 | + Source Package Upstream Project Series |
1330 | + netapplet NetApplet trunk series |
1331 | + |
1332 | +The unlinked translatable source packages is not displayed on pages after |
1333 | +the first page. |
1334 | + |
1335 | + >>> print find_tag_by_id(content, 'unlinked_translatables') |
1336 | + None |
1337 | +>>>>>>> MERGE-SOURCE |
1338 | |
1339 | === modified file 'lib/lp/registry/tests/test_productseries_vocabularies.py' |
1340 | --- lib/lp/registry/tests/test_productseries_vocabularies.py 2009-12-09 23:11:31 +0000 |
1341 | +++ lib/lp/registry/tests/test_productseries_vocabularies.py 2009-12-14 08:43:39 +0000 |
1342 | @@ -1,3 +1,4 @@ |
1343 | +<<<<<<< TREE |
1344 | # Copyright 2009 Canonical Ltd. This software is licensed under the |
1345 | # GNU Affero General Public License version 3 (see the file LICENSE). |
1346 | |
1347 | @@ -80,3 +81,77 @@ |
1348 | |
1349 | def test_suite(): |
1350 | return TestLoader().loadTestsFromName(__name__) |
1351 | +======= |
1352 | +# Copyright 2009 Canonical Ltd. This software is licensed under the |
1353 | +# GNU Affero General Public License version 3 (see the file LICENSE). |
1354 | + |
1355 | +"""Test the milestone vocabularies.""" |
1356 | + |
1357 | +__metaclass__ = type |
1358 | + |
1359 | +from unittest import TestLoader |
1360 | +from operator import attrgetter |
1361 | + |
1362 | +from lp.registry.vocabularies import ProductSeriesVocabulary |
1363 | +from lp.testing import TestCaseWithFactory |
1364 | + |
1365 | +from canonical.testing import DatabaseFunctionalLayer |
1366 | + |
1367 | + |
1368 | +class TestProductSeriesVocabulary(TestCaseWithFactory): |
1369 | + """Test that the ProductSeriesVocabulary behaves as expected.""" |
1370 | + layer = DatabaseFunctionalLayer |
1371 | + |
1372 | + def setUp(self): |
1373 | + super(TestProductSeriesVocabulary, self).setUp() |
1374 | + self.vocabulary = ProductSeriesVocabulary() |
1375 | + self.product_prefix = 'asdf987-' |
1376 | + self.series1_prefix = 'qwerty-' |
1377 | + self.product = self.factory.makeProduct( |
1378 | + self.product_prefix + 'product1') |
1379 | + self.series = self.factory.makeProductSeries( |
1380 | + product=self.product, name=self.series1_prefix + "series1") |
1381 | + |
1382 | + def tearDown(self): |
1383 | + super(TestProductSeriesVocabulary, self).tearDown() |
1384 | + |
1385 | + def test_search(self): |
1386 | + series2 = self.factory.makeProductSeries(product=self.product) |
1387 | + # Search by product name. |
1388 | + result = self.vocabulary.search(self.product.name) |
1389 | + self.assertEqual( |
1390 | + [self.series, series2].sort(key=attrgetter('id')), |
1391 | + list(result).sort(key=attrgetter('id'))) |
1392 | + # Search by series name. |
1393 | + result = self.vocabulary.search(self.series.name) |
1394 | + self.assertEqual([self.series], list(result)) |
1395 | + # Search by series2 name. |
1396 | + result = self.vocabulary.search(series2.name) |
1397 | + self.assertEqual([series2], list(result)) |
1398 | + # Search by product & series name substrings. |
1399 | + result = self.vocabulary.search( |
1400 | + '%s/%s' % (self.product_prefix, self.series1_prefix)) |
1401 | + self.assertEqual([self.series], list(result)) |
1402 | + |
1403 | + def test_toTerm(self): |
1404 | + term = self.vocabulary.toTerm(self.series) |
1405 | + self.assertEqual( |
1406 | + '%s/%s' % (self.product.name, self.series.name), |
1407 | + term.token) |
1408 | + self.assertEqual(self.series, term.value) |
1409 | + |
1410 | + def test_getTermByToken(self): |
1411 | + token = '%s/%s' % (self.product.name, self.series.name) |
1412 | + term = self.vocabulary.getTermByToken(token) |
1413 | + self.assertEqual(token, term.token) |
1414 | + self.assertEqual(self.series, term.value) |
1415 | + |
1416 | + def test_getTermByToken_LookupError(self): |
1417 | + self.assertRaises( |
1418 | + LookupError, |
1419 | + self.vocabulary.getTermByToken, 'does/notexist') |
1420 | + |
1421 | + |
1422 | +def test_suite(): |
1423 | + return TestLoader().loadTestsFromName(__name__) |
1424 | +>>>>>>> MERGE-SOURCE |
1425 | |
1426 | === modified file 'lib/lp/soyuz/doc/gina.txt' |
1427 | --- lib/lp/soyuz/doc/gina.txt 2009-09-09 21:41:04 +0000 |
1428 | +++ lib/lp/soyuz/doc/gina.txt 2009-12-14 08:43:38 +0000 |
1429 | @@ -187,7 +187,7 @@ |
1430 | 16 |
1431 | >>> count = SourcePackageRelease.select().count() |
1432 | >>> count - orig_spr_count |
1433 | - 16 |
1434 | + 17 |
1435 | |
1436 | Check that x11proto-damage has its Build-Depends-Indep value correctly set: |
1437 | |
1438 | @@ -317,13 +317,13 @@ |
1439 | util-linux (again, poor thing) |
1440 | |
1441 | >>> print SSPPH.select().count() - orig_sspph_count |
1442 | - 19 |
1443 | + 20 |
1444 | |
1445 | >>> print SSPPH.selectBy( |
1446 | ... componentID=1, |
1447 | ... pocket=PackagePublishingPocket.RELEASE).count() - \ |
1448 | ... orig_sspph_main_count |
1449 | - 19 |
1450 | + 20 |
1451 | |
1452 | === Testing Binary Package Results === |
1453 | |
1454 | @@ -441,11 +441,11 @@ |
1455 | >>> print p.name |
1456 | cjwatson |
1457 | >>> print Person.select().count() - orig_person_count |
1458 | - 12 |
1459 | + 13 |
1460 | >>> print TeamParticipation.select().count() - orig_tp_count |
1461 | - 12 |
1462 | + 13 |
1463 | >>> print EmailAddress.select().count() - orig_email_count |
1464 | - 12 |
1465 | + 13 |
1466 | |
1467 | |
1468 | === Re-run Gina === |
1469 | @@ -515,13 +515,13 @@ |
1470 | changed, etc. |
1471 | |
1472 | >>> SourcePackageRelease.select().count() - orig_spr_count |
1473 | - 16 |
1474 | + 17 |
1475 | >>> print Person.select().count() - orig_person_count |
1476 | - 12 |
1477 | + 13 |
1478 | >>> print TeamParticipation.select().count() - orig_tp_count |
1479 | - 12 |
1480 | + 13 |
1481 | >>> print EmailAddress.select().count() - orig_email_count |
1482 | - 12 |
1483 | + 13 |
1484 | >>> BinaryPackageRelease.select().count() - orig_bpr_count |
1485 | 40 |
1486 | >>> Build.select().count() - orig_build_count |
1487 | @@ -532,7 +532,7 @@ |
1488 | >>> SBPPH.select().count() - orig_sbpph_count |
1489 | 47 |
1490 | >>> print SSPPH.select().count() - orig_sspph_count |
1491 | - 21 |
1492 | + 22 |
1493 | |
1494 | Check that the overrides we did were correctly issued. We can't use selectOneBy |
1495 | because, of course, there may be multiple rows published for that package -- |
1496 | |
1497 | === modified file 'lib/lp/soyuz/scripts/gina/handlers.py' |
1498 | --- lib/lp/soyuz/scripts/gina/handlers.py 2009-11-10 01:00:23 +0000 |
1499 | +++ lib/lp/soyuz/scripts/gina/handlers.py 2009-12-14 08:43:39 +0000 |
1500 | @@ -29,6 +29,8 @@ |
1501 | |
1502 | from lp.archivepublisher.diskpool import poolify |
1503 | from lp.archiveuploader.tagfiles import parse_tagfile |
1504 | +from lp.archiveuploader.utils import (determine_binary_file_type, |
1505 | + determine_source_file_type) |
1506 | |
1507 | from canonical.database.sqlbase import sqlvalues |
1508 | |
1509 | @@ -47,9 +49,9 @@ |
1510 | from lp.registry.interfaces.person import IPersonSet, PersonCreationRationale |
1511 | from lp.registry.interfaces.sourcepackage import SourcePackageType |
1512 | from lp.soyuz.interfaces.binarypackagename import IBinaryPackageNameSet |
1513 | +from lp.soyuz.interfaces.binarypackagerelease import BinaryPackageFormat |
1514 | from lp.soyuz.interfaces.build import BuildStatus |
1515 | from lp.soyuz.interfaces.publishing import PackagePublishingStatus |
1516 | -from canonical.launchpad.helpers import getFileType, getBinaryPackageFormat |
1517 | |
1518 | |
1519 | def check_not_in_librarian(files, archive_root, directory): |
1520 | @@ -78,6 +80,39 @@ |
1521 | return to_upload |
1522 | |
1523 | |
1524 | +BINARYPACKAGE_EXTENSIONS = { |
1525 | + BinaryPackageFormat.DEB: '.deb', |
1526 | + BinaryPackageFormat.UDEB: '.udeb', |
1527 | + BinaryPackageFormat.RPM: '.rpm'} |
1528 | + |
1529 | + |
1530 | +class UnrecognizedBinaryFormat(Exception): |
1531 | + |
1532 | + def __init__(self, fname, *args): |
1533 | + Exception.__init__(self, *args) |
1534 | + self.fname = fname |
1535 | + |
1536 | + def __str__(self): |
1537 | + return '%s is not recognized as a binary file.' % self.fname |
1538 | + |
1539 | + |
1540 | +def getBinaryPackageFormat(fname): |
1541 | + """Return the BinaryPackageFormat for the given filename. |
1542 | + |
1543 | + >>> getBinaryPackageFormat('mozilla-firefox_0.9_i386.deb').name |
1544 | + 'DEB' |
1545 | + >>> getBinaryPackageFormat('debian-installer.9_all.udeb').name |
1546 | + 'UDEB' |
1547 | + >>> getBinaryPackageFormat('network-manager.9_i386.rpm').name |
1548 | + 'RPM' |
1549 | + """ |
1550 | + for key, value in BINARYPACKAGE_EXTENSIONS.items(): |
1551 | + if fname.endswith(value): |
1552 | + return key |
1553 | + |
1554 | + raise UnrecognizedBinaryFormat(fname) |
1555 | + |
1556 | + |
1557 | class DataSetupError(Exception): |
1558 | """Raised when required data is found to be missing in the database""" |
1559 | |
1560 | @@ -613,9 +648,10 @@ |
1561 | # SourcePackageReleaseFile entry on lp db. |
1562 | for fname, path in to_upload: |
1563 | alias = getLibraryAlias(path, fname) |
1564 | - SourcePackageReleaseFile(sourcepackagerelease=spr.id, |
1565 | - libraryfile=alias, |
1566 | - filetype=getFileType(fname)) |
1567 | + SourcePackageReleaseFile( |
1568 | + sourcepackagerelease=spr.id, |
1569 | + libraryfile=alias, |
1570 | + filetype=determine_source_file_type(fname)) |
1571 | log.info('Package file %s included into library' % fname) |
1572 | |
1573 | return spr |
1574 | @@ -805,9 +841,10 @@ |
1575 | (bin_name.name, bin.version)) |
1576 | |
1577 | alias = getLibraryAlias(path, fname) |
1578 | - BinaryPackageFile(binarypackagerelease=binpkg.id, |
1579 | - libraryfile=alias, |
1580 | - filetype=getFileType(fname)) |
1581 | + BinaryPackageFile( |
1582 | + binarypackagerelease=binpkg.id, |
1583 | + libraryfile=alias, |
1584 | + filetype=determine_binary_file_type(fname)) |
1585 | log.info('Package file %s included into library' % fname) |
1586 | |
1587 | # Return the binarypackage object. |
1588 | |
1589 | === modified file 'lib/lp/soyuz/scripts/tests/gina_test_archive/dists/breezy/main/source/Sources' |
1590 | --- lib/lp/soyuz/scripts/tests/gina_test_archive/dists/breezy/main/source/Sources 2005-11-05 18:06:43 +0000 |
1591 | +++ lib/lp/soyuz/scripts/tests/gina_test_archive/dists/breezy/main/source/Sources 2009-12-14 08:43:39 +0000 |
1592 | @@ -139,6 +139,23 @@ |
1593 | 7947f81d47c3ccdadf05d5e4a120b098 41936 x11proto-damage_6.8.99.7.orig.tar.gz |
1594 | a4e78902d591d87ab864cedc1e83278d 2201 x11proto-damage_6.8.99.7-2.diff.gz |
1595 | |
1596 | +Package: bar |
1597 | +Binary: bar |
1598 | +Version: 1.0-1 |
1599 | +Priority: optional |
1600 | +Section: misc |
1601 | +Maintainer: Launchpad team <launchpad@lists.canonical.com> |
1602 | +Architecture: all |
1603 | +Standards-Version: 3.6.2 |
1604 | +Format: 3.0 (quilt) |
1605 | +Directory: pool/main/b/bar |
1606 | +Files: |
1607 | + 662977e76501561c902c34bf94a2054d 1115 bar_1.0-1.dsc |
1608 | + eed105761436486f7eebaa8c017bc59a 178 bar_1.0.orig-comp1.tar.gz |
1609 | + 0a30b50fa846e75261808ee1f41d1cbe 156 bar_1.0.orig-comp2.tar.bz2 |
1610 | + fc1464e5985b962a042d5354452f361d 164 bar_1.0.orig.tar.gz |
1611 | + e68110184d4d9e7afd81520cc490b396 737 bar_1.0-1.debian.tar.bz2 |
1612 | + |
1613 | Bogus, bogus, bogus |
1614 | ain't invalid stanza's neat? |
1615 | |
1616 | |
1617 | === modified file 'lib/lp/soyuz/scripts/tests/gina_test_archive/dists/breezy/main/source/Sources.gz' |
1618 | Binary files lib/lp/soyuz/scripts/tests/gina_test_archive/dists/breezy/main/source/Sources.gz 2005-11-11 11:35:22 +0000 and lib/lp/soyuz/scripts/tests/gina_test_archive/dists/breezy/main/source/Sources.gz 2009-12-14 08:43:38 +0000 differ |
1619 | === added directory 'lib/lp/soyuz/scripts/tests/gina_test_archive/pool/main/b/bar' |
1620 | === added file 'lib/lp/soyuz/scripts/tests/gina_test_archive/pool/main/b/bar/bar_1.0-1.debian.tar.bz2' |
1621 | Binary files lib/lp/soyuz/scripts/tests/gina_test_archive/pool/main/b/bar/bar_1.0-1.debian.tar.bz2 1970-01-01 00:00:00 +0000 and lib/lp/soyuz/scripts/tests/gina_test_archive/pool/main/b/bar/bar_1.0-1.debian.tar.bz2 2009-12-14 08:43:39 +0000 differ |
1622 | === added file 'lib/lp/soyuz/scripts/tests/gina_test_archive/pool/main/b/bar/bar_1.0-1.dsc' |
1623 | --- lib/lp/soyuz/scripts/tests/gina_test_archive/pool/main/b/bar/bar_1.0-1.dsc 1970-01-01 00:00:00 +0000 |
1624 | +++ lib/lp/soyuz/scripts/tests/gina_test_archive/pool/main/b/bar/bar_1.0-1.dsc 2009-12-14 08:43:38 +0000 |
1625 | @@ -0,0 +1,22 @@ |
1626 | +Format: 3.0 (quilt) |
1627 | +Source: bar |
1628 | +Binary: bar |
1629 | +Architecture: any |
1630 | +Version: 1.0-1 |
1631 | +Maintainer: Launchpad team <launchpad@lists.canonical.com> |
1632 | +Standards-Version: 3.6.2 |
1633 | +Checksums-Sha1: |
1634 | + e7a106587e0f11220e27ccc5db7527cae05e4054 178 bar_1.0.orig-comp1.tar.gz |
1635 | + a645cc0856469f549f11bb9bdc4ca6dda4eedd4b 156 bar_1.0.orig-comp2.tar.bz2 |
1636 | + 73a04163fee97fd2257ab266bd48f1d3d528e012 164 bar_1.0.orig.tar.gz |
1637 | + 727de2395d3a3e35c375159db01072935fea02f8 737 bar_1.0-1.debian.tar.bz2 |
1638 | +Checksums-Sha256: |
1639 | + aff0bbc01c5883ac76e89cba7a9b6cd79b521183f0de86c93e93ab8804f5a256 178 bar_1.0.orig-comp1.tar.gz |
1640 | + 955131b3a5bd881c008ff822c0f9b7544350647fe1f355f65a138e0e5e5e8d71 156 bar_1.0.orig-comp2.tar.bz2 |
1641 | + f1ecff929899b567f45d6734b69d59a4f3c04dabce3cc8e6ed6d64073eda360e 164 bar_1.0.orig.tar.gz |
1642 | + 3d2137f9f80f4b6c80f73acb8b3ac7986c962c4268d8948f54823d27148a6116 737 bar_1.0-1.debian.tar.bz2 |
1643 | +Files: |
1644 | + eed105761436486f7eebaa8c017bc59a 178 bar_1.0.orig-comp1.tar.gz |
1645 | + 0a30b50fa846e75261808ee1f41d1cbe 156 bar_1.0.orig-comp2.tar.bz2 |
1646 | + fc1464e5985b962a042d5354452f361d 164 bar_1.0.orig.tar.gz |
1647 | + e68110184d4d9e7afd81520cc490b396 737 bar_1.0-1.debian.tar.bz2 |
1648 | |
1649 | === added file 'lib/lp/soyuz/scripts/tests/gina_test_archive/pool/main/b/bar/bar_1.0.orig-comp1.tar.gz' |
1650 | Binary files lib/lp/soyuz/scripts/tests/gina_test_archive/pool/main/b/bar/bar_1.0.orig-comp1.tar.gz 1970-01-01 00:00:00 +0000 and lib/lp/soyuz/scripts/tests/gina_test_archive/pool/main/b/bar/bar_1.0.orig-comp1.tar.gz 2009-12-14 08:43:39 +0000 differ |
1651 | === added file 'lib/lp/soyuz/scripts/tests/gina_test_archive/pool/main/b/bar/bar_1.0.orig-comp2.tar.bz2' |
1652 | Binary files lib/lp/soyuz/scripts/tests/gina_test_archive/pool/main/b/bar/bar_1.0.orig-comp2.tar.bz2 1970-01-01 00:00:00 +0000 and lib/lp/soyuz/scripts/tests/gina_test_archive/pool/main/b/bar/bar_1.0.orig-comp2.tar.bz2 2009-12-14 08:43:39 +0000 differ |
1653 | === added file 'lib/lp/soyuz/scripts/tests/gina_test_archive/pool/main/b/bar/bar_1.0.orig.tar.gz' |
1654 | Binary files lib/lp/soyuz/scripts/tests/gina_test_archive/pool/main/b/bar/bar_1.0.orig.tar.gz 1970-01-01 00:00:00 +0000 and lib/lp/soyuz/scripts/tests/gina_test_archive/pool/main/b/bar/bar_1.0.orig.tar.gz 2009-12-14 08:43:38 +0000 differ |
1655 | === added file 'lib/lp/soyuz/scripts/tests/test_gina.py' |
1656 | --- lib/lp/soyuz/scripts/tests/test_gina.py 1970-01-01 00:00:00 +0000 |
1657 | +++ lib/lp/soyuz/scripts/tests/test_gina.py 2009-12-14 08:43:39 +0000 |
1658 | @@ -0,0 +1,15 @@ |
1659 | +# Copyright 2009 Canonical Ltd. This software is licensed under the |
1660 | +# GNU Affero General Public License version 3 (see the file LICENSE). |
1661 | + |
1662 | +import unittest |
1663 | + |
1664 | +from zope.testing.doctest import DocTestSuite |
1665 | + |
1666 | +import lp.soyuz.scripts.gina.handlers |
1667 | + |
1668 | + |
1669 | +def test_suite(): |
1670 | + suite = unittest.TestSuite() |
1671 | + suite.addTest(DocTestSuite(lp.soyuz.scripts.gina.handlers)) |
1672 | + return suite |
1673 | + |
1674 | |
1675 | === modified file 'lib/lp/translations/stories/distroseries/xx-distroseries-templates.txt' |
1676 | --- lib/lp/translations/stories/distroseries/xx-distroseries-templates.txt 2009-12-10 12:46:11 +0000 |
1677 | +++ lib/lp/translations/stories/distroseries/xx-distroseries-templates.txt 2009-12-14 08:43:39 +0000 |
1678 | @@ -1,5 +1,12 @@ |
1679 | -Templates view for DistroSeries |
1680 | -=============================== |
1681 | +<<<<<<< TREE |
1682 | +Templates view for DistroSeries |
1683 | +=============================== |
1684 | +======= |
1685 | + |
1686 | + |
1687 | +Templates view for DistroSeries |
1688 | +=============================== |
1689 | +>>>>>>> MERGE-SOURCE |
1690 | |
1691 | The +templates view for DistroSeries gives an overview of the translation |
1692 | templates in this series and provides easy access to the various subpages of |
1693 | @@ -18,6 +25,7 @@ |
1694 | >>> print user_browser.url |
1695 | http://translations.launchpad.dev/ubuntu/hoary/+templates |
1696 | |
1697 | +<<<<<<< TREE |
1698 | |
1699 | The templates table |
1700 | ------------------- |
1701 | @@ -58,6 +66,47 @@ |
1702 | ... |
1703 | mozilla pkgconf-mozilla 2005-05-06 Download |
1704 | ... |
1705 | +======= |
1706 | +The templates table |
1707 | +------------------- |
1708 | + |
1709 | +Full template listing for a distribution series is reached by following |
1710 | +a link from the distribution series translations page. |
1711 | + |
1712 | + >>> anon_browser.open( |
1713 | + ... 'http://translations.launchpad.dev/ubuntu/hoary') |
1714 | + >>> anon_browser.getLink('full list of templates').click() |
1715 | + |
1716 | +Full listing of templates shows source package name, template name and |
1717 | +the date of last update for this distribution series. |
1718 | + |
1719 | + >>> table = find_tag_by_id(anon_browser.contents, 'templates_table') |
1720 | + >>> print extract_text(table) |
1721 | + Source package Template name Last update |
1722 | + evolution disabled-template 2007-01-05 |
1723 | + evolution evolution-2.2 2005-05-06 |
1724 | + evolution man 2006-08-14 |
1725 | + mozilla pkgconf-mozilla 2005-05-06 |
1726 | + pmount man 2006-08-14 |
1727 | + pmount pmount 2005-05-06 |
1728 | + |
1729 | + |
1730 | +Logged-in users will see a link from distro series |
1731 | + >>> user_browser.open( |
1732 | + ... 'http://translations.launchpad.dev/ubuntu/hoary') |
1733 | + >>> user_browser.getLink('full list of templates').click() |
1734 | + |
1735 | +Logged-in users can also choose to download all translations for each |
1736 | +of the templates. |
1737 | + |
1738 | + >>> table = find_tag_by_id(user_browser.contents, 'templates_table') |
1739 | + >>> print extract_text(table) |
1740 | + Source package Template name Last update Actions |
1741 | + evolution disabled-template 2007-01-05 Download |
1742 | + ... |
1743 | + mozilla pkgconf-mozilla 2005-05-06 Download |
1744 | + ... |
1745 | +>>>>>>> MERGE-SOURCE |
1746 | |
1747 | Administrator can see all editing options. |
1748 | |
1749 | @@ -69,6 +118,7 @@ |
1750 | |
1751 | >>> table = find_tag_by_id(admin_browser.contents, 'templates_table') |
1752 | >>> print extract_text(table) |
1753 | +<<<<<<< TREE |
1754 | Source package Template name Last update Actions |
1755 | evolution disabled-template (inactive) 2007-01-05 Edit Upload Download Administer |
1756 | evolution evolution-2.2 2005-05-06 Edit Upload Download Administer |
1757 | @@ -137,6 +187,19 @@ |
1758 | |
1759 | Links to the templates |
1760 | ---------------------- |
1761 | +======= |
1762 | + Source package Template name Last update Actions |
1763 | + evolution disabled-template 2007-01-05 Edit Upload Download Administer |
1764 | + evolution evolution-2.2 2005-05-06 Edit Upload Download Administer |
1765 | + evolution man 2006-08-14 Edit Upload Download Administer |
1766 | + mozilla pkgconf-mozilla 2005-05-06 Edit Upload Download Administer |
1767 | + pmount man 2006-08-14 Edit Upload Download Administer |
1768 | + pmount pmount 2005-05-06 Edit Upload Download Administer |
1769 | + |
1770 | + |
1771 | +Links to the templates |
1772 | +---------------------- |
1773 | +>>>>>>> MERGE-SOURCE |
1774 | |
1775 | Clicking on a template name will take the user to that template's overview |
1776 | page. |
1777 | |
1778 | === modified file 'lib/lp/translations/templates/object-templates.pt' |
1779 | --- lib/lp/translations/templates/object-templates.pt 2009-12-10 12:46:11 +0000 |
1780 | +++ lib/lp/translations/templates/object-templates.pt 2009-12-14 08:43:37 +0000 |
1781 | @@ -82,6 +82,7 @@ |
1782 | </tr> |
1783 | </thead> |
1784 | <tbody> |
1785 | +<<<<<<< TREE |
1786 | <tal:templates repeat="template view/iter_templates"> |
1787 | <tal:not-current condition="not: template/iscurrent"> |
1788 | <tal:admin condition="template/required:launchpad.TranslationsAdmin"> |
1789 | @@ -133,6 +134,49 @@ |
1790 | </div> |
1791 | </td> |
1792 | </tr> |
1793 | +======= |
1794 | + <tr tal:repeat="template view/iter_templates" class="template_row"> |
1795 | + <td tal:condition="view/is_distroseries" |
1796 | + tal:content="template/sourcepackagename/name" |
1797 | + class="sourcepackage_column">Source package |
1798 | + </td> |
1799 | + <td class="template_column"><a tal:attributes="href template/fmt:url" |
1800 | + tal:content="template/name">Template name</a></td> |
1801 | + <td class="lastupdate_column"> |
1802 | + <span class="sortkey" |
1803 | + tal:condition="template/date_last_updated" |
1804 | + tal:content="template/date_last_updated/fmt:datetime"> |
1805 | + time sort key |
1806 | + </span> |
1807 | + <span class="lastupdate_column" |
1808 | + tal:condition="template/date_last_updated" |
1809 | + tal:attributes=" |
1810 | + title template/date_last_updated/fmt:datetime" |
1811 | + tal:content=" |
1812 | + template/date_last_updated/fmt:approximatedate" |
1813 | + > |
1814 | + 2009-09-23 |
1815 | + </span> |
1816 | + </td> |
1817 | + <td class="actions_column" |
1818 | + tal:condition="context/required:launchpad.AnyPerson"> |
1819 | + <div class="template_links"> |
1820 | + <tal:maintainer condition="template/required:launchpad.Edit"> |
1821 | + <a tal:attributes="href string:${template/fmt:url}/+edit; |
1822 | + title string:Edit ${template/name}'s details"> |
1823 | + <img src="/@@/edit" /> Edit</a> |
1824 | + <a tal:attributes="href string:${template/fmt:url}/+upload; |
1825 | + title string:Upload translations to ${template/name}"> |
1826 | + <img src="/@@/add" /> Upload</a> |
1827 | + </tal:maintainer> |
1828 | + <a tal:attributes="href string:${template/fmt:url}/+export; |
1829 | + title string:Download translations from ${template/name}"> |
1830 | + <img src="/@@/download" /> Download</a> |
1831 | + <tal:admin condition="template/required:launchpad.Admin"> |
1832 | + <a tal:attributes="href string:${template/fmt:url}/+admin; |
1833 | + title string:Administer ${template/name}"> |
1834 | + <img src="/@@/edit" /> Administer</a> |
1835 | +>>>>>>> MERGE-SOURCE |
1836 | </tal:admin> |
1837 | </tal:not-current> |
1838 | <tal:current condition="template/iscurrent"> |
gina needs to support 3.0 (quilt) and 3.0 (native) sources. To do this, it just needs to identify files as the correct types. Since archiveuploader already has a function to do this, I've altered gina to use that rather than the duplicated canonical. launchpad. helpers. getFileType. As gina was the final callsite of getFileType, I've removed that.
Since determine_ source_ file_type only does source files, I've added determine_ binary_ file_type. It could possibly go along with determine_ source_ file_type in lp.archiveuploa der.utils, but I'm not quite sure.
For testing, I've added a 3.0 (quilt) source to the test archive.