36
29
IDistroSeriesDifferenceJobSource,
38
31
from lp.soyuz.interfaces.packageset import IPackagesetSet
39
from lp.soyuz.interfaces.publishing import active_publishing_status
40
32
from lp.soyuz.model.distributionjob import (
42
34
DistributionJobDerived,
44
from lp.soyuz.model.publishing import SourcePackagePublishingHistory
45
from lp.soyuz.model.sourcepackagerelease import SourcePackageRelease
48
38
FEATURE_FLAG_ENABLE_MODULE = u"soyuz.derived_series_jobs.enabled"
51
def make_metadata(sourcepackagename, parent_series):
41
def make_metadata(sourcepackagename):
52
42
"""Return JSON metadata for a job on `sourcepackagename`."""
54
'sourcepackagename': sourcepackagename.id,
55
'parent_series': parent_series.id,
59
def create_job(derived_series, sourcepackagename, parent_series):
43
return {'sourcepackagename': sourcepackagename.id}
46
def create_job(distroseries, sourcepackagename):
60
47
"""Create a `DistroSeriesDifferenceJob` for a given source package.
62
:param derived_series: A `DistroSeries` that is assumed to be derived
49
:param distroseries: A `DistroSeries` that is assumed to be derived
64
51
:param sourcepackagename: The `SourcePackageName` whose publication
65
52
history has changed.
66
:param parent_series: A `DistroSeries` that is a parent of
67
`derived_series`. The difference is between the versions of
68
`sourcepackagename` in `parent_series` and `derived_series`.
70
54
job = DistributionJob(
71
distribution=derived_series.distribution, distroseries=derived_series,
55
distribution=distroseries.distribution, distroseries=distroseries,
72
56
job_type=DistributionJobType.DISTROSERIESDIFFERENCE,
73
metadata=make_metadata(sourcepackagename, parent_series))
57
metadata=make_metadata(sourcepackagename))
74
58
IMasterStore(DistributionJob).add(job)
75
59
return DistroSeriesDifferenceJob(job)
78
def create_multiple_jobs(derived_series, parent_series):
79
"""Create a `DistroSeriesDifferenceJob` for all the source packages in
82
:param derived_series: A `DistroSeries` that is assumed to be derived
84
:param parent_series: A `DistroSeries` that is a parent of
87
store = IStore(SourcePackageRelease)
88
source_package_releases = store.find(
91
SourcePackagePublishingHistory.sourcepackagerelease ==
92
SourcePackageRelease.id,
93
SourcePackagePublishingHistory.distroseries == derived_series.id,
94
SourcePackagePublishingHistory.status.is_in(
95
active_publishing_status)))
96
nb_jobs = source_package_releases.count()
97
sourcepackagenames = source_package_releases.values(
98
SourcePackageRelease.sourcepackagenameID)
99
job_ids = Job.createMultiple(store, nb_jobs)
101
def composeJobInsertionTuple(derived_series, parent_series,
102
sourcepackagename, job_id):
104
derived_series.distribution.id, derived_series.id,
105
DistributionJobType.DISTROSERIESDIFFERENCE, job_id,
106
DistributionJob.serializeMetadata(
107
{'sourcepackagename': sourcepackagename,
108
'parent_series': parent_series.id}))
109
format_string = "(%s)" % ", ".join(["%s"] * len(data))
110
return format_string % sqlvalues(*data)
113
composeJobInsertionTuple(
114
derived_series, parent_series, sourcepackagename, job_id)
115
for job_id, sourcepackagename in
116
zip(job_ids, sourcepackagenames)]
118
store = IStore(DistributionJob)
119
result = store.execute("""
120
INSERT INTO DistributionJob (
121
distribution, distroseries, job_type, job, json_data)
124
""" % ", ".join(job_contents))
125
return [job_id for job_id, in result]
128
def find_waiting_jobs(derived_series, sourcepackagename, parent_series):
62
def find_waiting_jobs(distroseries, sourcepackagename):
129
63
"""Look for pending `DistroSeriesDifference` jobs on a package."""
130
64
# Look for identical pending jobs. This compares directly on
131
65
# the metadata string. It's fragile, but this is only an
132
66
# optimization. It's not actually disastrous to create
133
67
# redundant jobs occasionally.
134
68
json_metadata = DistributionJob.serializeMetadata(
135
make_metadata(sourcepackagename, parent_series))
69
make_metadata(sourcepackagename))
137
71
# Use master store because we don't like outdated information
139
73
store = IMasterStore(DistributionJob)
141
candidates = store.find(
143
77
DistributionJob.job_type ==
144
78
DistributionJobType.DISTROSERIESDIFFERENCE,
145
DistributionJob.distroseries == derived_series,
79
DistributionJob.distroseries == distroseries,
146
80
DistributionJob._json_data == json_metadata,
147
81
DistributionJob.job_id.is_in(Job.ready_jobs))
151
for job in candidates
152
if job.metadata["parent_series"] == parent_series.id]
155
def may_require_job(derived_series, sourcepackagename, parent_series):
84
def may_require_job(distroseries, sourcepackagename):
156
85
"""Might publishing this package require a new job?
158
87
Use this to determine whether to create a new
205
130
PackagePublishingPocket.PROPOSED):
208
parent_series = derived_series.getParentSeries()
209
# Create jobs for DSDs between the derived_series and its
211
for parent in parent_series:
213
derived_series, sourcepackagename, parent):
214
jobs.append(create_job(
215
derived_series, sourcepackagename, parent))
216
# Create jobs for DSDs between the derived_series and its
218
for child in derived_series.getDerivedSeries():
220
child, sourcepackagename, derived_series):
221
jobs.append(create_job(
222
child, sourcepackagename, derived_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))
226
def massCreateForSeries(cls, derived_series):
227
"""See `IDistroSeriesDifferenceJobSource`."""
228
if not getFeatureFlag(FEATURE_FLAG_ENABLE_MODULE):
230
for parent_series in derived_series.getParentSeries():
231
create_multiple_jobs(derived_series, parent_series)
234
def getPendingJobsForDifferences(cls, derived_series,
235
distroseriesdifferences):
236
"""See `IDistroSeriesDifferenceJobSource`."""
237
jobs = IStore(DistributionJob).find(
239
DistributionJob.job_type == cls.class_job_type,
240
Job.id == DistributionJob.job_id,
241
Job._status.is_in(Job.PENDING_STATUSES),
242
DistributionJob.distroseries == derived_series)
244
parent_series_ids = set(
245
dsd.parent_series.id for dsd in distroseriesdifferences)
247
(dsd.source_package_name.id, dsd)
248
for dsd in distroseriesdifferences)
251
if job.metadata["parent_series"] not in parent_series_ids:
253
dsd = keyed_dsds.get(job.metadata["sourcepackagename"])
255
jobs_by_dsd.setdefault(dsd, []).append(cls(job))
259
140
def sourcepackagename(self):
260
141
return SourcePackageName.get(self.metadata['sourcepackagename'])
263
def derived_series(self):
264
return self.distroseries
267
def parent_series(self):
268
parent_id = self.metadata['parent_series']
269
return IStore(DistroSeries).get(DistroSeries, parent_id)
271
143
def passesPackagesetFilter(self):
272
144
"""Is this package of interest as far as packagesets are concerned?
275
147
missing in the derived series are only of interest if they are
276
148
in a packageset that the derived series also has.
278
derived_series = self.derived_series
279
parent_series = self.parent_series
281
sourcepackagename = self.sourcepackagename
282
if has_package(derived_series, sourcepackagename):
150
derived_series = self.distroseries
151
previous_series = derived_series.previous_series
152
if has_package(derived_series, self.sourcepackagename):
284
if not has_package(parent_series, sourcepackagename):
154
if not has_package(previous_series, self.sourcepackagename):
286
156
packagesetset = getUtility(IPackagesetSet)
287
if packagesetset.getBySeries(parent_series).is_empty():
157
if packagesetset.getBySeries(previous_series).is_empty():
288
158
# Parent series does not have packagesets, as would be the
289
159
# case for e.g. Debian. In that case, don't filter.
291
161
parent_sets = packagesetset.setsIncludingSource(
292
sourcepackagename, distroseries=parent_series)
162
self.sourcepackagename, distroseries=previous_series)
293
163
for parent_set in parent_sets:
294
164
for related_set in parent_set.relatedSets():
295
165
if related_set.distroseries == derived_series:
299
def getMatchingDSD(self):
300
"""Find an existing `DistroSeriesDifference` for this difference."""
301
spn_id = self.metadata["sourcepackagename"]
302
parent_id = self.metadata["parent_series"]
303
store = IMasterStore(DistroSeriesDifference)
305
DistroSeriesDifference,
306
DistroSeriesDifference.derived_series == self.derived_series,
307
DistroSeriesDifference.parent_series_id == parent_id,
308
DistroSeriesDifference.source_package_name_id == spn_id)
312
170
"""See `IRunnableJob`."""
313
171
if not self.passesPackagesetFilter():
316
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()
317
180
if ds_diff is None:
318
181
ds_diff = getUtility(IDistroSeriesDifferenceSource).new(
319
self.distroseries, self.sourcepackagename, self.parent_series)
182
self.distroseries, self.sourcepackagename)