~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 `parent_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.parent_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
221
    """Find all derived `DistroSeries`.
215
 
 
216
 
    Derived `DistroSeries` are ones that have a `parent_series`, but
217
 
    where the `parent_series` is not in the same distribution.
218
222
    """
 
223
    Child = ClassAlias(DistroSeries, "Child")
219
224
    Parent = ClassAlias(DistroSeries, "Parent")
220
 
    return IStore(DistroSeries).find(
221
 
        DistroSeries,
222
 
        Parent.id == DistroSeries.parent_seriesID,
223
 
        Parent.distributionID != DistroSeries.distributionID).order_by(
224
 
            (DistroSeries.parent_seriesID, DistroSeries.id))
 
225
    relations = IStore(DistroSeries).find(
 
226
        (Child, Parent),
 
227
        DistroSeriesParent.derived_series_id == Child.id,
 
228
        DistroSeriesParent.parent_series_id == Parent.id)
 
229
    collated = defaultdict(list)
 
230
    for child, parent in relations:
 
231
        collated[child].append(parent)
 
232
    return collated
225
233
 
226
234
 
227
235
class DSDUpdater(TunableLoop):
301
309
    def getDistroSeries(self):
302
310
        """Return the `DistroSeries` that are to be processed."""
303
311
        if self.options.all:
304
 
            return list(find_derived_series())
 
312
            return find_derived_series()
305
313
        else:
306
314
            distro = getUtility(IDistributionSet).getByName(
307
315
                self.options.distribution)
308
316
            series = distro.getSeries(self.options.series)
 
317
            augmented_series = defaultdict(list)
309
318
            if series is None:
310
319
                raise OptionValueError(
311
320
                    "Could not find %s series %s." % (
312
321
                        self.options.distribution, self.options.series))
313
 
            if series.parent_series is None:
 
322
            dsp = getUtility(IDistroSeriesParentSet).getByDerivedSeries(
 
323
                series)
 
324
            for rel in dsp:
 
325
                augmented_series[rel.derived_series].append(
 
326
                    rel.parent_series)
 
327
            if len(augmented_series) == 0:
314
328
                raise OptionValueError(
315
329
                    "%s series %s is not derived." % (
316
330
                        self.options.distribution, self.options.series))
317
 
            return [series]
 
331
            return augmented_series
318
332
 
319
 
    def processDistroSeries(self, distroseries):
 
333
    def processDistroSeries(self, distroseries, parent):
320
334
        """Generate `DistroSeriesDifference`s for `distroseries`."""
321
 
        self.logger.info("Looking for differences in %s.", distroseries)
322
 
        populate_distroseriesdiff(self.logger, distroseries)
 
335
        self.logger.info(
 
336
            "Looking for differences in %s with regards to %s.",
 
337
            distroseries, parent)
 
338
        populate_distroseriesdiff(self.logger, distroseries, parent)
323
339
        self.commit()
324
340
        self.logger.info("Updating base_versions.")
325
341
        self.update(distroseries)
335
351
 
336
352
    def listDerivedSeries(self):
337
353
        """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)
 
354
        relationships = self.getDistroSeries()
 
355
        for child in relationships:
 
356
            for parent in relationships[child]:
 
357
               self.logger.info(
 
358
                    "%s %s with a parent of %s %s", child.distribution.name,
 
359
                    child.name, parent.distribution.name, parent.name)
340
360
 
341
361
    def checkOptions(self):
342
362
        """Verify command-line options."""
363
383
        if self.options.dry_run:
364
384
            self.logger.info("Dry run requested.  Not committing changes.")
365
385
 
366
 
        for series in self.getDistroSeries():
367
 
            self.processDistroSeries(series)
 
386
        relationships = self.getDistroSeries()
 
387
        for child in relationships.keys():
 
388
            for parent in relationships[child]:
 
389
                self.processDistroSeries(child, parent)
368
390
 
369
391
    def update(self, distroseries):
370
392
        """Call `DistroSeriesDifference.update()` where appropriate.