Merge ~cjwatson/launchpad:move-publishing-queries into launchpad:master
- Git
- lp:~cjwatson/launchpad
- move-publishing-queries
- Merge into master
Proposed by
Colin Watson
Status: | Merged |
---|---|
Approved by: | Colin Watson |
Approved revision: | 9934601567f43b71a7c4a999c6f98e50353b3e12 |
Merge reported by: | Otto Co-Pilot |
Merged at revision: | not available |
Proposed branch: | ~cjwatson/launchpad:move-publishing-queries |
Merge into: | launchpad:master |
Diff against target: |
766 lines (+293/-243) 8 files modified
lib/lp/archivepublisher/publishing.py (+7/-5) lib/lp/registry/doc/distroseries.txt (+0/-72) lib/lp/registry/interfaces/distroseries.py (+1/-21) lib/lp/registry/model/distroseries.py (+3/-94) lib/lp/registry/tests/test_distroseries.py (+1/-48) lib/lp/soyuz/interfaces/publishing.py (+27/-1) lib/lp/soyuz/model/publishing.py (+78/-1) lib/lp/soyuz/tests/test_publishing.py (+176/-1) |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Ioana Lasc (community) | Approve | ||
Review via email: mp+417751@code.launchpad.net |
Commit message
Move publishing queries from DistroSeries to PublishingSet
Description of the change
The existence of `DistroSeries.
As well as cleaning up some minor technical debt, this helps to prepare for Artifactory publishing, where we're likely to need to be able to query for publications in an archive without filtering by series.
To post a comment you must log in.
Revision history for this message
Ioana Lasc (ilasc) : | # |
review:
Approve
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | diff --git a/lib/lp/archivepublisher/publishing.py b/lib/lp/archivepublisher/publishing.py |
2 | index a5a0cc4..e280b79 100644 |
3 | --- a/lib/lp/archivepublisher/publishing.py |
4 | +++ b/lib/lp/archivepublisher/publishing.py |
5 | @@ -1,4 +1,4 @@ |
6 | -# Copyright 2009-2021 Canonical Ltd. This software is licensed under the |
7 | +# Copyright 2009-2022 Canonical Ltd. This software is licensed under the |
8 | # GNU Affero General Public License version 3 (see the file LICENSE). |
9 | |
10 | __all__ = [ |
11 | @@ -910,8 +910,9 @@ class Publisher: |
12 | get_sources_path(self._config, suite_name, component), |
13 | self._config.temproot, distroseries.index_compressors) |
14 | |
15 | - for spp in distroseries.getSourcePackagePublishing( |
16 | - pocket, component, self.archive): |
17 | + for spp in getUtility(IPublishingSet).getSourcesForPublishing( |
18 | + archive=self.archive, distroseries=distroseries, pocket=pocket, |
19 | + component=component): |
20 | stanza = build_source_stanza_fields( |
21 | spp.sourcepackagerelease, spp.component, spp.section) |
22 | source_index.write(stanza.makeOutput().encode('utf-8') + b'\n\n') |
23 | @@ -937,8 +938,9 @@ class Publisher: |
24 | self._config, suite_name, component, arch, subcomp), |
25 | self._config.temproot, distroseries.index_compressors) |
26 | |
27 | - for bpp in distroseries.getBinaryPackagePublishing( |
28 | - arch.architecturetag, pocket, component, self.archive): |
29 | + for bpp in getUtility(IPublishingSet).getBinariesForPublishing( |
30 | + archive=self.archive, distroarchseries=arch, pocket=pocket, |
31 | + component=component): |
32 | subcomp = FORMAT_TO_SUBCOMPONENT.get( |
33 | bpp.binarypackagerelease.binpackageformat) |
34 | if subcomp not in indices: |
35 | diff --git a/lib/lp/registry/doc/distroseries.txt b/lib/lp/registry/doc/distroseries.txt |
36 | index 7d202f5..82a8ff8 100644 |
37 | --- a/lib/lp/registry/doc/distroseries.txt |
38 | +++ b/lib/lp/registry/doc/distroseries.txt |
39 | @@ -232,7 +232,6 @@ other things) the uploader for validating incoming uploads. |
40 | devel |
41 | translations |
42 | |
43 | - >>> from lp.soyuz.interfaces.component import IComponentSet |
44 | >>> from lp.soyuz.interfaces.section import ISectionSet |
45 | >>> python = getUtility(ISectionSet).ensure('python') |
46 | |
47 | @@ -490,50 +489,9 @@ upstream. |
48 | SourcePackagePublishingHistory |
49 | ------------------------------ |
50 | |
51 | -IDistroSeries.getSourcePackagePublishing returns all the ISPPH |
52 | -records for a given status in a given pocket. It makes easy to |
53 | -generate a list of currently published sources for override-check, for |
54 | -instance. it can also be used to generate the archive packages list in |
55 | -the future. |
56 | - |
57 | - >>> ubuntu = getUtility(IDistributionSet)['ubuntu'] |
58 | - >>> hoary = ubuntu['hoary'] |
59 | - >>> component_main = getUtility(IComponentSet)['main'] |
60 | - >>> component_multiverse = getUtility(IComponentSet)['multiverse'] |
61 | - >>> debian_archive = getUtility(IDistributionSet)['debian'].main_archive |
62 | - |
63 | - >>> spphs = hoary.getSourcePackagePublishing( |
64 | - ... PackagePublishingPocket.RELEASE, component_main, |
65 | - ... warty.main_archive) |
66 | - >>> spphs.count() |
67 | - 6 |
68 | - >>> for name in sorted(set( |
69 | - ... pkgpub.sourcepackagerelease.sourcepackagename.name |
70 | - ... for pkgpub in spphs)): |
71 | - ... print(name) |
72 | - alsa-utils |
73 | - evolution |
74 | - libstdc++ |
75 | - linux-source-2.6.15 |
76 | - netapplet |
77 | - pmount |
78 | - >>> hoary.getSourcePackagePublishing( |
79 | - ... PackagePublishingPocket.RELEASE, component_multiverse, |
80 | - ... hoary.main_archive).count() |
81 | - 0 |
82 | - >>> hoary.getSourcePackagePublishing( |
83 | - ... PackagePublishingPocket.BACKPORTS, component_main, |
84 | - ... hoary.main_archive).count() |
85 | - 0 |
86 | - >>> hoary.getSourcePackagePublishing( |
87 | - ... PackagePublishingPocket.RELEASE, component_main, |
88 | - ... debian_archive).count() |
89 | - 0 |
90 | - |
91 | ISPP.getPublishedBinaries returns all the binaries generated by the |
92 | publication in question: |
93 | |
94 | - >>> warty = ubuntu['warty'] |
95 | >>> warty_pub_source = warty.main_archive.getPublishedSources( |
96 | ... distroseries=warty, name=u'mozilla-firefox', |
97 | ... status=PackagePublishingStatus.PUBLISHED).one() |
98 | @@ -566,36 +524,6 @@ publication in question: |
99 | >>> print(warty_mozilla_pub_bin.section.name) |
100 | base |
101 | |
102 | -DistroSeries.getBinaryPackagePublishing will return |
103 | -BinaryPackagePublishingHistory objects for the DistroSeries: |
104 | - |
105 | - >>> warty = ubuntu['warty'] |
106 | - >>> bpphs = warty.getBinaryPackagePublishing( |
107 | - ... "i386", PackagePublishingPocket.RELEASE, component_main, |
108 | - ... warty.main_archive) |
109 | - >>> bpphs.count() |
110 | - 8 |
111 | - >>> 'mozilla-firefox' in set( |
112 | - ... pkgpub.binarypackagerelease.binarypackagename.name |
113 | - ... for pkgpub in bpphs) |
114 | - True |
115 | - >>> warty.getBinaryPackagePublishing( |
116 | - ... "nope", PackagePublishingPocket.RELEASE, component_main, |
117 | - ... warty.main_archive).count() |
118 | - 0 |
119 | - >>> warty.getBinaryPackagePublishing( |
120 | - ... "i386", PackagePublishingPocket.RELEASE, component_multiverse, |
121 | - ... warty.main_archive).count() |
122 | - 0 |
123 | - >>> warty.getBinaryPackagePublishing( |
124 | - ... "i386", PackagePublishingPocket.BACKPORTS, component_main, |
125 | - ... warty.main_archive).count() |
126 | - 0 |
127 | - >>> warty.getBinaryPackagePublishing( |
128 | - ... "i386", PackagePublishingPocket.RELEASE, component_main, |
129 | - ... debian_archive).count() |
130 | - 0 |
131 | - |
132 | getAllPublishedSources will return all publications with status PUBLISHED |
133 | and in the main archives for this distroseries: |
134 | |
135 | diff --git a/lib/lp/registry/interfaces/distroseries.py b/lib/lp/registry/interfaces/distroseries.py |
136 | index d8c6370..ac2959c 100644 |
137 | --- a/lib/lp/registry/interfaces/distroseries.py |
138 | +++ b/lib/lp/registry/interfaces/distroseries.py |
139 | @@ -1,4 +1,4 @@ |
140 | -# Copyright 2009-2021 Canonical Ltd. This software is licensed under the |
141 | +# Copyright 2009-2022 Canonical Ltd. This software is licensed under the |
142 | # GNU Affero General Public License version 3 (see the file LICENSE). |
143 | |
144 | """Interfaces including and related to IDistroSeries.""" |
145 | @@ -729,26 +729,6 @@ class IDistroSeriesPublic( |
146 | def addSection(section): |
147 | """SQLObject provided method to fill a related join key section.""" |
148 | |
149 | - def getBinaryPackagePublishing(archtag, pocket, component, archive): |
150 | - """Get BinaryPackagePublishings in a DistroSeries. |
151 | - |
152 | - Can optionally restrict the results by architecturetag, pocket and/or |
153 | - component. |
154 | - |
155 | - If archive is passed, restricted the results to the given archive, |
156 | - if it is suppressed the results will be restricted to the |
157 | - distribution 'main_archive'. |
158 | - """ |
159 | - |
160 | - def getSourcePackagePublishing(pocket, component, archive): |
161 | - """Return a selectResult of ISourcePackagePublishingHistory. |
162 | - |
163 | - According status and pocket. |
164 | - If archive is passed, restricted the results to the given archive, |
165 | - if it is suppressed the results will be restricted to the |
166 | - distribution 'main_archive'. |
167 | - """ |
168 | - |
169 | def searchPackages(text): |
170 | """Search through the package cache for this distroseries and return |
171 | DistroSeriesBinaryPackage objects that match the given text. |
172 | diff --git a/lib/lp/registry/model/distroseries.py b/lib/lp/registry/model/distroseries.py |
173 | index cc209a5..8c3d76c 100644 |
174 | --- a/lib/lp/registry/model/distroseries.py |
175 | +++ b/lib/lp/registry/model/distroseries.py |
176 | @@ -1,4 +1,4 @@ |
177 | -# Copyright 2009-2021 Canonical Ltd. This software is licensed under the |
178 | +# Copyright 2009-2022 Canonical Ltd. This software is licensed under the |
179 | # GNU Affero General Public License version 3 (see the file LICENSE). |
180 | |
181 | """Database classes for a distribution series.""" |
182 | @@ -12,10 +12,7 @@ __all__ = [ |
183 | |
184 | import collections |
185 | from io import BytesIO |
186 | -from operator import ( |
187 | - attrgetter, |
188 | - itemgetter, |
189 | - ) |
190 | +from operator import itemgetter |
191 | |
192 | import apt_pkg |
193 | from lazr.delegates import delegate_to |
194 | @@ -86,10 +83,6 @@ from lp.registry.model.person import Person |
195 | from lp.registry.model.series import SeriesMixin |
196 | from lp.registry.model.sourcepackage import SourcePackage |
197 | from lp.registry.model.sourcepackagename import SourcePackageName |
198 | -from lp.services.database.bulk import ( |
199 | - load_referencing, |
200 | - load_related, |
201 | - ) |
202 | from lp.services.database.constants import ( |
203 | DEFAULT, |
204 | UTC_NOW, |
205 | @@ -116,10 +109,7 @@ from lp.services.database.stormexpr import ( |
206 | IsTrue, |
207 | ) |
208 | from lp.services.librarian.interfaces import ILibraryFileAliasSet |
209 | -from lp.services.librarian.model import ( |
210 | - LibraryFileAlias, |
211 | - LibraryFileContent, |
212 | - ) |
213 | +from lp.services.librarian.model import LibraryFileAlias |
214 | from lp.services.mail.signedmessage import signed_message_from_bytes |
215 | from lp.services.propertycache import ( |
216 | cachedproperty, |
217 | @@ -146,9 +136,7 @@ from lp.soyuz.interfaces.queue import ( |
218 | from lp.soyuz.interfaces.sourcepackageformat import ( |
219 | ISourcePackageFormatSelectionSet, |
220 | ) |
221 | -from lp.soyuz.model.binarypackagebuild import BinaryPackageBuild |
222 | from lp.soyuz.model.binarypackagename import BinaryPackageName |
223 | -from lp.soyuz.model.binarypackagerelease import BinaryPackageRelease |
224 | from lp.soyuz.model.component import Component |
225 | from lp.soyuz.model.distributionsourcepackagerelease import ( |
226 | DistributionSourcePackageRelease, |
227 | @@ -159,10 +147,6 @@ from lp.soyuz.model.distroarchseries import ( |
228 | ) |
229 | from lp.soyuz.model.distroseriesbinarypackage import DistroSeriesBinaryPackage |
230 | from lp.soyuz.model.distroseriespackagecache import DistroSeriesPackageCache |
231 | -from lp.soyuz.model.files import ( |
232 | - BinaryPackageFile, |
233 | - SourcePackageReleaseFile, |
234 | - ) |
235 | from lp.soyuz.model.publishing import ( |
236 | BinaryPackagePublishingHistory, |
237 | get_current_source_releases, |
238 | @@ -173,7 +157,6 @@ from lp.soyuz.model.queue import ( |
239 | PackageUploadQueue, |
240 | PackageUploadSource, |
241 | ) |
242 | -from lp.soyuz.model.section import Section |
243 | from lp.soyuz.model.sourcepackagerelease import SourcePackageRelease |
244 | from lp.translations.enums import LanguagePackType |
245 | from lp.translations.model.distroserieslanguage import ( |
246 | @@ -1067,80 +1050,6 @@ class DistroSeries(SQLBase, BugTargetBase, HasSpecificationsMixin, |
247 | """See `IDistroSeries`.""" |
248 | return self._getAllBinaries().find(scheduleddeletiondate=None) |
249 | |
250 | - def getSourcePackagePublishing(self, pocket, component, archive): |
251 | - """See `IDistroSeries`.""" |
252 | - spphs = Store.of(self).find( |
253 | - SourcePackagePublishingHistory, |
254 | - SourcePackagePublishingHistory.archive == archive, |
255 | - SourcePackagePublishingHistory.distroseries == self, |
256 | - SourcePackagePublishingHistory.pocket == pocket, |
257 | - SourcePackagePublishingHistory.component == component, |
258 | - SourcePackagePublishingHistory.status == |
259 | - PackagePublishingStatus.PUBLISHED, |
260 | - SourcePackagePublishingHistory.sourcepackagename == |
261 | - SourcePackageName.id).order_by(SourcePackageName.name) |
262 | - |
263 | - def eager_load(spphs): |
264 | - # Preload everything which will be used by archivepublisher's |
265 | - # build_source_stanza_fields. |
266 | - load_related(Section, spphs, ["sectionID"]) |
267 | - sprs = load_related( |
268 | - SourcePackageRelease, spphs, ["sourcepackagereleaseID"]) |
269 | - load_related(SourcePackageName, sprs, ["sourcepackagenameID"]) |
270 | - spr_ids = set(map(attrgetter("id"), sprs)) |
271 | - sprfs = list(Store.of(self).find( |
272 | - SourcePackageReleaseFile, |
273 | - SourcePackageReleaseFile.sourcepackagereleaseID.is_in( |
274 | - spr_ids)).order_by(SourcePackageReleaseFile.libraryfileID)) |
275 | - file_map = collections.defaultdict(list) |
276 | - for sprf in sprfs: |
277 | - file_map[sprf.sourcepackagerelease].append(sprf) |
278 | - for spr, files in file_map.items(): |
279 | - get_property_cache(spr).files = files |
280 | - lfas = load_related(LibraryFileAlias, sprfs, ["libraryfileID"]) |
281 | - load_related(LibraryFileContent, lfas, ["contentID"]) |
282 | - |
283 | - return DecoratedResultSet(spphs, pre_iter_hook=eager_load) |
284 | - |
285 | - def getBinaryPackagePublishing(self, archtag, pocket, component, archive): |
286 | - """See `IDistroSeries`.""" |
287 | - bpphs = Store.of(self).find( |
288 | - BinaryPackagePublishingHistory, |
289 | - DistroArchSeries.distroseries == self, |
290 | - DistroArchSeries.architecturetag == archtag, |
291 | - BinaryPackagePublishingHistory.archive == archive, |
292 | - BinaryPackagePublishingHistory.distroarchseries == |
293 | - DistroArchSeries.id, |
294 | - BinaryPackagePublishingHistory.pocket == pocket, |
295 | - BinaryPackagePublishingHistory.component == component, |
296 | - BinaryPackagePublishingHistory.status == |
297 | - PackagePublishingStatus.PUBLISHED, |
298 | - BinaryPackagePublishingHistory.binarypackagename == |
299 | - BinaryPackageName.id).order_by(BinaryPackageName.name) |
300 | - |
301 | - def eager_load(bpphs): |
302 | - # Preload everything which will be used by archivepublisher's |
303 | - # build_binary_stanza_fields. |
304 | - load_related(Section, bpphs, ["sectionID"]) |
305 | - bprs = load_related( |
306 | - BinaryPackageRelease, bpphs, ["binarypackagereleaseID"]) |
307 | - bpbs = load_related(BinaryPackageBuild, bprs, ["buildID"]) |
308 | - sprs = load_related( |
309 | - SourcePackageRelease, bpbs, ["source_package_release_id"]) |
310 | - bpfs = load_referencing( |
311 | - BinaryPackageFile, bprs, ["binarypackagereleaseID"]) |
312 | - file_map = collections.defaultdict(list) |
313 | - for bpf in bpfs: |
314 | - file_map[bpf.binarypackagerelease].append(bpf) |
315 | - for bpr, files in file_map.items(): |
316 | - get_property_cache(bpr).files = files |
317 | - lfas = load_related(LibraryFileAlias, bpfs, ["libraryfileID"]) |
318 | - load_related(LibraryFileContent, lfas, ["contentID"]) |
319 | - load_related(SourcePackageName, sprs, ["sourcepackagenameID"]) |
320 | - load_related(BinaryPackageName, bprs, ["binarypackagenameID"]) |
321 | - |
322 | - return DecoratedResultSet(bpphs, pre_iter_hook=eager_load) |
323 | - |
324 | def getBuildRecords(self, build_state=None, name=None, pocket=None, |
325 | arch_tag=None, user=None, binary_only=True): |
326 | """See IHasBuildRecords""" |
327 | diff --git a/lib/lp/registry/tests/test_distroseries.py b/lib/lp/registry/tests/test_distroseries.py |
328 | index f076ecd..a46cdcd 100644 |
329 | --- a/lib/lp/registry/tests/test_distroseries.py |
330 | +++ b/lib/lp/registry/tests/test_distroseries.py |
331 | @@ -1,4 +1,4 @@ |
332 | -# Copyright 2009-2021 Canonical Ltd. This software is licensed under the |
333 | +# Copyright 2009-2022 Canonical Ltd. This software is licensed under the |
334 | # GNU Affero General Public License version 3 (see the file LICENSE). |
335 | |
336 | """Tests for distroseries.""" |
337 | @@ -7,7 +7,6 @@ __all__ = [ |
338 | 'CurrentSourceReleasesMixin', |
339 | ] |
340 | |
341 | -from functools import partial |
342 | import json |
343 | |
344 | from testtools.matchers import Equals |
345 | @@ -16,10 +15,6 @@ from zope.component import getUtility |
346 | from zope.security.proxy import removeSecurityProxy |
347 | |
348 | from lp.app.interfaces.launchpad import ILaunchpadCelebrities |
349 | -from lp.archivepublisher.indices import ( |
350 | - build_binary_stanza_fields, |
351 | - build_source_stanza_fields, |
352 | - ) |
353 | from lp.registry.errors import NoSuchDistroSeries |
354 | from lp.registry.interfaces.distroseries import IDistroSeriesSet |
355 | from lp.registry.interfaces.pocket import PackagePublishingPocket |
356 | @@ -46,7 +41,6 @@ from lp.testing import ( |
357 | api_url, |
358 | login, |
359 | person_logged_in, |
360 | - record_two_runs, |
361 | StormStatementRecorder, |
362 | TestCase, |
363 | TestCaseWithFactory, |
364 | @@ -584,47 +578,6 @@ class TestDistroSeriesPackaging(TestCaseWithFactory): |
365 | expected = ['translatable', 'linked', 'importabletranslatable'] |
366 | self.assertEqual(expected, names) |
367 | |
368 | - def test_getSourcePackagePublishing_query_count(self): |
369 | - # Check that the number of queries required to publish source |
370 | - # packages is constant in the number of source packages. |
371 | - def get_index_stanzas(): |
372 | - for spp in self.series.getSourcePackagePublishing( |
373 | - PackagePublishingPocket.RELEASE, self.universe_component, |
374 | - self.series.main_archive): |
375 | - build_source_stanza_fields( |
376 | - spp.sourcepackagerelease, spp.component, spp.section) |
377 | - |
378 | - recorder1, recorder2 = record_two_runs( |
379 | - get_index_stanzas, |
380 | - partial( |
381 | - self.makeSeriesPackage, pocket=PackagePublishingPocket.RELEASE, |
382 | - status=PackagePublishingStatus.PUBLISHED), |
383 | - 5, 5) |
384 | - self.assertThat(recorder1, HasQueryCount(Equals(11))) |
385 | - self.assertThat(recorder2, HasQueryCount.byEquality(recorder1)) |
386 | - |
387 | - def test_getBinaryPackagePublishing_query_count(self): |
388 | - # Check that the number of queries required to publish binary |
389 | - # packages is constant in the number of binary packages. |
390 | - def get_index_stanzas(das): |
391 | - for bpp in self.series.getBinaryPackagePublishing( |
392 | - das.architecturetag, PackagePublishingPocket.RELEASE, |
393 | - self.universe_component, self.series.main_archive): |
394 | - build_binary_stanza_fields( |
395 | - bpp.binarypackagerelease, bpp.component, bpp.section, |
396 | - bpp.priority, bpp.phased_update_percentage, False) |
397 | - |
398 | - das = self.factory.makeDistroArchSeries(distroseries=self.series) |
399 | - recorder1, recorder2 = record_two_runs( |
400 | - partial(get_index_stanzas, das), |
401 | - partial( |
402 | - self.makeSeriesBinaryPackage, das=das, |
403 | - pocket=PackagePublishingPocket.RELEASE, |
404 | - status=PackagePublishingStatus.PUBLISHED), |
405 | - 5, 5) |
406 | - self.assertThat(recorder1, HasQueryCount(Equals(15))) |
407 | - self.assertThat(recorder2, HasQueryCount.byEquality(recorder1)) |
408 | - |
409 | |
410 | class TestDistroSeriesWebservice(TestCaseWithFactory): |
411 | |
412 | diff --git a/lib/lp/soyuz/interfaces/publishing.py b/lib/lp/soyuz/interfaces/publishing.py |
413 | index a1d5dc2..874d1a1 100644 |
414 | --- a/lib/lp/soyuz/interfaces/publishing.py |
415 | +++ b/lib/lp/soyuz/interfaces/publishing.py |
416 | @@ -1,4 +1,4 @@ |
417 | -# Copyright 2009-2020 Canonical Ltd. This software is licensed under the |
418 | +# Copyright 2009-2022 Canonical Ltd. This software is licensed under the |
419 | # GNU Affero General Public License version 3 (see the file LICENSE). |
420 | |
421 | """Publishing interfaces.""" |
422 | @@ -1133,6 +1133,32 @@ class IPublishingSet(Interface): |
423 | release in the given `archive`, `distroseries`, and `pocket`. |
424 | """ |
425 | |
426 | + def getSourcesForPublishing(archive, distroseries, pocket, component): |
427 | + """Get source publications which are published in a given context. |
428 | + |
429 | + :param archive: The `Archive` to search. |
430 | + :param distroseries: The `DistroSeries` to search. |
431 | + :param pocket: The `PackagePublishingPocket` to search. |
432 | + :param component: The `Component` to search. |
433 | + :return: A result set of `SourcePackagePublishingHistory` objects in |
434 | + the given context and with the `PUBLISHED` status, ordered by |
435 | + source package name, with associated publisher-relevant objects |
436 | + preloaded. |
437 | + """ |
438 | + |
439 | + def getBinariesForPublishing(archive, distroarchseries, pocket, component): |
440 | + """Get binary publications which are published in a given context. |
441 | + |
442 | + :param archive: The `Archive` to search. |
443 | + :param distroarchseries: The `DistroArchSeries` to search. |
444 | + :param pocket: The `PackagePublishingPocket` to search. |
445 | + :param component: The `Component` to search. |
446 | + :return: A result set of `BinaryPackagePublishingHistory` objects in |
447 | + the given context and with the `PUBLISHED` status, ordered by |
448 | + binary package name, with associated publisher-relevant objects |
449 | + preloaded. |
450 | + """ |
451 | + |
452 | def getChangesFilesForSources(one_or_more_source_publications): |
453 | """Return all changesfiles for each given source publication. |
454 | |
455 | diff --git a/lib/lp/soyuz/model/publishing.py b/lib/lp/soyuz/model/publishing.py |
456 | index 421e649..ea0b012 100644 |
457 | --- a/lib/lp/soyuz/model/publishing.py |
458 | +++ b/lib/lp/soyuz/model/publishing.py |
459 | @@ -1,4 +1,4 @@ |
460 | -# Copyright 2009-2020 Canonical Ltd. This software is licensed under the |
461 | +# Copyright 2009-2022 Canonical Ltd. This software is licensed under the |
462 | # GNU Affero General Public License version 3 (see the file LICENSE). |
463 | |
464 | __all__ = [ |
465 | @@ -45,6 +45,7 @@ from lp.app.errors import NotFoundError |
466 | from lp.buildmaster.enums import BuildStatus |
467 | from lp.registry.interfaces.person import validate_public_person |
468 | from lp.registry.interfaces.pocket import PackagePublishingPocket |
469 | +from lp.registry.model.sourcepackagename import SourcePackageName |
470 | from lp.services.database import bulk |
471 | from lp.services.database.constants import UTC_NOW |
472 | from lp.services.database.datetimecol import UtcDateTimeCol |
473 | @@ -112,6 +113,7 @@ from lp.soyuz.model.files import ( |
474 | BinaryPackageFile, |
475 | SourcePackageReleaseFile, |
476 | ) |
477 | +from lp.soyuz.model.section import Section |
478 | from lp.soyuz.model.sourcepackagerelease import SourcePackageRelease |
479 | |
480 | |
481 | @@ -1511,6 +1513,81 @@ class PublishingSet: |
482 | active_publishing_status), |
483 | BinaryPackageRelease.architecturespecific == True) |
484 | |
485 | + def getSourcesForPublishing(self, archive, distroseries, pocket, |
486 | + component): |
487 | + """See `IPublishingSet`.""" |
488 | + spphs = IStore(SourcePackagePublishingHistory).find( |
489 | + SourcePackagePublishingHistory, |
490 | + SourcePackagePublishingHistory.archive == archive, |
491 | + SourcePackagePublishingHistory.distroseries == distroseries, |
492 | + SourcePackagePublishingHistory.pocket == pocket, |
493 | + SourcePackagePublishingHistory.component == component, |
494 | + SourcePackagePublishingHistory.status == |
495 | + PackagePublishingStatus.PUBLISHED, |
496 | + SourcePackagePublishingHistory.sourcepackagename == |
497 | + SourcePackageName.id).order_by(SourcePackageName.name) |
498 | + |
499 | + def eager_load(spphs): |
500 | + # Preload everything which will be used by archivepublisher's |
501 | + # build_source_stanza_fields. |
502 | + bulk.load_related(Section, spphs, ["sectionID"]) |
503 | + sprs = bulk.load_related( |
504 | + SourcePackageRelease, spphs, ["sourcepackagereleaseID"]) |
505 | + bulk.load_related(SourcePackageName, sprs, ["sourcepackagenameID"]) |
506 | + spr_ids = set(map(attrgetter("id"), sprs)) |
507 | + sprfs = list(IStore(SourcePackageReleaseFile).find( |
508 | + SourcePackageReleaseFile, |
509 | + SourcePackageReleaseFile.sourcepackagereleaseID.is_in( |
510 | + spr_ids)).order_by(SourcePackageReleaseFile.libraryfileID)) |
511 | + file_map = defaultdict(list) |
512 | + for sprf in sprfs: |
513 | + file_map[sprf.sourcepackagerelease].append(sprf) |
514 | + for spr, files in file_map.items(): |
515 | + get_property_cache(spr).files = files |
516 | + lfas = bulk.load_related( |
517 | + LibraryFileAlias, sprfs, ["libraryfileID"]) |
518 | + bulk.load_related(LibraryFileContent, lfas, ["contentID"]) |
519 | + |
520 | + return DecoratedResultSet(spphs, pre_iter_hook=eager_load) |
521 | + |
522 | + def getBinariesForPublishing(self, archive, distroarchseries, pocket, |
523 | + component): |
524 | + """See `IPublishingSet`.""" |
525 | + bpphs = IStore(BinaryPackagePublishingHistory).find( |
526 | + BinaryPackagePublishingHistory, |
527 | + BinaryPackagePublishingHistory.archive == archive, |
528 | + BinaryPackagePublishingHistory.distroarchseries == |
529 | + distroarchseries, |
530 | + BinaryPackagePublishingHistory.pocket == pocket, |
531 | + BinaryPackagePublishingHistory.component == component, |
532 | + BinaryPackagePublishingHistory.status == |
533 | + PackagePublishingStatus.PUBLISHED, |
534 | + BinaryPackagePublishingHistory.binarypackagename == |
535 | + BinaryPackageName.id).order_by(BinaryPackageName.name) |
536 | + |
537 | + def eager_load(bpphs): |
538 | + # Preload everything which will be used by archivepublisher's |
539 | + # build_binary_stanza_fields. |
540 | + bulk.load_related(Section, bpphs, ["sectionID"]) |
541 | + bprs = bulk.load_related( |
542 | + BinaryPackageRelease, bpphs, ["binarypackagereleaseID"]) |
543 | + bpbs = bulk.load_related(BinaryPackageBuild, bprs, ["buildID"]) |
544 | + sprs = bulk.load_related( |
545 | + SourcePackageRelease, bpbs, ["source_package_release_id"]) |
546 | + bpfs = bulk.load_referencing( |
547 | + BinaryPackageFile, bprs, ["binarypackagereleaseID"]) |
548 | + file_map = defaultdict(list) |
549 | + for bpf in bpfs: |
550 | + file_map[bpf.binarypackagerelease].append(bpf) |
551 | + for bpr, files in file_map.items(): |
552 | + get_property_cache(bpr).files = files |
553 | + lfas = bulk.load_related(LibraryFileAlias, bpfs, ["libraryfileID"]) |
554 | + bulk.load_related(LibraryFileContent, lfas, ["contentID"]) |
555 | + bulk.load_related(SourcePackageName, sprs, ["sourcepackagenameID"]) |
556 | + bulk.load_related(BinaryPackageName, bprs, ["binarypackagenameID"]) |
557 | + |
558 | + return DecoratedResultSet(bpphs, pre_iter_hook=eager_load) |
559 | + |
560 | def getChangesFilesForSources(self, one_or_more_source_publications): |
561 | """See `IPublishingSet`.""" |
562 | # Avoid circular imports. |
563 | diff --git a/lib/lp/soyuz/tests/test_publishing.py b/lib/lp/soyuz/tests/test_publishing.py |
564 | index fbb19f0..d645ef8 100644 |
565 | --- a/lib/lp/soyuz/tests/test_publishing.py |
566 | +++ b/lib/lp/soyuz/tests/test_publishing.py |
567 | @@ -1,9 +1,10 @@ |
568 | -# Copyright 2009-2020 Canonical Ltd. This software is licensed under the |
569 | +# Copyright 2009-2022 Canonical Ltd. This software is licensed under the |
570 | # GNU Affero General Public License version 3 (see the file LICENSE). |
571 | |
572 | """Test native publication workflow for Soyuz. """ |
573 | |
574 | import datetime |
575 | +from functools import partial |
576 | import io |
577 | import operator |
578 | import os |
579 | @@ -20,6 +21,10 @@ from zope.security.proxy import removeSecurityProxy |
580 | from lp.app.errors import NotFoundError |
581 | from lp.archivepublisher.config import getPubConfig |
582 | from lp.archivepublisher.diskpool import DiskPool |
583 | +from lp.archivepublisher.indices import ( |
584 | + build_binary_stanza_fields, |
585 | + build_source_stanza_fields, |
586 | + ) |
587 | from lp.buildmaster.enums import BuildStatus |
588 | from lp.buildmaster.interfaces.processor import IProcessorSet |
589 | from lp.registry.interfaces.distribution import IDistributionSet |
590 | @@ -1029,6 +1034,176 @@ class TestPublishingSetLite(TestCaseWithFactory): |
591 | "override the corresponding deb instead.", |
592 | debug_bpph.changeOverride, new_phased_update_percentage=20) |
593 | |
594 | + def makePublishedSourcePackage(self, series, pocket=None, status=None): |
595 | + # Make a published source package. |
596 | + name = self.factory.getUniqueUnicode() |
597 | + sourcepackagename = self.factory.makeSourcePackageName(name) |
598 | + component = getUtility(IComponentSet)["universe"] |
599 | + spph = self.factory.makeSourcePackagePublishingHistory( |
600 | + sourcepackagename=sourcepackagename, distroseries=series, |
601 | + component=component, pocket=pocket, status=status) |
602 | + source_package = self.factory.makeSourcePackage( |
603 | + sourcepackagename=spph.sourcepackagename, distroseries=series) |
604 | + spr = spph.sourcepackagerelease |
605 | + for extension in ("dsc", "tar.gz"): |
606 | + filename = "%s_%s.%s" % (spr.name, spr.version, extension) |
607 | + spr.addFile(self.factory.makeLibraryFileAlias( |
608 | + filename=filename, db_only=True)) |
609 | + return source_package |
610 | + |
611 | + def test_getSourcesForPublishing(self): |
612 | + # PublisherSet.getSourcesForPublishing returns all the ISPPH records |
613 | + # in a given publishing context. It is used as part of publishing |
614 | + # some types of archives. |
615 | + # XXX cjwatson 2022-03-28: Detach test from sampledata. |
616 | + ubuntu = getUtility(IDistributionSet)["ubuntu"] |
617 | + hoary = ubuntu["hoary"] |
618 | + component_main = getUtility(IComponentSet)["main"] |
619 | + component_multiverse = getUtility(IComponentSet)["multiverse"] |
620 | + debian_archive = getUtility(IDistributionSet)["debian"].main_archive |
621 | + publishing_set = getUtility(IPublishingSet) |
622 | + |
623 | + spphs = publishing_set.getSourcesForPublishing( |
624 | + archive=hoary.main_archive, distroseries=hoary, |
625 | + pocket=PackagePublishingPocket.RELEASE, component=component_main) |
626 | + self.assertEqual(6, spphs.count()) |
627 | + self.assertContentEqual( |
628 | + ["alsa-utils", "evolution", "libstdc++", "linux-source-2.6.15", |
629 | + "netapplet", "pmount"], |
630 | + {spph.sourcepackagerelease.name for spph in spphs}) |
631 | + self.assertEqual( |
632 | + 0, |
633 | + publishing_set.getSourcesForPublishing( |
634 | + archive=hoary.main_archive, distroseries=hoary, |
635 | + pocket=PackagePublishingPocket.RELEASE, |
636 | + component=component_multiverse).count()) |
637 | + self.assertEqual( |
638 | + 0, |
639 | + publishing_set.getSourcesForPublishing( |
640 | + archive=hoary.main_archive, distroseries=hoary, |
641 | + pocket=PackagePublishingPocket.BACKPORTS, |
642 | + component=component_main).count()) |
643 | + self.assertEqual( |
644 | + 0, |
645 | + publishing_set.getSourcesForPublishing( |
646 | + archive=debian_archive, distroseries=hoary, |
647 | + pocket=PackagePublishingPocket.RELEASE, |
648 | + component=component_main).count()) |
649 | + |
650 | + def test_getSourcesForPublishing_query_count(self): |
651 | + # Check that the number of queries required to publish source |
652 | + # packages is constant in the number of source packages. |
653 | + series = self.factory.makeDistroSeries() |
654 | + archive = series.main_archive |
655 | + component_universe = getUtility(IComponentSet)["universe"] |
656 | + |
657 | + def get_index_stanzas(): |
658 | + for spp in getUtility(IPublishingSet).getSourcesForPublishing( |
659 | + archive=archive, distroseries=series, |
660 | + pocket=PackagePublishingPocket.RELEASE, |
661 | + component=component_universe): |
662 | + build_source_stanza_fields( |
663 | + spp.sourcepackagerelease, spp.component, spp.section) |
664 | + |
665 | + recorder1, recorder2 = record_two_runs( |
666 | + get_index_stanzas, |
667 | + partial( |
668 | + self.makePublishedSourcePackage, series=series, |
669 | + pocket=PackagePublishingPocket.RELEASE, |
670 | + status=PackagePublishingStatus.PUBLISHED), |
671 | + 5, 5) |
672 | + self.assertThat(recorder1, HasQueryCount(Equals(8))) |
673 | + self.assertThat(recorder2, HasQueryCount.byEquality(recorder1)) |
674 | + |
675 | + def makePublishedBinaryPackage(self, das, pocket=None, status=None): |
676 | + # Make a published binary package. |
677 | + source = self.makePublishedSourcePackage( |
678 | + das.distroseries, pocket=pocket, status=status) |
679 | + spr = source.distinctreleases[0] |
680 | + binarypackagename = self.factory.makeBinaryPackageName(source.name) |
681 | + bpph = self.factory.makeBinaryPackagePublishingHistory( |
682 | + binarypackagename=binarypackagename, distroarchseries=das, |
683 | + component=spr.component, section_name=spr.section.name, |
684 | + status=status, pocket=pocket, source_package_release=spr) |
685 | + bpr = bpph.binarypackagerelease |
686 | + filename = "%s_%s_%s.deb" % ( |
687 | + bpr.name, bpr.version, das.architecturetag) |
688 | + bpr.addFile(self.factory.makeLibraryFileAlias( |
689 | + filename=filename, db_only=True)) |
690 | + return bpph |
691 | + |
692 | + def test_getBinariesForPublishing(self): |
693 | + # PublisherSet.getBinariesForPublishing returns all the IBPPH |
694 | + # records in a given publishing context. It is used as part of |
695 | + # publishing some types of archives. |
696 | + # XXX cjwatson 2022-03-28: Detach test from sampledata. |
697 | + ubuntu = getUtility(IDistributionSet)["ubuntu"] |
698 | + warty = ubuntu["warty"] |
699 | + warty_i386 = warty["i386"] |
700 | + warty_another = self.factory.makeDistroArchSeries(distroseries=warty) |
701 | + component_main = getUtility(IComponentSet)["main"] |
702 | + component_multiverse = getUtility(IComponentSet)["multiverse"] |
703 | + debian_archive = getUtility(IDistributionSet)["debian"].main_archive |
704 | + publishing_set = getUtility(IPublishingSet) |
705 | + |
706 | + bpphs = publishing_set.getBinariesForPublishing( |
707 | + archive=warty.main_archive, distroarchseries=warty_i386, |
708 | + pocket=PackagePublishingPocket.RELEASE, component=component_main) |
709 | + self.assertEqual(8, bpphs.count()) |
710 | + self.assertIn( |
711 | + "mozilla-firefox", |
712 | + {bpph.binarypackagerelease.name for bpph in bpphs}) |
713 | + self.assertEqual( |
714 | + 0, |
715 | + publishing_set.getBinariesForPublishing( |
716 | + archive=warty.main_archive, distroarchseries=warty_another, |
717 | + pocket=PackagePublishingPocket.RELEASE, |
718 | + component=component_main).count()) |
719 | + self.assertEqual( |
720 | + 0, |
721 | + publishing_set.getBinariesForPublishing( |
722 | + archive=warty.main_archive, distroarchseries=warty_i386, |
723 | + pocket=PackagePublishingPocket.RELEASE, |
724 | + component=component_multiverse).count()) |
725 | + self.assertEqual( |
726 | + 0, |
727 | + publishing_set.getBinariesForPublishing( |
728 | + archive=warty.main_archive, distroarchseries=warty_i386, |
729 | + pocket=PackagePublishingPocket.BACKPORTS, |
730 | + component=component_main).count()) |
731 | + self.assertEqual( |
732 | + 0, |
733 | + publishing_set.getBinariesForPublishing( |
734 | + archive=debian_archive, distroarchseries=warty_i386, |
735 | + pocket=PackagePublishingPocket.RELEASE, |
736 | + component=component_main).count()) |
737 | + |
738 | + def test_getBinariesForPublishing_query_count(self): |
739 | + # Check that the number of queries required to publish binary |
740 | + # packages is constant in the number of binary packages. |
741 | + das = self.factory.makeDistroArchSeries() |
742 | + archive = das.main_archive |
743 | + component_universe = getUtility(IComponentSet)["universe"] |
744 | + |
745 | + def get_index_stanzas(): |
746 | + for bpp in getUtility(IPublishingSet).getBinariesForPublishing( |
747 | + archive=archive, distroarchseries=das, |
748 | + pocket=PackagePublishingPocket.RELEASE, |
749 | + component=component_universe): |
750 | + build_binary_stanza_fields( |
751 | + bpp.binarypackagerelease, bpp.component, bpp.section, |
752 | + bpp.priority, bpp.phased_update_percentage, False) |
753 | + |
754 | + recorder1, recorder2 = record_two_runs( |
755 | + get_index_stanzas, |
756 | + partial( |
757 | + self.makePublishedBinaryPackage, das=das, |
758 | + pocket=PackagePublishingPocket.RELEASE, |
759 | + status=PackagePublishingStatus.PUBLISHED), |
760 | + 5, 5) |
761 | + self.assertThat(recorder1, HasQueryCount(Equals(11))) |
762 | + self.assertThat(recorder2, HasQueryCount.byEquality(recorder1)) |
763 | + |
764 | |
765 | class TestSourceDomination(TestNativePublishingBase): |
766 | """Test SourcePackagePublishingHistory.supersede() operates correctly.""" |