~launchpad-pqm/launchpad/devel

« back to all changes in this revision

Viewing changes to lib/lp/soyuz/model/distributionsourcepackagecache.py

  • Committer: Graham Binns
  • Date: 2011-09-07 15:59:13 UTC
  • mto: This revision was merged to the branch mainline in revision 13914.
  • Revision ID: graham@canonical.com-20110907155913-p97tx2e34ysbcgp3
Added an XXX.

Show diffs side-by-side

added added

removed removed

Lines of Context:
6
6
__metaclass__ = type
7
7
__all__ = ['DistributionSourcePackageCache', ]
8
8
 
 
9
from operator import itemgetter
 
10
 
9
11
from sqlobject import (
10
12
    ForeignKey,
11
13
    StringCol,
12
14
    )
13
15
from zope.interface import implements
14
16
 
15
 
from canonical.database.sqlbase import SQLBase
 
17
from canonical.database.sqlbase import (
 
18
    SQLBase,
 
19
    sqlvalues,
 
20
    )
 
21
from canonical.launchpad.components.decoratedresultset import (
 
22
    DecoratedResultSet,
 
23
    )
 
24
from canonical.launchpad.interfaces.lpstorm import IStore
 
25
from lp.registry.model.sourcepackagename import SourcePackageName
16
26
from lp.soyuz.interfaces.distributionsourcepackagecache import (
17
27
    IDistributionSourcePackageCache,
18
28
    )
 
29
from lp.soyuz.model.sourcepackagerelease import SourcePackageRelease
 
30
from lp.soyuz.model.binarypackagerelease import BinaryPackageRelease
19
31
 
20
32
 
21
33
class DistributionSourcePackageCache(SQLBase):
46
58
        return DistributionSourcePackage(self.distribution,
47
59
            self.sourcepackagename)
48
60
 
 
61
    @classmethod
 
62
    def _find(cls, distro, archive=None):
 
63
        """The set of all source package info caches for this distribution.
 
64
 
 
65
        If 'archive' is not given it will return all caches stored for the
 
66
        distribution main archives (PRIMARY and PARTNER).
 
67
        """
 
68
        if archive is not None:
 
69
            archives = [archive.id]
 
70
        else:
 
71
            archives = distro.all_distro_archive_ids
 
72
 
 
73
        result = IStore(DistributionSourcePackageCache).find(
 
74
            (DistributionSourcePackageCache, SourcePackageName),
 
75
            DistributionSourcePackageCache.distribution == distro,
 
76
            DistributionSourcePackageCache.archiveID.is_in(archives),
 
77
            SourcePackageName.id ==
 
78
                DistributionSourcePackageCache.sourcepackagenameID,
 
79
            ).order_by(DistributionSourcePackageCache.name)
 
80
        return DecoratedResultSet(result, itemgetter(0))
 
81
 
 
82
    @classmethod
 
83
    def removeOld(cls, distro, archive, log):
 
84
        """Delete any cache records for removed packages.
 
85
 
 
86
        Also purges all existing cache records for disabled archives.
 
87
 
 
88
        :param archive: target `IArchive`.
 
89
        :param log: the context logger object able to print DEBUG level
 
90
            messages.
 
91
        """
 
92
 
 
93
        # Get the set of source package names to deal with.
 
94
        spns = set(SourcePackageName.select("""
 
95
            SourcePackagePublishingHistory.distroseries =
 
96
                DistroSeries.id AND
 
97
            DistroSeries.distribution = %s AND
 
98
            Archive.id = %s AND
 
99
            SourcePackagePublishingHistory.archive = Archive.id AND
 
100
            SourcePackagePublishingHistory.sourcepackagerelease =
 
101
                SourcePackageRelease.id AND
 
102
            SourcePackageRelease.sourcepackagename =
 
103
                SourcePackageName.id AND
 
104
            SourcePackagePublishingHistory.dateremoved is NULL AND
 
105
            Archive.enabled = TRUE
 
106
            """ % sqlvalues(distro, archive),
 
107
            distinct=True,
 
108
            clauseTables=[
 
109
                'Archive',
 
110
                'DistroSeries',
 
111
                'SourcePackagePublishingHistory',
 
112
                'SourcePackageRelease']))
 
113
 
 
114
        # Remove the cache entries for packages we no longer publish.
 
115
        for cache in cls._find(distro, archive):
 
116
            if cache.sourcepackagename not in spns:
 
117
                log.debug(
 
118
                    "Removing source cache for '%s' (%s)"
 
119
                    % (cache.name, cache.id))
 
120
                cache.destroySelf()
 
121
 
 
122
    @classmethod
 
123
    def _update(cls, distro, sourcepackagename, archive, log):
 
124
        """Update cached source package details.
 
125
 
 
126
        Update cache details for a given ISourcePackageName, including
 
127
        generated binarypackage names, summary and description fti.
 
128
        'log' is required and only prints debug level information.
 
129
        """
 
130
 
 
131
        # Get the set of published sourcepackage releases.
 
132
        sprs = list(SourcePackageRelease.select("""
 
133
            SourcePackageRelease.sourcepackagename = %s AND
 
134
            SourcePackageRelease.id =
 
135
                SourcePackagePublishingHistory.sourcepackagerelease AND
 
136
            SourcePackagePublishingHistory.distroseries =
 
137
                DistroSeries.id AND
 
138
            DistroSeries.distribution = %s AND
 
139
            SourcePackagePublishingHistory.archive = %s AND
 
140
            SourcePackagePublishingHistory.dateremoved is NULL
 
141
            """ % sqlvalues(sourcepackagename, distro, archive),
 
142
            orderBy='id',
 
143
            clauseTables=['SourcePackagePublishingHistory', 'DistroSeries'],
 
144
            distinct=True))
 
145
 
 
146
        if len(sprs) == 0:
 
147
            log.debug("No sources releases found.")
 
148
            return
 
149
 
 
150
        # Find or create the cache entry.
 
151
        cache = DistributionSourcePackageCache.selectOne("""
 
152
            distribution = %s AND
 
153
            archive = %s AND
 
154
            sourcepackagename = %s
 
155
            """ % sqlvalues(distro, archive, sourcepackagename))
 
156
        if cache is None:
 
157
            log.debug("Creating new source cache entry.")
 
158
            cache = DistributionSourcePackageCache(
 
159
                archive=archive,
 
160
                distribution=distro,
 
161
                sourcepackagename=sourcepackagename)
 
162
 
 
163
        # Make sure the name is correct.
 
164
        cache.name = sourcepackagename.name
 
165
 
 
166
        # Get the sets of binary package names, summaries, descriptions.
 
167
 
 
168
        # XXX Julian 2007-04-03:
 
169
        # This bit of code needs fixing up, it is doing stuff that
 
170
        # really needs to be done in SQL, such as sorting and uniqueness.
 
171
        # This would also improve the performance.
 
172
        binpkgnames = set()
 
173
        binpkgsummaries = set()
 
174
        binpkgdescriptions = set()
 
175
        sprchangelog = set()
 
176
        for spr in sprs:
 
177
            log.debug("Considering source version %s" % spr.version)
 
178
            # changelog may be empty, in which case we don't want to add it
 
179
            # to the set as the join would fail below.
 
180
            if spr.changelog_entry is not None:
 
181
                sprchangelog.add(spr.changelog_entry)
 
182
            binpkgs = BinaryPackageRelease.select("""
 
183
                BinaryPackageRelease.build = BinaryPackageBuild.id AND
 
184
                BinaryPackageBuild.source_package_release = %s
 
185
                """ % sqlvalues(spr.id),
 
186
                clauseTables=['BinaryPackageBuild'])
 
187
            for binpkg in binpkgs:
 
188
                log.debug("Considering binary '%s'" % binpkg.name)
 
189
                binpkgnames.add(binpkg.name)
 
190
                binpkgsummaries.add(binpkg.summary)
 
191
                binpkgdescriptions.add(binpkg.description)
 
192
 
 
193
        # Update the caches.
 
194
        cache.binpkgnames = ' '.join(sorted(binpkgnames))
 
195
        cache.binpkgsummaries = ' '.join(sorted(binpkgsummaries))
 
196
        cache.binpkgdescriptions = ' '.join(sorted(binpkgdescriptions))
 
197
        cache.changelog = ' '.join(sorted(sprchangelog))
 
198
 
 
199
    @classmethod
 
200
    def updateAll(cls, distro, archive, log, ztm, commit_chunk=500):
 
201
        """Update the source package cache.
 
202
 
 
203
        Consider every non-REMOVED sourcepackage and entirely skips updates
 
204
        for disabled archives.
 
205
 
 
206
        :param archive: target `IArchive`;
 
207
        :param log: logger object for printing debug level information;
 
208
        :param ztm:  transaction used for partial commits, every chunk of
 
209
            'commit_chunk' updates is committed;
 
210
        :param commit_chunk: number of updates before commit, defaults to 500.
 
211
 
 
212
        :return the number packages updated done
 
213
        """
 
214
        # Do not create cache entries for disabled archives.
 
215
        if not archive.enabled:
 
216
            return
 
217
 
 
218
        # Get the set of source package names to deal with.
 
219
        spns = list(SourcePackageName.select("""
 
220
            SourcePackagePublishingHistory.distroseries =
 
221
                DistroSeries.id AND
 
222
            DistroSeries.distribution = %s AND
 
223
            SourcePackagePublishingHistory.archive = %s AND
 
224
            SourcePackagePublishingHistory.sourcepackagerelease =
 
225
                SourcePackageRelease.id AND
 
226
            SourcePackageRelease.sourcepackagename =
 
227
                SourcePackageName.id AND
 
228
            SourcePackagePublishingHistory.dateremoved is NULL
 
229
            """ % sqlvalues(distro, archive),
 
230
            distinct=True,
 
231
            orderBy="name",
 
232
            clauseTables=['SourcePackagePublishingHistory', 'DistroSeries',
 
233
                'SourcePackageRelease']))
 
234
 
 
235
        number_of_updates = 0
 
236
        chunk_size = 0
 
237
        for spn in spns:
 
238
            log.debug("Considering source '%s'" % spn.name)
 
239
            cls._update(distro, spn, archive, log)
 
240
            chunk_size += 1
 
241
            number_of_updates += 1
 
242
            if chunk_size == commit_chunk:
 
243
                chunk_size = 0
 
244
                log.debug("Committing")
 
245
                ztm.commit()
 
246
 
 
247
        return number_of_updates