Merge lp:~wgrant/launchpad/slimmer-bfjo into lp:launchpad

Proposed by William Grant
Status: Merged
Approved by: Steve Kowalik
Approved revision: no longer in the source branch.
Merged at revision: 16823
Proposed branch: lp:~wgrant/launchpad/slimmer-bfjo
Merge into: lp:launchpad
Diff against target: 938 lines (+248/-279)
16 files modified
lib/lp/buildmaster/interfaces/buildfarmjob.py (+36/-58)
lib/lp/buildmaster/model/builder.py (+6/-6)
lib/lp/buildmaster/model/buildfarmjob.py (+14/-26)
lib/lp/buildmaster/model/buildqueue.py (+35/-6)
lib/lp/buildmaster/model/packagebuild.py (+2/-3)
lib/lp/buildmaster/tests/test_buildqueue.py (+4/-2)
lib/lp/code/browser/tests/test_sourcepackagerecipe.py (+2/-0)
lib/lp/code/mail/tests/test_sourcepackagerecipebuild.py (+4/-0)
lib/lp/code/model/sourcepackagerecipebuild.py (+4/-10)
lib/lp/code/model/tests/test_recipebuilder.py (+2/-3)
lib/lp/code/model/tests/test_sourcepackagerecipebuild.py (+6/-0)
lib/lp/soyuz/model/binarypackagebuild.py (+82/-3)
lib/lp/soyuz/model/buildpackagejob.py (+0/-87)
lib/lp/soyuz/tests/test_binarypackagebuild.py (+45/-1)
lib/lp/soyuz/tests/test_buildpackagejob.py (+0/-72)
lib/lp/translations/model/translationtemplatesbuild.py (+6/-2)
To merge this branch: bzr merge lp:~wgrant/launchpad/slimmer-bfjo
Reviewer Review Type Date Requested Status
Steve Kowalik (community) code Approve
Review via email: mp+194767@code.launchpad.net

Commit message

Eliminate most of IBuildFarmJobOld.

Description of the change

Inline IBuildFarmJobOld.{processor,virtualized,jobStarted,jobCancelled,jobReset} and move IBuildFarmJobOld.{addCandidateSelectionCriteria,postprocessCandidate} to ISpecificBuildFarmJobSource.

IBuildFarmJobOld will shortly perish.

To post a comment you must log in.
Revision history for this message
Steve Kowalik (stevenk) wrote :

213 + return ('')

Isn't that just empty string? If you want to return a tuple, you need a comma, no?

I also expect this branch impacts on bug #1233145.

review: Approve (code)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'lib/lp/buildmaster/interfaces/buildfarmjob.py'
2--- lib/lp/buildmaster/interfaces/buildfarmjob.py 2013-09-02 12:45:50 +0000
3+++ lib/lp/buildmaster/interfaces/buildfarmjob.py 2013-11-11 23:47:32 +0000
4@@ -59,67 +59,9 @@
5 BuildQueue have been transitioned to the new database schema.
6 """
7
8- processor = Reference(
9- IProcessor, title=_("Processor"), required=False, readonly=True,
10- description=_(
11- "The Processor required by this build farm job. "
12- "This should be None for processor-independent job types."))
13-
14- virtualized = Bool(
15- title=_('Virtualized'), required=False, readonly=True,
16- description=_(
17- "The virtualization setting required by this build farm job. "
18- "This should be None for job types that do not care whether "
19- "they run virtualized."))
20-
21 def score():
22 """Calculate a job score appropriate for the job type in question."""
23
24- def jobStarted():
25- """'Job started' life cycle event, handle as appropriate."""
26-
27- def jobReset():
28- """'Job reset' life cycle event, handle as appropriate."""
29-
30- def jobCancel():
31- """'Job cancel' life cycle event."""
32-
33- def addCandidateSelectionCriteria(processor, virtualized):
34- """Provide a sub-query to refine the candidate job selection.
35-
36- Return a sub-query to narrow down the list of candidate jobs.
37- The sub-query will become part of an "outer query" and is free to
38- refer to the `BuildQueue` and `Job` tables already utilized in the
39- latter.
40-
41- Example (please see the `BuildPackageJob` implementation for a
42- complete example):
43-
44- SELECT TRUE
45- FROM Archive, Build, BuildPackageJob, DistroArchSeries
46- WHERE
47- BuildPackageJob.job = Job.id AND
48- ..
49-
50- :param processor: the type of processor that the candidate jobs are
51- expected to run on.
52- :param virtualized: whether the candidate jobs are expected to run on
53- the `processor` natively or inside a virtual machine.
54- :return: a string containing a sub-query that narrows down the list of
55- candidate jobs.
56- """
57-
58- def postprocessCandidate(job, logger):
59- """True if the candidate job is fine and should be dispatched
60- to a builder, False otherwise.
61-
62- :param job: The `BuildQueue` instance to be scrutinized.
63- :param logger: The logger to use.
64-
65- :return: True if the candidate job should be dispatched
66- to a builder, False otherwise.
67- """
68-
69 def getByJob(job):
70 """Get the specific `IBuildFarmJob` for the given `Job`.
71
72@@ -328,6 +270,42 @@
73 job.
74 """
75
76+ def addCandidateSelectionCriteria(processor, virtualized):
77+ """Provide a sub-query to refine the candidate job selection.
78+
79+ Return a sub-query to narrow down the list of candidate jobs.
80+ The sub-query will become part of an "outer query" and is free to
81+ refer to the `BuildQueue` and `Job` tables already utilized in the
82+ latter.
83+
84+ Example (please see the `BuildPackageJob` implementation for a
85+ complete example):
86+
87+ SELECT TRUE
88+ FROM Archive, Build, BuildPackageJob, DistroArchSeries
89+ WHERE
90+ BuildPackageJob.job = Job.id AND
91+ ..
92+
93+ :param processor: the type of processor that the candidate jobs are
94+ expected to run on.
95+ :param virtualized: whether the candidate jobs are expected to run on
96+ the `processor` natively or inside a virtual machine.
97+ :return: a string containing a sub-query that narrows down the list of
98+ candidate jobs.
99+ """
100+
101+ def postprocessCandidate(job, logger):
102+ """True if the candidate job is fine and should be dispatched
103+ to a builder, False otherwise.
104+
105+ :param job: The `BuildQueue` instance to be scrutinized.
106+ :param logger: The logger to use.
107+
108+ :return: True if the candidate job should be dispatched
109+ to a builder, False otherwise.
110+ """
111+
112
113 class IBuildFarmJobSource(Interface):
114 """A utility of BuildFarmJob used to create _things_."""
115
116=== modified file 'lib/lp/buildmaster/model/builder.py'
117--- lib/lp/buildmaster/model/builder.py 2013-10-26 11:00:53 +0000
118+++ lib/lp/buildmaster/model/builder.py 2013-11-11 23:47:32 +0000
119@@ -35,7 +35,7 @@
120 from lp.buildmaster.interfaces.buildqueue import IBuildQueueSet
121 from lp.buildmaster.model.buildqueue import (
122 BuildQueue,
123- specific_job_classes,
124+ specific_build_farm_job_sources,
125 )
126 from lp.registry.interfaces.person import validate_public_person
127 from lp.services.database.interfaces import (
128@@ -206,9 +206,9 @@
129 order_clause = " ORDER BY buildqueue.lastscore DESC, buildqueue.id"
130
131 extra_queries = []
132- job_classes = specific_job_classes()
133- for job_type, job_class in job_classes.iteritems():
134- query = job_class.addCandidateSelectionCriteria(
135+ job_sources = specific_build_farm_job_sources()
136+ for job_type, job_source in job_sources.iteritems():
137+ query = job_source.addCandidateSelectionCriteria(
138 self.processor, self.virtualized)
139 if query == '':
140 # This job class does not need to refine candidate jobs
141@@ -224,8 +224,8 @@
142
143 for (candidate_id,) in candidate_jobs:
144 candidate = getUtility(IBuildQueueSet).get(candidate_id)
145- job_class = job_classes[candidate.job_type]
146- candidate_approved = job_class.postprocessCandidate(
147+ job_source = job_sources[candidate.job_type]
148+ candidate_approved = job_source.postprocessCandidate(
149 candidate, logger)
150 if candidate_approved:
151 return candidate
152
153=== modified file 'lib/lp/buildmaster/model/buildfarmjob.py'
154--- lib/lp/buildmaster/model/buildfarmjob.py 2013-09-02 12:45:50 +0000
155+++ lib/lp/buildmaster/model/buildfarmjob.py 2013-11-11 23:47:32 +0000
156@@ -6,6 +6,7 @@
157 'BuildFarmJob',
158 'BuildFarmJobMixin',
159 'BuildFarmJobOld',
160+ 'SpecificBuildFarmJobSourceMixin',
161 ]
162
163 import datetime
164@@ -50,9 +51,6 @@
165
166 implements(IBuildFarmJobOld)
167
168- processor = None
169- virtualized = None
170-
171 @staticmethod
172 def preloadBuildFarmJobs(jobs):
173 """Preload the build farm jobs to which the given jobs will delegate.
174@@ -83,29 +81,6 @@
175 """
176 Store.of(self).remove(self)
177
178- @staticmethod
179- def addCandidateSelectionCriteria(processor, virtualized):
180- """See `IBuildFarmJobOld`."""
181- return ('')
182-
183- @staticmethod
184- def postprocessCandidate(job, logger):
185- """See `IBuildFarmJobOld`."""
186- return True
187-
188- def jobStarted(self):
189- """See `IBuildFarmJobOld`."""
190- # XXX wgrant: builder should be set here.
191- self.build.updateStatus(BuildStatus.BUILDING)
192-
193- def jobReset(self):
194- """See `IBuildFarmJob`."""
195- self.build.updateStatus(BuildStatus.NEEDSBUILD)
196-
197- def jobCancel(self):
198- """See `IBuildFarmJob`."""
199- self.build.updateStatus(BuildStatus.CANCELLED)
200-
201
202 class BuildFarmJob(Storm):
203 """A base implementation for `IBuildFarmJob` classes."""
204@@ -249,6 +224,19 @@
205 self.failure_count += 1
206
207
208+class SpecificBuildFarmJobSourceMixin:
209+
210+ @staticmethod
211+ def addCandidateSelectionCriteria(processor, virtualized):
212+ """See `ISpecificBuildFarmJobSource`."""
213+ return ('')
214+
215+ @staticmethod
216+ def postprocessCandidate(job, logger):
217+ """See `ISpecificBuildFarmJobSource`."""
218+ return True
219+
220+
221 class BuildFarmJobSet:
222 implements(IBuildFarmJobSet)
223
224
225=== modified file 'lib/lp/buildmaster/model/buildqueue.py'
226--- lib/lp/buildmaster/model/buildqueue.py 2013-11-10 23:56:44 +0000
227+++ lib/lp/buildmaster/model/buildqueue.py 2013-11-11 23:47:32 +0000
228@@ -7,6 +7,7 @@
229 'BuildQueue',
230 'BuildQueueSet',
231 'specific_job_classes',
232+ 'specific_build_farm_job_sources',
233 ]
234
235 from datetime import datetime
236@@ -21,11 +22,18 @@
237 IntervalCol,
238 StringCol,
239 )
240+from storm.store import Store
241 from zope.component import getSiteManager
242 from zope.interface import implements
243
244-from lp.buildmaster.enums import BuildFarmJobType
245-from lp.buildmaster.interfaces.buildfarmjob import IBuildFarmJob
246+from lp.buildmaster.enums import (
247+ BuildFarmJobType,
248+ BuildStatus,
249+ )
250+from lp.buildmaster.interfaces.buildfarmjob import (
251+ IBuildFarmJob,
252+ ISpecificBuildFarmJobSource,
253+ )
254 from lp.buildmaster.interfaces.buildqueue import (
255 IBuildQueue,
256 IBuildQueueSet,
257@@ -58,6 +66,26 @@
258 return job_classes
259
260
261+def specific_build_farm_job_sources():
262+ """Sources for specific jobs that may run on the build farm."""
263+ job_sources = dict()
264+ # Get all components that implement the `ISpecificBuildFarmJobSource`
265+ # interface.
266+ components = getSiteManager()
267+ implementations = sorted(
268+ components.getUtilitiesFor(ISpecificBuildFarmJobSource))
269+ # The above yields a collection of 2-tuples where the first element
270+ # is the name of the `BuildFarmJobType` enum and the second element
271+ # is the implementing class respectively.
272+ for job_enum_name, job_source in implementations:
273+ if not job_enum_name:
274+ continue
275+ job_enum = getattr(BuildFarmJobType, job_enum_name)
276+ job_sources[job_enum] = job_source
277+
278+ return job_sources
279+
280+
281 class BuildQueue(SQLBase):
282 implements(IBuildQueue)
283 _table = "BuildQueue"
284@@ -133,8 +161,9 @@
285 job = self.job
286 specific_job = self.specific_job
287 builder = self.builder
288- SQLBase.destroySelf(self)
289+ Store.of(self).remove(self)
290 specific_job.cleanUp()
291+ Store.of(self).flush()
292 job.destroySelf()
293 if builder is not None:
294 del get_property_cache(builder).currentjob
295@@ -158,7 +187,7 @@
296 self.builder = builder
297 if self.job.status != JobStatus.RUNNING:
298 self.job.start()
299- self.specific_job.jobStarted()
300+ self.specific_job.build.updateStatus(BuildStatus.BUILDING)
301 if builder is not None:
302 del get_property_cache(builder).currentjob
303
304@@ -171,13 +200,13 @@
305 self.job.date_started = None
306 self.job.date_finished = None
307 self.logtail = None
308- self.specific_job.jobReset()
309+ self.specific_job.build.updateStatus(BuildStatus.NEEDSBUILD)
310 if builder is not None:
311 del get_property_cache(builder).currentjob
312
313 def cancel(self):
314 """See `IBuildQueue`."""
315- self.specific_job.jobCancel()
316+ self.specific_job.build.updateStatus(BuildStatus.CANCELLED)
317 self.destroySelf()
318
319 def getEstimatedJobStartTime(self, now=None):
320
321=== modified file 'lib/lp/buildmaster/model/packagebuild.py'
322--- lib/lp/buildmaster/model/packagebuild.py 2013-08-28 04:40:32 +0000
323+++ lib/lp/buildmaster/model/packagebuild.py 2013-11-11 23:47:32 +0000
324@@ -120,11 +120,10 @@
325
326 duration_estimate = self.estimateDuration()
327 job = specific_job.job
328- processor = specific_job.processor
329 queue_entry = BuildQueue(
330 estimated_duration=duration_estimate,
331 job_type=self.job_type,
332- job=job, processor=processor,
333- virtualized=specific_job.virtualized)
334+ job=job, processor=self.processor,
335+ virtualized=self.virtualized)
336 Store.of(self).add(queue_entry)
337 return queue_entry
338
339=== modified file 'lib/lp/buildmaster/tests/test_buildqueue.py'
340--- lib/lp/buildmaster/tests/test_buildqueue.py 2013-10-31 06:29:13 +0000
341+++ lib/lp/buildmaster/tests/test_buildqueue.py 2013-11-11 23:47:32 +0000
342@@ -14,9 +14,11 @@
343 BuildStatus,
344 )
345 from lp.buildmaster.interfaces.buildfarmjob import IBuildFarmJob
346-from lp.buildmaster.model.builder import specific_job_classes
347 from lp.buildmaster.model.buildfarmjob import BuildFarmJobMixin
348-from lp.buildmaster.model.buildqueue import BuildQueue
349+from lp.buildmaster.model.buildqueue import (
350+ BuildQueue,
351+ specific_job_classes,
352+ )
353 from lp.services.database.interfaces import IStore
354 from lp.soyuz.enums import (
355 ArchivePurpose,
356
357=== modified file 'lib/lp/code/browser/tests/test_sourcepackagerecipe.py'
358--- lib/lp/code/browser/tests/test_sourcepackagerecipe.py 2013-09-11 06:05:44 +0000
359+++ lib/lp/code/browser/tests/test_sourcepackagerecipe.py 2013-11-11 23:47:32 +0000
360@@ -1614,6 +1614,8 @@
361 owner=self.user, name=u'my-recipe')
362 distro_series = self.factory.makeDistroSeries(
363 name='squirrel', distribution=archive.distribution)
364+ removeSecurityProxy(distro_series).nominatedarchindep = (
365+ self.factory.makeDistroArchSeries(distroseries=distro_series))
366 build = self.factory.makeSourcePackageRecipeBuild(
367 requester=self.user, archive=archive, recipe=recipe,
368 distroseries=distro_series)
369
370=== modified file 'lib/lp/code/mail/tests/test_sourcepackagerecipebuild.py'
371--- lib/lp/code/mail/tests/test_sourcepackagerecipebuild.py 2013-01-23 10:16:18 +0000
372+++ lib/lp/code/mail/tests/test_sourcepackagerecipebuild.py 2013-11-11 23:47:32 +0000
373@@ -60,6 +60,8 @@
374 pantry_owner = self.factory.makePerson(name='archiveowner')
375 pantry = self.factory.makeArchive(name='ppa', owner=pantry_owner)
376 secret = self.factory.makeDistroSeries(name=u'distroseries')
377+ removeSecurityProxy(secret).nominatedarchindep = (
378+ self.factory.makeDistroArchSeries(distroseries=secret))
379 build = self.factory.makeSourcePackageRecipeBuild(
380 recipe=cake, distroseries=secret, archive=pantry,
381 status=BuildStatus.FULLYBUILT, duration=timedelta(minutes=5))
382@@ -95,6 +97,8 @@
383 pantry_owner = self.factory.makePerson(name='archiveowner')
384 pantry = self.factory.makeArchive(name='ppa', owner=pantry_owner)
385 secret = self.factory.makeDistroSeries(name=u'distroseries')
386+ removeSecurityProxy(secret).nominatedarchindep = (
387+ self.factory.makeDistroArchSeries(distroseries=secret))
388 build = self.factory.makeSourcePackageRecipeBuild(
389 recipe=cake, distroseries=secret, archive=pantry,
390 status=BuildStatus.SUPERSEDED)
391
392=== modified file 'lib/lp/code/model/sourcepackagerecipebuild.py'
393--- lib/lp/code/model/sourcepackagerecipebuild.py 2013-09-24 05:45:06 +0000
394+++ lib/lp/code/model/sourcepackagerecipebuild.py 2013-11-11 23:47:32 +0000
395@@ -43,6 +43,7 @@
396 from lp.buildmaster.model.buildfarmjob import (
397 BuildFarmJob,
398 BuildFarmJobOld,
399+ SpecificBuildFarmJobSourceMixin,
400 )
401 from lp.buildmaster.model.buildqueue import BuildQueue
402 from lp.buildmaster.model.packagebuild import PackageBuildMixin
403@@ -78,7 +79,8 @@
404 from lp.soyuz.model.sourcepackagerelease import SourcePackageRelease
405
406
407-class SourcePackageRecipeBuild(PackageBuildMixin, Storm):
408+class SourcePackageRecipeBuild(SpecificBuildFarmJobSourceMixin,
409+ PackageBuildMixin, Storm):
410
411 __storm_table__ = 'SourcePackageRecipeBuild'
412
413@@ -212,6 +214,7 @@
414 self.archive = archive
415 self.pocket = pocket
416 self.status = BuildStatus.NEEDSBUILD
417+ self.processor = self.distroseries.nominatedarchindep.processor
418 self.virtualized = True
419 if date_created is not None:
420 self.date_created = date_created
421@@ -431,15 +434,6 @@
422 build = Reference(
423 build_id, 'SourcePackageRecipeBuild.id')
424
425- @property
426- def processor(self):
427- return self.build.distroseries.nominatedarchindep.processor
428-
429- @property
430- def virtualized(self):
431- """See `IBuildFarmJob`."""
432- return self.build.is_virtualized
433-
434 def __init__(self, build, job):
435 self.build = build
436 self.job = job
437
438=== modified file 'lib/lp/code/model/tests/test_recipebuilder.py'
439--- lib/lp/code/model/tests/test_recipebuilder.py 2013-10-01 00:32:26 +0000
440+++ lib/lp/code/model/tests/test_recipebuilder.py 2013-11-11 23:47:32 +0000
441@@ -9,8 +9,6 @@
442 import tempfile
443 from textwrap import dedent
444
445-from zope.component import getUtility
446-
447 from testtools import run_test_with
448 from testtools.deferredruntest import (
449 assert_fails_with,
450@@ -20,6 +18,7 @@
451 import transaction
452 from twisted.internet import defer
453 from twisted.trial.unittest import TestCase as TrialTestCase
454+from zope.component import getUtility
455 from zope.security.proxy import removeSecurityProxy
456
457 from lp.buildmaster.enums import (
458@@ -72,7 +71,7 @@
459 distroseries = self.factory.makeDistroSeries(name="mydistro",
460 distribution=distro)
461 processor = getUtility(IProcessorSet).getByName('386')
462- distroseries.newArch(
463+ distroseries.nominatedarchindep = distroseries.newArch(
464 'i386', processor, True, self.factory.makePerson())
465 sourcepackage = self.factory.makeSourcePackage(spn, distroseries)
466 if recipe_registrant is None:
467
468=== modified file 'lib/lp/code/model/tests/test_sourcepackagerecipebuild.py'
469--- lib/lp/code/model/tests/test_sourcepackagerecipebuild.py 2013-09-24 05:45:06 +0000
470+++ lib/lp/code/model/tests/test_sourcepackagerecipebuild.py 2013-11-11 23:47:32 +0000
471@@ -423,6 +423,8 @@
472 requester = self.factory.makePerson()
473 recipe = self.factory.makeSourcePackageRecipe()
474 series = self.factory.makeDistroSeries()
475+ removeSecurityProxy(series).nominatedarchindep = (
476+ self.factory.makeDistroArchSeries(distroseries=series))
477 now = self.factory.getUniqueDate()
478 build = self.factory.makeSourcePackageRecipeBuild(recipe=recipe,
479 requester=requester)
480@@ -526,6 +528,8 @@
481 name=u'recipe', owner=person)
482 pantry = self.factory.makeArchive(name='ppa')
483 secret = self.factory.makeDistroSeries(name=u'distroseries')
484+ secret.nominatedarchindep = self.factory.makeDistroArchSeries(
485+ distroseries=secret)
486 build = self.factory.makeSourcePackageRecipeBuild(
487 recipe=cake, distroseries=secret, archive=pantry)
488 build.updateStatus(BuildStatus.FULLYBUILT)
489@@ -556,6 +560,8 @@
490 name=u'recipe', owner=person)
491 pantry = self.factory.makeArchive(name='ppa')
492 secret = self.factory.makeDistroSeries(name=u'distroseries')
493+ secret.nominatedarchindep = self.factory.makeDistroArchSeries(
494+ distroseries=secret)
495 build = self.factory.makeSourcePackageRecipeBuild(
496 recipe=cake, distroseries=secret, archive=pantry)
497 build.updateStatus(BuildStatus.FULLYBUILT)
498
499=== modified file 'lib/lp/soyuz/model/binarypackagebuild.py'
500--- lib/lp/soyuz/model/binarypackagebuild.py 2013-08-28 12:03:57 +0000
501+++ lib/lp/soyuz/model/binarypackagebuild.py 2013-11-11 23:47:32 +0000
502@@ -44,12 +44,16 @@
503 )
504 from lp.buildmaster.interfaces.buildfarmjob import IBuildFarmJobSource
505 from lp.buildmaster.model.builder import Builder
506-from lp.buildmaster.model.buildfarmjob import BuildFarmJob
507+from lp.buildmaster.model.buildfarmjob import (
508+ BuildFarmJob,
509+ SpecificBuildFarmJobSourceMixin,
510+ )
511 from lp.buildmaster.model.buildqueue import BuildQueue
512 from lp.buildmaster.model.packagebuild import PackageBuildMixin
513 from lp.registry.interfaces.distribution import IDistribution
514 from lp.registry.interfaces.distroseries import IDistroSeries
515 from lp.registry.interfaces.pocket import PackagePublishingPocket
516+from lp.registry.interfaces.series import SeriesStatus
517 from lp.registry.model.sourcepackagename import SourcePackageName
518 from lp.services.config import config
519 from lp.services.database.bulk import load_related
520@@ -75,7 +79,10 @@
521 simple_sendmail,
522 )
523 from lp.services.webapp import canonical_url
524-from lp.soyuz.enums import ArchivePurpose
525+from lp.soyuz.enums import (
526+ ArchivePurpose,
527+ PackagePublishingStatus,
528+ )
529 from lp.soyuz.interfaces.binarypackagebuild import (
530 BuildSetStatus,
531 CannotBeRescored,
532@@ -825,7 +832,7 @@
533 return changes.signer
534
535
536-class BinaryPackageBuildSet:
537+class BinaryPackageBuildSet(SpecificBuildFarmJobSourceMixin):
538 implements(IBinaryPackageBuildSet)
539
540 def new(self, distro_arch_series, source_package_release, processor,
541@@ -1204,3 +1211,75 @@
542 return IStore(BinaryPackageBuild).using(*origin).find(
543 (BuildQueue, Builder, BuildPackageJob),
544 BinaryPackageBuild.id.is_in(build_ids))
545+
546+ @staticmethod
547+ def addCandidateSelectionCriteria(processor, virtualized):
548+ """See `ISpecificBuildFarmJobSource`."""
549+ private_statuses = (
550+ PackagePublishingStatus.PUBLISHED,
551+ PackagePublishingStatus.SUPERSEDED,
552+ PackagePublishingStatus.DELETED,
553+ )
554+ return """
555+ SELECT TRUE FROM Archive, BinaryPackageBuild, BuildPackageJob,
556+ DistroArchSeries
557+ WHERE
558+ BuildPackageJob.job = Job.id AND
559+ BuildPackageJob.build = BinaryPackageBuild.id AND
560+ BinaryPackageBuild.distro_arch_series =
561+ DistroArchSeries.id AND
562+ BinaryPackageBuild.archive = Archive.id AND
563+ ((Archive.private IS TRUE AND
564+ EXISTS (
565+ SELECT SourcePackagePublishingHistory.id
566+ FROM SourcePackagePublishingHistory
567+ WHERE
568+ SourcePackagePublishingHistory.distroseries =
569+ DistroArchSeries.distroseries AND
570+ SourcePackagePublishingHistory.sourcepackagerelease =
571+ BinaryPackageBuild.source_package_release AND
572+ SourcePackagePublishingHistory.archive = Archive.id AND
573+ SourcePackagePublishingHistory.status IN %s))
574+ OR
575+ archive.private IS FALSE) AND
576+ BinaryPackageBuild.status = %s
577+ """ % sqlvalues(private_statuses, BuildStatus.NEEDSBUILD)
578+
579+ @staticmethod
580+ def postprocessCandidate(job, logger):
581+ """See `ISpecificBuildFarmJobSource`."""
582+ # Mark build records targeted to old source versions as SUPERSEDED
583+ # and build records target to SECURITY pocket or against an OBSOLETE
584+ # distroseries without a flag as FAILEDTOBUILD.
585+ # Builds in those situation should not be built because they will
586+ # be wasting build-time. In the former case, there is already a
587+ # newer source; the latter case needs an overhaul of the way
588+ # security builds are handled (by copying from a PPA) to avoid
589+ # creating duplicate builds.
590+ build = getUtility(IBinaryPackageBuildSet).getByQueueEntry(job)
591+ distroseries = build.distro_arch_series.distroseries
592+ if (
593+ build.pocket == PackagePublishingPocket.SECURITY or
594+ (distroseries.status == SeriesStatus.OBSOLETE and
595+ not build.archive.permit_obsolete_series_uploads)):
596+ # We never build anything in the security pocket, or for obsolete
597+ # series without the flag set.
598+ logger.debug(
599+ "Build %s FAILEDTOBUILD, queue item %s REMOVED"
600+ % (build.id, job.id))
601+ build.updateStatus(BuildStatus.FAILEDTOBUILD)
602+ job.destroySelf()
603+ return False
604+
605+ publication = build.current_source_publication
606+ if publication is None:
607+ # The build should be superseded if it no longer has a
608+ # current publishing record.
609+ logger.debug(
610+ "Build %s SUPERSEDED, queue item %s REMOVED"
611+ % (build.id, job.id))
612+ build.updateStatus(BuildStatus.SUPERSEDED)
613+ job.destroySelf()
614+ return False
615+
616+ return True
617
618=== modified file 'lib/lp/soyuz/model/buildpackagejob.py'
619--- lib/lp/soyuz/model/buildpackagejob.py 2013-09-04 08:04:25 +0000
620+++ lib/lp/soyuz/model/buildpackagejob.py 2013-11-11 23:47:32 +0000
621@@ -15,14 +15,9 @@
622 from zope.component import getUtility
623 from zope.interface import implements
624
625-from lp.buildmaster.enums import BuildStatus
626 from lp.buildmaster.model.buildfarmjob import BuildFarmJobOld
627-from lp.registry.interfaces.pocket import PackagePublishingPocket
628-from lp.registry.interfaces.series import SeriesStatus
629 from lp.services.database.bulk import load_related
630 from lp.services.database.interfaces import IStore
631-from lp.services.database.sqlbase import sqlvalues
632-from lp.soyuz.enums import PackagePublishingStatus
633 from lp.soyuz.interfaces.binarypackagebuild import IBinaryPackageBuildSet
634 from lp.soyuz.interfaces.buildpackagejob import (
635 COPY_ARCHIVE_SCORE_PENALTY,
636@@ -99,16 +94,6 @@
637
638 return score
639
640- @property
641- def processor(self):
642- """See `IBuildFarmJob`."""
643- return self.build.processor
644-
645- @property
646- def virtualized(self):
647- """See `IBuildFarmJob`."""
648- return self.build.is_virtualized
649-
650 @classmethod
651 def preloadJobsData(cls, jobs):
652 from lp.soyuz.model.binarypackagebuild import BinaryPackageBuild
653@@ -116,75 +101,3 @@
654 load_related(Job, jobs, ['job_id'])
655 builds = load_related(BinaryPackageBuild, jobs, ['build_id'])
656 getUtility(IBinaryPackageBuildSet).preloadBuildsData(list(builds))
657-
658- @staticmethod
659- def addCandidateSelectionCriteria(processor, virtualized):
660- """See `IBuildFarmJob`."""
661- private_statuses = (
662- PackagePublishingStatus.PUBLISHED,
663- PackagePublishingStatus.SUPERSEDED,
664- PackagePublishingStatus.DELETED,
665- )
666- return """
667- SELECT TRUE FROM Archive, BinaryPackageBuild, BuildPackageJob,
668- DistroArchSeries
669- WHERE
670- BuildPackageJob.job = Job.id AND
671- BuildPackageJob.build = BinaryPackageBuild.id AND
672- BinaryPackageBuild.distro_arch_series =
673- DistroArchSeries.id AND
674- BinaryPackageBuild.archive = Archive.id AND
675- ((Archive.private IS TRUE AND
676- EXISTS (
677- SELECT SourcePackagePublishingHistory.id
678- FROM SourcePackagePublishingHistory
679- WHERE
680- SourcePackagePublishingHistory.distroseries =
681- DistroArchSeries.distroseries AND
682- SourcePackagePublishingHistory.sourcepackagerelease =
683- BinaryPackageBuild.source_package_release AND
684- SourcePackagePublishingHistory.archive = Archive.id AND
685- SourcePackagePublishingHistory.status IN %s))
686- OR
687- archive.private IS FALSE) AND
688- BinaryPackageBuild.status = %s
689- """ % sqlvalues(private_statuses, BuildStatus.NEEDSBUILD)
690-
691- @staticmethod
692- def postprocessCandidate(job, logger):
693- """See `IBuildFarmJob`."""
694- # Mark build records targeted to old source versions as SUPERSEDED
695- # and build records target to SECURITY pocket or against an OBSOLETE
696- # distroseries without a flag as FAILEDTOBUILD.
697- # Builds in those situation should not be built because they will
698- # be wasting build-time. In the former case, there is already a
699- # newer source; the latter case needs an overhaul of the way
700- # security builds are handled (by copying from a PPA) to avoid
701- # creating duplicate builds.
702- build = getUtility(IBinaryPackageBuildSet).getByQueueEntry(job)
703- distroseries = build.distro_arch_series.distroseries
704- if (
705- build.pocket == PackagePublishingPocket.SECURITY or
706- (distroseries.status == SeriesStatus.OBSOLETE and
707- not build.archive.permit_obsolete_series_uploads)):
708- # We never build anything in the security pocket, or for obsolete
709- # series without the flag set.
710- logger.debug(
711- "Build %s FAILEDTOBUILD, queue item %s REMOVED"
712- % (build.id, job.id))
713- build.updateStatus(BuildStatus.FAILEDTOBUILD)
714- job.destroySelf()
715- return False
716-
717- publication = build.current_source_publication
718- if publication is None:
719- # The build should be superseded if it no longer has a
720- # current publishing record.
721- logger.debug(
722- "Build %s SUPERSEDED, queue item %s REMOVED"
723- % (build.id, job.id))
724- build.updateStatus(BuildStatus.SUPERSEDED)
725- job.destroySelf()
726- return False
727-
728- return True
729
730=== modified file 'lib/lp/soyuz/tests/test_binarypackagebuild.py'
731--- lib/lp/soyuz/tests/test_binarypackagebuild.py 2013-09-10 06:28:26 +0000
732+++ lib/lp/soyuz/tests/test_binarypackagebuild.py 2013-11-11 23:47:32 +0000
733@@ -17,7 +17,9 @@
734 from lp.buildmaster.interfaces.buildqueue import IBuildQueue
735 from lp.buildmaster.interfaces.packagebuild import IPackageBuild
736 from lp.buildmaster.model.buildqueue import BuildQueue
737+from lp.registry.interfaces.series import SeriesStatus
738 from lp.services.job.model.job import Job
739+from lp.services.log.logger import DevNullLogger
740 from lp.services.webapp.interaction import ANONYMOUS
741 from lp.services.webapp.interfaces import OAuthPermission
742 from lp.soyuz.enums import (
743@@ -31,7 +33,10 @@
744 )
745 from lp.soyuz.interfaces.buildpackagejob import IBuildPackageJob
746 from lp.soyuz.interfaces.component import IComponentSet
747-from lp.soyuz.model.binarypackagebuild import BinaryPackageBuild
748+from lp.soyuz.model.binarypackagebuild import (
749+ BinaryPackageBuild,
750+ BinaryPackageBuildSet,
751+ )
752 from lp.soyuz.model.buildpackagejob import BuildPackageJob
753 from lp.soyuz.tests.test_publishing import SoyuzTestPublisher
754 from lp.testing import (
755@@ -497,3 +502,42 @@
756 logout()
757 entry = self.webservice.get(build_url, api_version='devel').jsonBody()
758 self.assertEndsWith(entry['builder_link'], builder_url)
759+
760+
761+class TestPostprocessCandidate(TestCaseWithFactory):
762+
763+ layer = DatabaseFunctionalLayer
764+
765+ def makeBuildJob(self, pocket="RELEASE"):
766+ build = self.factory.makeBinaryPackageBuild(pocket=pocket)
767+ return build.queueBuild()
768+
769+ def test_release_job(self):
770+ job = self.makeBuildJob()
771+ build = getUtility(IBinaryPackageBuildSet).getByQueueEntry(job)
772+ self.assertTrue(BinaryPackageBuildSet.postprocessCandidate(job, None))
773+ self.assertEqual(BuildStatus.NEEDSBUILD, build.status)
774+
775+ def test_security_job_is_failed(self):
776+ job = self.makeBuildJob(pocket="SECURITY")
777+ build = getUtility(IBinaryPackageBuildSet).getByQueueEntry(job)
778+ BinaryPackageBuildSet.postprocessCandidate(job, DevNullLogger())
779+ self.assertEqual(BuildStatus.FAILEDTOBUILD, build.status)
780+
781+ def test_obsolete_job_without_flag_is_failed(self):
782+ job = self.makeBuildJob()
783+ build = getUtility(IBinaryPackageBuildSet).getByQueueEntry(job)
784+ distroseries = build.distro_arch_series.distroseries
785+ removeSecurityProxy(distroseries).status = SeriesStatus.OBSOLETE
786+ BinaryPackageBuildSet.postprocessCandidate(job, DevNullLogger())
787+ self.assertEqual(BuildStatus.FAILEDTOBUILD, build.status)
788+
789+ def test_obsolete_job_with_flag_is_not_failed(self):
790+ job = self.makeBuildJob()
791+ build = getUtility(IBinaryPackageBuildSet).getByQueueEntry(job)
792+ distroseries = build.distro_arch_series.distroseries
793+ archive = build.archive
794+ removeSecurityProxy(distroseries).status = SeriesStatus.OBSOLETE
795+ removeSecurityProxy(archive).permit_obsolete_series_uploads = True
796+ BinaryPackageBuildSet.postprocessCandidate(job, DevNullLogger())
797+ self.assertEqual(BuildStatus.NEEDSBUILD, build.status)
798
799=== modified file 'lib/lp/soyuz/tests/test_buildpackagejob.py'
800--- lib/lp/soyuz/tests/test_buildpackagejob.py 2013-09-10 06:28:26 +0000
801+++ lib/lp/soyuz/tests/test_buildpackagejob.py 2013-11-11 23:47:32 +0000
802@@ -13,16 +13,13 @@
803 from lp.buildmaster.enums import BuildStatus
804 from lp.buildmaster.interfaces.builder import IBuilderSet
805 from lp.registry.interfaces.pocket import PackagePublishingPocket
806-from lp.registry.interfaces.series import SeriesStatus
807 from lp.registry.interfaces.sourcepackage import SourcePackageUrgency
808 from lp.services.database.interfaces import IStore
809-from lp.services.log.logger import DevNullLogger
810 from lp.services.webapp.interfaces import OAuthPermission
811 from lp.soyuz.enums import (
812 ArchivePurpose,
813 PackagePublishingStatus,
814 )
815-from lp.soyuz.interfaces.binarypackagebuild import IBinaryPackageBuildSet
816 from lp.soyuz.interfaces.buildfarmbuildjob import IBuildFarmBuildJob
817 from lp.soyuz.interfaces.buildpackagejob import (
818 COPY_ARCHIVE_SCORE_PENALTY,
819@@ -34,7 +31,6 @@
820 )
821 from lp.soyuz.interfaces.processor import IProcessorSet
822 from lp.soyuz.model.binarypackagebuild import BinaryPackageBuild
823-from lp.soyuz.model.buildpackagejob import BuildPackageJob
824 from lp.soyuz.tests.test_publishing import SoyuzTestPublisher
825 from lp.testing import (
826 anonymous_logged_in,
827@@ -197,24 +193,6 @@
828 removeSecurityProxy(bq).estimated_duration = timedelta(
829 seconds=duration)
830
831- def test_processor(self):
832- # Test that BuildPackageJob returns the correct processor.
833- build, bq = find_job(self, 'gcc', '386')
834- bpj = bq.specific_job
835- self.assertEqual(bpj.processor.id, 1)
836- build, bq = find_job(self, 'bison', 'hppa')
837- bpj = bq.specific_job
838- self.assertEqual(bpj.processor.id, 3)
839-
840- def test_virtualized(self):
841- # Test that BuildPackageJob returns the correct virtualized flag.
842- build, bq = find_job(self, 'apg', '386')
843- bpj = bq.specific_job
844- self.assertEqual(bpj.virtualized, False)
845- build, bq = find_job(self, 'flex', 'hppa')
846- bpj = bq.specific_job
847- self.assertEqual(bpj.virtualized, False)
848-
849 def test_providesInterfaces(self):
850 # Ensure that a BuildPackageJob generates an appropriate cookie.
851 build, bq = find_job(self, 'gcc', '386')
852@@ -222,17 +200,6 @@
853 self.assertProvides(build_farm_job, IBuildPackageJob)
854 self.assertProvides(build_farm_job, IBuildFarmBuildJob)
855
856- def test_jobStarted(self):
857- # Starting a build updates the status.
858- build, bq = find_job(self, 'gcc', '386')
859- build_package_job = bq.specific_job
860- build_package_job.jobStarted()
861- self.assertEqual(
862- BuildStatus.BUILDING, build_package_job.build.status)
863- self.assertIsNot(None, build_package_job.build.date_started)
864- self.assertIsNot(None, build_package_job.build.date_first_dispatched)
865- self.assertIs(None, build_package_job.build.date_finished)
866-
867
868 class TestBuildPackageJobScore(TestCaseWithFactory):
869
870@@ -469,42 +436,3 @@
871 with anonymous_logged_in():
872 self.assertScoreWriteableByTeam(
873 archive, getUtility(ILaunchpadCelebrities).commercial_admin)
874-
875-
876-class TestBuildPackageJobPostProcess(TestCaseWithFactory):
877-
878- layer = DatabaseFunctionalLayer
879-
880- def makeBuildJob(self, pocket="RELEASE"):
881- build = self.factory.makeBinaryPackageBuild(pocket=pocket)
882- return build.queueBuild()
883-
884- def test_release_job(self):
885- job = self.makeBuildJob()
886- build = getUtility(IBinaryPackageBuildSet).getByQueueEntry(job)
887- self.assertTrue(BuildPackageJob.postprocessCandidate(job, None))
888- self.assertEqual(BuildStatus.NEEDSBUILD, build.status)
889-
890- def test_security_job_is_failed(self):
891- job = self.makeBuildJob(pocket="SECURITY")
892- build = getUtility(IBinaryPackageBuildSet).getByQueueEntry(job)
893- BuildPackageJob.postprocessCandidate(job, DevNullLogger())
894- self.assertEqual(BuildStatus.FAILEDTOBUILD, build.status)
895-
896- def test_obsolete_job_without_flag_is_failed(self):
897- job = self.makeBuildJob()
898- build = getUtility(IBinaryPackageBuildSet).getByQueueEntry(job)
899- distroseries = build.distro_arch_series.distroseries
900- removeSecurityProxy(distroseries).status = SeriesStatus.OBSOLETE
901- BuildPackageJob.postprocessCandidate(job, DevNullLogger())
902- self.assertEqual(BuildStatus.FAILEDTOBUILD, build.status)
903-
904- def test_obsolete_job_with_flag_is_not_failed(self):
905- job = self.makeBuildJob()
906- build = getUtility(IBinaryPackageBuildSet).getByQueueEntry(job)
907- distroseries = build.distro_arch_series.distroseries
908- archive = build.archive
909- removeSecurityProxy(distroseries).status = SeriesStatus.OBSOLETE
910- removeSecurityProxy(archive).permit_obsolete_series_uploads = True
911- BuildPackageJob.postprocessCandidate(job, DevNullLogger())
912- self.assertEqual(BuildStatus.NEEDSBUILD, build.status)
913
914=== modified file 'lib/lp/translations/model/translationtemplatesbuild.py'
915--- lib/lp/translations/model/translationtemplatesbuild.py 2013-09-24 05:45:06 +0000
916+++ lib/lp/translations/model/translationtemplatesbuild.py 2013-11-11 23:47:32 +0000
917@@ -28,7 +28,10 @@
918 BuildStatus,
919 )
920 from lp.buildmaster.interfaces.buildfarmjob import IBuildFarmJobSource
921-from lp.buildmaster.model.buildfarmjob import BuildFarmJobMixin
922+from lp.buildmaster.model.buildfarmjob import (
923+ BuildFarmJobMixin,
924+ SpecificBuildFarmJobSourceMixin,
925+ )
926 from lp.code.model.branch import Branch
927 from lp.code.model.branchcollection import GenericBranchCollection
928 from lp.code.model.branchjob import (
929@@ -49,7 +52,8 @@
930 )
931
932
933-class TranslationTemplatesBuild(BuildFarmJobMixin, Storm):
934+class TranslationTemplatesBuild(SpecificBuildFarmJobSourceMixin,
935+ BuildFarmJobMixin, Storm):
936 """A `BuildFarmJob` extension for translation templates builds."""
937
938 implements(ITranslationTemplatesBuild)