Merge lp:~cjwatson/launchpad/archive-unambiguous-files-traversals into lp:launchpad
- archive-unambiguous-files-traversals
- Merge into devel
Proposed by
Colin Watson
Status: | Merged |
---|---|
Merged at revision: | 18638 |
Proposed branch: | lp:~cjwatson/launchpad/archive-unambiguous-files-traversals |
Merge into: | lp:launchpad |
Diff against target: |
695 lines (+262/-59) 18 files modified
lib/lp/services/librarian/browser.py (+9/-6) lib/lp/soyuz/adapters/proxiedsourcefiles.py (+36/-0) lib/lp/soyuz/browser/archive.py (+27/-1) lib/lp/soyuz/browser/distributionsourcepackagerelease.py (+4/-4) lib/lp/soyuz/browser/publishing.py (+7/-4) lib/lp/soyuz/browser/tests/distributionsourcepackagerelease-views.txt (+2/-2) lib/lp/soyuz/browser/tests/publishing-views.txt (+3/-3) lib/lp/soyuz/browser/tests/test_publishing_webservice.py (+4/-4) lib/lp/soyuz/interfaces/archive.py (+16/-1) lib/lp/soyuz/model/archive.py (+24/-1) lib/lp/soyuz/model/publishing.py (+10/-3) lib/lp/soyuz/stories/ppa/xx-ppa-files.txt (+21/-14) lib/lp/soyuz/stories/ppa/xx-ppa-packages.txt (+1/-1) lib/lp/soyuz/stories/soyuz/xx-distributionsourcepackagerelease-pages.txt (+1/-1) lib/lp/soyuz/stories/soyuz/xx-distroseries-sources.txt (+8/-8) lib/lp/soyuz/stories/webservice/xx-source-package-publishing.txt (+4/-4) lib/lp/soyuz/tests/test_archive.py (+83/-0) lib/lp/soyuz/tests/test_publishing_models.py (+2/-2) |
To merge this branch: | bzr merge lp:~cjwatson/launchpad/archive-unambiguous-files-traversals |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
William Grant | code | Approve | |
Review via email: mp+345118@code.launchpad.net |
Commit message
Disambiguate URLs to source package files in the face of filename clashes in imported archives.
Description of the change
This gives us a way to cope with fetching the source files for e.g. d3-format 1.0.2-1 vs. 1:1.0.2-1 in the imported Debian archive, which would be helpful to merge-o-matic.
To post a comment you must log in.
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'lib/lp/services/librarian/browser.py' | |||
2 | --- lib/lp/services/librarian/browser.py 2015-07-09 20:06:17 +0000 | |||
3 | +++ lib/lp/services/librarian/browser.py 2018-05-08 18:13:25 +0000 | |||
4 | @@ -1,4 +1,4 @@ | |||
6 | 1 | # Copyright 2010 Canonical Ltd. This software is licensed under the | 1 | # Copyright 2010-2018 Canonical Ltd. This software is licensed under the |
7 | 2 | # GNU Affero General Public License version 3 (see the file LICENSE). | 2 | # GNU Affero General Public License version 3 (see the file LICENSE). |
8 | 3 | 3 | ||
9 | 4 | """Browser file for LibraryFileAlias.""" | 4 | """Browser file for LibraryFileAlias.""" |
10 | @@ -125,6 +125,13 @@ | |||
11 | 125 | self.parent = parent | 125 | self.parent = parent |
12 | 126 | 126 | ||
13 | 127 | @property | 127 | @property |
14 | 128 | def request(self): | ||
15 | 129 | request = get_current_browser_request() | ||
16 | 130 | if WebServiceLayer.providedBy(request): | ||
17 | 131 | request = IWebBrowserOriginatingRequest(request) | ||
18 | 132 | return request | ||
19 | 133 | |||
20 | 134 | @property | ||
21 | 128 | def http_url(self): | 135 | def http_url(self): |
22 | 129 | """Return the webapp URL for the context `LibraryFileAlias`. | 136 | """Return the webapp URL for the context `LibraryFileAlias`. |
23 | 130 | 137 | ||
24 | @@ -137,11 +144,7 @@ | |||
25 | 137 | if self.context.deleted: | 144 | if self.context.deleted: |
26 | 138 | return None | 145 | return None |
27 | 139 | 146 | ||
33 | 140 | request = get_current_browser_request() | 147 | parent_url = canonical_url(self.parent, request=self.request) |
29 | 141 | if WebServiceLayer.providedBy(request): | ||
30 | 142 | request = IWebBrowserOriginatingRequest(request) | ||
31 | 143 | |||
32 | 144 | parent_url = canonical_url(self.parent, request=request) | ||
34 | 145 | traversal_url = urlappend(parent_url, '+files') | 148 | traversal_url = urlappend(parent_url, '+files') |
35 | 146 | url = urlappend( | 149 | url = urlappend( |
36 | 147 | traversal_url, | 150 | traversal_url, |
37 | 148 | 151 | ||
38 | === added file 'lib/lp/soyuz/adapters/proxiedsourcefiles.py' | |||
39 | --- lib/lp/soyuz/adapters/proxiedsourcefiles.py 1970-01-01 00:00:00 +0000 | |||
40 | +++ lib/lp/soyuz/adapters/proxiedsourcefiles.py 2018-05-08 18:13:25 +0000 | |||
41 | @@ -0,0 +1,36 @@ | |||
42 | 1 | # Copyright 2018 Canonical Ltd. This software is licensed under the | ||
43 | 2 | # GNU Affero General Public License version 3 (see the file LICENSE). | ||
44 | 3 | |||
45 | 4 | """Proxied source files.""" | ||
46 | 5 | |||
47 | 6 | from __future__ import absolute_import, print_function, unicode_literals | ||
48 | 7 | |||
49 | 8 | __metaclass__ = type | ||
50 | 9 | __all__ = [ | ||
51 | 10 | 'ProxiedSourceLibraryFileAlias', | ||
52 | 11 | ] | ||
53 | 12 | |||
54 | 13 | from lp.services.librarian.browser import ProxiedLibraryFileAlias | ||
55 | 14 | from lp.services.librarian.client import url_path_quote | ||
56 | 15 | from lp.services.webapp.publisher import canonical_url | ||
57 | 16 | from lp.services.webapp.url import urlappend | ||
58 | 17 | |||
59 | 18 | |||
60 | 19 | class ProxiedSourceLibraryFileAlias(ProxiedLibraryFileAlias): | ||
61 | 20 | """A `ProxiedLibraryFileAlias` variant that traverses via +sourcefiles. | ||
62 | 21 | |||
63 | 22 | This can be used to construct unambiguous source file URLs even for | ||
64 | 23 | imports from upstream archives without robust historical filename | ||
65 | 24 | uniqueness checks. | ||
66 | 25 | """ | ||
67 | 26 | |||
68 | 27 | @property | ||
69 | 28 | def http_url(self): | ||
70 | 29 | if self.context.deleted: | ||
71 | 30 | return None | ||
72 | 31 | |||
73 | 32 | url = canonical_url(self.parent.archive, request=self.request) | ||
74 | 33 | return urlappend(url, '/'.join([ | ||
75 | 34 | '+sourcefiles', self.parent.source_package_name, | ||
76 | 35 | self.parent.source_package_version, | ||
77 | 36 | url_path_quote(self.context.filename.encode('utf-8'))])) | ||
78 | 0 | 37 | ||
79 | === modified file 'lib/lp/soyuz/browser/archive.py' | |||
80 | --- lib/lp/soyuz/browser/archive.py 2017-04-22 13:13:22 +0000 | |||
81 | +++ lib/lp/soyuz/browser/archive.py 2018-05-08 18:13:25 +0000 | |||
82 | @@ -1,4 +1,4 @@ | |||
84 | 1 | # Copyright 2009-2017 Canonical Ltd. This software is licensed under the | 1 | # Copyright 2009-2018 Canonical Ltd. This software is licensed under the |
85 | 2 | # GNU Affero General Public License version 3 (see the file LICENSE). | 2 | # GNU Affero General Public License version 3 (see the file LICENSE). |
86 | 3 | 3 | ||
87 | 4 | """Browser views for archive.""" | 4 | """Browser views for archive.""" |
88 | @@ -455,6 +455,32 @@ | |||
89 | 455 | 455 | ||
90 | 456 | return self.context.getArchiveDependency(archive) | 456 | return self.context.getArchiveDependency(archive) |
91 | 457 | 457 | ||
92 | 458 | @stepthrough('+sourcefiles') | ||
93 | 459 | def traverse_sourcefiles(self, sourcepackagename): | ||
94 | 460 | """Traverse to a source file in the archive. | ||
95 | 461 | |||
96 | 462 | Normally, files in an archive are unique by filename, so the +files | ||
97 | 463 | traversal is sufficient. Unfortunately, a gina-imported archive may | ||
98 | 464 | contain the same filename with different contents due to a | ||
99 | 465 | combination of epochs and less stringent checks applied by the | ||
100 | 466 | upstream archive software. (In practice this only happens for | ||
101 | 467 | source packages because that's normally all we import using gina.) | ||
102 | 468 | This provides an unambiguous way to traverse to such files even with | ||
103 | 469 | this problem. | ||
104 | 470 | |||
105 | 471 | The path scheme is:: | ||
106 | 472 | |||
107 | 473 | +sourcefiles/:sourcename/:sourceversion/:filename | ||
108 | 474 | """ | ||
109 | 475 | if len(self.request.stepstogo) < 2: | ||
110 | 476 | return None | ||
111 | 477 | |||
112 | 478 | version = self.request.stepstogo.consume() | ||
113 | 479 | filename = self.request.stepstogo.consume() | ||
114 | 480 | |||
115 | 481 | return self.context.getSourceFileByName( | ||
116 | 482 | sourcepackagename, version, filename) | ||
117 | 483 | |||
118 | 458 | 484 | ||
119 | 459 | class ArchiveMenuMixin: | 485 | class ArchiveMenuMixin: |
120 | 460 | 486 | ||
121 | 461 | 487 | ||
122 | === modified file 'lib/lp/soyuz/browser/distributionsourcepackagerelease.py' | |||
123 | --- lib/lp/soyuz/browser/distributionsourcepackagerelease.py 2014-12-18 13:05:10 +0000 | |||
124 | +++ lib/lp/soyuz/browser/distributionsourcepackagerelease.py 2018-05-08 18:13:25 +0000 | |||
125 | @@ -1,4 +1,4 @@ | |||
127 | 1 | # Copyright 2009 Canonical Ltd. This software is licensed under the | 1 | # Copyright 2009-2018 Canonical Ltd. This software is licensed under the |
128 | 2 | # GNU Affero General Public License version 3 (see the file LICENSE). | 2 | # GNU Affero General Public License version 3 (see the file LICENSE). |
129 | 3 | 3 | ||
130 | 4 | __metaclass__ = type | 4 | __metaclass__ = type |
131 | @@ -18,7 +18,6 @@ | |||
132 | 18 | from lp.registry.browser.distributionsourcepackage import ( | 18 | from lp.registry.browser.distributionsourcepackage import ( |
133 | 19 | PublishingHistoryViewMixin, | 19 | PublishingHistoryViewMixin, |
134 | 20 | ) | 20 | ) |
135 | 21 | from lp.services.librarian.browser import ProxiedLibraryFileAlias | ||
136 | 22 | from lp.services.propertycache import cachedproperty | 21 | from lp.services.propertycache import cachedproperty |
137 | 23 | from lp.services.webapp import ( | 22 | from lp.services.webapp import ( |
138 | 24 | canonical_url, | 23 | canonical_url, |
139 | @@ -27,6 +26,7 @@ | |||
140 | 27 | stepthrough, | 26 | stepthrough, |
141 | 28 | ) | 27 | ) |
142 | 29 | from lp.services.webapp.breadcrumb import Breadcrumb | 28 | from lp.services.webapp.breadcrumb import Breadcrumb |
143 | 29 | from lp.soyuz.adapters.proxiedsourcefiles import ProxiedSourceLibraryFileAlias | ||
144 | 30 | from lp.soyuz.browser.build import get_build_by_id_str | 30 | from lp.soyuz.browser.build import get_build_by_id_str |
145 | 31 | from lp.soyuz.enums import PackagePublishingStatus | 31 | from lp.soyuz.enums import PackagePublishingStatus |
146 | 32 | from lp.soyuz.interfaces.binarypackagebuild import IBinaryPackageBuildSet | 32 | from lp.soyuz.interfaces.binarypackagebuild import IBinaryPackageBuildSet |
147 | @@ -101,8 +101,8 @@ | |||
148 | 101 | """The source package release files as `ProxiedLibraryFileAlias`.""" | 101 | """The source package release files as `ProxiedLibraryFileAlias`.""" |
149 | 102 | last_publication = self._cached_publishing_history[0] | 102 | last_publication = self._cached_publishing_history[0] |
150 | 103 | return [ | 103 | return [ |
153 | 104 | ProxiedLibraryFileAlias( | 104 | ProxiedSourceLibraryFileAlias( |
154 | 105 | source_file.libraryfile, last_publication.archive) | 105 | source_file.libraryfile, last_publication) |
155 | 106 | for source_file in self.context.files] | 106 | for source_file in self.context.files] |
156 | 107 | 107 | ||
157 | 108 | @cachedproperty | 108 | @cachedproperty |
158 | 109 | 109 | ||
159 | === modified file 'lib/lp/soyuz/browser/publishing.py' | |||
160 | --- lib/lp/soyuz/browser/publishing.py 2015-07-09 20:06:17 +0000 | |||
161 | +++ lib/lp/soyuz/browser/publishing.py 2018-05-08 18:13:25 +0000 | |||
162 | @@ -1,4 +1,4 @@ | |||
164 | 1 | # Copyright 2009-2013 Canonical Ltd. This software is licensed under the | 1 | # Copyright 2009-2018 Canonical Ltd. This software is licensed under the |
165 | 2 | # GNU Affero General Public License version 3 (see the file LICENSE). | 2 | # GNU Affero General Public License version 3 (see the file LICENSE). |
166 | 3 | 3 | ||
167 | 4 | """Browser views for Soyuz publishing records.""" | 4 | """Browser views for Soyuz publishing records.""" |
168 | @@ -30,6 +30,7 @@ | |||
169 | 30 | canonical_url, | 30 | canonical_url, |
170 | 31 | LaunchpadView, | 31 | LaunchpadView, |
171 | 32 | ) | 32 | ) |
172 | 33 | from lp.soyuz.adapters.proxiedsourcefiles import ProxiedSourceLibraryFileAlias | ||
173 | 33 | from lp.soyuz.enums import PackagePublishingStatus | 34 | from lp.soyuz.enums import PackagePublishingStatus |
174 | 34 | from lp.soyuz.interfaces.binarypackagebuild import BuildSetStatus | 35 | from lp.soyuz.interfaces.binarypackagebuild import BuildSetStatus |
175 | 35 | from lp.soyuz.interfaces.packagediff import IPackageDiff | 36 | from lp.soyuz.interfaces.packagediff import IPackageDiff |
176 | @@ -270,8 +271,7 @@ | |||
177 | 270 | def published_source_and_binary_files(self): | 271 | def published_source_and_binary_files(self): |
178 | 271 | """Return list of dictionaries representing published files.""" | 272 | """Return list of dictionaries representing published files.""" |
179 | 272 | files = sorted( | 273 | files = sorted( |
182 | 273 | (ProxiedLibraryFileAlias(lfa, self.context.archive) | 274 | self.context.getSourceAndBinaryLibraryFiles(), |
181 | 274 | for lfa in self.context.getSourceAndBinaryLibraryFiles()), | ||
183 | 275 | key=attrgetter('filename')) | 275 | key=attrgetter('filename')) |
184 | 276 | result = [] | 276 | result = [] |
185 | 277 | urls = set() | 277 | urls = set() |
186 | @@ -285,14 +285,17 @@ | |||
187 | 285 | urls.add(url) | 285 | urls.add(url) |
188 | 286 | 286 | ||
189 | 287 | custom_dict = {} | 287 | custom_dict = {} |
190 | 288 | custom_dict["url"] = url | ||
191 | 289 | custom_dict["filename"] = library_file.filename | 288 | custom_dict["filename"] = library_file.filename |
192 | 290 | custom_dict["filesize"] = library_file.content.filesize | 289 | custom_dict["filesize"] = library_file.content.filesize |
193 | 291 | if (library_file.filename.endswith('.deb') or | 290 | if (library_file.filename.endswith('.deb') or |
194 | 292 | library_file.filename.endswith('.udeb')): | 291 | library_file.filename.endswith('.udeb')): |
195 | 293 | custom_dict['class'] = 'binary' | 292 | custom_dict['class'] = 'binary' |
196 | 293 | custom_dict["url"] = ProxiedLibraryFileAlias( | ||
197 | 294 | library_file, self.context.archive).http_url | ||
198 | 294 | else: | 295 | else: |
199 | 295 | custom_dict['class'] = 'source' | 296 | custom_dict['class'] = 'source' |
200 | 297 | custom_dict["url"] = ProxiedSourceLibraryFileAlias( | ||
201 | 298 | library_file, self.context).http_url | ||
202 | 296 | 299 | ||
203 | 297 | result.append(custom_dict) | 300 | result.append(custom_dict) |
204 | 298 | 301 | ||
205 | 299 | 302 | ||
206 | === modified file 'lib/lp/soyuz/browser/tests/distributionsourcepackagerelease-views.txt' | |||
207 | --- lib/lp/soyuz/browser/tests/distributionsourcepackagerelease-views.txt 2014-11-27 22:13:36 +0000 | |||
208 | +++ lib/lp/soyuz/browser/tests/distributionsourcepackagerelease-views.txt 2018-05-08 18:13:25 +0000 | |||
209 | @@ -24,14 +24,14 @@ | |||
210 | 24 | u'testing-dspr 1.0 source package in ubuntutest' | 24 | u'testing-dspr 1.0 source package in ubuntutest' |
211 | 25 | 25 | ||
212 | 26 | The 'files' property returns a list of files included in the source | 26 | The 'files' property returns a list of files included in the source |
214 | 27 | upload encapsulated as `ProxiedLibraryFileAlias` objects. Their | 27 | upload encapsulated as `ProxiedSourceLibraryFileAlias` objects. Their |
215 | 28 | 'http_url' points to the LP proxied url which normalizes the path | 28 | 'http_url' points to the LP proxied url which normalizes the path |
216 | 29 | tofiles allowing them to be downloaded using `dget`. | 29 | tofiles allowing them to be downloaded using `dget`. |
217 | 30 | 30 | ||
218 | 31 | >>> for source_file in dspr_view.files: | 31 | >>> for source_file in dspr_view.files: |
219 | 32 | ... print source_file.filename, source_file.http_url | 32 | ... print source_file.filename, source_file.http_url |
220 | 33 | testing-dspr_1.0.dsc | 33 | testing-dspr_1.0.dsc |
222 | 34 | http://.../ubuntutest/+archive/primary/+files/testing-dspr_1.0.dsc | 34 | http://.../ubuntutest/+archive/primary/+sourcefiles/testing-dspr/1.0/testing-dspr_1.0.dsc |
223 | 35 | 35 | ||
224 | 36 | The 'sponsor' property indicates whether the upload was 'sponsored' or | 36 | The 'sponsor' property indicates whether the upload was 'sponsored' or |
225 | 37 | not. When the upload was signed by someone else than the source | 37 | not. When the upload was signed by someone else than the source |
226 | 38 | 38 | ||
227 | === modified file 'lib/lp/soyuz/browser/tests/publishing-views.txt' | |||
228 | --- lib/lp/soyuz/browser/tests/publishing-views.txt 2014-07-24 09:37:03 +0000 | |||
229 | +++ lib/lp/soyuz/browser/tests/publishing-views.txt 2018-05-08 18:13:25 +0000 | |||
230 | @@ -63,7 +63,7 @@ | |||
231 | 63 | >>> view = create_initialized_view(alsa_pub, "+listing-archive-detailed") | 63 | >>> view = create_initialized_view(alsa_pub, "+listing-archive-detailed") |
232 | 64 | 64 | ||
233 | 65 | >>> view.published_source_and_binary_files | 65 | >>> view.published_source_and_binary_files |
235 | 66 | [{'url': u'http://launchpad.dev/ubuntutest/+archive/primary/+files/alsa-utils-test_666.dsc', | 66 | [{'url': u'http://launchpad.dev/ubuntutest/+archive/primary/+sourcefiles/alsa-utils-test/666/alsa-utils-test_666.dsc', |
236 | 67 | 'class': 'source', | 67 | 'class': 'source', |
237 | 68 | 'filesize': 28, | 68 | 'filesize': 28, |
238 | 69 | 'filename': u'alsa-utils-test_666.dsc'}] | 69 | 'filename': u'alsa-utils-test_666.dsc'}] |
239 | @@ -81,11 +81,11 @@ | |||
240 | 81 | ... iceweasel_source_pub, "+listing-archive-detailed") | 81 | ... iceweasel_source_pub, "+listing-archive-detailed") |
241 | 82 | 82 | ||
242 | 83 | >>> ppa_source_view.published_source_and_binary_files | 83 | >>> ppa_source_view.published_source_and_binary_files |
244 | 84 | [{'url': u'http://launchpad.dev/~cprov/+archive/ubuntu/ppa/+files/firefox_0.9.2.orig.tar.gz', | 84 | [{'url': u'http://launchpad.dev/~cprov/+archive/ubuntu/ppa/+sourcefiles/iceweasel/1.0/firefox_0.9.2.orig.tar.gz', |
245 | 85 | 'class': 'source', | 85 | 'class': 'source', |
246 | 86 | 'filesize': 9922560, | 86 | 'filesize': 9922560, |
247 | 87 | 'filename': u'firefox_0.9.2.orig.tar.gz'}, | 87 | 'filename': u'firefox_0.9.2.orig.tar.gz'}, |
249 | 88 | {'url': u'http://launchpad.dev/~cprov/+archive/ubuntu/ppa/+files/iceweasel-1.0.dsc', | 88 | {'url': u'http://launchpad.dev/~cprov/+archive/ubuntu/ppa/+sourcefiles/iceweasel/1.0/iceweasel-1.0.dsc', |
250 | 89 | 'class': 'source', | 89 | 'class': 'source', |
251 | 90 | 'filesize': 123, | 90 | 'filesize': 123, |
252 | 91 | 'filename': u'iceweasel-1.0.dsc'}, | 91 | 'filename': u'iceweasel-1.0.dsc'}, |
253 | 92 | 92 | ||
254 | === modified file 'lib/lp/soyuz/browser/tests/test_publishing_webservice.py' | |||
255 | --- lib/lp/soyuz/browser/tests/test_publishing_webservice.py 2018-02-01 18:44:21 +0000 | |||
256 | +++ lib/lp/soyuz/browser/tests/test_publishing_webservice.py 2018-05-08 18:13:25 +0000 | |||
257 | @@ -9,6 +9,7 @@ | |||
258 | 9 | 9 | ||
259 | 10 | from lp.services.librarian.browser import ProxiedLibraryFileAlias | 10 | from lp.services.librarian.browser import ProxiedLibraryFileAlias |
260 | 11 | from lp.services.webapp.interfaces import OAuthPermission | 11 | from lp.services.webapp.interfaces import OAuthPermission |
261 | 12 | from lp.soyuz.adapters.proxiedsourcefiles import ProxiedSourceLibraryFileAlias | ||
262 | 12 | from lp.testing import ( | 13 | from lp.testing import ( |
263 | 13 | api_url, | 14 | api_url, |
264 | 14 | login_person, | 15 | login_person, |
265 | @@ -47,8 +48,7 @@ | |||
266 | 47 | with person_logged_in(person): | 48 | with person_logged_in(person): |
267 | 48 | sprf = spph.sourcepackagerelease.files[0] | 49 | sprf = spph.sourcepackagerelease.files[0] |
268 | 49 | expected_urls = [ | 50 | expected_urls = [ |
271 | 50 | ProxiedLibraryFileAlias( | 51 | ProxiedSourceLibraryFileAlias(sprf.libraryfile, spph).http_url] |
270 | 51 | sprf.libraryfile, spph.archive).http_url] | ||
272 | 52 | self.assertEqual(expected_urls, urls) | 52 | self.assertEqual(expected_urls, urls) |
273 | 53 | 53 | ||
274 | 54 | def test_sourceFileUrls_include_meta(self): | 54 | def test_sourceFileUrls_include_meta(self): |
275 | @@ -75,8 +75,8 @@ | |||
276 | 75 | info = response.jsonBody() | 75 | info = response.jsonBody() |
277 | 76 | with person_logged_in(person): | 76 | with person_logged_in(person): |
278 | 77 | expected_info = [{ | 77 | expected_info = [{ |
281 | 78 | "url": ProxiedLibraryFileAlias( | 78 | "url": ProxiedSourceLibraryFileAlias( |
282 | 79 | sprf.libraryfile, spph.archive).http_url, | 79 | sprf.libraryfile, spph).http_url, |
283 | 80 | "size": sprf.libraryfile.content.filesize, | 80 | "size": sprf.libraryfile.content.filesize, |
284 | 81 | "sha256": sprf.libraryfile.content.sha256, | 81 | "sha256": sprf.libraryfile.content.sha256, |
285 | 82 | } for sprf in spph.sourcepackagerelease.files] | 82 | } for sprf in spph.sourcepackagerelease.files] |
286 | 83 | 83 | ||
287 | === modified file 'lib/lp/soyuz/interfaces/archive.py' | |||
288 | --- lib/lp/soyuz/interfaces/archive.py 2017-09-28 14:06:20 +0000 | |||
289 | +++ lib/lp/soyuz/interfaces/archive.py 2018-05-08 18:13:25 +0000 | |||
290 | @@ -1,4 +1,4 @@ | |||
292 | 1 | # Copyright 2009-2017 Canonical Ltd. This software is licensed under the | 1 | # Copyright 2009-2018 Canonical Ltd. This software is licensed under the |
293 | 2 | # GNU Affero General Public License version 3 (see the file LICENSE). | 2 | # GNU Affero General Public License version 3 (see the file LICENSE). |
294 | 3 | 3 | ||
295 | 4 | """Archive interfaces.""" | 4 | """Archive interfaces.""" |
296 | @@ -936,6 +936,21 @@ | |||
297 | 936 | :return the corresponding `ILibraryFileAlias` is the file was found. | 936 | :return the corresponding `ILibraryFileAlias` is the file was found. |
298 | 937 | """ | 937 | """ |
299 | 938 | 938 | ||
300 | 939 | def getSourceFileByName(name, version, filename): | ||
301 | 940 | """Return the `ILibraryFileAlias` for a source name/version/filename. | ||
302 | 941 | |||
303 | 942 | This can be used to avoid ambiguities with `getFileByName` in | ||
304 | 943 | imported archives, where the upstream archive software may not | ||
305 | 944 | always have had robust historical filename uniqueness checks. | ||
306 | 945 | |||
307 | 946 | :param name: The name of the source package. | ||
308 | 947 | :param version: The version of the source package. | ||
309 | 948 | :param filename: The exact filename to look up. | ||
310 | 949 | |||
311 | 950 | :raises NotFoundError: if no matching file could be found. | ||
312 | 951 | :return: the corresponding `ILibraryFileAlias`. | ||
313 | 952 | """ | ||
314 | 953 | |||
315 | 939 | def getBinaryPackageRelease(name, version, archtag): | 954 | def getBinaryPackageRelease(name, version, archtag): |
316 | 940 | """Find the specified `IBinaryPackageRelease` in the archive. | 955 | """Find the specified `IBinaryPackageRelease` in the archive. |
317 | 941 | 956 | ||
318 | 942 | 957 | ||
319 | === modified file 'lib/lp/soyuz/model/archive.py' | |||
320 | --- lib/lp/soyuz/model/archive.py 2018-01-30 16:19:15 +0000 | |||
321 | +++ lib/lp/soyuz/model/archive.py 2018-05-08 18:13:25 +0000 | |||
322 | @@ -1,4 +1,4 @@ | |||
324 | 1 | # Copyright 2009-2017 Canonical Ltd. This software is licensed under the | 1 | # Copyright 2009-2018 Canonical Ltd. This software is licensed under the |
325 | 2 | # GNU Affero General Public License version 3 (see the file LICENSE). | 2 | # GNU Affero General Public License version 3 (see the file LICENSE). |
326 | 3 | 3 | ||
327 | 4 | """Database class for table Archive.""" | 4 | """Database class for table Archive.""" |
328 | @@ -1688,6 +1688,29 @@ | |||
329 | 1688 | 1688 | ||
330 | 1689 | return archive_file | 1689 | return archive_file |
331 | 1690 | 1690 | ||
332 | 1691 | def getSourceFileByName(self, name, version, filename): | ||
333 | 1692 | """See `IArchive`.""" | ||
334 | 1693 | result = IStore(LibraryFileAlias).find( | ||
335 | 1694 | LibraryFileAlias, | ||
336 | 1695 | SourcePackagePublishingHistory.archive == self, | ||
337 | 1696 | SourcePackagePublishingHistory.sourcepackagereleaseID == | ||
338 | 1697 | SourcePackageRelease.id, | ||
339 | 1698 | SourcePackageRelease.sourcepackagename == SourcePackageName.id, | ||
340 | 1699 | SourcePackageName.name == name, | ||
341 | 1700 | SourcePackageRelease.version == version, | ||
342 | 1701 | SourcePackageRelease.id == | ||
343 | 1702 | SourcePackageReleaseFile.sourcepackagereleaseID, | ||
344 | 1703 | SourcePackageReleaseFile.libraryfileID == LibraryFileAlias.id, | ||
345 | 1704 | LibraryFileAlias.filename == filename, | ||
346 | 1705 | LibraryFileAlias.content != None) | ||
347 | 1706 | result = result.config(distinct=True).order_by(LibraryFileAlias.id) | ||
348 | 1707 | # Unlike `getFileByName`, we are guaranteed at most one match even | ||
349 | 1708 | # for files in imported archives. | ||
350 | 1709 | archive_file = result.one() | ||
351 | 1710 | if archive_file is None: | ||
352 | 1711 | raise NotFoundError(filename) | ||
353 | 1712 | return archive_file | ||
354 | 1713 | |||
355 | 1691 | def getBinaryPackageRelease(self, name, version, archtag): | 1714 | def getBinaryPackageRelease(self, name, version, archtag): |
356 | 1692 | """See `IArchive`.""" | 1715 | """See `IArchive`.""" |
357 | 1693 | from lp.soyuz.model.distroarchseries import DistroArchSeries | 1716 | from lp.soyuz.model.distroarchseries import DistroArchSeries |
358 | 1694 | 1717 | ||
359 | === modified file 'lib/lp/soyuz/model/publishing.py' | |||
360 | --- lib/lp/soyuz/model/publishing.py 2017-06-02 21:46:50 +0000 | |||
361 | +++ lib/lp/soyuz/model/publishing.py 2018-05-08 18:13:25 +0000 | |||
362 | @@ -1,4 +1,4 @@ | |||
364 | 1 | # Copyright 2009-2017 Canonical Ltd. This software is licensed under the | 1 | # Copyright 2009-2018 Canonical Ltd. This software is licensed under the |
365 | 2 | # GNU Affero General Public License version 3 (see the file LICENSE). | 2 | # GNU Affero General Public License version 3 (see the file LICENSE). |
366 | 3 | 3 | ||
367 | 4 | __metaclass__ = type | 4 | __metaclass__ = type |
368 | @@ -76,6 +76,7 @@ | |||
369 | 76 | ScriptRequest, | 76 | ScriptRequest, |
370 | 77 | ) | 77 | ) |
371 | 78 | from lp.services.worlddata.model.country import Country | 78 | from lp.services.worlddata.model.country import Country |
372 | 79 | from lp.soyuz.adapters.proxiedsourcefiles import ProxiedSourceLibraryFileAlias | ||
373 | 79 | from lp.soyuz.enums import ( | 80 | from lp.soyuz.enums import ( |
374 | 80 | BinaryPackageFormat, | 81 | BinaryPackageFormat, |
375 | 81 | PackagePublishingPriority, | 82 | PackagePublishingPriority, |
376 | @@ -142,6 +143,12 @@ | |||
377 | 142 | return [ProxiedLibraryFileAlias(file, parent).http_url for file in files] | 143 | return [ProxiedLibraryFileAlias(file, parent).http_url for file in files] |
378 | 143 | 144 | ||
379 | 144 | 145 | ||
380 | 146 | def proxied_source_urls(files, parent): | ||
381 | 147 | """Return the files passed through `ProxiedSourceLibraryFileAlias`.""" | ||
382 | 148 | return [ | ||
383 | 149 | ProxiedSourceLibraryFileAlias(file, parent).http_url for file in files] | ||
384 | 150 | |||
385 | 151 | |||
386 | 145 | class ArchivePublisherBase: | 152 | class ArchivePublisherBase: |
387 | 146 | """Base class for `IArchivePublisher`.""" | 153 | """Base class for `IArchivePublisher`.""" |
388 | 147 | 154 | ||
389 | @@ -548,8 +555,8 @@ | |||
390 | 548 | SourcePackageReleaseFile.sourcepackagerelease == | 555 | SourcePackageReleaseFile.sourcepackagerelease == |
391 | 549 | SourcePackageRelease.id, | 556 | SourcePackageRelease.id, |
392 | 550 | SourcePackageRelease.id == self.sourcepackagereleaseID) | 557 | SourcePackageRelease.id == self.sourcepackagereleaseID) |
395 | 551 | source_urls = proxied_urls( | 558 | source_urls = proxied_source_urls( |
396 | 552 | [source for source, _ in sources], self.archive) | 559 | [source for source, _ in sources], self) |
397 | 553 | if include_meta: | 560 | if include_meta: |
398 | 554 | meta = [ | 561 | meta = [ |
399 | 555 | (content.filesize, content.sha256) for _, content in sources] | 562 | (content.filesize, content.sha256) for _, content in sources] |
400 | 556 | 563 | ||
401 | === modified file 'lib/lp/soyuz/stories/ppa/xx-ppa-files.txt' | |||
402 | --- lib/lp/soyuz/stories/ppa/xx-ppa-files.txt 2016-01-26 15:47:37 +0000 | |||
403 | +++ lib/lp/soyuz/stories/ppa/xx-ppa-files.txt 2018-05-08 18:13:25 +0000 | |||
404 | @@ -90,18 +90,19 @@ | |||
405 | 90 | 90 | ||
406 | 91 | >>> ppa_links = [ | 91 | >>> ppa_links = [ |
407 | 92 | ... ('(changes file)', | 92 | ... ('(changes file)', |
409 | 93 | ... another_test_source.sourcepackagerelease.upload_changesfile), | 93 | ... another_test_source.sourcepackagerelease.upload_changesfile, |
410 | 94 | ... None, None), | ||
411 | 94 | ... ] | 95 | ... ] |
412 | 95 | 96 | ||
413 | 96 | >>> ppa_1_0_links = [ | 97 | >>> ppa_1_0_links = [ |
417 | 97 | ... ('test-pkg_1.0.dsc', dsc_file), | 98 | ... ('test-pkg_1.0.dsc', dsc_file, 'test-pkg', '1.0'), |
418 | 98 | ... ('test-pkg_1.0.tar.gz', tar_gz), | 99 | ... ('test-pkg_1.0.tar.gz', tar_gz, 'test-pkg', '1.0'), |
419 | 99 | ... ('test-bin_1.0_all.deb', deb_file), | 100 | ... ('test-bin_1.0_all.deb', deb_file, None, None), |
420 | 100 | ... ] | 101 | ... ] |
421 | 101 | 102 | ||
422 | 102 | >>> ppa_1_1_links = [ | 103 | >>> ppa_1_1_links = [ |
425 | 103 | ... ('test-pkg_1.1.dsc', another_dsc_file), | 104 | ... ('test-pkg_1.1.dsc', another_dsc_file, 'test-pkg', '1.1'), |
426 | 104 | ... ('1.0 to 1.1', package_diff.diff_content), | 105 | ... ('1.0 to 1.1', package_diff.diff_content, None, None), |
427 | 105 | ... ] | 106 | ... ] |
428 | 106 | 107 | ||
429 | 107 | Links to files accessible via +files/ proxy in the Build page. | 108 | Links to files accessible via +files/ proxy in the Build page. |
430 | @@ -109,13 +110,14 @@ | |||
431 | 109 | >>> build_id = build.id | 110 | >>> build_id = build.id |
432 | 110 | 111 | ||
433 | 111 | >>> builds_links = [ | 112 | >>> builds_links = [ |
435 | 112 | ... ('see the log', build.log), | 113 | ... ('see the log', build.log, None, None), |
436 | 113 | ... ] | 114 | ... ] |
437 | 114 | 115 | ||
438 | 115 | >>> build_links = [ | 116 | >>> build_links = [ |
442 | 116 | ... ('test-bin_1.0_i386.changes', build.upload_changesfile), | 117 | ... ('test-bin_1.0_i386.changes', build.upload_changesfile, |
443 | 117 | ... ('buildlog', build.log), | 118 | ... None, None), |
444 | 118 | ... ('uploadlog', build.upload_log), | 119 | ... ('buildlog', build.log, None, None), |
445 | 120 | ... ('uploadlog', build.upload_log, None, None), | ||
446 | 119 | ... ] | 121 | ... ] |
447 | 120 | 122 | ||
448 | 121 | >>> logout() | 123 | >>> logout() |
449 | @@ -124,15 +126,20 @@ | |||
450 | 124 | 126 | ||
451 | 125 | >>> from mechanize import LinkNotFoundError | 127 | >>> from mechanize import LinkNotFoundError |
452 | 126 | >>> def check_urls(browser, links, base_url): | 128 | >>> def check_urls(browser, links, base_url): |
454 | 127 | ... for link, libraryfile in links: | 129 | ... for link, libraryfile, source_name, source_version in links: |
455 | 128 | ... try: | 130 | ... try: |
456 | 129 | ... found_url = browser.getLink(link).url | 131 | ... found_url = browser.getLink(link).url |
457 | 130 | ... except LinkNotFoundError: | 132 | ... except LinkNotFoundError: |
458 | 131 | ... print '%s: NOT FOUND' % libraryfile.filename | 133 | ... print '%s: NOT FOUND' % libraryfile.filename |
459 | 132 | ... continue | 134 | ... continue |
460 | 133 | ... found_url = found_url.replace('%7E', '~') | 135 | ... found_url = found_url.replace('%7E', '~') |
463 | 134 | ... expected_url = '/'.join( | 136 | ... if source_name is not None: |
464 | 135 | ... (base_url, '+files', libraryfile.filename)) | 137 | ... expected_url = '/'.join( |
465 | 138 | ... (base_url, '+sourcefiles', source_name, | ||
466 | 139 | ... source_version, libraryfile.filename)) | ||
467 | 140 | ... else: | ||
468 | 141 | ... expected_url = '/'.join( | ||
469 | 142 | ... (base_url, '+files', libraryfile.filename)) | ||
470 | 136 | ... if found_url == expected_url: | 143 | ... if found_url == expected_url: |
471 | 137 | ... print '%s: OK' % libraryfile.filename | 144 | ... print '%s: OK' % libraryfile.filename |
472 | 138 | ... else: | 145 | ... else: |
473 | @@ -184,7 +191,7 @@ | |||
474 | 184 | ... 'http://launchpad.dev/~no-priv/+archive/ubuntu/p3a/+packages') | 191 | ... 'http://launchpad.dev/~no-priv/+archive/ubuntu/p3a/+packages') |
475 | 185 | 192 | ||
476 | 186 | Source and binary files, in the expandable-row area, are served via | 193 | Source and binary files, in the expandable-row area, are served via |
478 | 187 | the PPA '+files' traversal. | 194 | the PPA '+sourcefiles' and '+files' traversals. |
479 | 188 | 195 | ||
480 | 189 | >>> expander_id = find_tags_by_class( | 196 | >>> expander_id = find_tags_by_class( |
481 | 190 | ... no_priv_browser.contents, 'expander')[1]['id'] | 197 | ... no_priv_browser.contents, 'expander')[1]['id'] |
482 | 191 | 198 | ||
483 | === modified file 'lib/lp/soyuz/stories/ppa/xx-ppa-packages.txt' | |||
484 | --- lib/lp/soyuz/stories/ppa/xx-ppa-packages.txt 2015-04-09 05:16:37 +0000 | |||
485 | +++ lib/lp/soyuz/stories/ppa/xx-ppa-packages.txt 2018-05-08 18:13:25 +0000 | |||
486 | @@ -383,7 +383,7 @@ | |||
487 | 383 | >>> expander_url = foo_browser.getLink(id=expander_id).url | 383 | >>> expander_url = foo_browser.getLink(id=expander_id).url |
488 | 384 | >>> anon_browser.open(expander_url) | 384 | >>> anon_browser.open(expander_url) |
489 | 385 | >>> print anon_browser.getLink("orig").url | 385 | >>> print anon_browser.getLink("orig").url |
491 | 386 | http://.../+files/foo.orig.tar.gz | 386 | http://.../+sourcefiles/.../foo.orig.tar.gz |
492 | 387 | 387 | ||
493 | 388 | The uploader name is linkified to that user's home page: | 388 | The uploader name is linkified to that user's home page: |
494 | 389 | 389 | ||
495 | 390 | 390 | ||
496 | === modified file 'lib/lp/soyuz/stories/soyuz/xx-distributionsourcepackagerelease-pages.txt' | |||
497 | --- lib/lp/soyuz/stories/soyuz/xx-distributionsourcepackagerelease-pages.txt 2016-03-30 10:01:57 +0000 | |||
498 | +++ lib/lp/soyuz/stories/soyuz/xx-distributionsourcepackagerelease-pages.txt 2018-05-08 18:13:25 +0000 | |||
499 | @@ -201,7 +201,7 @@ | |||
500 | 201 | View changes file | 201 | View changes file |
501 | 202 | 202 | ||
502 | 203 | >>> print anon_browser.getLink('testing-dspr_1.0.dsc').url | 203 | >>> print anon_browser.getLink('testing-dspr_1.0.dsc').url |
504 | 204 | http://.../ubuntutest/+archive/primary/+files/testing-dspr_1.0.dsc | 204 | http://.../ubuntutest/+archive/primary/+sourcefiles/testing-dspr/1.0/testing-dspr_1.0.dsc |
505 | 205 | 205 | ||
506 | 206 | The 'Downloads' section also lists and link to package diffs when they | 206 | The 'Downloads' section also lists and link to package diffs when they |
507 | 207 | are available. | 207 | are available. |
508 | 208 | 208 | ||
509 | === modified file 'lib/lp/soyuz/stories/soyuz/xx-distroseries-sources.txt' | |||
510 | --- lib/lp/soyuz/stories/soyuz/xx-distroseries-sources.txt 2016-03-30 10:01:57 +0000 | |||
511 | +++ lib/lp/soyuz/stories/soyuz/xx-distroseries-sources.txt 2018-05-08 18:13:25 +0000 | |||
512 | @@ -90,7 +90,7 @@ | |||
513 | 90 | firefox_0.9.2.orig.tar.gz 9.5 MiB ... | 90 | firefox_0.9.2.orig.tar.gz 9.5 MiB ... |
514 | 91 | 91 | ||
515 | 92 | >>> print browser.getLink("firefox_0.9.2.orig.tar.gz").url | 92 | >>> print browser.getLink("firefox_0.9.2.orig.tar.gz").url |
517 | 93 | http://launchpad.dev/ubuntu/+archive/primary/+files/firefox_0.9.2.orig.tar.gz | 93 | http://launchpad.dev/ubuntu/+archive/primary/+sourcefiles/mozilla-firefox/0.9/firefox_0.9.2.orig.tar.gz |
518 | 94 | 94 | ||
519 | 95 | This page also provides links to the binary packages generated by this | 95 | This page also provides links to the binary packages generated by this |
520 | 96 | source in a specfic architecture: | 96 | source in a specfic architecture: |
521 | @@ -285,7 +285,7 @@ | |||
522 | 285 | firefox_0.9.2.orig.tar.gz 9.5 MiB ... | 285 | firefox_0.9.2.orig.tar.gz 9.5 MiB ... |
523 | 286 | 286 | ||
524 | 287 | >>> print browser.getLink("firefox_0.9.2.orig.tar.gz").url | 287 | >>> print browser.getLink("firefox_0.9.2.orig.tar.gz").url |
526 | 288 | http://launchpad.dev/ubuntu/+archive/primary/+files/firefox_0.9.2.orig.tar.gz | 288 | http://launchpad.dev/ubuntu/+archive/primary/+sourcefiles/mozilla-firefox/0.9/firefox_0.9.2.orig.tar.gz |
527 | 289 | 289 | ||
528 | 290 | If we go to the same page for alsa-utils, the changelog has text that is | 290 | If we go to the same page for alsa-utils, the changelog has text that is |
529 | 291 | linkified. | 291 | linkified. |
530 | @@ -353,11 +353,11 @@ | |||
531 | 353 | commercialpackage_1.0-1.dsc 567 bytes ... | 353 | commercialpackage_1.0-1.dsc 567 bytes ... |
532 | 354 | 354 | ||
533 | 355 | >>> print browser.getLink("commercialpackage_1.0.orig.tar.gz").url | 355 | >>> print browser.getLink("commercialpackage_1.0.orig.tar.gz").url |
535 | 356 | http://launchpad.dev/ubuntu/+archive/partner/+files/commercialpackage_1.0.orig.tar.gz | 356 | http://launchpad.dev/ubuntu/+archive/partner/+sourcefiles/commercialpackage/1.0-1/commercialpackage_1.0.orig.tar.gz |
536 | 357 | >>> print browser.getLink("commercialpackage_1.0-1.diff.gz").url | 357 | >>> print browser.getLink("commercialpackage_1.0-1.diff.gz").url |
538 | 358 | http://launchpad.dev/ubuntu/+archive/partner/+files/commercialpackage_1.0-1.diff.gz | 358 | http://launchpad.dev/ubuntu/+archive/partner/+sourcefiles/commercialpackage/1.0-1/commercialpackage_1.0-1.diff.gz |
539 | 359 | >>> print browser.getLink("commercialpackage_1.0-1.dsc").url | 359 | >>> print browser.getLink("commercialpackage_1.0-1.dsc").url |
541 | 360 | http://launchpad.dev/ubuntu/+archive/partner/+files/commercialpackage_1.0-1.dsc | 360 | http://launchpad.dev/ubuntu/+archive/partner/+sourcefiles/commercialpackage/1.0-1/commercialpackage_1.0-1.dsc |
542 | 361 | 361 | ||
543 | 362 | This page also provides links to the binary packages generated by this | 362 | This page also provides links to the binary packages generated by this |
544 | 363 | source in a specfic architecture: | 363 | source in a specfic architecture: |
545 | @@ -433,11 +433,11 @@ | |||
546 | 433 | commercialpackage_1.0-1.dsc 567 bytes ... | 433 | commercialpackage_1.0-1.dsc 567 bytes ... |
547 | 434 | 434 | ||
548 | 435 | >>> print browser.getLink("commercialpackage_1.0.orig.tar.gz").url | 435 | >>> print browser.getLink("commercialpackage_1.0.orig.tar.gz").url |
550 | 436 | http://launchpad.dev/ubuntu/+archive/partner/+files/commercialpackage_1.0.orig.tar.gz | 436 | http://launchpad.dev/ubuntu/+archive/partner/+sourcefiles/commercialpackage/1.0-1/commercialpackage_1.0.orig.tar.gz |
551 | 437 | >>> print browser.getLink("commercialpackage_1.0-1.diff.gz").url | 437 | >>> print browser.getLink("commercialpackage_1.0-1.diff.gz").url |
553 | 438 | http://launchpad.dev/ubuntu/+archive/partner/+files/commercialpackage_1.0-1.diff.gz | 438 | http://launchpad.dev/ubuntu/+archive/partner/+sourcefiles/commercialpackage/1.0-1/commercialpackage_1.0-1.diff.gz |
554 | 439 | >>> print browser.getLink("commercialpackage_1.0-1.dsc").url | 439 | >>> print browser.getLink("commercialpackage_1.0-1.dsc").url |
556 | 440 | http://launchpad.dev/ubuntu/+archive/partner/+files/commercialpackage_1.0-1.dsc | 440 | http://launchpad.dev/ubuntu/+archive/partner/+sourcefiles/commercialpackage/1.0-1/commercialpackage_1.0-1.dsc |
557 | 441 | 441 | ||
558 | 442 | 442 | ||
559 | 443 | Tracing copied sources | 443 | Tracing copied sources |
560 | 444 | 444 | ||
561 | === modified file 'lib/lp/soyuz/stories/webservice/xx-source-package-publishing.txt' | |||
562 | --- lib/lp/soyuz/stories/webservice/xx-source-package-publishing.txt 2016-03-02 15:52:33 +0000 | |||
563 | +++ lib/lp/soyuz/stories/webservice/xx-source-package-publishing.txt 2018-05-08 18:13:25 +0000 | |||
564 | @@ -375,11 +375,11 @@ | |||
565 | 375 | ... source_urls = webservice.named_get( | 375 | ... source_urls = webservice.named_get( |
566 | 376 | ... pub_link, 'sourceFileUrls').jsonBody() | 376 | ... pub_link, 'sourceFileUrls').jsonBody() |
567 | 377 | ... print source_urls | 377 | ... print source_urls |
571 | 378 | [u'http://.../~cprov/+archive/ubuntu/ppa/+files/foobar-1.0.dsc'] | 378 | [u'http://.../~cprov/+archive/ubuntu/ppa/+sourcefiles/cdrkit/1.0/foobar-1.0.dsc'] |
572 | 379 | [u'http://.../~cprov/+archive/ubuntu/ppa/+files/firefox_0.9.2.orig.tar.gz', | 379 | [u'http://.../~cprov/+archive/ubuntu/ppa/+sourcefiles/iceweasel/1.0/firefox_0.9.2.orig.tar.gz', |
573 | 380 | u'http://.../~cprov/+archive/ubuntu/ppa/+files/iceweasel-1.0.dsc'] | 380 | u'http://.../~cprov/+archive/ubuntu/ppa/+sourcefiles/iceweasel/1.0/iceweasel-1.0.dsc'] |
574 | 381 | [] | 381 | [] |
576 | 382 | [u'http://.../~cprov/+archive/ubuntu/ppa/+files/testwebservice_666.dsc'] | 382 | [u'http://.../~cprov/+archive/ubuntu/ppa/+sourcefiles/testwebservice/666/testwebservice_666.dsc'] |
577 | 383 | 383 | ||
578 | 384 | binaryFileUrls() is similar: | 384 | binaryFileUrls() is similar: |
579 | 385 | 385 | ||
580 | 386 | 386 | ||
581 | === modified file 'lib/lp/soyuz/tests/test_archive.py' | |||
582 | --- lib/lp/soyuz/tests/test_archive.py 2018-02-14 11:13:47 +0000 | |||
583 | +++ lib/lp/soyuz/tests/test_archive.py 2018-05-08 18:13:25 +0000 | |||
584 | @@ -2425,6 +2425,89 @@ | |||
585 | 2425 | self.archive.getFileByName(pu.changesfile.filename)) | 2425 | self.archive.getFileByName(pu.changesfile.filename)) |
586 | 2426 | 2426 | ||
587 | 2427 | 2427 | ||
588 | 2428 | class TestGetSourceFileByName(TestCaseWithFactory): | ||
589 | 2429 | """Tests for Archive.getSourceFileByName.""" | ||
590 | 2430 | |||
591 | 2431 | layer = LaunchpadZopelessLayer | ||
592 | 2432 | |||
593 | 2433 | def setUp(self): | ||
594 | 2434 | super(TestGetSourceFileByName, self).setUp() | ||
595 | 2435 | self.archive = self.factory.makeArchive() | ||
596 | 2436 | |||
597 | 2437 | def test_source_file_is_found(self): | ||
598 | 2438 | # A file from a published source package can be retrieved. | ||
599 | 2439 | pub = self.factory.makeSourcePackagePublishingHistory( | ||
600 | 2440 | archive=self.archive) | ||
601 | 2441 | dsc = self.factory.makeLibraryFileAlias(filename='foo_1.0.dsc') | ||
602 | 2442 | self.assertRaises( | ||
603 | 2443 | NotFoundError, self.archive.getSourceFileByName, | ||
604 | 2444 | pub.source_package_name, pub.source_package_version, dsc.filename) | ||
605 | 2445 | pub.sourcepackagerelease.addFile(dsc) | ||
606 | 2446 | self.assertEqual( | ||
607 | 2447 | dsc, self.archive.getSourceFileByName( | ||
608 | 2448 | pub.source_package_name, pub.source_package_version, | ||
609 | 2449 | dsc.filename)) | ||
610 | 2450 | |||
611 | 2451 | def test_nonexistent_source_file_is_not_found(self): | ||
612 | 2452 | # Something that looks like a source file but isn't is not | ||
613 | 2453 | # found. | ||
614 | 2454 | pub = self.factory.makeSourcePackagePublishingHistory( | ||
615 | 2455 | archive=self.archive) | ||
616 | 2456 | self.assertRaises( | ||
617 | 2457 | NotFoundError, self.archive.getSourceFileByName, | ||
618 | 2458 | pub.source_package_name, pub.source_package_version, | ||
619 | 2459 | 'foo_1.0.dsc') | ||
620 | 2460 | |||
621 | 2461 | def test_nonexistent_source_package_version_is_not_found(self): | ||
622 | 2462 | # The source package version must match exactly. | ||
623 | 2463 | pub = self.factory.makeSourcePackagePublishingHistory( | ||
624 | 2464 | archive=self.archive) | ||
625 | 2465 | pub2 = self.factory.makeSourcePackagePublishingHistory( | ||
626 | 2466 | archive=self.archive, sourcepackagename=pub.source_package_name) | ||
627 | 2467 | dsc = self.factory.makeLibraryFileAlias(filename='foo_1.0.dsc') | ||
628 | 2468 | pub2.sourcepackagerelease.addFile(dsc) | ||
629 | 2469 | self.assertRaises( | ||
630 | 2470 | NotFoundError, self.archive.getSourceFileByName, | ||
631 | 2471 | pub.source_package_name, pub.source_package_version, | ||
632 | 2472 | 'foo_1.0.dsc') | ||
633 | 2473 | |||
634 | 2474 | def test_nonexistent_source_package_name_is_not_found(self): | ||
635 | 2475 | # The source package name must match exactly. | ||
636 | 2476 | pub = self.factory.makeSourcePackagePublishingHistory( | ||
637 | 2477 | archive=self.archive) | ||
638 | 2478 | pub2 = self.factory.makeSourcePackagePublishingHistory( | ||
639 | 2479 | archive=self.archive) | ||
640 | 2480 | dsc = self.factory.makeLibraryFileAlias(filename='foo_1.0.dsc') | ||
641 | 2481 | pub2.sourcepackagerelease.addFile(dsc) | ||
642 | 2482 | self.assertRaises( | ||
643 | 2483 | NotFoundError, self.archive.getSourceFileByName, | ||
644 | 2484 | pub.source_package_name, pub.source_package_version, | ||
645 | 2485 | 'foo_1.0.dsc') | ||
646 | 2486 | |||
647 | 2487 | def test_epoch_stripping_collision(self): | ||
648 | 2488 | # Even if the archive contains two source packages with identical | ||
649 | 2489 | # names and versions apart from epochs which have the same filenames | ||
650 | 2490 | # with different contents (the worst case), getSourceFileByName | ||
651 | 2491 | # returns the correct files. | ||
652 | 2492 | pub = self.factory.makeSourcePackagePublishingHistory( | ||
653 | 2493 | archive=self.archive, version='1.0-1') | ||
654 | 2494 | dsc = self.factory.makeLibraryFileAlias(filename='foo_1.0.dsc') | ||
655 | 2495 | pub.sourcepackagerelease.addFile(dsc) | ||
656 | 2496 | pub2 = self.factory.makeSourcePackagePublishingHistory( | ||
657 | 2497 | archive=self.archive, sourcepackagename=pub.source_package_name, | ||
658 | 2498 | version='1:1.0-1') | ||
659 | 2499 | dsc2 = self.factory.makeLibraryFileAlias(filename='foo_1.0.dsc') | ||
660 | 2500 | pub2.sourcepackagerelease.addFile(dsc2) | ||
661 | 2501 | self.assertEqual( | ||
662 | 2502 | dsc, self.archive.getSourceFileByName( | ||
663 | 2503 | pub.source_package_name, pub.source_package_version, | ||
664 | 2504 | dsc.filename)) | ||
665 | 2505 | self.assertEqual( | ||
666 | 2506 | dsc2, self.archive.getSourceFileByName( | ||
667 | 2507 | pub2.source_package_name, pub2.source_package_version, | ||
668 | 2508 | dsc2.filename)) | ||
669 | 2509 | |||
670 | 2510 | |||
671 | 2428 | class TestGetPublishedSources(TestCaseWithFactory): | 2511 | class TestGetPublishedSources(TestCaseWithFactory): |
672 | 2429 | 2512 | ||
673 | 2430 | layer = DatabaseFunctionalLayer | 2513 | layer = DatabaseFunctionalLayer |
674 | 2431 | 2514 | ||
675 | === modified file 'lib/lp/soyuz/tests/test_publishing_models.py' | |||
676 | --- lib/lp/soyuz/tests/test_publishing_models.py 2018-02-02 03:14:35 +0000 | |||
677 | +++ lib/lp/soyuz/tests/test_publishing_models.py 2018-05-08 18:13:25 +0000 | |||
678 | @@ -14,6 +14,7 @@ | |||
679 | 14 | from lp.services.database.constants import UTC_NOW | 14 | from lp.services.database.constants import UTC_NOW |
680 | 15 | from lp.services.librarian.browser import ProxiedLibraryFileAlias | 15 | from lp.services.librarian.browser import ProxiedLibraryFileAlias |
681 | 16 | from lp.services.webapp.publisher import canonical_url | 16 | from lp.services.webapp.publisher import canonical_url |
682 | 17 | from lp.soyuz.adapters.proxiedsourcefiles import ProxiedSourceLibraryFileAlias | ||
683 | 17 | from lp.soyuz.enums import ( | 18 | from lp.soyuz.enums import ( |
684 | 18 | BinaryPackageFileType, | 19 | BinaryPackageFileType, |
685 | 19 | BinaryPackageFormat, | 20 | BinaryPackageFormat, |
686 | @@ -159,8 +160,7 @@ | |||
687 | 159 | 160 | ||
688 | 160 | def getURLsForSPPH(self, spph, include_meta=False): | 161 | def getURLsForSPPH(self, spph, include_meta=False): |
689 | 161 | spr = spph.sourcepackagerelease | 162 | spr = spph.sourcepackagerelease |
692 | 162 | archive = spph.archive | 163 | urls = [ProxiedSourceLibraryFileAlias(f.libraryfile, spph).http_url |
691 | 163 | urls = [ProxiedLibraryFileAlias(f.libraryfile, archive).http_url | ||
693 | 164 | for f in spr.files] | 164 | for f in spr.files] |
694 | 165 | 165 | ||
695 | 166 | if include_meta: | 166 | if include_meta: |
I guess we'll find all the clients that match on /+files/ paths.