~launchpad-pqm/launchpad/devel

« back to all changes in this revision

Viewing changes to lib/lp/registry/scripts/populate_distroseriesdiff.py

Merge db-devel.

Show diffs side-by-side

added added

removed removed

Lines of Context:
16
16
    'PopulateDistroSeriesDiff',
17
17
    ]
18
18
 
 
19
from collections import defaultdict
19
20
from optparse import (
20
21
    Option,
21
22
    OptionValueError,
22
23
    )
23
 
from storm.info import ClassAlias
 
24
from storm.locals import ClassAlias
24
25
import transaction
25
26
from zope.component import getUtility
26
27
 
35
36
    )
36
37
from canonical.launchpad.utilities.looptuner import TunableLoop
37
38
from lp.registry.interfaces.distribution import IDistributionSet
 
39
from lp.registry.interfaces.distroseriesparent import IDistroSeriesParentSet
38
40
from lp.registry.interfaces.pocket import PackagePublishingPocket
39
41
from lp.registry.model.distroseries import DistroSeries
40
42
from lp.registry.model.distroseriesdifference import DistroSeriesDifference
 
43
from lp.registry.model.distroseriesparent import DistroSeriesParent
41
44
from lp.services.scripts.base import LaunchpadScript
42
45
from lp.soyuz.interfaces.publishing import active_publishing_status
43
46
 
78
81
        """ % parameters
79
82
 
80
83
 
81
 
def compose_sql_find_differences(derived_distroseries):
 
84
def compose_sql_find_differences(derived_series, parent_series):
82
85
    """Produce SQL that finds differences for a `DistroSeries`.
83
86
 
84
87
    The query compares `derived_distroseries` and its `previous_series`
92
95
    """
93
96
    parameters = {
94
97
        'derived_query': compose_sql_find_latest_source_package_releases(
95
 
            derived_distroseries),
 
98
            derived_series),
96
99
        'parent_query': compose_sql_find_latest_source_package_releases(
97
 
            derived_distroseries.previous_series),
 
100
            parent_series),
98
101
    }
99
102
    return """
100
103
        SELECT DISTINCT
137
140
        """ % parameters
138
141
 
139
142
 
140
 
def compose_sql_populate_distroseriesdiff(derived_distroseries, temp_table):
 
143
def compose_sql_populate_distroseriesdiff(derived_series, parent_series,
 
144
                                          temp_table):
141
145
    """Create `DistroSeriesDifference` rows based on found differences.
142
146
 
143
147
    Uses field values that describe the difference, as produced by the
154
158
    :return: SQL query, as a string.
155
159
    """
156
160
    parameters = {
157
 
        'derived_series': quote(derived_distroseries),
 
161
        'derived_series': quote(derived_series),
 
162
        'parent_series': quote(parent_series),
158
163
        'difference_type_expression': compose_sql_difference_type(),
159
164
        'needs_attention': quote(
160
165
            DistroSeriesDifferenceStatus.NEEDS_ATTENTION),
163
168
    return """
164
169
        INSERT INTO DistroSeriesDifference (
165
170
            derived_series,
 
171
            parent_series,
166
172
            source_package_name,
167
173
            status,
168
174
            difference_type,
170
176
            parent_source_version)
171
177
        SELECT
172
178
            %(derived_series)s,
 
179
            %(parent_series)s,
173
180
            sourcepackagename,
174
181
            %(needs_attention)s,
175
182
            %(difference_type_expression)s,
188
195
    store.execute("DROP TABLE IF EXISTS %s" % quote_identifier(table))
189
196
 
190
197
 
191
 
def populate_distroseriesdiff(logger, derived_distroseries):
 
198
def populate_distroseriesdiff(logger, derived_series, parent_series):
192
199
    """Compare `derived_distroseries` to parent, and register differences.
193
200
 
194
201
    The differences are registered by creating `DistroSeriesDifference`
196
203
    """
197
204
    temp_table = "temp_potentialdistroseriesdiff"
198
205
 
199
 
    store = IStore(derived_distroseries)
 
206
    store = IStore(derived_series)
200
207
    drop_table(store, temp_table)
201
208
    store.execute("CREATE TEMP TABLE %s AS %s" % (
202
209
        quote_identifier(temp_table),
203
 
        compose_sql_find_differences(derived_distroseries)))
 
210
        compose_sql_find_differences(derived_series, parent_series)))
204
211
    logger.info(
205
212
        "Found %d potential difference(s).",
206
213
        store.execute("SELECT count(*) FROM %s" % temp_table).get_one()[0])
207
214
    store.execute(
208
215
        compose_sql_populate_distroseriesdiff(
209
 
            derived_distroseries, temp_table))
 
216
            derived_series, parent_series, temp_table))
210
217
    drop_table(store, temp_table)
211
218
 
212
219
 
213
220
def find_derived_series():
214
 
    """Find all derived `DistroSeries`.
215
 
 
216
 
    Derived `DistroSeries` are ones that have a `previous_series`, but
217
 
    where the `previous_series` is not in the same distribution.
218
 
    """
 
221
    """Find all derived `DistroSeries`."""
 
222
    Child = ClassAlias(DistroSeries, "Child")
219
223
    Parent = ClassAlias(DistroSeries, "Parent")
220
 
    return IStore(DistroSeries).find(
221
 
        DistroSeries,
222
 
        Parent.id == DistroSeries.previous_seriesID,
223
 
        Parent.distributionID != DistroSeries.distributionID).order_by(
224
 
            (DistroSeries.previous_seriesID, DistroSeries.id))
 
224
    relations = IStore(DistroSeries).find(
 
225
        (Child, Parent),
 
226
        DistroSeriesParent.derived_series_id == Child.id,
 
227
        DistroSeriesParent.parent_series_id == Parent.id)
 
228
    collated = defaultdict(list)
 
229
    for child, parent in relations:
 
230
        collated[child].append(parent)
 
231
    return collated
225
232
 
226
233
 
227
234
class DSDUpdater(TunableLoop):
301
308
    def getDistroSeries(self):
302
309
        """Return the `DistroSeries` that are to be processed."""
303
310
        if self.options.all:
304
 
            return list(find_derived_series())
 
311
            return find_derived_series()
305
312
        else:
306
313
            distro = getUtility(IDistributionSet).getByName(
307
314
                self.options.distribution)
308
315
            series = distro.getSeries(self.options.series)
 
316
            augmented_series = defaultdict(list)
309
317
            if series is None:
310
318
                raise OptionValueError(
311
319
                    "Could not find %s series %s." % (
312
320
                        self.options.distribution, self.options.series))
313
 
            if series.previous_series is None:
 
321
            dsp = getUtility(IDistroSeriesParentSet).getByDerivedSeries(
 
322
                series)
 
323
            for rel in dsp:
 
324
                augmented_series[rel.derived_series].append(
 
325
                    rel.parent_series)
 
326
            if len(augmented_series) == 0:
314
327
                raise OptionValueError(
315
328
                    "%s series %s is not derived." % (
316
329
                        self.options.distribution, self.options.series))
317
 
            return [series]
 
330
            return augmented_series
318
331
 
319
 
    def processDistroSeries(self, distroseries):
 
332
    def processDistroSeries(self, distroseries, parent):
320
333
        """Generate `DistroSeriesDifference`s for `distroseries`."""
321
 
        self.logger.info("Looking for differences in %s.", distroseries)
322
 
        populate_distroseriesdiff(self.logger, distroseries)
 
334
        self.logger.info(
 
335
            "Looking for differences in %s with regards to %s.",
 
336
            distroseries, parent)
 
337
        populate_distroseriesdiff(self.logger, distroseries, parent)
323
338
        self.commit()
324
339
        self.logger.info("Updating base_versions.")
325
340
        self.update(distroseries)
335
350
 
336
351
    def listDerivedSeries(self):
337
352
        """Log all `DistroSeries` that the --all option would cover."""
338
 
        for series in self.getDistroSeries():
339
 
            self.logger.info("%s %s", series.distribution.name, series.name)
 
353
        relationships = self.getDistroSeries()
 
354
        for child in relationships:
 
355
            for parent in relationships[child]:
 
356
               self.logger.info(
 
357
                    "%s %s with a parent of %s %s", child.distribution.name,
 
358
                    child.name, parent.distribution.name, parent.name)
340
359
 
341
360
    def checkOptions(self):
342
361
        """Verify command-line options."""
363
382
        if self.options.dry_run:
364
383
            self.logger.info("Dry run requested.  Not committing changes.")
365
384
 
366
 
        for series in self.getDistroSeries():
367
 
            self.processDistroSeries(series)
 
385
        relationships = self.getDistroSeries()
 
386
        for child in relationships.keys():
 
387
            for parent in relationships[child]:
 
388
                self.processDistroSeries(child, parent)
368
389
 
369
390
    def update(self, distroseries):
370
391
        """Call `DistroSeriesDifference.update()` where appropriate.