43
45
IDistroSeriesDifferenceCommentSource,
45
47
from lp.services.database.stormbase import StormBase
46
from lp.services.job.interfaces.job import JobStatus
48
from lp.services.job.interfaces.job import (
47
52
from lp.services.job.model.job import Job
48
53
from lp.services.job.runner import BaseRunnableJob
49
from lp.soyuz.adapters.overrides import SourceOverride
54
from lp.soyuz.adapters.overrides import (
55
FromExistingOverridePolicy,
57
UnknownOverridePolicy,
50
59
from lp.soyuz.enums import PackageCopyPolicy
51
60
from lp.soyuz.interfaces.archive import CannotCopy
52
61
from lp.soyuz.interfaces.component import IComponentSet
184
194
classProvides(IPlainPackageCopyJobSource)
197
def _makeMetadata(cls, target_pocket, package_version, include_binaries):
200
'target_pocket': target_pocket.value,
201
'package_version': package_version,
202
'include_binaries': bool(include_binaries),
187
206
def create(cls, package_name, source_archive,
188
207
target_archive, target_distroseries, target_pocket,
189
208
include_binaries=False, package_version=None,
190
209
copy_policy=PackageCopyPolicy.INSECURE):
191
210
"""See `IPlainPackageCopyJobSource`."""
192
211
assert package_version is not None, "No package version specified."
194
'target_pocket': target_pocket.value,
195
'package_version': package_version,
196
'include_binaries': bool(include_binaries),
212
metadata = cls._makeMetadata(
213
target_pocket, package_version, include_binaries)
198
214
job = PackageCopyJob(
199
215
job_type=cls.class_job_type,
200
216
source_archive=source_archive,
226
def _composeJobInsertionTuple(cls, target_distroseries, copy_policy,
227
include_binaries, job_id, copy_task):
228
"""Create an SQL fragment for inserting a job into the database.
230
:return: A string representing an SQL tuple containing initializers
231
for a `PackageCopyJob` in the database (minus `id`, which is
232
assigned automatically). Contents are escaped for use in SQL.
241
metadata = cls._makeMetadata(
242
target_pocket, package_version, include_binaries)
244
cls.class_job_type, target_distroseries, copy_policy,
245
source_archive, target_archive, package_name, job_id,
246
PackageCopyJob.serializeMetadata(metadata))
247
format_string = "(%s)" % ", ".join(["%s"] * len(data))
248
return format_string % sqlvalues(*data)
251
def createMultiple(cls, target_distroseries, copy_tasks,
252
copy_policy=PackageCopyPolicy.INSECURE,
253
include_binaries=False):
254
"""See `IPlainPackageCopyJobSource`."""
255
store = IMasterStore(Job)
256
job_ids = Job.createMultiple(store, len(copy_tasks))
258
cls._composeJobInsertionTuple(
259
target_distroseries, copy_policy, include_binaries, job_id,
261
for job_id, task in zip(job_ids, copy_tasks)]
262
result = store.execute("""
263
INSERT INTO PackageCopyJob (
274
""" % ", ".join(job_contents))
275
return [job_id for job_id, in result]
210
278
def getActiveJobs(cls, target_archive):
211
279
"""See `IPlainPackageCopyJobSource`."""
212
280
jobs = IStore(PackageCopyJob).find(
254
322
def include_binaries(self):
255
323
return self.metadata['include_binaries']
325
def _createPackageUpload(self, unapproved=False):
326
pu = self.target_distroseries.createQueueEntry(
327
pocket=self.target_pocket, archive=self.target_archive,
328
package_copy_job=self.context)
257
332
def addSourceOverride(self, override):
258
333
"""Add an `ISourceOverride` to the metadata."""
336
if override.component is not None:
337
component = override.component.name
338
if override.section is not None:
339
section = override.section.name
259
340
metadata_dict = dict(
260
component_override=override.component.name,
261
section_override=override.section.name)
341
component_override=component,
342
section_override=section)
262
343
self.context.extendMetadata(metadata_dict)
264
345
def getSourceOverride(self):
265
346
"""Fetch an `ISourceOverride` from the metadata."""
266
# There's only one package per job; although the schema allows
267
# multiple we're not using that.
268
347
name = self.package_name
269
348
component_name = self.metadata.get("component_override")
270
349
section_name = self.metadata.get("section_override")
271
350
source_package_name = getUtility(ISourcePackageNameSet)[name]
272
component = getUtility(IComponentSet)[component_name]
273
section = getUtility(ISectionSet)[section_name]
352
component = getUtility(IComponentSet)[component_name]
353
except NotFoundError:
356
section = getUtility(ISectionSet)[section_name]
357
except NotFoundError:
274
360
return SourceOverride(source_package_name, component, section)
362
def _checkPolicies(self, source_name):
363
# This helper will only return if it's safe to carry on with the
364
# copy, otherwise it raises SuspendJobException to tell the job
365
# runner to suspend the job.
366
override_policy = FromExistingOverridePolicy()
367
ancestry = override_policy.calculateSourceOverrides(
368
self.target_archive, self.target_distroseries,
369
self.target_pocket, [source_name])
371
copy_policy = self.getPolicyImplementation()
373
if len(ancestry) == 0:
374
# We need to get the default overrides and put them in the
376
defaults = UnknownOverridePolicy().calculateSourceOverrides(
377
self.target_archive, self.target_distroseries,
378
self.target_pocket, [source_name])
379
self.addSourceOverride(defaults[0])
381
approve_new = copy_policy.autoApproveNew(
382
self.target_archive, self.target_distroseries,
386
# There's no existing package with the same name and the
387
# policy says unapproved, so we poke it in the NEW queue.
388
self._createPackageUpload()
389
raise SuspendJobException
391
# Put the existing override in the metadata.
392
self.addSourceOverride(ancestry[0])
394
# The package is not new (it has ancestry) so check the copy
395
# policy for existing packages.
396
approve_existing = copy_policy.autoApprove(
397
self.target_archive, self.target_distroseries, self.target_pocket)
398
if not approve_existing:
399
self._createPackageUpload(unapproved=True)
400
raise SuspendJobException
277
403
"""See `IRunnableJob`."""
298
424
name=name, version=version, exact_match=True).first()
299
425
if source_package is None:
300
426
raise CannotCopy("Package %r %r not found." % (name, version))
427
source_name = getUtility(ISourcePackageNameSet)[name]
429
# If there's a PackageUpload associated with this job then this
430
# job has just been released by an archive admin from the queue.
431
# We don't need to check any policies, but the admin may have
432
# set overrides which we will get from the job's metadata.
433
pu = getUtility(IPackageUploadSet).getByPackageCopyJobIDs(
436
self._checkPolicies(source_name)
438
# The package is free to go right in, so just copy it now.
439
override = self.getSourceOverride()
440
copy_policy = self.getPolicyImplementation()
441
send_email = copy_policy.send_email(self.target_archive)
303
443
sources=[source_package], archive=self.target_archive,
304
444
series=self.target_distroseries, pocket=self.target_pocket,
305
include_binaries=self.include_binaries, check_permissions=False)
445
include_binaries=self.include_binaries, check_permissions=False,
446
overrides=[override], send_email=send_email)
308
449
"""Abort work."""