Merge ~cjwatson/launchpad:move-publishing-queries into launchpad: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)
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.getSourcePackagePublishing` and `DistroSeries.getBinaryPackagePublishing` was a historical anomaly, as this sort of publishing-specific code should live in `lp.soyuz` or `lp.archivepublisher`. Move these to the more appropriate `PublishingSet.getSourcesForPublishing` and `PublishingSet.getBinariesForPublishing`.

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
diff --git a/lib/lp/archivepublisher/publishing.py b/lib/lp/archivepublisher/publishing.py
index a5a0cc4..e280b79 100644
--- a/lib/lp/archivepublisher/publishing.py
+++ b/lib/lp/archivepublisher/publishing.py
@@ -1,4 +1,4 @@
1# Copyright 2009-2021 Canonical Ltd. This software is licensed under the1# Copyright 2009-2022 Canonical Ltd. This software is licensed under the
2# GNU Affero General Public License version 3 (see the file LICENSE).2# GNU Affero General Public License version 3 (see the file LICENSE).
33
4__all__ = [4__all__ = [
@@ -910,8 +910,9 @@ class Publisher:
910 get_sources_path(self._config, suite_name, component),910 get_sources_path(self._config, suite_name, component),
911 self._config.temproot, distroseries.index_compressors)911 self._config.temproot, distroseries.index_compressors)
912912
913 for spp in distroseries.getSourcePackagePublishing(913 for spp in getUtility(IPublishingSet).getSourcesForPublishing(
914 pocket, component, self.archive):914 archive=self.archive, distroseries=distroseries, pocket=pocket,
915 component=component):
915 stanza = build_source_stanza_fields(916 stanza = build_source_stanza_fields(
916 spp.sourcepackagerelease, spp.component, spp.section)917 spp.sourcepackagerelease, spp.component, spp.section)
917 source_index.write(stanza.makeOutput().encode('utf-8') + b'\n\n')918 source_index.write(stanza.makeOutput().encode('utf-8') + b'\n\n')
@@ -937,8 +938,9 @@ class Publisher:
937 self._config, suite_name, component, arch, subcomp),938 self._config, suite_name, component, arch, subcomp),
938 self._config.temproot, distroseries.index_compressors)939 self._config.temproot, distroseries.index_compressors)
939940
940 for bpp in distroseries.getBinaryPackagePublishing(941 for bpp in getUtility(IPublishingSet).getBinariesForPublishing(
941 arch.architecturetag, pocket, component, self.archive):942 archive=self.archive, distroarchseries=arch, pocket=pocket,
943 component=component):
942 subcomp = FORMAT_TO_SUBCOMPONENT.get(944 subcomp = FORMAT_TO_SUBCOMPONENT.get(
943 bpp.binarypackagerelease.binpackageformat)945 bpp.binarypackagerelease.binpackageformat)
944 if subcomp not in indices:946 if subcomp not in indices:
diff --git a/lib/lp/registry/doc/distroseries.txt b/lib/lp/registry/doc/distroseries.txt
index 7d202f5..82a8ff8 100644
--- a/lib/lp/registry/doc/distroseries.txt
+++ b/lib/lp/registry/doc/distroseries.txt
@@ -232,7 +232,6 @@ other things) the uploader for validating incoming uploads.
232 devel232 devel
233 translations233 translations
234234
235 >>> from lp.soyuz.interfaces.component import IComponentSet
236 >>> from lp.soyuz.interfaces.section import ISectionSet235 >>> from lp.soyuz.interfaces.section import ISectionSet
237 >>> python = getUtility(ISectionSet).ensure('python')236 >>> python = getUtility(ISectionSet).ensure('python')
238237
@@ -490,50 +489,9 @@ upstream.
490SourcePackagePublishingHistory489SourcePackagePublishingHistory
491------------------------------490------------------------------
492491
493IDistroSeries.getSourcePackagePublishing returns all the ISPPH
494records for a given status in a given pocket. It makes easy to
495generate a list of currently published sources for override-check, for
496instance. it can also be used to generate the archive packages list in
497the future.
498
499 >>> ubuntu = getUtility(IDistributionSet)['ubuntu']
500 >>> hoary = ubuntu['hoary']
501 >>> component_main = getUtility(IComponentSet)['main']
502 >>> component_multiverse = getUtility(IComponentSet)['multiverse']
503 >>> debian_archive = getUtility(IDistributionSet)['debian'].main_archive
504
505 >>> spphs = hoary.getSourcePackagePublishing(
506 ... PackagePublishingPocket.RELEASE, component_main,
507 ... warty.main_archive)
508 >>> spphs.count()
509 6
510 >>> for name in sorted(set(
511 ... pkgpub.sourcepackagerelease.sourcepackagename.name
512 ... for pkgpub in spphs)):
513 ... print(name)
514 alsa-utils
515 evolution
516 libstdc++
517 linux-source-2.6.15
518 netapplet
519 pmount
520 >>> hoary.getSourcePackagePublishing(
521 ... PackagePublishingPocket.RELEASE, component_multiverse,
522 ... hoary.main_archive).count()
523 0
524 >>> hoary.getSourcePackagePublishing(
525 ... PackagePublishingPocket.BACKPORTS, component_main,
526 ... hoary.main_archive).count()
527 0
528 >>> hoary.getSourcePackagePublishing(
529 ... PackagePublishingPocket.RELEASE, component_main,
530 ... debian_archive).count()
531 0
532
533ISPP.getPublishedBinaries returns all the binaries generated by the492ISPP.getPublishedBinaries returns all the binaries generated by the
534publication in question:493publication in question:
535494
536 >>> warty = ubuntu['warty']
537 >>> warty_pub_source = warty.main_archive.getPublishedSources(495 >>> warty_pub_source = warty.main_archive.getPublishedSources(
538 ... distroseries=warty, name=u'mozilla-firefox',496 ... distroseries=warty, name=u'mozilla-firefox',
539 ... status=PackagePublishingStatus.PUBLISHED).one()497 ... status=PackagePublishingStatus.PUBLISHED).one()
@@ -566,36 +524,6 @@ publication in question:
566 >>> print(warty_mozilla_pub_bin.section.name)524 >>> print(warty_mozilla_pub_bin.section.name)
567 base525 base
568526
569DistroSeries.getBinaryPackagePublishing will return
570BinaryPackagePublishingHistory objects for the DistroSeries:
571
572 >>> warty = ubuntu['warty']
573 >>> bpphs = warty.getBinaryPackagePublishing(
574 ... "i386", PackagePublishingPocket.RELEASE, component_main,
575 ... warty.main_archive)
576 >>> bpphs.count()
577 8
578 >>> 'mozilla-firefox' in set(
579 ... pkgpub.binarypackagerelease.binarypackagename.name
580 ... for pkgpub in bpphs)
581 True
582 >>> warty.getBinaryPackagePublishing(
583 ... "nope", PackagePublishingPocket.RELEASE, component_main,
584 ... warty.main_archive).count()
585 0
586 >>> warty.getBinaryPackagePublishing(
587 ... "i386", PackagePublishingPocket.RELEASE, component_multiverse,
588 ... warty.main_archive).count()
589 0
590 >>> warty.getBinaryPackagePublishing(
591 ... "i386", PackagePublishingPocket.BACKPORTS, component_main,
592 ... warty.main_archive).count()
593 0
594 >>> warty.getBinaryPackagePublishing(
595 ... "i386", PackagePublishingPocket.RELEASE, component_main,
596 ... debian_archive).count()
597 0
598
599getAllPublishedSources will return all publications with status PUBLISHED527getAllPublishedSources will return all publications with status PUBLISHED
600and in the main archives for this distroseries:528and in the main archives for this distroseries:
601529
diff --git a/lib/lp/registry/interfaces/distroseries.py b/lib/lp/registry/interfaces/distroseries.py
index d8c6370..ac2959c 100644
--- a/lib/lp/registry/interfaces/distroseries.py
+++ b/lib/lp/registry/interfaces/distroseries.py
@@ -1,4 +1,4 @@
1# Copyright 2009-2021 Canonical Ltd. This software is licensed under the1# Copyright 2009-2022 Canonical Ltd. This software is licensed under the
2# GNU Affero General Public License version 3 (see the file LICENSE).2# GNU Affero General Public License version 3 (see the file LICENSE).
33
4"""Interfaces including and related to IDistroSeries."""4"""Interfaces including and related to IDistroSeries."""
@@ -729,26 +729,6 @@ class IDistroSeriesPublic(
729 def addSection(section):729 def addSection(section):
730 """SQLObject provided method to fill a related join key section."""730 """SQLObject provided method to fill a related join key section."""
731731
732 def getBinaryPackagePublishing(archtag, pocket, component, archive):
733 """Get BinaryPackagePublishings in a DistroSeries.
734
735 Can optionally restrict the results by architecturetag, pocket and/or
736 component.
737
738 If archive is passed, restricted the results to the given archive,
739 if it is suppressed the results will be restricted to the
740 distribution 'main_archive'.
741 """
742
743 def getSourcePackagePublishing(pocket, component, archive):
744 """Return a selectResult of ISourcePackagePublishingHistory.
745
746 According status and pocket.
747 If archive is passed, restricted the results to the given archive,
748 if it is suppressed the results will be restricted to the
749 distribution 'main_archive'.
750 """
751
752 def searchPackages(text):732 def searchPackages(text):
753 """Search through the package cache for this distroseries and return733 """Search through the package cache for this distroseries and return
754 DistroSeriesBinaryPackage objects that match the given text.734 DistroSeriesBinaryPackage objects that match the given text.
diff --git a/lib/lp/registry/model/distroseries.py b/lib/lp/registry/model/distroseries.py
index cc209a5..8c3d76c 100644
--- a/lib/lp/registry/model/distroseries.py
+++ b/lib/lp/registry/model/distroseries.py
@@ -1,4 +1,4 @@
1# Copyright 2009-2021 Canonical Ltd. This software is licensed under the1# Copyright 2009-2022 Canonical Ltd. This software is licensed under the
2# GNU Affero General Public License version 3 (see the file LICENSE).2# GNU Affero General Public License version 3 (see the file LICENSE).
33
4"""Database classes for a distribution series."""4"""Database classes for a distribution series."""
@@ -12,10 +12,7 @@ __all__ = [
1212
13import collections13import collections
14from io import BytesIO14from io import BytesIO
15from operator import (15from operator import itemgetter
16 attrgetter,
17 itemgetter,
18 )
1916
20import apt_pkg17import apt_pkg
21from lazr.delegates import delegate_to18from lazr.delegates import delegate_to
@@ -86,10 +83,6 @@ from lp.registry.model.person import Person
86from lp.registry.model.series import SeriesMixin83from lp.registry.model.series import SeriesMixin
87from lp.registry.model.sourcepackage import SourcePackage84from lp.registry.model.sourcepackage import SourcePackage
88from lp.registry.model.sourcepackagename import SourcePackageName85from lp.registry.model.sourcepackagename import SourcePackageName
89from lp.services.database.bulk import (
90 load_referencing,
91 load_related,
92 )
93from lp.services.database.constants import (86from lp.services.database.constants import (
94 DEFAULT,87 DEFAULT,
95 UTC_NOW,88 UTC_NOW,
@@ -116,10 +109,7 @@ from lp.services.database.stormexpr import (
116 IsTrue,109 IsTrue,
117 )110 )
118from lp.services.librarian.interfaces import ILibraryFileAliasSet111from lp.services.librarian.interfaces import ILibraryFileAliasSet
119from lp.services.librarian.model import (112from lp.services.librarian.model import LibraryFileAlias
120 LibraryFileAlias,
121 LibraryFileContent,
122 )
123from lp.services.mail.signedmessage import signed_message_from_bytes113from lp.services.mail.signedmessage import signed_message_from_bytes
124from lp.services.propertycache import (114from lp.services.propertycache import (
125 cachedproperty,115 cachedproperty,
@@ -146,9 +136,7 @@ from lp.soyuz.interfaces.queue import (
146from lp.soyuz.interfaces.sourcepackageformat import (136from lp.soyuz.interfaces.sourcepackageformat import (
147 ISourcePackageFormatSelectionSet,137 ISourcePackageFormatSelectionSet,
148 )138 )
149from lp.soyuz.model.binarypackagebuild import BinaryPackageBuild
150from lp.soyuz.model.binarypackagename import BinaryPackageName139from lp.soyuz.model.binarypackagename import BinaryPackageName
151from lp.soyuz.model.binarypackagerelease import BinaryPackageRelease
152from lp.soyuz.model.component import Component140from lp.soyuz.model.component import Component
153from lp.soyuz.model.distributionsourcepackagerelease import (141from lp.soyuz.model.distributionsourcepackagerelease import (
154 DistributionSourcePackageRelease,142 DistributionSourcePackageRelease,
@@ -159,10 +147,6 @@ from lp.soyuz.model.distroarchseries import (
159 )147 )
160from lp.soyuz.model.distroseriesbinarypackage import DistroSeriesBinaryPackage148from lp.soyuz.model.distroseriesbinarypackage import DistroSeriesBinaryPackage
161from lp.soyuz.model.distroseriespackagecache import DistroSeriesPackageCache149from lp.soyuz.model.distroseriespackagecache import DistroSeriesPackageCache
162from lp.soyuz.model.files import (
163 BinaryPackageFile,
164 SourcePackageReleaseFile,
165 )
166from lp.soyuz.model.publishing import (150from lp.soyuz.model.publishing import (
167 BinaryPackagePublishingHistory,151 BinaryPackagePublishingHistory,
168 get_current_source_releases,152 get_current_source_releases,
@@ -173,7 +157,6 @@ from lp.soyuz.model.queue import (
173 PackageUploadQueue,157 PackageUploadQueue,
174 PackageUploadSource,158 PackageUploadSource,
175 )159 )
176from lp.soyuz.model.section import Section
177from lp.soyuz.model.sourcepackagerelease import SourcePackageRelease160from lp.soyuz.model.sourcepackagerelease import SourcePackageRelease
178from lp.translations.enums import LanguagePackType161from lp.translations.enums import LanguagePackType
179from lp.translations.model.distroserieslanguage import (162from lp.translations.model.distroserieslanguage import (
@@ -1067,80 +1050,6 @@ class DistroSeries(SQLBase, BugTargetBase, HasSpecificationsMixin,
1067 """See `IDistroSeries`."""1050 """See `IDistroSeries`."""
1068 return self._getAllBinaries().find(scheduleddeletiondate=None)1051 return self._getAllBinaries().find(scheduleddeletiondate=None)
10691052
1070 def getSourcePackagePublishing(self, pocket, component, archive):
1071 """See `IDistroSeries`."""
1072 spphs = Store.of(self).find(
1073 SourcePackagePublishingHistory,
1074 SourcePackagePublishingHistory.archive == archive,
1075 SourcePackagePublishingHistory.distroseries == self,
1076 SourcePackagePublishingHistory.pocket == pocket,
1077 SourcePackagePublishingHistory.component == component,
1078 SourcePackagePublishingHistory.status ==
1079 PackagePublishingStatus.PUBLISHED,
1080 SourcePackagePublishingHistory.sourcepackagename ==
1081 SourcePackageName.id).order_by(SourcePackageName.name)
1082
1083 def eager_load(spphs):
1084 # Preload everything which will be used by archivepublisher's
1085 # build_source_stanza_fields.
1086 load_related(Section, spphs, ["sectionID"])
1087 sprs = load_related(
1088 SourcePackageRelease, spphs, ["sourcepackagereleaseID"])
1089 load_related(SourcePackageName, sprs, ["sourcepackagenameID"])
1090 spr_ids = set(map(attrgetter("id"), sprs))
1091 sprfs = list(Store.of(self).find(
1092 SourcePackageReleaseFile,
1093 SourcePackageReleaseFile.sourcepackagereleaseID.is_in(
1094 spr_ids)).order_by(SourcePackageReleaseFile.libraryfileID))
1095 file_map = collections.defaultdict(list)
1096 for sprf in sprfs:
1097 file_map[sprf.sourcepackagerelease].append(sprf)
1098 for spr, files in file_map.items():
1099 get_property_cache(spr).files = files
1100 lfas = load_related(LibraryFileAlias, sprfs, ["libraryfileID"])
1101 load_related(LibraryFileContent, lfas, ["contentID"])
1102
1103 return DecoratedResultSet(spphs, pre_iter_hook=eager_load)
1104
1105 def getBinaryPackagePublishing(self, archtag, pocket, component, archive):
1106 """See `IDistroSeries`."""
1107 bpphs = Store.of(self).find(
1108 BinaryPackagePublishingHistory,
1109 DistroArchSeries.distroseries == self,
1110 DistroArchSeries.architecturetag == archtag,
1111 BinaryPackagePublishingHistory.archive == archive,
1112 BinaryPackagePublishingHistory.distroarchseries ==
1113 DistroArchSeries.id,
1114 BinaryPackagePublishingHistory.pocket == pocket,
1115 BinaryPackagePublishingHistory.component == component,
1116 BinaryPackagePublishingHistory.status ==
1117 PackagePublishingStatus.PUBLISHED,
1118 BinaryPackagePublishingHistory.binarypackagename ==
1119 BinaryPackageName.id).order_by(BinaryPackageName.name)
1120
1121 def eager_load(bpphs):
1122 # Preload everything which will be used by archivepublisher's
1123 # build_binary_stanza_fields.
1124 load_related(Section, bpphs, ["sectionID"])
1125 bprs = load_related(
1126 BinaryPackageRelease, bpphs, ["binarypackagereleaseID"])
1127 bpbs = load_related(BinaryPackageBuild, bprs, ["buildID"])
1128 sprs = load_related(
1129 SourcePackageRelease, bpbs, ["source_package_release_id"])
1130 bpfs = load_referencing(
1131 BinaryPackageFile, bprs, ["binarypackagereleaseID"])
1132 file_map = collections.defaultdict(list)
1133 for bpf in bpfs:
1134 file_map[bpf.binarypackagerelease].append(bpf)
1135 for bpr, files in file_map.items():
1136 get_property_cache(bpr).files = files
1137 lfas = load_related(LibraryFileAlias, bpfs, ["libraryfileID"])
1138 load_related(LibraryFileContent, lfas, ["contentID"])
1139 load_related(SourcePackageName, sprs, ["sourcepackagenameID"])
1140 load_related(BinaryPackageName, bprs, ["binarypackagenameID"])
1141
1142 return DecoratedResultSet(bpphs, pre_iter_hook=eager_load)
1143
1144 def getBuildRecords(self, build_state=None, name=None, pocket=None,1053 def getBuildRecords(self, build_state=None, name=None, pocket=None,
1145 arch_tag=None, user=None, binary_only=True):1054 arch_tag=None, user=None, binary_only=True):
1146 """See IHasBuildRecords"""1055 """See IHasBuildRecords"""
diff --git a/lib/lp/registry/tests/test_distroseries.py b/lib/lp/registry/tests/test_distroseries.py
index f076ecd..a46cdcd 100644
--- a/lib/lp/registry/tests/test_distroseries.py
+++ b/lib/lp/registry/tests/test_distroseries.py
@@ -1,4 +1,4 @@
1# Copyright 2009-2021 Canonical Ltd. This software is licensed under the1# Copyright 2009-2022 Canonical Ltd. This software is licensed under the
2# GNU Affero General Public License version 3 (see the file LICENSE).2# GNU Affero General Public License version 3 (see the file LICENSE).
33
4"""Tests for distroseries."""4"""Tests for distroseries."""
@@ -7,7 +7,6 @@ __all__ = [
7 'CurrentSourceReleasesMixin',7 'CurrentSourceReleasesMixin',
8 ]8 ]
99
10from functools import partial
11import json10import json
1211
13from testtools.matchers import Equals12from testtools.matchers import Equals
@@ -16,10 +15,6 @@ from zope.component import getUtility
16from zope.security.proxy import removeSecurityProxy15from zope.security.proxy import removeSecurityProxy
1716
18from lp.app.interfaces.launchpad import ILaunchpadCelebrities17from lp.app.interfaces.launchpad import ILaunchpadCelebrities
19from lp.archivepublisher.indices import (
20 build_binary_stanza_fields,
21 build_source_stanza_fields,
22 )
23from lp.registry.errors import NoSuchDistroSeries18from lp.registry.errors import NoSuchDistroSeries
24from lp.registry.interfaces.distroseries import IDistroSeriesSet19from lp.registry.interfaces.distroseries import IDistroSeriesSet
25from lp.registry.interfaces.pocket import PackagePublishingPocket20from lp.registry.interfaces.pocket import PackagePublishingPocket
@@ -46,7 +41,6 @@ from lp.testing import (
46 api_url,41 api_url,
47 login,42 login,
48 person_logged_in,43 person_logged_in,
49 record_two_runs,
50 StormStatementRecorder,44 StormStatementRecorder,
51 TestCase,45 TestCase,
52 TestCaseWithFactory,46 TestCaseWithFactory,
@@ -584,47 +578,6 @@ class TestDistroSeriesPackaging(TestCaseWithFactory):
584 expected = ['translatable', 'linked', 'importabletranslatable']578 expected = ['translatable', 'linked', 'importabletranslatable']
585 self.assertEqual(expected, names)579 self.assertEqual(expected, names)
586580
587 def test_getSourcePackagePublishing_query_count(self):
588 # Check that the number of queries required to publish source
589 # packages is constant in the number of source packages.
590 def get_index_stanzas():
591 for spp in self.series.getSourcePackagePublishing(
592 PackagePublishingPocket.RELEASE, self.universe_component,
593 self.series.main_archive):
594 build_source_stanza_fields(
595 spp.sourcepackagerelease, spp.component, spp.section)
596
597 recorder1, recorder2 = record_two_runs(
598 get_index_stanzas,
599 partial(
600 self.makeSeriesPackage, pocket=PackagePublishingPocket.RELEASE,
601 status=PackagePublishingStatus.PUBLISHED),
602 5, 5)
603 self.assertThat(recorder1, HasQueryCount(Equals(11)))
604 self.assertThat(recorder2, HasQueryCount.byEquality(recorder1))
605
606 def test_getBinaryPackagePublishing_query_count(self):
607 # Check that the number of queries required to publish binary
608 # packages is constant in the number of binary packages.
609 def get_index_stanzas(das):
610 for bpp in self.series.getBinaryPackagePublishing(
611 das.architecturetag, PackagePublishingPocket.RELEASE,
612 self.universe_component, self.series.main_archive):
613 build_binary_stanza_fields(
614 bpp.binarypackagerelease, bpp.component, bpp.section,
615 bpp.priority, bpp.phased_update_percentage, False)
616
617 das = self.factory.makeDistroArchSeries(distroseries=self.series)
618 recorder1, recorder2 = record_two_runs(
619 partial(get_index_stanzas, das),
620 partial(
621 self.makeSeriesBinaryPackage, das=das,
622 pocket=PackagePublishingPocket.RELEASE,
623 status=PackagePublishingStatus.PUBLISHED),
624 5, 5)
625 self.assertThat(recorder1, HasQueryCount(Equals(15)))
626 self.assertThat(recorder2, HasQueryCount.byEquality(recorder1))
627
628581
629class TestDistroSeriesWebservice(TestCaseWithFactory):582class TestDistroSeriesWebservice(TestCaseWithFactory):
630583
diff --git a/lib/lp/soyuz/interfaces/publishing.py b/lib/lp/soyuz/interfaces/publishing.py
index a1d5dc2..874d1a1 100644
--- a/lib/lp/soyuz/interfaces/publishing.py
+++ b/lib/lp/soyuz/interfaces/publishing.py
@@ -1,4 +1,4 @@
1# Copyright 2009-2020 Canonical Ltd. This software is licensed under the1# Copyright 2009-2022 Canonical Ltd. This software is licensed under the
2# GNU Affero General Public License version 3 (see the file LICENSE).2# GNU Affero General Public License version 3 (see the file LICENSE).
33
4"""Publishing interfaces."""4"""Publishing interfaces."""
@@ -1133,6 +1133,32 @@ class IPublishingSet(Interface):
1133 release in the given `archive`, `distroseries`, and `pocket`.1133 release in the given `archive`, `distroseries`, and `pocket`.
1134 """1134 """
11351135
1136 def getSourcesForPublishing(archive, distroseries, pocket, component):
1137 """Get source publications which are published in a given context.
1138
1139 :param archive: The `Archive` to search.
1140 :param distroseries: The `DistroSeries` to search.
1141 :param pocket: The `PackagePublishingPocket` to search.
1142 :param component: The `Component` to search.
1143 :return: A result set of `SourcePackagePublishingHistory` objects in
1144 the given context and with the `PUBLISHED` status, ordered by
1145 source package name, with associated publisher-relevant objects
1146 preloaded.
1147 """
1148
1149 def getBinariesForPublishing(archive, distroarchseries, pocket, component):
1150 """Get binary publications which are published in a given context.
1151
1152 :param archive: The `Archive` to search.
1153 :param distroarchseries: The `DistroArchSeries` to search.
1154 :param pocket: The `PackagePublishingPocket` to search.
1155 :param component: The `Component` to search.
1156 :return: A result set of `BinaryPackagePublishingHistory` objects in
1157 the given context and with the `PUBLISHED` status, ordered by
1158 binary package name, with associated publisher-relevant objects
1159 preloaded.
1160 """
1161
1136 def getChangesFilesForSources(one_or_more_source_publications):1162 def getChangesFilesForSources(one_or_more_source_publications):
1137 """Return all changesfiles for each given source publication.1163 """Return all changesfiles for each given source publication.
11381164
diff --git a/lib/lp/soyuz/model/publishing.py b/lib/lp/soyuz/model/publishing.py
index 421e649..ea0b012 100644
--- a/lib/lp/soyuz/model/publishing.py
+++ b/lib/lp/soyuz/model/publishing.py
@@ -1,4 +1,4 @@
1# Copyright 2009-2020 Canonical Ltd. This software is licensed under the1# Copyright 2009-2022 Canonical Ltd. This software is licensed under the
2# GNU Affero General Public License version 3 (see the file LICENSE).2# GNU Affero General Public License version 3 (see the file LICENSE).
33
4__all__ = [4__all__ = [
@@ -45,6 +45,7 @@ from lp.app.errors import NotFoundError
45from lp.buildmaster.enums import BuildStatus45from lp.buildmaster.enums import BuildStatus
46from lp.registry.interfaces.person import validate_public_person46from lp.registry.interfaces.person import validate_public_person
47from lp.registry.interfaces.pocket import PackagePublishingPocket47from lp.registry.interfaces.pocket import PackagePublishingPocket
48from lp.registry.model.sourcepackagename import SourcePackageName
48from lp.services.database import bulk49from lp.services.database import bulk
49from lp.services.database.constants import UTC_NOW50from lp.services.database.constants import UTC_NOW
50from lp.services.database.datetimecol import UtcDateTimeCol51from lp.services.database.datetimecol import UtcDateTimeCol
@@ -112,6 +113,7 @@ from lp.soyuz.model.files import (
112 BinaryPackageFile,113 BinaryPackageFile,
113 SourcePackageReleaseFile,114 SourcePackageReleaseFile,
114 )115 )
116from lp.soyuz.model.section import Section
115from lp.soyuz.model.sourcepackagerelease import SourcePackageRelease117from lp.soyuz.model.sourcepackagerelease import SourcePackageRelease
116118
117119
@@ -1511,6 +1513,81 @@ class PublishingSet:
1511 active_publishing_status),1513 active_publishing_status),
1512 BinaryPackageRelease.architecturespecific == True)1514 BinaryPackageRelease.architecturespecific == True)
15131515
1516 def getSourcesForPublishing(self, archive, distroseries, pocket,
1517 component):
1518 """See `IPublishingSet`."""
1519 spphs = IStore(SourcePackagePublishingHistory).find(
1520 SourcePackagePublishingHistory,
1521 SourcePackagePublishingHistory.archive == archive,
1522 SourcePackagePublishingHistory.distroseries == distroseries,
1523 SourcePackagePublishingHistory.pocket == pocket,
1524 SourcePackagePublishingHistory.component == component,
1525 SourcePackagePublishingHistory.status ==
1526 PackagePublishingStatus.PUBLISHED,
1527 SourcePackagePublishingHistory.sourcepackagename ==
1528 SourcePackageName.id).order_by(SourcePackageName.name)
1529
1530 def eager_load(spphs):
1531 # Preload everything which will be used by archivepublisher's
1532 # build_source_stanza_fields.
1533 bulk.load_related(Section, spphs, ["sectionID"])
1534 sprs = bulk.load_related(
1535 SourcePackageRelease, spphs, ["sourcepackagereleaseID"])
1536 bulk.load_related(SourcePackageName, sprs, ["sourcepackagenameID"])
1537 spr_ids = set(map(attrgetter("id"), sprs))
1538 sprfs = list(IStore(SourcePackageReleaseFile).find(
1539 SourcePackageReleaseFile,
1540 SourcePackageReleaseFile.sourcepackagereleaseID.is_in(
1541 spr_ids)).order_by(SourcePackageReleaseFile.libraryfileID))
1542 file_map = defaultdict(list)
1543 for sprf in sprfs:
1544 file_map[sprf.sourcepackagerelease].append(sprf)
1545 for spr, files in file_map.items():
1546 get_property_cache(spr).files = files
1547 lfas = bulk.load_related(
1548 LibraryFileAlias, sprfs, ["libraryfileID"])
1549 bulk.load_related(LibraryFileContent, lfas, ["contentID"])
1550
1551 return DecoratedResultSet(spphs, pre_iter_hook=eager_load)
1552
1553 def getBinariesForPublishing(self, archive, distroarchseries, pocket,
1554 component):
1555 """See `IPublishingSet`."""
1556 bpphs = IStore(BinaryPackagePublishingHistory).find(
1557 BinaryPackagePublishingHistory,
1558 BinaryPackagePublishingHistory.archive == archive,
1559 BinaryPackagePublishingHistory.distroarchseries ==
1560 distroarchseries,
1561 BinaryPackagePublishingHistory.pocket == pocket,
1562 BinaryPackagePublishingHistory.component == component,
1563 BinaryPackagePublishingHistory.status ==
1564 PackagePublishingStatus.PUBLISHED,
1565 BinaryPackagePublishingHistory.binarypackagename ==
1566 BinaryPackageName.id).order_by(BinaryPackageName.name)
1567
1568 def eager_load(bpphs):
1569 # Preload everything which will be used by archivepublisher's
1570 # build_binary_stanza_fields.
1571 bulk.load_related(Section, bpphs, ["sectionID"])
1572 bprs = bulk.load_related(
1573 BinaryPackageRelease, bpphs, ["binarypackagereleaseID"])
1574 bpbs = bulk.load_related(BinaryPackageBuild, bprs, ["buildID"])
1575 sprs = bulk.load_related(
1576 SourcePackageRelease, bpbs, ["source_package_release_id"])
1577 bpfs = bulk.load_referencing(
1578 BinaryPackageFile, bprs, ["binarypackagereleaseID"])
1579 file_map = defaultdict(list)
1580 for bpf in bpfs:
1581 file_map[bpf.binarypackagerelease].append(bpf)
1582 for bpr, files in file_map.items():
1583 get_property_cache(bpr).files = files
1584 lfas = bulk.load_related(LibraryFileAlias, bpfs, ["libraryfileID"])
1585 bulk.load_related(LibraryFileContent, lfas, ["contentID"])
1586 bulk.load_related(SourcePackageName, sprs, ["sourcepackagenameID"])
1587 bulk.load_related(BinaryPackageName, bprs, ["binarypackagenameID"])
1588
1589 return DecoratedResultSet(bpphs, pre_iter_hook=eager_load)
1590
1514 def getChangesFilesForSources(self, one_or_more_source_publications):1591 def getChangesFilesForSources(self, one_or_more_source_publications):
1515 """See `IPublishingSet`."""1592 """See `IPublishingSet`."""
1516 # Avoid circular imports.1593 # Avoid circular imports.
diff --git a/lib/lp/soyuz/tests/test_publishing.py b/lib/lp/soyuz/tests/test_publishing.py
index fbb19f0..d645ef8 100644
--- a/lib/lp/soyuz/tests/test_publishing.py
+++ b/lib/lp/soyuz/tests/test_publishing.py
@@ -1,9 +1,10 @@
1# Copyright 2009-2020 Canonical Ltd. This software is licensed under the1# Copyright 2009-2022 Canonical Ltd. This software is licensed under the
2# GNU Affero General Public License version 3 (see the file LICENSE).2# GNU Affero General Public License version 3 (see the file LICENSE).
33
4"""Test native publication workflow for Soyuz. """4"""Test native publication workflow for Soyuz. """
55
6import datetime6import datetime
7from functools import partial
7import io8import io
8import operator9import operator
9import os10import os
@@ -20,6 +21,10 @@ from zope.security.proxy import removeSecurityProxy
20from lp.app.errors import NotFoundError21from lp.app.errors import NotFoundError
21from lp.archivepublisher.config import getPubConfig22from lp.archivepublisher.config import getPubConfig
22from lp.archivepublisher.diskpool import DiskPool23from lp.archivepublisher.diskpool import DiskPool
24from lp.archivepublisher.indices import (
25 build_binary_stanza_fields,
26 build_source_stanza_fields,
27 )
23from lp.buildmaster.enums import BuildStatus28from lp.buildmaster.enums import BuildStatus
24from lp.buildmaster.interfaces.processor import IProcessorSet29from lp.buildmaster.interfaces.processor import IProcessorSet
25from lp.registry.interfaces.distribution import IDistributionSet30from lp.registry.interfaces.distribution import IDistributionSet
@@ -1029,6 +1034,176 @@ class TestPublishingSetLite(TestCaseWithFactory):
1029 "override the corresponding deb instead.",1034 "override the corresponding deb instead.",
1030 debug_bpph.changeOverride, new_phased_update_percentage=20)1035 debug_bpph.changeOverride, new_phased_update_percentage=20)
10311036
1037 def makePublishedSourcePackage(self, series, pocket=None, status=None):
1038 # Make a published source package.
1039 name = self.factory.getUniqueUnicode()
1040 sourcepackagename = self.factory.makeSourcePackageName(name)
1041 component = getUtility(IComponentSet)["universe"]
1042 spph = self.factory.makeSourcePackagePublishingHistory(
1043 sourcepackagename=sourcepackagename, distroseries=series,
1044 component=component, pocket=pocket, status=status)
1045 source_package = self.factory.makeSourcePackage(
1046 sourcepackagename=spph.sourcepackagename, distroseries=series)
1047 spr = spph.sourcepackagerelease
1048 for extension in ("dsc", "tar.gz"):
1049 filename = "%s_%s.%s" % (spr.name, spr.version, extension)
1050 spr.addFile(self.factory.makeLibraryFileAlias(
1051 filename=filename, db_only=True))
1052 return source_package
1053
1054 def test_getSourcesForPublishing(self):
1055 # PublisherSet.getSourcesForPublishing returns all the ISPPH records
1056 # in a given publishing context. It is used as part of publishing
1057 # some types of archives.
1058 # XXX cjwatson 2022-03-28: Detach test from sampledata.
1059 ubuntu = getUtility(IDistributionSet)["ubuntu"]
1060 hoary = ubuntu["hoary"]
1061 component_main = getUtility(IComponentSet)["main"]
1062 component_multiverse = getUtility(IComponentSet)["multiverse"]
1063 debian_archive = getUtility(IDistributionSet)["debian"].main_archive
1064 publishing_set = getUtility(IPublishingSet)
1065
1066 spphs = publishing_set.getSourcesForPublishing(
1067 archive=hoary.main_archive, distroseries=hoary,
1068 pocket=PackagePublishingPocket.RELEASE, component=component_main)
1069 self.assertEqual(6, spphs.count())
1070 self.assertContentEqual(
1071 ["alsa-utils", "evolution", "libstdc++", "linux-source-2.6.15",
1072 "netapplet", "pmount"],
1073 {spph.sourcepackagerelease.name for spph in spphs})
1074 self.assertEqual(
1075 0,
1076 publishing_set.getSourcesForPublishing(
1077 archive=hoary.main_archive, distroseries=hoary,
1078 pocket=PackagePublishingPocket.RELEASE,
1079 component=component_multiverse).count())
1080 self.assertEqual(
1081 0,
1082 publishing_set.getSourcesForPublishing(
1083 archive=hoary.main_archive, distroseries=hoary,
1084 pocket=PackagePublishingPocket.BACKPORTS,
1085 component=component_main).count())
1086 self.assertEqual(
1087 0,
1088 publishing_set.getSourcesForPublishing(
1089 archive=debian_archive, distroseries=hoary,
1090 pocket=PackagePublishingPocket.RELEASE,
1091 component=component_main).count())
1092
1093 def test_getSourcesForPublishing_query_count(self):
1094 # Check that the number of queries required to publish source
1095 # packages is constant in the number of source packages.
1096 series = self.factory.makeDistroSeries()
1097 archive = series.main_archive
1098 component_universe = getUtility(IComponentSet)["universe"]
1099
1100 def get_index_stanzas():
1101 for spp in getUtility(IPublishingSet).getSourcesForPublishing(
1102 archive=archive, distroseries=series,
1103 pocket=PackagePublishingPocket.RELEASE,
1104 component=component_universe):
1105 build_source_stanza_fields(
1106 spp.sourcepackagerelease, spp.component, spp.section)
1107
1108 recorder1, recorder2 = record_two_runs(
1109 get_index_stanzas,
1110 partial(
1111 self.makePublishedSourcePackage, series=series,
1112 pocket=PackagePublishingPocket.RELEASE,
1113 status=PackagePublishingStatus.PUBLISHED),
1114 5, 5)
1115 self.assertThat(recorder1, HasQueryCount(Equals(8)))
1116 self.assertThat(recorder2, HasQueryCount.byEquality(recorder1))
1117
1118 def makePublishedBinaryPackage(self, das, pocket=None, status=None):
1119 # Make a published binary package.
1120 source = self.makePublishedSourcePackage(
1121 das.distroseries, pocket=pocket, status=status)
1122 spr = source.distinctreleases[0]
1123 binarypackagename = self.factory.makeBinaryPackageName(source.name)
1124 bpph = self.factory.makeBinaryPackagePublishingHistory(
1125 binarypackagename=binarypackagename, distroarchseries=das,
1126 component=spr.component, section_name=spr.section.name,
1127 status=status, pocket=pocket, source_package_release=spr)
1128 bpr = bpph.binarypackagerelease
1129 filename = "%s_%s_%s.deb" % (
1130 bpr.name, bpr.version, das.architecturetag)
1131 bpr.addFile(self.factory.makeLibraryFileAlias(
1132 filename=filename, db_only=True))
1133 return bpph
1134
1135 def test_getBinariesForPublishing(self):
1136 # PublisherSet.getBinariesForPublishing returns all the IBPPH
1137 # records in a given publishing context. It is used as part of
1138 # publishing some types of archives.
1139 # XXX cjwatson 2022-03-28: Detach test from sampledata.
1140 ubuntu = getUtility(IDistributionSet)["ubuntu"]
1141 warty = ubuntu["warty"]
1142 warty_i386 = warty["i386"]
1143 warty_another = self.factory.makeDistroArchSeries(distroseries=warty)
1144 component_main = getUtility(IComponentSet)["main"]
1145 component_multiverse = getUtility(IComponentSet)["multiverse"]
1146 debian_archive = getUtility(IDistributionSet)["debian"].main_archive
1147 publishing_set = getUtility(IPublishingSet)
1148
1149 bpphs = publishing_set.getBinariesForPublishing(
1150 archive=warty.main_archive, distroarchseries=warty_i386,
1151 pocket=PackagePublishingPocket.RELEASE, component=component_main)
1152 self.assertEqual(8, bpphs.count())
1153 self.assertIn(
1154 "mozilla-firefox",
1155 {bpph.binarypackagerelease.name for bpph in bpphs})
1156 self.assertEqual(
1157 0,
1158 publishing_set.getBinariesForPublishing(
1159 archive=warty.main_archive, distroarchseries=warty_another,
1160 pocket=PackagePublishingPocket.RELEASE,
1161 component=component_main).count())
1162 self.assertEqual(
1163 0,
1164 publishing_set.getBinariesForPublishing(
1165 archive=warty.main_archive, distroarchseries=warty_i386,
1166 pocket=PackagePublishingPocket.RELEASE,
1167 component=component_multiverse).count())
1168 self.assertEqual(
1169 0,
1170 publishing_set.getBinariesForPublishing(
1171 archive=warty.main_archive, distroarchseries=warty_i386,
1172 pocket=PackagePublishingPocket.BACKPORTS,
1173 component=component_main).count())
1174 self.assertEqual(
1175 0,
1176 publishing_set.getBinariesForPublishing(
1177 archive=debian_archive, distroarchseries=warty_i386,
1178 pocket=PackagePublishingPocket.RELEASE,
1179 component=component_main).count())
1180
1181 def test_getBinariesForPublishing_query_count(self):
1182 # Check that the number of queries required to publish binary
1183 # packages is constant in the number of binary packages.
1184 das = self.factory.makeDistroArchSeries()
1185 archive = das.main_archive
1186 component_universe = getUtility(IComponentSet)["universe"]
1187
1188 def get_index_stanzas():
1189 for bpp in getUtility(IPublishingSet).getBinariesForPublishing(
1190 archive=archive, distroarchseries=das,
1191 pocket=PackagePublishingPocket.RELEASE,
1192 component=component_universe):
1193 build_binary_stanza_fields(
1194 bpp.binarypackagerelease, bpp.component, bpp.section,
1195 bpp.priority, bpp.phased_update_percentage, False)
1196
1197 recorder1, recorder2 = record_two_runs(
1198 get_index_stanzas,
1199 partial(
1200 self.makePublishedBinaryPackage, das=das,
1201 pocket=PackagePublishingPocket.RELEASE,
1202 status=PackagePublishingStatus.PUBLISHED),
1203 5, 5)
1204 self.assertThat(recorder1, HasQueryCount(Equals(11)))
1205 self.assertThat(recorder2, HasQueryCount.byEquality(recorder1))
1206
10321207
1033class TestSourceDomination(TestNativePublishingBase):1208class TestSourceDomination(TestNativePublishingBase):
1034 """Test SourcePackagePublishingHistory.supersede() operates correctly."""1209 """Test SourcePackagePublishingHistory.supersede() operates correctly."""

Subscribers

People subscribed via source and target branches

to status/vote changes: