~launchpad-pqm/launchpad/devel

« back to all changes in this revision

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

  • Committer: Francis J. Lacoste
  • Date: 2011-04-27 21:40:03 UTC
  • mto: This revision was merged to the branch mainline in revision 12971.
  • Revision ID: francis.lacoste@canonical.com-20110427214003-iiqhcyyswppyqjsx
Change the default timeout to production value, improved options documentation and use only one bin above timeout value.

Show diffs side-by-side

added added

removed removed

Lines of Context:
14
14
    implements,
15
15
    )
16
16
 
17
 
from canonical.launchpad.interfaces.lpstorm import (
18
 
    IMasterStore,
19
 
    IStore,
20
 
    )
 
17
from canonical.launchpad.interfaces.lpstorm import IMasterStore
21
18
from lp.registry.interfaces.distroseriesdifference import (
22
19
    IDistroSeriesDifferenceSource,
23
20
    )
24
 
from lp.registry.interfaces.distroseriesparent import IDistroSeriesParentSet
25
21
from lp.registry.interfaces.pocket import PackagePublishingPocket
26
 
from lp.registry.model.distroseries import DistroSeries
27
22
from lp.registry.model.distroseriesdifference import DistroSeriesDifference
28
23
from lp.registry.model.sourcepackagename import SourcePackageName
29
24
from lp.services.features import getFeatureFlag
43
38
FEATURE_FLAG_ENABLE_MODULE = u"soyuz.derived_series_jobs.enabled"
44
39
 
45
40
 
46
 
def make_metadata(sourcepackagename, parent_series=None):
 
41
def make_metadata(sourcepackagename):
47
42
    """Return JSON metadata for a job on `sourcepackagename`."""
48
 
    # XXX JeroenVermeulen 2011-05-26 bug=758906: Make parent_series
49
 
    # mandatory as part of multi-parent support.
50
 
    if parent_series is None:
51
 
        parent_id = None
52
 
    else:
53
 
        parent_id = parent_series.id
54
 
    return {
55
 
        'sourcepackagename': sourcepackagename.id,
56
 
        'parent_series': parent_id,
57
 
    }
58
 
 
59
 
 
60
 
def create_job(derived_series, sourcepackagename, parent_series=None):
 
43
    return {'sourcepackagename': sourcepackagename.id}
 
44
 
 
45
 
 
46
def create_job(distroseries, sourcepackagename):
61
47
    """Create a `DistroSeriesDifferenceJob` for a given source package.
62
48
 
63
 
    :param derived_series: A `DistroSeries` that is assumed to be derived
 
49
    :param distroseries: A `DistroSeries` that is assumed to be derived
64
50
        from another one.
65
51
    :param sourcepackagename: The `SourcePackageName` whose publication
66
52
        history has changed.
67
 
    :param parent_series: A `DistroSeries` that is a parent of
68
 
        `derived_series`.  The difference is between the versions of
69
 
        `sourcepackagename` in `parent_series` and `derived_series`.
70
53
    """
71
 
    # XXX JeroenVermeulen 2011-05-26 bug=758906: Make parent_series
72
 
    # mandatory as part of multi-parent support.
73
54
    job = DistributionJob(
74
 
        distribution=derived_series.distribution, distroseries=derived_series,
 
55
        distribution=distroseries.distribution, distroseries=distroseries,
75
56
        job_type=DistributionJobType.DISTROSERIESDIFFERENCE,
76
 
        metadata=make_metadata(sourcepackagename, parent_series))
 
57
        metadata=make_metadata(sourcepackagename))
77
58
    IMasterStore(DistributionJob).add(job)
78
59
    return DistroSeriesDifferenceJob(job)
79
60
 
80
61
 
81
 
def find_waiting_jobs(derived_series, sourcepackagename, parent_series=None):
 
62
def find_waiting_jobs(distroseries, sourcepackagename):
82
63
    """Look for pending `DistroSeriesDifference` jobs on a package."""
83
64
    # Look for identical pending jobs.  This compares directly on
84
65
    # the metadata string.  It's fragile, but this is only an
85
66
    # optimization.  It's not actually disastrous to create
86
67
    # redundant jobs occasionally.
87
68
    json_metadata = DistributionJob.serializeMetadata(
88
 
        make_metadata(sourcepackagename, parent_series))
 
69
        make_metadata(sourcepackagename))
89
70
 
90
71
    # Use master store because we don't like outdated information
91
72
    # here.
92
73
    store = IMasterStore(DistributionJob)
93
74
 
94
 
    candidates = store.find(
 
75
    return store.find(
95
76
        DistributionJob,
96
77
        DistributionJob.job_type ==
97
78
            DistributionJobType.DISTROSERIESDIFFERENCE,
98
 
        DistributionJob.distroseries == derived_series,
 
79
        DistributionJob.distroseries == distroseries,
99
80
        DistributionJob._json_data == json_metadata,
100
81
        DistributionJob.job_id.is_in(Job.ready_jobs))
101
82
 
102
 
    # XXX JeroenVermeulen 2011-05-26 bug=758906: Make parent_series
103
 
    # mandatory as part of multi-parent support.
104
 
    if parent_series is None:
105
 
        return list(candidates)
106
 
 
107
 
    return [
108
 
        job
109
 
        for job in candidates
110
 
            if job.metadata["parent_series"] == parent_series.id]
111
 
 
112
 
 
113
 
def may_require_job(derived_series, sourcepackagename, parent_series=None):
 
83
 
 
84
def may_require_job(distroseries, sourcepackagename):
114
85
    """Might publishing this package require a new job?
115
86
 
116
87
    Use this to determine whether to create a new
119
90
    runner some unnecessary work, but we don't expect a bit of
120
91
    unnecessary work to be a big problem.
121
92
    """
122
 
    # XXX JeroenVermeulen 2011-05-26 bug=758906: Make parent_series
123
 
    # mandatory as part of multi-parent support.
124
 
    if derived_series is None:
125
 
        return False
126
 
    dsp = getUtility(IDistroSeriesParentSet).getByDerivedSeries(
127
 
        derived_series)
128
 
    if dsp.count() == 0:
129
 
        return False
130
 
    for parent in dsp:
131
 
        if parent.parent_series.distribution == derived_series.distribution:
132
 
            # Differences within a distribution are not tracked.
133
 
            return False
134
 
    existing_jobs = find_waiting_jobs(
135
 
        derived_series, sourcepackagename, parent_series)
136
 
    return len(existing_jobs) == 0
 
93
    if distroseries is None:
 
94
        return False
 
95
    parent_series = distroseries.parent_series
 
96
    if parent_series is None:
 
97
        return False
 
98
    if parent_series.distribution == distroseries.distribution:
 
99
        # Differences within a distribution are not tracked.
 
100
        return False
 
101
    return find_waiting_jobs(distroseries, sourcepackagename).is_empty()
137
102
 
138
103
 
139
104
def has_package(distroseries, sourcepackagename):
151
116
    class_job_type = DistributionJobType.DISTROSERIESDIFFERENCE
152
117
 
153
118
    @classmethod
154
 
    def createForPackagePublication(cls, derived_series, sourcepackagename,
155
 
                                    pocket, parent_series=None):
 
119
    def createForPackagePublication(cls, distroseries, sourcepackagename,
 
120
                                    pocket):
156
121
        """See `IDistroSeriesDifferenceJobSource`."""
157
 
        # XXX JeroenVermeulen 2011-05-26 bug=758906: Make parent_series
158
 
        # mandatory as part of multi-parent support.
159
122
        if not getFeatureFlag(FEATURE_FLAG_ENABLE_MODULE):
160
123
            return
161
124
        # -backports and -proposed are not really part of a standard
167
130
            PackagePublishingPocket.PROPOSED):
168
131
            return
169
132
        jobs = []
170
 
        children = list(derived_series.getDerivedSeries())
171
 
        for relative in children + [derived_series]:
172
 
            if may_require_job(relative, sourcepackagename, parent_series):
173
 
                jobs.append(create_job(
174
 
                    relative, sourcepackagename, parent_series))
 
133
        children = list(distroseries.getDerivedSeries())
 
134
        for relative in children + [distroseries]:
 
135
            if may_require_job(relative, sourcepackagename):
 
136
                jobs.append(create_job(relative, sourcepackagename))
175
137
        return jobs
176
138
 
177
 
    @classmethod
178
 
    def getPendingJobsForDifferences(cls, derived_series,
179
 
                                     distroseriesdifferences):
180
 
        """See `IDistroSeriesDifferenceJobSource`."""
181
 
        jobs = IStore(DistributionJob).find(
182
 
            DistributionJob,
183
 
            DistributionJob.job_type == cls.class_job_type,
184
 
            Job.id == DistributionJob.job_id,
185
 
            Job._status.is_in(Job.PENDING_STATUSES),
186
 
            DistributionJob.distroseries == derived_series)
187
 
 
188
 
        # XXX JeroenVermeulen 2011-05-26 bug=758906: Check for parent
189
 
        # series once it becomes available.
190
 
        keyed_dsds = dict(
191
 
            (dsd.source_package_name.id, dsd)
192
 
            for dsd in distroseriesdifferences)
193
 
        jobs_by_dsd = {}
194
 
        for job in jobs:
195
 
            dsd = keyed_dsds.get(job.metadata["sourcepackagename"])
196
 
            if dsd is not None:
197
 
                jobs_by_dsd.setdefault(dsd, []).append(cls(job))
198
 
        return jobs_by_dsd
199
 
 
200
139
    @property
201
140
    def sourcepackagename(self):
202
141
        return SourcePackageName.get(self.metadata['sourcepackagename'])
203
142
 
204
 
    @property
205
 
    def derived_series(self):
206
 
        return self.distroseries
207
 
 
208
 
    @property
209
 
    def parent_series(self):
210
 
        parent_id = self.metadata['parent_series']
211
 
        if not parent_id:
212
 
            # XXX JeroenVermeulen 2011-05-26 bug=758906: Make parent_series
213
 
            # mandatory as part of multi-parent support.
214
 
            return None
215
 
        return IStore(DistroSeries).get(DistroSeries, parent_id)
216
 
 
217
143
    def passesPackagesetFilter(self):
218
144
        """Is this package of interest as far as packagesets are concerned?
219
145
 
221
147
        missing in the derived series are only of interest if they are
222
148
        in a packageset that the derived series also has.
223
149
        """
224
 
        derived_series = self.derived_series
225
 
        parent_series = self.parent_series
226
 
        # XXX JeroenVermeulen 2011-05-26 bug=758906: Make parent_series
227
 
        # mandatory as part of multi-parent support.
228
 
        if parent_series is None:
229
 
            dsp = getUtility(IDistroSeriesParentSet).getByDerivedSeries(
230
 
                derived_series)
231
 
            parent_series = dsp[0].parent_series
232
 
 
233
 
        sourcepackagename = self.sourcepackagename
234
 
        if has_package(derived_series, sourcepackagename):
 
150
        derived_series = self.distroseries
 
151
        parent_series = derived_series.parent_series
 
152
        if has_package(derived_series, self.sourcepackagename):
235
153
            return True
236
 
        if not has_package(parent_series, sourcepackagename):
 
154
        if not has_package(parent_series, self.sourcepackagename):
237
155
            return True
238
156
        packagesetset = getUtility(IPackagesetSet)
239
157
        if packagesetset.getBySeries(parent_series).is_empty():
241
159
            # case for e.g. Debian.  In that case, don't filter.
242
160
            return True
243
161
        parent_sets = packagesetset.setsIncludingSource(
244
 
            sourcepackagename, distroseries=parent_series)
 
162
            self.sourcepackagename, distroseries=parent_series)
245
163
        for parent_set in parent_sets:
246
164
            for related_set in parent_set.relatedSets():
247
165
                if related_set.distroseries == derived_series:
248
166
                    return True
249
167
        return False
250
168
 
251
 
    def getMatchingDSD(self):
252
 
        """Find an existing `DistroSeriesDifference` for this difference."""
253
 
        spn_id = self.metadata["sourcepackagename"]
254
 
        parent_id = self.metadata["parent_series"]
255
 
        store = IMasterStore(DistroSeriesDifference)
256
 
        # XXX JeroenVermeulen 2011-05-26 bug=758906: Make parent_series
257
 
        # mandatory as part of multi-parent support.
258
 
        if parent_id is None:
259
 
            match_parent = True
260
 
        else:
261
 
            match_parent = (
262
 
                DistroSeriesDifference.parent_series_id == parent_id)
263
 
        search = store.find(
264
 
            DistroSeriesDifference,
265
 
            DistroSeriesDifference.derived_series == self.derived_series,
266
 
            DistroSeriesDifference.source_package_name_id == spn_id,
267
 
            match_parent)
268
 
        return search.one()
269
 
 
270
169
    def run(self):
271
170
        """See `IRunnableJob`."""
272
171
        if not self.passesPackagesetFilter():
273
172
            return
274
173
 
275
 
        ds_diff = self.getMatchingDSD()
 
174
        store = IMasterStore(DistroSeriesDifference)
 
175
        ds_diff = store.find(
 
176
            DistroSeriesDifference,
 
177
            DistroSeriesDifference.derived_series == self.distroseries,
 
178
            DistroSeriesDifference.source_package_name ==
 
179
            self.sourcepackagename).one()
276
180
        if ds_diff is None:
277
181
            ds_diff = getUtility(IDistroSeriesDifferenceSource).new(
278
 
                self.distroseries, self.sourcepackagename, self.parent_series)
 
182
                self.distroseries, self.sourcepackagename)
279
183
        else:
280
184
            ds_diff.update()