launchpad-reviewers team mailing list archive
-
launchpad-reviewers team
-
Mailing list archive
-
Message #30424
[Merge] ~cjwatson/launchpad:stormify-archive into launchpad:master
Colin Watson has proposed merging ~cjwatson/launchpad:stormify-archive into launchpad:master.
Commit message:
Convert Archive to Storm
Requested reviews:
Launchpad code reviewers (launchpad-reviewers)
For more details, see:
https://code.launchpad.net/~cjwatson/launchpad/+git/launchpad/+merge/450462
--
Your team Launchpad code reviewers is requested to review the proposed merge of ~cjwatson/launchpad:stormify-archive into launchpad:master.
diff --git a/lib/lp/archivepublisher/scripts/sync_signingkeys.py b/lib/lp/archivepublisher/scripts/sync_signingkeys.py
index 7bb200a..3b0046f 100644
--- a/lib/lp/archivepublisher/scripts/sync_signingkeys.py
+++ b/lib/lp/archivepublisher/scripts/sync_signingkeys.py
@@ -100,7 +100,7 @@ class SyncSigningKeysScript(LaunchpadScript):
else:
archives = IStore(Archive).find(
Archive,
- PublisherConfig.distribution_id == Archive.distributionID,
+ PublisherConfig.distribution_id == Archive.distribution_id,
)
archives = archives.order_by(Archive.id)
start = self.options.offset if self.options.offset else 0
diff --git a/lib/lp/archivepublisher/tests/test_sync_signingkeys.py b/lib/lp/archivepublisher/tests/test_sync_signingkeys.py
index bf5a5a2..3c73754 100644
--- a/lib/lp/archivepublisher/tests/test_sync_signingkeys.py
+++ b/lib/lp/archivepublisher/tests/test_sync_signingkeys.py
@@ -86,7 +86,7 @@ class TestSyncSigningKeysScript(TestCaseWithFactory):
def makeArchives(self):
for i in range(10):
self.factory.makeArchive()
- conditions = PublisherConfig.distribution_id == Archive.distributionID
+ conditions = PublisherConfig.distribution_id == Archive.distribution_id
return IStore(Archive).find(Archive, conditions).order_by(Archive.id)
def makeArchiveSigningDir(self, ppa, series=None):
diff --git a/lib/lp/code/model/sourcepackagerecipebuild.py b/lib/lp/code/model/sourcepackagerecipebuild.py
index 1ec64c9..00d6ddb 100644
--- a/lib/lp/code/model/sourcepackagerecipebuild.py
+++ b/lib/lp/code/model/sourcepackagerecipebuild.py
@@ -328,7 +328,7 @@ class SourcePackageRecipeBuild(
load_related(LibraryFileAlias, builds, ["log_id"])
archives = load_related(Archive, builds, ["archive_id"])
- load_related(Person, archives, ["ownerID"])
+ load_related(Person, archives, ["owner_id"])
distroseries = load_related(DistroSeries, builds, ["distroseries_id"])
load_related(Distribution, distroseries, ["distribution_id"])
sprs = load_related(SourcePackageRecipe, builds, ["recipe_id"])
diff --git a/lib/lp/registry/browser/person.py b/lib/lp/registry/browser/person.py
index 5ca39fe..d14004b 100644
--- a/lib/lp/registry/browser/person.py
+++ b/lib/lp/registry/browser/person.py
@@ -576,7 +576,7 @@ class PersonNavigation(BranchTraversalMixin, Navigation):
if not archive_id.isdigit():
return None
return traverse_archive_subscription_for_subscriber(
- self.context, archive_id
+ self.context, int(archive_id)
)
else:
# Otherwise we return the normal view for a person's
diff --git a/lib/lp/registry/model/distribution.py b/lib/lp/registry/model/distribution.py
index 44085f9..c0cc091 100644
--- a/lib/lp/registry/model/distribution.py
+++ b/lib/lp/registry/model/distribution.py
@@ -17,15 +17,19 @@ from storm.expr import (
SQL,
And,
Coalesce,
+ Column,
Desc,
Exists,
Func,
+ In,
+ Is,
Join,
LeftJoin,
Max,
Not,
Or,
Select,
+ Table,
)
from storm.info import ClassAlias
from storm.locals import Int, List, Reference
@@ -157,7 +161,7 @@ from lp.services.database.datetimecol import UtcDateTimeCol
from lp.services.database.decoratedresultset import DecoratedResultSet
from lp.services.database.enumcol import DBEnum
from lp.services.database.interfaces import IStore
-from lp.services.database.sqlbase import SQLBase, sqlvalues
+from lp.services.database.sqlbase import SQLBase
from lp.services.database.sqlobject import BoolCol, ForeignKey, StringCol
from lp.services.database.stormexpr import (
ArrayAgg,
@@ -194,6 +198,7 @@ from lp.soyuz.model.publishing import (
SourcePackagePublishingHistory,
get_current_source_releases,
)
+from lp.soyuz.model.queue import PackageUpload
from lp.translations.enums import TranslationPermission
from lp.translations.model.hastranslationimports import (
HasTranslationImportsMixin,
@@ -1848,70 +1853,69 @@ class Distribution(
def searchPPAs(self, text=None, show_inactive=False, user=None):
"""See `IDistribution`."""
clauses = [
- """
- Archive.purpose = %s AND
- Archive.distribution = %s AND
- Archive.owner = ValidPersonOrTeamCache.id
- """
- % sqlvalues(ArchivePurpose.PPA, self)
+ Archive.purpose == ArchivePurpose.PPA,
+ Archive.distribution == self,
+ Archive.owner == Column("id", Table("ValidPersonOrTeamCache")),
]
-
- clauseTables = ["ValidPersonOrTeamCache"]
- orderBy = ["Archive.displayname"]
+ order_by = [Archive.displayname]
if not show_inactive:
clauses.append(
- """
- Archive.id IN (
- SELECT archive FROM SourcepackagePublishingHistory
- WHERE status IN %s)
- """
- % sqlvalues(active_publishing_status)
+ Archive.id.is_in(
+ Select(
+ SourcePackagePublishingHistory.archive_id,
+ where=SourcePackagePublishingHistory.status.is_in(
+ active_publishing_status
+ ),
+ )
+ )
)
if text:
- orderBy.insert(0, rank_by_fti(Archive, text))
+ order_by.insert(0, rank_by_fti(Archive, text))
clauses.append(fti_search(Archive, text))
+ public_archive = And(
+ Is(Archive.private, False), Is(Archive._enabled, True)
+ )
if user is not None:
if not user.inTeam(getUtility(ILaunchpadCelebrities).admin):
clauses.append(
- """
- ((Archive.private = FALSE AND Archive.enabled = TRUE) OR
- Archive.owner = %s OR
- %s IN (SELECT TeamParticipation.person
- FROM TeamParticipation
- WHERE TeamParticipation.person = %s AND
- TeamParticipation.team = Archive.owner)
- )
- """
- % sqlvalues(user, user, user)
+ Or(
+ public_archive,
+ Archive.owner == user,
+ In(
+ user.id,
+ Select(
+ TeamParticipation.person_id,
+ tables=[TeamParticipation],
+ where=And(
+ TeamParticipation.person == user,
+ TeamParticipation.team_id
+ == Archive.owner_id,
+ ),
+ ),
+ ),
+ )
)
else:
- clauses.append(
- "Archive.private = FALSE AND Archive.enabled = TRUE"
- )
+ clauses.append(public_archive)
- return Archive.select(
- And(*clauses), orderBy=orderBy, clauseTables=clauseTables
- )
+ return IStore(Archive).find(Archive, *clauses).order_by(order_by)
def getPendingAcceptancePPAs(self):
"""See `IDistribution`."""
- query = """
- Archive.purpose = %s AND
- Archive.distribution = %s AND
- PackageUpload.archive = Archive.id AND
- PackageUpload.status = %s
- """ % sqlvalues(
- ArchivePurpose.PPA, self, PackageUploadStatus.ACCEPTED
- )
-
- return Archive.select(
- query,
- clauseTables=["PackageUpload"],
- orderBy=["archive.id"],
- distinct=True,
+ return (
+ IStore(Archive)
+ .find(
+ Archive,
+ Archive.purpose == ArchivePurpose.PPA,
+ Archive.distribution == self,
+ PackageUpload.archive == Archive.id,
+ PackageUpload.status == PackageUploadStatus.ACCEPTED,
+ )
+ .order_by(Archive.id)
+ .config(distinct=True)
)
def getPendingPublicationPPAs(self):
diff --git a/lib/lp/registry/model/distroseriesdifference.py b/lib/lp/registry/model/distroseriesdifference.py
index 28859ba..e82e975 100644
--- a/lib/lp/registry/model/distroseriesdifference.py
+++ b/lib/lp/registry/model/distroseriesdifference.py
@@ -98,7 +98,7 @@ def most_recent_publications(dsds, in_parent, statuses, match_version=False):
tables=[Archive, DistroSeries],
where=And(
DistroSeries.id == series_col,
- Archive.distributionID == DistroSeries.distribution_id,
+ Archive.distribution_id == DistroSeries.distribution_id,
Archive.purpose == ArchivePurpose.PRIMARY,
),
)
diff --git a/lib/lp/registry/model/person.py b/lib/lp/registry/model/person.py
index 8aef249..8bb69c3 100644
--- a/lib/lp/registry/model/person.py
+++ b/lib/lp/registry/model/person.py
@@ -3576,8 +3576,10 @@ class Person(
@property
def ppas(self):
"""See `IPerson`."""
- return Archive.selectBy(
- owner=self, purpose=ArchivePurpose.PPA, orderBy="name"
+ return (
+ IStore(Archive)
+ .find(Archive, owner=self, purpose=ArchivePurpose.PPA)
+ .order_by(Archive.name)
)
def getVisiblePPAs(self, user):
diff --git a/lib/lp/registry/scripts/populate_distroseriesdiff.py b/lib/lp/registry/scripts/populate_distroseriesdiff.py
index 7847ee6..97adebd 100644
--- a/lib/lp/registry/scripts/populate_distroseriesdiff.py
+++ b/lib/lp/registry/scripts/populate_distroseriesdiff.py
@@ -56,7 +56,7 @@ def compose_sql_find_latest_source_package_releases(distroseries):
parameters = {
"active_status": quote(active_publishing_status),
"distroseries": quote(distroseries.id),
- "main_archive": quote(distroseries.distribution.main_archive),
+ "main_archive": quote(distroseries.distribution.main_archive.id),
"release_pocket": quote(PackagePublishingPocket.RELEASE),
}
return (
diff --git a/lib/lp/scripts/garbo.py b/lib/lp/scripts/garbo.py
index 1461757..06da799 100644
--- a/lib/lp/scripts/garbo.py
+++ b/lib/lp/scripts/garbo.py
@@ -505,7 +505,7 @@ class PopulateDistributionSourcePackageCache(TunableLoop):
(
SourcePackagePublishingHistory.id,
Archive.id,
- Archive.distributionID,
+ Archive.distribution_id,
SourcePackageName.id,
SourcePackageName.name,
),
@@ -1994,7 +1994,7 @@ class ArchiveAuthTokenDeactivator(BulkPruner):
)
)
affected_ppas = load_related(Archive, tokens, ["archive_id"])
- load_related(Person, affected_ppas, ["ownerID"])
+ load_related(Person, affected_ppas, ["owner_id"])
getUtility(IPersonSet).getPrecachedPersonsFromIDs(
[token.person_id for token in tokens], need_preferred_email=True
)
diff --git a/lib/lp/snappy/model/snapbuild.py b/lib/lp/snappy/model/snapbuild.py
index afc3275..0f4f041 100644
--- a/lib/lp/snappy/model/snapbuild.py
+++ b/lib/lp/snappy/model/snapbuild.py
@@ -604,7 +604,7 @@ class SnapBuildSet(SpecificBuildFarmJobSourceMixin):
lfas = load_related(LibraryFileAlias, builds, ["log_id"])
load_related(LibraryFileContent, lfas, ["contentID"])
archives = load_related(Archive, builds, ["archive_id"])
- load_related(Person, archives, ["ownerID"])
+ load_related(Person, archives, ["owner_id"])
distroarchseries = load_related(
DistroArchSeries, builds, ["distro_arch_series_id"]
)
diff --git a/lib/lp/soyuz/browser/queue.py b/lib/lp/soyuz/browser/queue.py
index bcae209..5112ea7 100644
--- a/lib/lp/soyuz/browser/queue.py
+++ b/lib/lp/soyuz/browser/queue.py
@@ -190,7 +190,7 @@ class QueueItemsView(LaunchpadView):
if upload.package_copy_job_id is not None
}
archives = {pcj.source_archive for pcj in package_copy_jobs}
- person_ids = [archive.ownerID for archive in archives]
+ person_ids = [archive.owner_id for archive in archives]
jobs = load_related(Job, package_copy_jobs, ["job_id"])
person_ids.extend(job.requester_id for job in jobs)
list(
diff --git a/lib/lp/soyuz/model/archive.py b/lib/lp/soyuz/model/archive.py
index 9cae655..bdfe117 100644
--- a/lib/lp/soyuz/model/archive.py
+++ b/lib/lp/soyuz/model/archive.py
@@ -14,18 +14,20 @@ __all__ = [
import logging
import re
import typing
-from datetime import datetime
+from datetime import datetime, timedelta, timezone
from operator import attrgetter
from pathlib import PurePath
import six
from lazr.lifecycle.event import ObjectCreatedEvent
from storm.expr import (
+ Alias,
And,
Cast,
Count,
Desc,
Exists,
+ Is,
Join,
Not,
Or,
@@ -33,7 +35,7 @@ from storm.expr import (
Sum,
Union,
)
-from storm.properties import JSON, Int, Unicode
+from storm.properties import JSON, Bool, DateTime, Int, Unicode
from storm.references import Reference
from storm.store import EmptyResultSet, Store
from zope.component import getAdapter, getUtility
@@ -81,17 +83,9 @@ from lp.registry.model.teammembership import TeamParticipation
from lp.services.config import config
from lp.services.database.bulk import create, load_referencing, load_related
from lp.services.database.constants import UTC_NOW
-from lp.services.database.datetimecol import UtcDateTimeCol
from lp.services.database.decoratedresultset import DecoratedResultSet
from lp.services.database.enumcol import DBEnum
from lp.services.database.interfaces import IStandbyStore, IStore
-from lp.services.database.sqlbase import SQLBase, cursor, sqlvalues
-from lp.services.database.sqlobject import (
- BoolCol,
- ForeignKey,
- IntCol,
- StringCol,
-)
from lp.services.database.stormbase import StormBase
from lp.services.database.stormexpr import BulkUpdate
from lp.services.features import getFeatureFlag
@@ -209,23 +203,21 @@ def storm_validate_external_dependencies(archive, attr, value):
@implementer(IArchive, IHasOwner, IHasBuildRecords)
-class Archive(SQLBase):
- _table = "Archive"
- _defaultOrder = "id"
-
- owner = ForeignKey(
- dbName="owner",
- foreignKey="Person",
- storm_validator=validate_person,
- notNull=True,
- )
+class Archive(StormBase):
+ __storm_table__ = "Archive"
+ __storm_order__ = "id"
+
+ id = Int(primary=True)
+
+ owner_id = Int(name="owner", validator=validate_person, allow_none=False)
+ owner = Reference(owner_id, "Person.id")
def _validate_archive_name(self, attr, value):
"""Only allow renaming of COPY archives.
Also assert the name is valid when set via an unproxied object.
"""
- if not self._SO_creating:
+ if not self._creating:
renamable = self.is_copy or (
self.is_ppa and self.status == ArchiveStatus.DELETED
)
@@ -277,17 +269,16 @@ class Archive(SQLBase):
return value
- name = StringCol(
- dbName="name", notNull=True, storm_validator=_validate_archive_name
+ name = Unicode(
+ name="name", allow_none=False, validator=_validate_archive_name
)
- displayname = StringCol(dbName="displayname", notNull=True)
+ displayname = Unicode(name="displayname", allow_none=False)
- description = StringCol(dbName="description", notNull=False, default=None)
+ description = Unicode(name="description", allow_none=True, default=None)
- distribution = ForeignKey(
- foreignKey="Distribution", dbName="distribution", notNull=False
- )
+ distribution_id = Int(name="distribution", allow_none=True)
+ distribution = Reference(distribution_id, "Distribution.id")
purpose = DBEnum(name="purpose", allow_none=False, enum=ArchivePurpose)
@@ -298,78 +289,76 @@ class Archive(SQLBase):
default=ArchiveStatus.ACTIVE,
)
- _enabled = BoolCol(dbName="enabled", notNull=True, default=True)
+ _enabled = Bool(name="enabled", allow_none=False, default=True)
enabled = property(lambda x: x._enabled)
- publish = BoolCol(dbName="publish", notNull=True, default=True)
+ publish = Bool(name="publish", allow_none=False, default=True)
- private = BoolCol(
- dbName="private",
- notNull=True,
+ private = Bool(
+ name="private",
+ allow_none=False,
default=False,
- storm_validator=_validate_archive_privacy,
+ validator=_validate_archive_privacy,
)
- require_virtualized = BoolCol(
- dbName="require_virtualized", notNull=True, default=True
+ require_virtualized = Bool(
+ name="require_virtualized", allow_none=False, default=True
)
- build_debug_symbols = BoolCol(
- dbName="build_debug_symbols", notNull=True, default=False
+ build_debug_symbols = Bool(
+ name="build_debug_symbols", allow_none=False, default=False
)
- publish_debug_symbols = BoolCol(
- dbName="publish_debug_symbols", notNull=False, default=False
+ publish_debug_symbols = Bool(
+ name="publish_debug_symbols", allow_none=True, default=False
)
- permit_obsolete_series_uploads = BoolCol(
- dbName="permit_obsolete_series_uploads", default=False
+ permit_obsolete_series_uploads = Bool(
+ name="permit_obsolete_series_uploads", default=False
)
- authorized_size = IntCol(dbName="authorized_size", notNull=False)
+ authorized_size = Int(name="authorized_size", allow_none=True)
- sources_cached = IntCol(dbName="sources_cached", notNull=False, default=0)
+ sources_cached = Int(name="sources_cached", allow_none=True, default=0)
- binaries_cached = IntCol(
- dbName="binaries_cached", notNull=False, default=0
- )
+ binaries_cached = Int(name="binaries_cached", allow_none=True, default=0)
- package_description_cache = StringCol(
- dbName="package_description_cache", notNull=False, default=None
+ package_description_cache = Unicode(
+ name="package_description_cache", allow_none=True, default=None
)
- total_count = IntCol(dbName="total_count", notNull=True, default=0)
+ total_count = Int(name="total_count", allow_none=False, default=0)
- pending_count = IntCol(dbName="pending_count", notNull=True, default=0)
+ pending_count = Int(name="pending_count", allow_none=False, default=0)
- succeeded_count = IntCol(dbName="succeeded_count", notNull=True, default=0)
+ succeeded_count = Int(name="succeeded_count", allow_none=False, default=0)
- building_count = IntCol(dbName="building_count", notNull=True, default=0)
+ building_count = Int(name="building_count", allow_none=False, default=0)
- failed_count = IntCol(dbName="failed_count", notNull=True, default=0)
+ failed_count = Int(name="failed_count", allow_none=False, default=0)
- date_created = UtcDateTimeCol(dbName="date_created")
+ date_created = DateTime(name="date_created", tzinfo=timezone.utc)
signing_key_owner_id = Int(name="signing_key_owner")
signing_key_owner = Reference(signing_key_owner_id, "Person.id")
signing_key_fingerprint = Unicode()
- relative_build_score = IntCol(
- dbName="relative_build_score", notNull=True, default=0
+ relative_build_score = Int(
+ name="relative_build_score", allow_none=False, default=0
)
# This field is specifically and only intended for OEM migration to
# Launchpad and should be re-examined in October 2010 to see if it
# is still relevant.
- external_dependencies = StringCol(
- dbName="external_dependencies",
- notNull=False,
+ external_dependencies = Unicode(
+ name="external_dependencies",
+ allow_none=True,
default=None,
- storm_validator=storm_validate_external_dependencies,
+ validator=storm_validate_external_dependencies,
)
- suppress_subscription_notifications = BoolCol(
- dbName="suppress_subscription_notifications",
- notNull=True,
+ suppress_subscription_notifications = Bool(
+ name="suppress_subscription_notifications",
+ allow_none=False,
default=False,
)
@@ -383,10 +372,49 @@ class Archive(SQLBase):
name="repository_format", allow_none=True, enum=ArchiveRepositoryFormat
)
- def _init(self, *args, **kw):
- """Provide the right interface for URL traversal."""
- SQLBase._init(self, *args, **kw)
+ _creating = False
+ def __init__(
+ self,
+ owner,
+ distribution,
+ name,
+ displayname,
+ purpose,
+ description=None,
+ publish=True,
+ require_virtualized=True,
+ signing_key_owner=None,
+ signing_key_fingerprint=None,
+ publishing_method=None,
+ repository_format=None,
+ ):
+ super().__init__()
+ try:
+ self._creating = True
+ self.owner = owner
+ self.distribution = distribution
+ self.name = name
+ self.displayname = displayname
+ self.purpose = purpose
+ self.description = description
+ self.publish = publish
+ self.require_virtualized = require_virtualized
+ self.signing_key_owner = signing_key_owner
+ self.signing_key_fingerprint = signing_key_fingerprint
+ self.publishing_method = publishing_method
+ self.repository_format = repository_format
+ except Exception:
+ # If validation fails, then the new object may have been added
+ # to the store first. Remove it again in that case.
+ store = Store.of(self)
+ if store is not None:
+ store.remove(self)
+ raise
+ self.__storm_loaded__()
+ del self._creating
+
+ def __storm_loaded__(self):
# Provide the additional marker interface depending on what type
# of archive this is. See also the lp:url declarations in
# zcml/archive.zcml.
@@ -3247,7 +3275,7 @@ class ArchiveSet:
def get(self, archive_id):
"""See `IArchiveSet`."""
- return Archive.get(archive_id)
+ return IStore(Archive).get(Archive, archive_id)
def getByReference(self, reference, check_permissions=False, user=None):
"""See `IArchiveSet`."""
@@ -3352,8 +3380,12 @@ class ArchiveSet:
if name is None:
name = self._getDefaultArchiveNameByPurpose(purpose)
- return Archive.selectOneBy(
- distribution=distribution, purpose=purpose, name=name
+ return (
+ IStore(Archive)
+ .find(
+ Archive, distribution=distribution, purpose=purpose, name=name
+ )
+ .one()
)
def getByDistroAndName(self, distribution, name):
@@ -3444,11 +3476,16 @@ class ArchiveSet:
% (name, distribution.name)
)
else:
- archive = Archive.selectOneBy(
- owner=owner,
- distribution=distribution,
- name=name,
- purpose=ArchivePurpose.PPA,
+ archive = (
+ IStore(Archive)
+ .find(
+ Archive,
+ owner=owner,
+ distribution=distribution,
+ name=name,
+ purpose=ArchivePurpose.PPA,
+ )
+ .one()
)
if archive is not None:
raise AssertionError(
@@ -3478,12 +3515,12 @@ class ArchiveSet:
signing_key_owner=signing_key_owner,
signing_key_fingerprint=signing_key_fingerprint,
require_virtualized=require_virtualized,
- _publishing_method=publishing_method,
- _repository_format=repository_format,
+ publishing_method=publishing_method,
+ repository_format=repository_format,
)
# Upon creation archives are enabled by default.
- if enabled == False:
+ if not enabled:
new_archive.disable()
# Private teams cannot have public PPAs.
@@ -3509,11 +3546,12 @@ class ArchiveSet:
]
new_archive.setProcessors(processors)
+ Store.of(new_archive).flush()
return new_archive
def __iter__(self):
"""See `IArchiveSet`."""
- return iter(Archive.select())
+ return iter(IStore(Archive).find(Archive))
def getPPAOwnedByPerson(
self,
@@ -3546,9 +3584,9 @@ class ArchiveSet:
direct_membership = Select(
Archive.id,
where=And(
- Archive._enabled == True,
+ Is(Archive._enabled, True),
Archive.purpose == ArchivePurpose.PPA,
- TeamParticipation.team == Archive.ownerID,
+ TeamParticipation.team == Archive.owner_id,
TeamParticipation.person == user,
),
)
@@ -3577,7 +3615,7 @@ class ArchiveSet:
result.order_by(Archive.displayname)
def preload_owners(rows):
- load_related(Person, rows, ["ownerID"])
+ load_related(Person, rows, ["owner_id"])
return DecoratedResultSet(result, pre_iter_hook=preload_owners)
@@ -3591,7 +3629,7 @@ class ArchiveSet:
store = Store.of(user)
result = store.find(
Distribution,
- Distribution.id == Archive.distributionID,
+ Distribution.id == Archive.distribution_id,
self._getPPAsForUserClause(user),
)
return result.config(distinct=True)
@@ -3612,7 +3650,7 @@ class ArchiveSet:
Archive,
Archive.signing_key_fingerprint == None,
Archive.purpose == purpose,
- Archive._enabled == True,
+ Is(Archive._enabled, True),
)
)
results.order_by(Archive.date_created)
@@ -3629,8 +3667,8 @@ class ArchiveSet:
SourcePackagePublishingHistory,
SourcePackagePublishingHistory.archive == Archive.id,
SourcePackagePublishingHistory.distroseries == DistroSeries.id,
- Archive.private == False,
- Archive._enabled == True,
+ Is(Archive.private, False),
+ Is(Archive._enabled, True),
Archive.distribution == distribution,
DistroSeries.distribution == distribution,
Archive.purpose == ArchivePurpose.PPA,
@@ -3643,28 +3681,24 @@ class ArchiveSet:
def getMostActivePPAsForDistribution(self, distribution):
"""See `IArchiveSet`."""
- cur = cursor()
- query = """
- SELECT a.id, count(*) as C
- FROM Archive a, SourcePackagePublishingHistory spph
- WHERE
- spph.archive = a.id AND
- a.private = FALSE AND
- spph.datecreated >= now() - INTERVAL '1 week' AND
- a.distribution = %s AND
- a.purpose = %s
- GROUP BY a.id
- ORDER BY C DESC, a.id
- LIMIT 5
- """ % sqlvalues(
- distribution, ArchivePurpose.PPA
- )
-
- cur.execute(query)
+ spph_count = Alias(Count(SourcePackagePublishingHistory.id))
+ results = (
+ IStore(Archive)
+ .find(
+ (Archive, spph_count),
+ SourcePackagePublishingHistory.archive == Archive.id,
+ Is(Archive.private, False),
+ SourcePackagePublishingHistory.datecreated
+ >= UTC_NOW - Cast(timedelta(weeks=1), "interval"),
+ Archive.distribution == distribution,
+ Archive.purpose == ArchivePurpose.PPA,
+ )
+ .group_by(Archive.id)
+ .order_by(Desc(spph_count), Archive.id)[:5]
+ )
most_active = []
- for archive_id, number_of_uploads in cur.fetchall():
- archive = Archive.get(int(archive_id))
+ for archive, number_of_uploads in results:
the_dict = {"archive": archive, "uploads": number_of_uploads}
most_active.append(the_dict)
@@ -3674,7 +3708,7 @@ class ArchiveSet:
"""See `IArchiveSet`."""
return IStore(Archive).find(
Archive,
- Archive.private == True,
+ Is(Archive.private, True),
Archive.purpose == ArchivePurpose.PPA,
)
@@ -3703,7 +3737,7 @@ class ArchiveSet:
extra_exprs.append(Archive.name == name)
public_archive = And(
- Archive.private == False, Archive._enabled == True
+ Is(Archive.private, False), Is(Archive._enabled, True)
)
if not check_permissions:
@@ -3721,14 +3755,14 @@ class ArchiveSet:
TeamParticipation.team_id,
where=And(
TeamParticipation.person == user,
- TeamParticipation.team_id == Archive.ownerID,
+ TeamParticipation.team_id == Archive.owner_id,
),
)
# Append the extra expression to capture either public
# archives, or archives owned by the user, or archives
# owned by a team of which the user is a member:
- # Note: 'Archive.ownerID == user.id'
+ # Note: 'Archive.owner_id == user.id'
# is unnecessary below because there is a TeamParticipation
# entry showing that each person is a member of the "team"
# that consists of themselves.
@@ -3737,7 +3771,7 @@ class ArchiveSet:
extra_exprs.append(
Or(
public_archive,
- Archive.ownerID.is_in(user_teams_subselect),
+ Archive.owner_id.is_in(user_teams_subselect),
)
)
else:
@@ -3746,7 +3780,7 @@ class ArchiveSet:
extra_exprs.append(public_archive)
if exclude_disabled:
- extra_exprs.append(Archive._enabled == True)
+ extra_exprs.append(Is(Archive._enabled, True))
if exclude_pristine:
extra_exprs.append(
@@ -3843,7 +3877,7 @@ class ArchiveSet:
# when a user is the direct owner of the PPA.
# Team ownership is accounted for in `get_enabled_archive_filter`
# below
- elif user.id == removeSecurityProxy(archive).ownerID:
+ elif user.id == removeSecurityProxy(archive).owner_id:
allowed_ids.add(archive.id)
else:
@@ -3889,7 +3923,7 @@ def get_archive_privacy_filter(user):
else:
privacy_filter = Or(
Not(Archive.private),
- Archive.ownerID.is_in(
+ Archive.owner_id.is_in(
Select(
TeamParticipation.team_id,
where=(TeamParticipation.person == user),
@@ -3913,8 +3947,8 @@ def get_enabled_archive_filter(
if include_public:
terms = [
purpose_term,
- Archive.private == False,
- Archive._enabled == True,
+ Is(Archive.private, False),
+ Is(Archive._enabled, True),
]
return And(*terms)
else:
@@ -3930,7 +3964,7 @@ def get_enabled_archive_filter(
TeamParticipation.team_id, where=TeamParticipation.person == user
)
- is_owner = Archive.ownerID.is_in(user_teams)
+ is_owner = Archive.owner_id.is_in(user_teams)
from lp.soyuz.model.archivesubscriber import ArchiveSubscriber
@@ -3971,6 +4005,6 @@ def get_enabled_archive_filter(
if include_public:
filter_terms.append(
- And(Archive._enabled == True, Archive.private == False)
+ And(Is(Archive._enabled, True), Is(Archive.private, False))
)
return And(purpose_term, Or(*filter_terms))
diff --git a/lib/lp/soyuz/model/archivesubscriber.py b/lib/lp/soyuz/model/archivesubscriber.py
index 0ff0cc7..d3173df 100644
--- a/lib/lp/soyuz/model/archivesubscriber.py
+++ b/lib/lp/soyuz/model/archivesubscriber.py
@@ -240,7 +240,7 @@ class ArchiveSubscriberSet:
archives = load_related(Archive, subscriptions, ["archive_id"])
list(
getUtility(IPersonSet).getPrecachedPersonsFromIDs(
- [archive.ownerID for archive in archives],
+ [archive.owner_id for archive in archives],
need_validity=True,
)
)
diff --git a/lib/lp/soyuz/model/binarypackagebuild.py b/lib/lp/soyuz/model/binarypackagebuild.py
index ca82a8e..4616feb 100644
--- a/lib/lp/soyuz/model/binarypackagebuild.py
+++ b/lib/lp/soyuz/model/binarypackagebuild.py
@@ -942,7 +942,7 @@ class BinaryPackageBuildSet(SpecificBuildFarmJobSourceMixin):
self._prefetchBuildData(builds)
das = load_related(DistroArchSeries, builds, ["distro_arch_series_id"])
archives = load_related(Archive, builds, ["archive_id"])
- load_related(Person, archives, ["ownerID"])
+ load_related(Person, archives, ["owner_id"])
distroseries = load_related(DistroSeries, das, ["distroseries_id"])
load_related(Distribution, distroseries, ["distribution_id"])
diff --git a/lib/lp/soyuz/model/livefsbuild.py b/lib/lp/soyuz/model/livefsbuild.py
index d4a3396..f7312a9 100644
--- a/lib/lp/soyuz/model/livefsbuild.py
+++ b/lib/lp/soyuz/model/livefsbuild.py
@@ -429,7 +429,7 @@ class LiveFSBuildSet(SpecificBuildFarmJobSourceMixin):
load_related(Person, builds, ["requester_id"])
load_related(LibraryFileAlias, builds, ["log_id"])
archives = load_related(Archive, builds, ["archive_id"])
- load_related(Person, archives, ["ownerID"])
+ load_related(Person, archives, ["owner_id"])
load_related(LiveFS, builds, ["livefs_id"])
def getByBuildFarmJobs(self, build_farm_jobs):
diff --git a/lib/lp/soyuz/model/packagecloner.py b/lib/lp/soyuz/model/packagecloner.py
index 15029b4..fee1b4c 100644
--- a/lib/lp/soyuz/model/packagecloner.py
+++ b/lib/lp/soyuz/model/packagecloner.py
@@ -171,7 +171,7 @@ class PackageCloner:
bpph.binarypackagename
""" % sqlvalues(
destination_das.id,
- destination.archive,
+ destination.archive.id,
UTC_NOW,
UTC_NOW,
destination.pocket,
@@ -188,7 +188,7 @@ class PackageCloner:
PackagePublishingStatus.PENDING,
PackagePublishingStatus.PUBLISHED,
origin.pocket,
- origin.archive,
+ origin.archive.id,
)
if use_names:
@@ -230,7 +230,7 @@ class PackageCloner:
"""
% sqlvalues(
destination.distroseries.id,
- destination.archive,
+ destination.archive.id,
UTC_NOW,
UTC_NOW,
destination.pocket,
@@ -291,7 +291,7 @@ class PackageCloner:
spn.name = mcd.sourcepackagename AND
spr.version > mcd.t_version
""" % sqlvalues(
- origin.archive,
+ origin.archive.id,
PackagePublishingStatus.PENDING,
PackagePublishingStatus.PUBLISHED,
origin.distroseries.id,
@@ -334,7 +334,7 @@ class PackageCloner:
spn.name NOT IN (
SELECT sourcepackagename FROM tmp_merge_copy_data)
""" % sqlvalues(
- origin.archive,
+ origin.archive.id,
PackagePublishingStatus.PENDING,
PackagePublishingStatus.PUBLISHED,
origin.distroseries.id,
@@ -414,7 +414,7 @@ class PackageCloner:
secsrc.distroseries = %s AND
secsrc.pocket = %s
""" % sqlvalues(
- destination.archive,
+ destination.archive.id,
PackagePublishingStatus.PENDING,
PackagePublishingStatus.PUBLISHED,
destination.distroseries.id,
@@ -465,7 +465,7 @@ class PackageCloner:
spph.archive = %s
""" % sqlvalues(
destination.distroseries.id,
- destination.archive,
+ destination.archive.id,
UTC_NOW,
UTC_NOW,
destination.pocket,
@@ -473,7 +473,7 @@ class PackageCloner:
PackagePublishingStatus.PENDING,
PackagePublishingStatus.PUBLISHED,
origin.pocket,
- origin.archive,
+ origin.archive.id,
)
if sourcepackagenames and len(sourcepackagenames) > 0:
diff --git a/lib/lp/soyuz/model/packagecopyjob.py b/lib/lp/soyuz/model/packagecopyjob.py
index d441a99..16dd6f2 100644
--- a/lib/lp/soyuz/model/packagecopyjob.py
+++ b/lib/lp/soyuz/model/packagecopyjob.py
@@ -874,7 +874,7 @@ class PlainPackageCopyJob(PackageCopyJobDerived):
# coming from, and the version number in the DSD may have
# changed. We can however filter out DSDs that are from
# different distributions, based on the job's target archive.
- source_distro_id = self.source_archive.distributionID
+ source_distro_id = self.source_archive.distribution_id
return [
dsd
for dsd in candidates
diff --git a/lib/lp/soyuz/model/packagediff.py b/lib/lp/soyuz/model/packagediff.py
index 47ed2b2..e21de8b 100644
--- a/lib/lp/soyuz/model/packagediff.py
+++ b/lib/lp/soyuz/model/packagediff.py
@@ -354,7 +354,7 @@ class PackageDiffSet:
),
)
archives = load(Archive, (spr.upload_archive_id for spr in sprs))
- load(Distribution, (a.distributionID for a in archives))
+ load(Distribution, (a.distribution_id for a in archives))
if preload_for_display:
return DecoratedResultSet(result, pre_iter_hook=preload_hook)
diff --git a/lib/lp/soyuz/model/queue.py b/lib/lp/soyuz/model/queue.py
index 89fe2f9..f330355 100644
--- a/lib/lp/soyuz/model/queue.py
+++ b/lib/lp/soyuz/model/queue.py
@@ -451,7 +451,7 @@ class PackageUpload(StormBase):
AND bpf.libraryfile = lfa.id
AND lfa.filename IN (%%s)
""" % sqlvalues(
- self.archive, self.distroseries.distribution
+ self.archive_id, self.distroseries.distribution_id
)
# Inject the inner query.
query %= inner_query
@@ -1914,4 +1914,4 @@ def prefill_packageupload_caches(uploads, puses, pubs, pucs, logs):
PackageCopyJob, uploads, ["package_copy_job_id"]
)
archives = load_related(Archive, package_copy_jobs, ["source_archive_id"])
- load_related(Distribution, archives, ["distributionID"])
+ load_related(Distribution, archives, ["distribution_id"])
diff --git a/lib/lp/soyuz/scripts/initialize_distroseries.py b/lib/lp/soyuz/scripts/initialize_distroseries.py
index bcb6f28..6a35b71 100644
--- a/lib/lp/soyuz/scripts/initialize_distroseries.py
+++ b/lib/lp/soyuz/scripts/initialize_distroseries.py
@@ -857,7 +857,7 @@ class InitializeDistroSeries:
FROM Archivepermission WHERE packageset = %s
"""
% sqlvalues(
- self.distroseries.main_archive,
+ self.distroseries.main_archive.id,
child_ps.id,
parent_ps.id,
)
@@ -913,7 +913,7 @@ class InitializeDistroSeries:
WHERE pocket IS NOT NULL AND distroseries = %s
"""
% sqlvalues(
- self.distroseries.main_archive,
+ self.distroseries.main_archive.id,
self.distroseries.id,
parent.id,
)
diff --git a/lib/lp/soyuz/scripts/packagecopier.py b/lib/lp/soyuz/scripts/packagecopier.py
index d0553f5..f377107 100644
--- a/lib/lp/soyuz/scripts/packagecopier.py
+++ b/lib/lp/soyuz/scripts/packagecopier.py
@@ -171,7 +171,7 @@ def check_copy_permissions(
# checks on each source archive. Not all of this is currently
# preloadable.
archives = load_related(Archive, sources, ["archive_id"])
- load_related(Person, archives, ["ownerID"])
+ load_related(Person, archives, ["owner_id"])
# If there is a requester, check that they have upload permission into
# the destination (archive, component, pocket). This check is done
diff --git a/lib/lp/soyuz/tests/test_archive.py b/lib/lp/soyuz/tests/test_archive.py
index a72d9b7..5c17662 100644
--- a/lib/lp/soyuz/tests/test_archive.py
+++ b/lib/lp/soyuz/tests/test_archive.py
@@ -44,6 +44,7 @@ from lp.buildmaster.interfaces.buildfarmjobbehaviour import (
IBuildFarmJobBehaviour,
)
from lp.buildmaster.interfaces.processor import IProcessorSet
+from lp.buildmaster.model.buildqueue import BuildQueue
from lp.registry.enums import PersonVisibility, TeamMembershipPolicy
from lp.registry.interfaces.distribution import IDistributionSet
from lp.registry.interfaces.person import IPersonSet
@@ -52,7 +53,6 @@ from lp.registry.interfaces.series import SeriesStatus
from lp.registry.interfaces.teammembership import TeamMembershipStatus
from lp.services.authserver.testing import InProcessAuthServerFixture
from lp.services.database.interfaces import IStore
-from lp.services.database.sqlbase import sqlvalues
from lp.services.features import getFeatureFlag
from lp.services.features.testing import FeatureFixture
from lp.services.gpg.interfaces import (
@@ -116,6 +116,7 @@ from lp.soyuz.model.archivepermission import (
ArchivePermission,
ArchivePermissionSet,
)
+from lp.soyuz.model.binarypackagebuild import BinaryPackageBuild
from lp.soyuz.model.binarypackagerelease import (
BinaryPackageReleaseDownloadCount,
)
@@ -398,20 +399,18 @@ class TestArchiveEnableDisable(TestCaseWithFactory):
def _getBuildQueuesByStatus(self, archive, status):
# Return the count for archive build jobs with the given status.
- query = """
- SELECT COUNT(BuildQueue.id)
- FROM BinaryPackageBuild, BuildQueue
- WHERE
- BinaryPackageBuild.build_farm_job =
- BuildQueue.build_farm_job
- AND BinaryPackageBuild.archive = %s
- AND BinaryPackageBuild.status = %s
- AND BuildQueue.status = %s;
- """ % sqlvalues(
- archive, BuildStatus.NEEDSBUILD, status
- )
-
- return IStore(Archive).execute(query).get_one()[0]
+ return (
+ IStore(BuildQueue)
+ .find(
+ BuildQueue.id,
+ BinaryPackageBuild.build_farm_job_id
+ == BuildQueue._build_farm_job_id,
+ BinaryPackageBuild.archive == archive,
+ BinaryPackageBuild.status == BuildStatus.NEEDSBUILD,
+ BuildQueue.status == status,
+ )
+ .count()
+ )
def assertNoBuildQueuesHaveStatus(self, archive, status):
# Check that that the jobs attached to this archive do not have this
diff --git a/lib/lp/soyuz/vocabularies.py b/lib/lp/soyuz/vocabularies.py
index 1b640b8..8254e63 100644
--- a/lib/lp/soyuz/vocabularies.py
+++ b/lib/lp/soyuz/vocabularies.py
@@ -11,6 +11,7 @@ __all__ = [
"PPAVocabulary",
]
+from storm.expr import Is
from storm.locals import And, Or
from zope.component import getUtility
from zope.interface import implementer
@@ -22,11 +23,7 @@ from lp.registry.model.person import Person
from lp.services.database.interfaces import IStore
from lp.services.database.stormexpr import fti_search
from lp.services.webapp.interfaces import ILaunchBag
-from lp.services.webapp.vocabulary import (
- IHugeVocabulary,
- SQLObjectVocabularyBase,
- StormVocabularyBase,
-)
+from lp.services.webapp.vocabulary import IHugeVocabulary, StormVocabularyBase
from lp.soyuz.enums import ArchivePurpose
from lp.soyuz.interfaces.archive import IArchiveSet
from lp.soyuz.model.archive import Archive, get_enabled_archive_filter
@@ -86,18 +83,17 @@ class PackageReleaseVocabulary(StormVocabularyBase):
@implementer(IHugeVocabulary)
-class PPAVocabulary(SQLObjectVocabularyBase):
+class PPAVocabulary(StormVocabularyBase):
_table = Archive
- _orderBy = ["Person.name, Archive.name"]
- _clauseTables = ["Person"]
+ _order_by = ["Person.name", "Archive.name"]
# This should probably also filter by privacy, but that becomes
# problematic when you need to remove a dependency that you can no
# longer see.
- _filter = And(
- Archive._enabled == True,
- Person.q.id == Archive.q.ownerID,
- Archive.q.purpose == ArchivePurpose.PPA,
- )
+ _clauses = [
+ Is(Archive._enabled, True),
+ Archive.owner == Person.id,
+ Archive.purpose == ArchivePurpose.PPA,
+ ]
displayname = "Select a PPA"
step_title = "Search"
@@ -121,7 +117,7 @@ class PPAVocabulary(SQLObjectVocabularyBase):
def search(self, query, vocab_filter=None):
"""Return a resultset of archives.
- This is a helper required by `SQLObjectVocabularyBase.searchForTerms`.
+ This is a helper required by `StormVocabularyBase.searchForTerms`.
"""
if not query:
return self.emptySelectResults()
@@ -147,17 +143,18 @@ class PPAVocabulary(SQLObjectVocabularyBase):
Person.name == owner_name, Archive.name == archive_name
)
- clause = And(
- self._filter,
+ extra_clauses = [
get_enabled_archive_filter(
getUtility(ILaunchBag).user,
purpose=ArchivePurpose.PPA,
include_public=True,
),
search_clause,
- )
- return self._table.select(
- clause, orderBy=self._orderBy, clauseTables=self._clauseTables
+ ]
+ return (
+ IStore(self._table)
+ .find(self._table, *self._clauses, *extra_clauses)
+ .order_by(self._order_by)
)