1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
|
# Copyright 2009 Canonical Ltd. This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).
# pylint: disable-msg=E0611,W0212
__metaclass__ = type
__all__ = [
'DistroSeriesPackageCache',
]
from sqlobject import (
ForeignKey,
StringCol,
)
from storm.locals import (
Desc,
RawStr,
)
from zope.interface import implements
from canonical.database.sqlbase import (
SQLBase,
sqlvalues,
)
from lp.services.database.lpstorm import IStore
from lp.soyuz.interfaces.distroseriespackagecache import (
IDistroSeriesPackageCache,
)
from lp.soyuz.model.binarypackagename import BinaryPackageName
from lp.soyuz.model.binarypackagerelease import BinaryPackageRelease
from lp.soyuz.model.distroarchseries import DistroArchSeries
from lp.soyuz.model.publishing import BinaryPackagePublishingHistory
class DistroSeriesPackageCache(SQLBase):
implements(IDistroSeriesPackageCache)
_table = 'DistroSeriesPackageCache'
archive = ForeignKey(dbName='archive',
foreignKey='Archive', notNull=True)
distroseries = ForeignKey(dbName='distroseries',
foreignKey='DistroSeries', notNull=True)
binarypackagename = ForeignKey(dbName='binarypackagename',
foreignKey='BinaryPackageName', notNull=True)
fti = RawStr(allow_none=True, default=None)
name = StringCol(notNull=False, default=None)
summary = StringCol(notNull=False, default=None)
description = StringCol(notNull=False, default=None)
summaries = StringCol(notNull=False, default=None)
descriptions = StringCol(notNull=False, default=None)
@classmethod
def _find(cls, distroseries, archive=None):
"""All of the cached binary package records for this distroseries.
If 'archive' is not given it will return all caches stored for the
distroseries main archives (PRIMARY and PARTNER).
"""
if archive is not None:
archives = [archive.id]
else:
archives = distroseries.distribution.all_distro_archive_ids
return IStore(cls).find(
cls,
cls.distroseries == distroseries,
cls.archiveID.is_in(archives)).order_by(cls.name)
@classmethod
def removeOld(cls, distroseries, archive, log):
"""Delete any records that are no longer applicable.
Consider all binarypackages marked as REMOVED.
Also purges all existing cache records for disabled archives.
:param archive: target `IArchive`.
:param log: the context logger object able to print DEBUG level
messages.
"""
# get the set of package names that should be there
bpns = set(BinaryPackageName.select("""
BinaryPackagePublishingHistory.distroarchseries =
DistroArchSeries.id AND
DistroArchSeries.distroseries = %s AND
Archive.id = %s AND
BinaryPackagePublishingHistory.archive = Archive.id AND
BinaryPackagePublishingHistory.binarypackagerelease =
BinaryPackageRelease.id AND
BinaryPackageRelease.binarypackagename =
BinaryPackageName.id AND
BinaryPackagePublishingHistory.dateremoved is NULL AND
Archive.enabled = TRUE
""" % sqlvalues(distroseries.id, archive.id),
distinct=True,
clauseTables=[
'Archive',
'DistroArchSeries',
'BinaryPackagePublishingHistory',
'BinaryPackageRelease']))
# remove the cache entries for binary packages we no longer want
for cache in cls._find(distroseries, archive):
if cache.binarypackagename not in bpns:
log.debug(
"Removing binary cache for '%s' (%s)"
% (cache.name, cache.id))
cache.destroySelf()
@classmethod
def _update(cls, distroseries, binarypackagename, archive, log):
"""Update the package cache for a given IBinaryPackageName
'log' is required, it should be a logger object able to print
DEBUG level messages.
'ztm' is the current trasaction manager used for partial commits
(in full batches of 100 elements)
"""
# get the set of published binarypackagereleases
bprs = IStore(BinaryPackageRelease).find(
BinaryPackageRelease,
BinaryPackageRelease.binarypackagename == binarypackagename,
BinaryPackageRelease.id ==
BinaryPackagePublishingHistory.binarypackagereleaseID,
BinaryPackagePublishingHistory.distroarchseriesID ==
DistroArchSeries.id,
DistroArchSeries.distroseries == distroseries,
BinaryPackagePublishingHistory.archive == archive,
BinaryPackagePublishingHistory.dateremoved == None)
bprs = bprs.order_by(Desc(BinaryPackageRelease.datecreated))
bprs = bprs.config(distinct=True)
if bprs.count() == 0:
log.debug("No binary releases found.")
return
# find or create the cache entry
cache = cls.selectOne("""
distroseries = %s AND
archive = %s AND
binarypackagename = %s
""" % sqlvalues(distroseries, archive, binarypackagename))
if cache is None:
log.debug("Creating new binary cache entry.")
cache = cls(
archive=archive,
distroseries=distroseries,
binarypackagename=binarypackagename)
# make sure the cached name, summary and description are correct
cache.name = binarypackagename.name
cache.summary = bprs[0].summary
cache.description = bprs[0].description
# get the sets of binary package summaries, descriptions. there is
# likely only one, but just in case...
summaries = set()
descriptions = set()
for bpr in bprs:
log.debug("Considering binary version %s" % bpr.version)
summaries.add(bpr.summary)
descriptions.add(bpr.description)
# and update the caches
cache.summaries = ' '.join(sorted(summaries))
cache.descriptions = ' '.join(sorted(descriptions))
@classmethod
def updateAll(cls, distroseries, archive, log, ztm, commit_chunk=500):
"""Update the binary package cache
Consider all binary package names published in this distro series
and entirely skips updates for disabled archives
:param archive: target `IArchive`;
:param log: logger object for printing debug level information;
:param ztm: transaction used for partial commits, every chunk of
'commit_chunk' updates is committed;
:param commit_chunk: number of updates before commit, defaults to 500.
:return the number of packages updated.
"""
# Do not create cache entries for disabled archives.
if not archive.enabled:
return
# Get the set of package names to deal with.
bpns = IStore(BinaryPackageName).find(
BinaryPackageName,
DistroArchSeries.distroseries == distroseries,
BinaryPackagePublishingHistory.distroarchseriesID ==
DistroArchSeries.id,
BinaryPackagePublishingHistory.archive == archive,
BinaryPackagePublishingHistory.binarypackagereleaseID ==
BinaryPackageRelease.id,
BinaryPackageRelease.binarypackagename == BinaryPackageName.id,
BinaryPackagePublishingHistory.dateremoved == None).config(
distinct=True).order_by(BinaryPackageName.name)
number_of_updates = 0
chunk_size = 0
for bpn in bpns:
log.debug("Considering binary '%s'" % bpn.name)
cls._update(distroseries, bpn, archive, log)
number_of_updates += 1
chunk_size += 1
if chunk_size == commit_chunk:
chunk_size = 0
log.debug("Committing")
ztm.commit()
return number_of_updates
|