Merge lp:~michael.nelson/launchpad/delegate-to-buildfarmjob into lp:launchpad

Proposed by Michael Nelson
Status: Merged
Approved by: Michael Nelson
Approved revision: no longer in the source branch.
Merged at revision: not available
Proposed branch: lp:~michael.nelson/launchpad/delegate-to-buildfarmjob
Merge into: lp:launchpad
Diff against target: 718 lines (+215/-123)
15 files modified
lib/lp/buildmaster/doc/buildfarmjob.txt (+32/-9)
lib/lp/buildmaster/interfaces/buildfarmbranchjob.py (+1/-2)
lib/lp/buildmaster/interfaces/buildfarmjob.py (+15/-25)
lib/lp/buildmaster/model/buildfarmjob.py (+64/-37)
lib/lp/buildmaster/model/packagebuildfarmjob.py (+29/-3)
lib/lp/buildmaster/tests/test_buildqueue.py (+24/-17)
lib/lp/code/configure.zcml (+2/-1)
lib/lp/code/model/sourcepackagerecipebuild.py (+5/-4)
lib/lp/soyuz/configure.zcml (+2/-0)
lib/lp/soyuz/model/binarypackagebuild.py (+1/-3)
lib/lp/soyuz/model/buildpackagejob.py (+11/-5)
lib/lp/soyuz/tests/test_buildpackagejob.py (+13/-0)
lib/lp/translations/configure.zcml (+2/-0)
lib/lp/translations/model/translationtemplatesbuildjob.py (+8/-9)
lib/lp/translations/tests/test_translationtemplatesbuildjob.py (+6/-8)
To merge this branch: bzr merge lp:~michael.nelson/launchpad/delegate-to-buildfarmjob
Reviewer Review Type Date Requested Status
Brad Crittenden (community) code Approve
Review via email: mp+23553@code.launchpad.net

Commit message

Switch BuildFarmJob from an inherited mix-in to a delegated object in preparation for the build generalisation work.

Description of the change

This branch switches BuildFarmJob from an inherited mix-in to a delegated object, in preparation for the build generalisation work (where BuildFarmJob will become a concrete Storm class).

While at it, I used the opportunity to merge two interfaces specific to the build farm queue scheduling into existing interfaces (see bug 562252).

There is no demo url, this is just an implementation detail.

Test command:
bin/test -vvt test_translationtemplatesbuildjob -t test_buildqueue -t doc/buildfarmjob.txt

Pre-implementation:
This is part of the LEP https://dev.launchpad.net/LEP/GeneralBuildHistories which has been discussed with jml. The reason for the delegation rather than inheritance is that BuildFarmJob will become a concrete Storm class.

To post a comment you must log in.
Revision history for this message
Brad Crittenden (bac) wrote :

Hi Michael,

This branch looks good.

Since _set_build_farm_job() is a method which is intended to be overridden please provide a docstring for it.

Also, our coding guidelines state the docstring must be a single line followed by a longer explanation if needed. It is quite Draconian and leads to some haiku-like challenges but please see if you can adhere to the rule.

review: Approve (code)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'lib/lp/buildmaster/doc/buildfarmjob.txt'
--- lib/lp/buildmaster/doc/buildfarmjob.txt 2010-01-14 09:55:06 +0000
+++ lib/lp/buildmaster/doc/buildfarmjob.txt 2010-04-21 11:53:24 +0000
@@ -1,20 +1,43 @@
1= BuildFarmJob =1BuildFarmJob
2============
23
3 >>> from lp.buildmaster.interfaces.buildfarmjob import IBuildFarmJob4 >>> from lp.buildmaster.interfaces.buildfarmjob import IBuildFarmJob
4 >>> from lp.buildmaster.model.buildfarmjob import BuildFarmJob5 >>> from lp.buildmaster.model.buildfarmjob import (
6 ... BuildFarmJob, BuildFarmJobDerived)
57
6BuildFarmJob provides a basic implementation of IBuildFarmJob. The8BuildFarmJob provides a basic implementation of IBuildFarmJob. The
7specific build farm job classes should inherit from it.9specific build farm job classes will automatically delegate to
10BuildFarmJob by inheriting BuildFarmJobDerived.
811
9 >>> buildfarmjob = BuildFarmJob()12 >>> buildfarmjob = BuildFarmJob()
10 >>> verifyObject(IBuildFarmJob, buildfarmjob) 13 >>> verifyObject(IBuildFarmJob, buildfarmjob)
11 True14 True
1215
13As a class, it also provides ISpecificBuildFarmJobClass so that16The BuildFarmJob class does not (yet) do a lot itself, other than
14BuildQueue can find the instance of a specific build-farm job17providing default implementations for its methods.
15implementation associated with a given Job instance.18
19 >>> print buildfarmjob.getLogFileName()
20 buildlog.txt
21
22 >>> buildfarmjob.getName()
23 Traceback (most recent call last):
24 ...
25 NotImplementedError
26
27
28BuildFarmJobDerived
29===================
30
31BuildFarmJobDerived exists to encapsulate the functionality required
32by classes delegating IBuildFarmJob.
1633
17 >>> from lp.buildmaster.interfaces.buildfarmjob import (34 >>> from lp.buildmaster.interfaces.buildfarmjob import (
18 ... ISpecificBuildFarmJobClass)35 ... IBuildFarmJobDerived)
19 >>> verifyObject(ISpecificBuildFarmJobClass, BuildFarmJob)36 >>> verifyObject(IBuildFarmJobDerived, BuildFarmJobDerived())
20 True37 True
38
39This class also includes the getByJob() class method used to find the
40instance of a specific build-farm job implementation associated with a
41given Job instance which must be called in the context of a concrete
42derived class. See lp.buildmaster.tests.test_buildqueue for examples.
43
2144
=== modified file 'lib/lp/buildmaster/interfaces/buildfarmbranchjob.py'
--- lib/lp/buildmaster/interfaces/buildfarmbranchjob.py 2010-03-17 05:58:22 +0000
+++ lib/lp/buildmaster/interfaces/buildfarmbranchjob.py 2010-04-21 11:53:24 +0000
@@ -8,11 +8,10 @@
8 'IBuildFarmBranchJob'8 'IBuildFarmBranchJob'
9 ]9 ]
1010
11from lp.buildmaster.interfaces.buildfarmjob import IBuildFarmJob
12from lp.code.interfaces.branchjob import IBranchJob11from lp.code.interfaces.branchjob import IBranchJob
1312
1413
15class IBuildFarmBranchJob(IBuildFarmJob, IBranchJob):14class IBuildFarmBranchJob(IBranchJob):
16 """An `IBuildFarmJob` that's also an `IBranchJob`.15 """An `IBuildFarmJob` that's also an `IBranchJob`.
1716
18 Use this interface for `IBuildFarmJob` implementations that do not17 Use this interface for `IBuildFarmJob` implementations that do not
1918
=== modified file 'lib/lp/buildmaster/interfaces/buildfarmjob.py'
--- lib/lp/buildmaster/interfaces/buildfarmjob.py 2010-04-12 05:52:01 +0000
+++ lib/lp/buildmaster/interfaces/buildfarmjob.py 2010-04-21 11:53:24 +0000
@@ -9,8 +9,7 @@
99
10__all__ = [10__all__ = [
11 'IBuildFarmJob',11 'IBuildFarmJob',
12 'IBuildFarmCandidateJobSelection',12 'IBuildFarmJobDerived',
13 'ISpecificBuildFarmJobClass',
14 'BuildFarmJobType',13 'BuildFarmJobType',
15 ]14 ]
1615
@@ -57,16 +56,6 @@
57class IBuildFarmJob(Interface):56class IBuildFarmJob(Interface):
58 """Operations that jobs for the build farm must implement."""57 """Operations that jobs for the build farm must implement."""
5958
60 def generateSlaveBuildCookie():
61 """Produce a cookie for the slave as a token of the job it's doing.
62
63 The cookie need not be unique, but should be hard for a
64 compromised slave to guess.
65
66 :return: a hard-to-guess ASCII string that can be reproduced
67 accurately based on this job's properties.
68 """
69
70 def score():59 def score():
71 """Calculate a job score appropriate for the job type in question."""60 """Calculate a job score appropriate for the job type in question."""
7261
@@ -101,11 +90,10 @@
101 "return None."))90 "return None."))
10291
10392
104class ISpecificBuildFarmJobClass(Interface):93class IBuildFarmJobDerived(Interface):
105 """Class interface provided by `IBuildFarmJob` classes.94 """Common functionality required by classes delegating IBuildFarmJob.
10695
107 Used by the `BuildQueue` to find the specific build-farm job objects96 An implementation of this class must setup the necessary delagation.
108 it needs to dispatch to builders.
109 """97 """
11098
111 def getByJob(job):99 def getByJob(job):
@@ -115,15 +103,6 @@
115 has an entry associated with `job`.103 has an entry associated with `job`.
116 """104 """
117105
118
119class IBuildFarmCandidateJobSelection(Interface):
120 """Operations for refining candidate job selection (optional).
121
122 Job type classes that do *not* need to refine candidate job selection may
123 be derived from `BuildFarmJob` which provides a base implementation of
124 this interface.
125 """
126
127 def addCandidateSelectionCriteria(processor, virtualized):106 def addCandidateSelectionCriteria(processor, virtualized):
128 """Provide a sub-query to refine the candidate job selection.107 """Provide a sub-query to refine the candidate job selection.
129108
@@ -159,3 +138,14 @@
159 :return: True if the candidate job should be dispatched138 :return: True if the candidate job should be dispatched
160 to a builder, False otherwise.139 to a builder, False otherwise.
161 """140 """
141
142 def generateSlaveBuildCookie():
143 """Produce a cookie for the slave as a token of the job it's doing.
144
145 The cookie need not be unique, but should be hard for a
146 compromised slave to guess.
147
148 :return: a hard-to-guess ASCII string that can be reproduced
149 accurately based on this job's properties.
150 """
151
162152
=== modified file 'lib/lp/buildmaster/model/buildfarmjob.py'
--- lib/lp/buildmaster/model/buildfarmjob.py 2010-04-12 05:52:01 +0000
+++ lib/lp/buildmaster/model/buildfarmjob.py 2010-04-21 11:53:24 +0000
@@ -2,48 +2,31 @@
2# GNU Affero General Public License version 3 (see the file LICENSE).2# GNU Affero General Public License version 3 (see the file LICENSE).
33
4__metaclass__ = type4__metaclass__ = type
5__all__ = ['BuildFarmJob']5__all__ = [
66 'BuildFarmJob',
7 'BuildFarmJobDerived',
8 ]
9
10
11from lazr.delegates import delegates
712
8import hashlib13import hashlib
914
10from zope.component import getUtility15from zope.component import getUtility
11from zope.interface import classProvides, implements16from zope.interface import implements
12from zope.security.proxy import removeSecurityProxy17from zope.security.proxy import removeSecurityProxy
1318
14from canonical.launchpad.webapp.interfaces import (19from canonical.launchpad.webapp.interfaces import (
15 DEFAULT_FLAVOR, IStoreSelector, MAIN_STORE)20 DEFAULT_FLAVOR, IStoreSelector, MAIN_STORE)
21
16from lp.buildmaster.interfaces.buildfarmjob import (22from lp.buildmaster.interfaces.buildfarmjob import (
17 IBuildFarmJob, IBuildFarmCandidateJobSelection,23 IBuildFarmJob, IBuildFarmJobDerived)
18 ISpecificBuildFarmJobClass)
19from lp.buildmaster.interfaces.buildqueue import IBuildQueueSet24from lp.buildmaster.interfaces.buildqueue import IBuildQueueSet
2025
2126
22class BuildFarmJob:27class BuildFarmJob:
23 """Mix-in class for `IBuildFarmJob` implementations."""28 """A base implementation for `IBuildFarmJob` classes."""
24 implements(IBuildFarmJob)29 implements(IBuildFarmJob)
25 classProvides(
26 IBuildFarmCandidateJobSelection, ISpecificBuildFarmJobClass)
27
28 def generateSlaveBuildCookie(self):
29 """See `IBuildFarmJob`."""
30 buildqueue = getUtility(IBuildQueueSet).getByJob(self.job)
31
32 if buildqueue.processor is None:
33 processor = '*'
34 else:
35 processor = repr(buildqueue.processor.id)
36
37 contents = ';'.join([
38 repr(removeSecurityProxy(self.job).id),
39 self.job.date_created.isoformat(),
40 repr(buildqueue.id),
41 buildqueue.job_type.name,
42 processor,
43 self.getName(),
44 ])
45
46 return hashlib.sha1(contents).hexdigest()
4730
48 def score(self):31 def score(self):
49 """See `IBuildFarmJob`."""32 """See `IBuildFarmJob`."""
@@ -83,22 +66,66 @@
83 """See `IBuildFarmJob`."""66 """See `IBuildFarmJob`."""
84 return None67 return None
8568
86 @staticmethod69
87 def addCandidateSelectionCriteria(processor, virtualized):70class BuildFarmJobDerived:
88 """See `IBuildFarmCandidateJobSelection`."""71 """See `IBuildFarmJobDerived`."""
89 return ('')72 implements(IBuildFarmJobDerived)
73 delegates(IBuildFarmJob, context='_build_farm_job')
74
75 def __init__(self, *args, **kwargs):
76 """Ensure the instance to which we delegate is set on creation."""
77 self._set_build_farm_job()
78 super(BuildFarmJobDerived, self).__init__(*args, **kwargs)
79
80 def __storm_loaded__(self):
81 """Set the attribute for our IBuildFarmJob delegation.
82
83 This is needed here as __init__() is not called when a storm object
84 is loaded from the database.
85 """
86 self._set_build_farm_job()
87
88 def _set_build_farm_job(self):
89 """Set the build farm job to which we will delegate.
90
91 Sub-classes can override as required.
92 """
93 self._build_farm_job = BuildFarmJob()
9094
91 @classmethod95 @classmethod
92 def getByJob(cls, job):96 def getByJob(cls, job):
93 """See `ISpecificBuildFarmJobClass`.97 """See `IBuildFarmJobDerived`."""
94 This base implementation should work for most build farm job
95 types, but some need to override it.
96 """
97 store = getUtility(IStoreSelector).get(MAIN_STORE, DEFAULT_FLAVOR)98 store = getUtility(IStoreSelector).get(MAIN_STORE, DEFAULT_FLAVOR)
98 return store.find(cls, cls.job == job).one()99 return store.find(cls, cls.job == job).one()
99100
100 @staticmethod101 @staticmethod
102 def addCandidateSelectionCriteria(processor, virtualized):
103 """See `IBuildFarmJobDerived`."""
104 return ('')
105
106 @staticmethod
101 def postprocessCandidate(job, logger):107 def postprocessCandidate(job, logger):
102 """See `IBuildFarmCandidateJobSelection`."""108 """See `IBuildFarmJobDerived`."""
103 return True109 return True
104110
111 def generateSlaveBuildCookie(self):
112 """See `IBuildFarmJobDerived`."""
113 buildqueue = getUtility(IBuildQueueSet).getByJob(self.job)
114
115 if buildqueue.processor is None:
116 processor = '*'
117 else:
118 processor = repr(buildqueue.processor.id)
119
120 contents = ';'.join([
121 repr(removeSecurityProxy(self.job).id),
122 self.job.date_created.isoformat(),
123 repr(buildqueue.id),
124 buildqueue.job_type.name,
125 processor,
126 self.getName(),
127 ])
128
129 return hashlib.sha1(contents).hexdigest()
130
131
105132
=== modified file 'lib/lp/buildmaster/model/packagebuildfarmjob.py'
--- lib/lp/buildmaster/model/packagebuildfarmjob.py 2010-03-25 14:38:25 +0000
+++ lib/lp/buildmaster/model/packagebuildfarmjob.py 2010-04-21 11:53:24 +0000
@@ -2,17 +2,32 @@
2# GNU Affero General Public License version 3 (see the file LICENSE).2# GNU Affero General Public License version 3 (see the file LICENSE).
33
4__metaclass__ = type4__metaclass__ = type
5__all__ = ['PackageBuildFarmJob']5__all__ = [
6 'PackageBuildFarmJob',
7 'PackageBuildFarmJobDerived',
8 ]
69
710
8from canonical.database.constants import UTC_NOW11from canonical.database.constants import UTC_NOW
912
10from lp.buildmaster.interfaces.buildbase import BuildStatus13from lp.buildmaster.interfaces.buildbase import BuildStatus
11from lp.buildmaster.model.buildfarmjob import BuildFarmJob14from lp.buildmaster.model.buildfarmjob import (
15 BuildFarmJob, BuildFarmJobDerived)
1216
1317
14class PackageBuildFarmJob(BuildFarmJob):18class PackageBuildFarmJob(BuildFarmJob):
15 """Mix-in class for `IBuildFarmJob` implementations for package builds."""19 """An implementation of `IBuildFarmJob` for package builds."""
20
21 def __init__(self, build):
22 """Store the build for this package build farm job.
23
24 XXX 2010-04-12 michael.nelson bug=536700
25 The build param will no longer be necessary once BuildFarmJob is
26 itself a concrete class. This class (PackageBuildFarmJob)
27 will also be renamed PackageBuild and turned into a concrete class.
28 """
29 super(PackageBuildFarmJob, self).__init__()
30 self.build = build
1631
17 def getTitle(self):32 def getTitle(self):
18 """See `IBuildFarmJob`."""33 """See `IBuildFarmJob`."""
@@ -32,3 +47,14 @@
32 def jobAborted(self):47 def jobAborted(self):
33 """See `IBuildFarmJob`."""48 """See `IBuildFarmJob`."""
34 self.build.buildstate = BuildStatus.NEEDSBUILD49 self.build.buildstate = BuildStatus.NEEDSBUILD
50
51
52class PackageBuildFarmJobDerived(BuildFarmJobDerived):
53 """Override the base delegate.
54
55 Ensure that we use a build farm job specific to packages.
56 """
57 def _set_build_farm_job(self):
58 self._build_farm_job = PackageBuildFarmJob(self.build)
59
60
3561
=== modified file 'lib/lp/buildmaster/tests/test_buildqueue.py'
--- lib/lp/buildmaster/tests/test_buildqueue.py 2010-04-12 08:29:02 +0000
+++ lib/lp/buildmaster/tests/test_buildqueue.py 2010-04-21 11:53:24 +0000
@@ -8,7 +8,8 @@
8from pytz import utc8from pytz import utc
9from unittest import TestLoader9from unittest import TestLoader
1010
11from zope.component import getUtility11from zope import component
12from zope.component import getGlobalSiteManager, getUtility
12from zope.interface.verify import verifyObject13from zope.interface.verify import verifyObject
1314
14from canonical.launchpad.webapp.interfaces import (15from canonical.launchpad.webapp.interfaces import (
@@ -17,10 +18,11 @@
1718
18from lp.buildmaster.interfaces.buildbase import BuildStatus19from lp.buildmaster.interfaces.buildbase import BuildStatus
19from lp.buildmaster.interfaces.builder import IBuilderSet20from lp.buildmaster.interfaces.builder import IBuilderSet
20from lp.buildmaster.interfaces.buildfarmjob import BuildFarmJobType21from lp.buildmaster.interfaces.buildfarmjob import (
22 BuildFarmJobType, IBuildFarmJob)
21from lp.buildmaster.interfaces.buildqueue import IBuildQueueSet23from lp.buildmaster.interfaces.buildqueue import IBuildQueueSet
22from lp.buildmaster.model.builder import specific_job_classes24from lp.buildmaster.model.builder import specific_job_classes
23from lp.buildmaster.model.buildfarmjob import BuildFarmJob25from lp.buildmaster.model.buildfarmjob import BuildFarmJobDerived
24from lp.buildmaster.model.buildqueue import BuildQueue, get_builder_data26from lp.buildmaster.model.buildqueue import BuildQueue, get_builder_data
25from lp.services.job.model.job import Job27from lp.services.job.model.job import Job
26from lp.soyuz.interfaces.archive import ArchivePurpose28from lp.soyuz.interfaces.archive import ArchivePurpose
@@ -885,9 +887,7 @@
885887
886 def test_OtherTypeClasses(self):888 def test_OtherTypeClasses(self):
887 """Other job type classes are picked up as well."""889 """Other job type classes are picked up as well."""
888 from zope import component890 class FakeBranchBuild(BuildFarmJobDerived):
889 from lp.buildmaster.interfaces.buildfarmjob import IBuildFarmJob
890 class FakeBranchBuild(BuildFarmJob):
891 pass891 pass
892892
893 _build, bq = find_job(self, 'gedit')893 _build, bq = find_job(self, 'gedit')
@@ -896,17 +896,24 @@
896 self.assertTrue(896 self.assertTrue(
897 specific_job_classes().get(BuildFarmJobType.BRANCHBUILD) is None)897 specific_job_classes().get(BuildFarmJobType.BRANCHBUILD) is None)
898898
899 # Pretend that our `FakeBranchBuild` class implements the899 try:
900 # `IBuildFarmJob` interface.900 # Pretend that our `FakeBranchBuild` class implements the
901 component.provideUtility(901 # `IBuildFarmJob` interface.
902 FakeBranchBuild, IBuildFarmJob, 'BRANCHBUILD')902 component.provideUtility(
903903 FakeBranchBuild, IBuildFarmJob, 'BRANCHBUILD')
904 # Now we should see the `FakeBranchBuild` class "registered" in the904
905 # `specific_job_classes` dictionary under the 'BRANCHBUILD' key.905 # Now we should see the `FakeBranchBuild` class "registered"
906 self.assertEqual(906 # in the `specific_job_classes` dictionary under the
907 specific_job_classes()[BuildFarmJobType.BRANCHBUILD],907 # 'BRANCHBUILD' key.
908 FakeBranchBuild)908 self.assertEqual(
909909 specific_job_classes()[BuildFarmJobType.BRANCHBUILD],
910 FakeBranchBuild)
911 finally:
912 # Just de-register the utility so we don't affect other
913 # tests.
914 site_manager = getGlobalSiteManager()
915 site_manager.unregisterUtility(
916 FakeBranchBuild, IBuildFarmJob, 'BRANCHBUILD')
910917
911class TestPlatformData(TestCaseWithFactory):918class TestPlatformData(TestCaseWithFactory):
912 """Tests covering the processor/virtualized properties."""919 """Tests covering the processor/virtualized properties."""
913920
=== modified file 'lib/lp/code/configure.zcml'
--- lib/lp/code/configure.zcml 2010-04-20 06:42:29 +0000
+++ lib/lp/code/configure.zcml 2010-04-21 11:53:24 +0000
@@ -31,7 +31,7 @@
3131
32 <class class="lp.code.model.codereviewvote.CodeReviewVoteReference">32 <class class="lp.code.model.codereviewvote.CodeReviewVoteReference">
33 <allow interface="lp.code.interfaces.codereviewvote.ICodeReviewVoteReferencePublic"/>33 <allow interface="lp.code.interfaces.codereviewvote.ICodeReviewVoteReferencePublic"/>
34 <require 34 <require
35 permission="launchpad.Edit"35 permission="launchpad.Edit"
36 interface="lp.code.interfaces.codereviewvote.ICodeReviewVoteReferenceEdit"/>36 interface="lp.code.interfaces.codereviewvote.ICodeReviewVoteReferenceEdit"/>
37 </class>37 </class>
@@ -988,6 +988,7 @@
988 <class988 <class
989 class="lp.code.model.sourcepackagerecipebuild.SourcePackageRecipeBuildJob">989 class="lp.code.model.sourcepackagerecipebuild.SourcePackageRecipeBuildJob">
990 <allow interface="lp.code.interfaces.sourcepackagerecipebuild.ISourcePackageRecipeBuildJob"/>990 <allow interface="lp.code.interfaces.sourcepackagerecipebuild.ISourcePackageRecipeBuildJob"/>
991 <allow interface="lp.buildmaster.interfaces.buildfarmjob.IBuildFarmJobDerived"/>
991 </class>992 </class>
992993
993 <securedutility994 <securedutility
994995
=== modified file 'lib/lp/code/model/sourcepackagerecipebuild.py'
--- lib/lp/code/model/sourcepackagerecipebuild.py 2010-04-19 03:36:27 +0000
+++ lib/lp/code/model/sourcepackagerecipebuild.py 2010-04-21 11:53:24 +0000
@@ -27,7 +27,8 @@
27from lp.buildmaster.interfaces.buildfarmjob import BuildFarmJobType27from lp.buildmaster.interfaces.buildfarmjob import BuildFarmJobType
28from lp.buildmaster.model.buildbase import BuildBase28from lp.buildmaster.model.buildbase import BuildBase
29from lp.buildmaster.model.buildqueue import BuildQueue29from lp.buildmaster.model.buildqueue import BuildQueue
30from lp.buildmaster.model.packagebuildfarmjob import PackageBuildFarmJob30from lp.buildmaster.model.packagebuildfarmjob import (
31 PackageBuildFarmJobDerived)
31from lp.code.interfaces.sourcepackagerecipebuild import (32from lp.code.interfaces.sourcepackagerecipebuild import (
32 ISourcePackageRecipeBuildJob, ISourcePackageRecipeBuildJobSource,33 ISourcePackageRecipeBuildJob, ISourcePackageRecipeBuildJobSource,
33 ISourcePackageRecipeBuild, ISourcePackageRecipeBuildSource)34 ISourcePackageRecipeBuild, ISourcePackageRecipeBuildSource)
@@ -198,7 +199,7 @@
198 return199 return
199200
200201
201class SourcePackageRecipeBuildJob(PackageBuildFarmJob, Storm):202class SourcePackageRecipeBuildJob(PackageBuildFarmJobDerived, Storm):
202 classProvides(ISourcePackageRecipeBuildJobSource)203 classProvides(ISourcePackageRecipeBuildJobSource)
203 implements(ISourcePackageRecipeBuildJob)204 implements(ISourcePackageRecipeBuildJob)
204205
@@ -217,15 +218,15 @@
217 virtualized = True218 virtualized = True
218219
219 def __init__(self, build, job):220 def __init__(self, build, job):
220 super(SourcePackageRecipeBuildJob, self).__init__()
221 self.build = build221 self.build = build
222 self.job = job222 self.job = job
223 super(SourcePackageRecipeBuildJob, self).__init__()
223224
224 @classmethod225 @classmethod
225 def new(cls, build, job):226 def new(cls, build, job):
226 """See `ISourcePackageRecipeBuildJobSource`."""227 """See `ISourcePackageRecipeBuildJobSource`."""
227 specific_job = cls(build, job)228 specific_job = cls(build, job)
228 store = IMasterStore(SourcePackageRecipeBuildJob)229 store = IMasterStore(cls)
229 store.add(specific_job)230 store.add(specific_job)
230 return specific_job231 return specific_job
231232
232233
=== modified file 'lib/lp/soyuz/configure.zcml'
--- lib/lp/soyuz/configure.zcml 2010-04-12 11:37:48 +0000
+++ lib/lp/soyuz/configure.zcml 2010-04-21 11:53:24 +0000
@@ -848,6 +848,8 @@
848 class="lp.soyuz.model.buildpackagejob.BuildPackageJob">848 class="lp.soyuz.model.buildpackagejob.BuildPackageJob">
849 <allow849 <allow
850 interface="lp.soyuz.interfaces.buildpackagejob.IBuildPackageJob"/>850 interface="lp.soyuz.interfaces.buildpackagejob.IBuildPackageJob"/>
851 <allow
852 interface="lp.buildmaster.interfaces.buildfarmjob.IBuildFarmJobDerived"/>
851 </class>853 </class>
852 <!--854 <!--
853 The registration below is used to discover all build farm job classes855 The registration below is used to discover all build farm job classes
854856
=== modified file 'lib/lp/soyuz/model/binarypackagebuild.py'
--- lib/lp/soyuz/model/binarypackagebuild.py 2010-04-09 15:46:09 +0000
+++ lib/lp/soyuz/model/binarypackagebuild.py 2010-04-21 11:53:24 +0000
@@ -313,9 +313,7 @@
313 store = Store.of(self)313 store = Store.of(self)
314 job = Job()314 job = Job()
315 store.add(job)315 store.add(job)
316 specific_job = BuildPackageJob()316 specific_job = BuildPackageJob(build=self, job=job)
317 specific_job.build = self.id
318 specific_job.job = job.id
319 store.add(specific_job)317 store.add(specific_job)
320 return specific_job318 return specific_job
321319
322320
=== modified file 'lib/lp/soyuz/model/buildpackagejob.py'
--- lib/lp/soyuz/model/buildpackagejob.py 2010-04-12 11:37:48 +0000
+++ lib/lp/soyuz/model/buildpackagejob.py 2010-04-21 11:53:24 +0000
@@ -12,13 +12,14 @@
1212
13from storm.locals import Int, Reference, Storm13from storm.locals import Int, Reference, Storm
1414
15from zope.component import getUtility
15from zope.interface import implements16from zope.interface import implements
16from zope.component import getUtility
1717
18from canonical.database.sqlbase import sqlvalues18from canonical.database.sqlbase import sqlvalues
1919
20from lp.buildmaster.interfaces.buildbase import BuildStatus20from lp.buildmaster.interfaces.buildbase import BuildStatus
21from lp.buildmaster.model.packagebuildfarmjob import PackageBuildFarmJob21from lp.buildmaster.model.packagebuildfarmjob import (
22 PackageBuildFarmJobDerived)
22from lp.registry.interfaces.sourcepackage import SourcePackageUrgency23from lp.registry.interfaces.sourcepackage import SourcePackageUrgency
23from lp.registry.interfaces.pocket import PackagePublishingPocket24from lp.registry.interfaces.pocket import PackagePublishingPocket
24from lp.soyuz.interfaces.archive import ArchivePurpose25from lp.soyuz.interfaces.archive import ArchivePurpose
@@ -27,7 +28,7 @@
27from lp.soyuz.interfaces.publishing import PackagePublishingStatus28from lp.soyuz.interfaces.publishing import PackagePublishingStatus
2829
2930
30class BuildPackageJob(PackageBuildFarmJob, Storm):31class BuildPackageJob(PackageBuildFarmJobDerived, Storm):
31 """See `IBuildPackageJob`."""32 """See `IBuildPackageJob`."""
32 implements(IBuildPackageJob)33 implements(IBuildPackageJob)
3334
@@ -40,6 +41,11 @@
40 build_id = Int(name='build', allow_none=False)41 build_id = Int(name='build', allow_none=False)
41 build = Reference(build_id, 'BinaryPackageBuild.id')42 build = Reference(build_id, 'BinaryPackageBuild.id')
4243
44 def __init__(self, build, job):
45 """ Setup the IBuildFarmJob delegation when new items are created."""
46 self.build, self.job = build, job
47 super(BuildPackageJob, self).__init__()
48
43 def score(self):49 def score(self):
44 """See `IBuildPackageJob`."""50 """See `IBuildPackageJob`."""
45 score_pocketname = {51 score_pocketname = {
@@ -166,7 +172,7 @@
166172
167 @staticmethod173 @staticmethod
168 def addCandidateSelectionCriteria(processor, virtualized):174 def addCandidateSelectionCriteria(processor, virtualized):
169 """See `IBuildFarmCandidateJobSelection`."""175 """See `IBuildFarmJob`."""
170 # Avoiding circular import.176 # Avoiding circular import.
171 from lp.buildmaster.model.builder import Builder177 from lp.buildmaster.model.builder import Builder
172178
@@ -236,7 +242,7 @@
236242
237 @staticmethod243 @staticmethod
238 def postprocessCandidate(job, logger):244 def postprocessCandidate(job, logger):
239 """See `IBuildFarmCandidateJobSelection`."""245 """See `IBuildFarmJob`."""
240 # Mark build records targeted to old source versions as SUPERSEDED246 # Mark build records targeted to old source versions as SUPERSEDED
241 # and build records target to SECURITY pocket as FAILEDTOBUILD.247 # and build records target to SECURITY pocket as FAILEDTOBUILD.
242 # Builds in those situation should not be built because they will248 # Builds in those situation should not be built because they will
243249
=== modified file 'lib/lp/soyuz/tests/test_buildpackagejob.py'
--- lib/lp/soyuz/tests/test_buildpackagejob.py 2010-04-12 08:29:02 +0000
+++ lib/lp/soyuz/tests/test_buildpackagejob.py 2010-04-21 11:53:24 +0000
@@ -13,7 +13,10 @@
1313
14from lp.buildmaster.interfaces.buildbase import BuildStatus14from lp.buildmaster.interfaces.buildbase import BuildStatus
15from lp.buildmaster.interfaces.builder import IBuilderSet15from lp.buildmaster.interfaces.builder import IBuilderSet
16from lp.buildmaster.interfaces.buildfarmjob import (
17 IBuildFarmJob, IBuildFarmJobDerived)
16from lp.soyuz.interfaces.archive import ArchivePurpose18from lp.soyuz.interfaces.archive import ArchivePurpose
19from lp.soyuz.interfaces.buildpackagejob import IBuildPackageJob
17from lp.soyuz.interfaces.publishing import PackagePublishingStatus20from lp.soyuz.interfaces.publishing import PackagePublishingStatus
18from lp.soyuz.model.binarypackagebuild import BinaryPackageBuild21from lp.soyuz.model.binarypackagebuild import BinaryPackageBuild
19from lp.soyuz.model.processor import ProcessorFamilySet22from lp.soyuz.model.processor import ProcessorFamilySet
@@ -225,3 +228,13 @@
225 # Test that BuildPackageJob returns the title of the build.228 # Test that BuildPackageJob returns the title of the build.
226 build, bq = find_job(self, 'gcc', '386')229 build, bq = find_job(self, 'gcc', '386')
227 self.assertEqual(bq.specific_job.getTitle(), build.title)230 self.assertEqual(bq.specific_job.getTitle(), build.title)
231
232 def test_providesInterfaces(self):
233 # Ensure that a BuildPackageJob generates an appropriate cookie.
234 build, bq = find_job(self, 'gcc', '386')
235 build_farm_job = bq.specific_job
236 self.assertProvides(build_farm_job, IBuildPackageJob)
237 self.assertProvides(build_farm_job, IBuildFarmJob)
238 self.assertProvides(build_farm_job, IBuildFarmJobDerived)
239
240
228241
=== modified file 'lib/lp/translations/configure.zcml'
--- lib/lp/translations/configure.zcml 2010-02-17 11:19:42 +0000
+++ lib/lp/translations/configure.zcml 2010-04-21 11:53:24 +0000
@@ -579,6 +579,8 @@
579 interface="lp.code.interfaces.branchjob.IBranchJob"/>579 interface="lp.code.interfaces.branchjob.IBranchJob"/>
580 <allow580 <allow
581 interface="lp.buildmaster.interfaces.buildfarmjob.IBuildFarmJob"/>581 interface="lp.buildmaster.interfaces.buildfarmjob.IBuildFarmJob"/>
582 <allow
583 interface="lp.buildmaster.interfaces.buildfarmjob.IBuildFarmJobDerived"/>
582 </class>584 </class>
583 <securedutility585 <securedutility
584 component="lp.translations.model.translationtemplatesbuildjob.TranslationTemplatesBuildJob"586 component="lp.translations.model.translationtemplatesbuildjob.TranslationTemplatesBuildJob"
585587
=== modified file 'lib/lp/translations/model/translationtemplatesbuildjob.py'
--- lib/lp/translations/model/translationtemplatesbuildjob.py 2010-03-18 12:25:36 +0000
+++ lib/lp/translations/model/translationtemplatesbuildjob.py 2010-04-21 11:53:24 +0000
@@ -18,10 +18,9 @@
18from canonical.launchpad.webapp.interfaces import (18from canonical.launchpad.webapp.interfaces import (
19 DEFAULT_FLAVOR, IStoreSelector, MAIN_STORE, MASTER_FLAVOR)19 DEFAULT_FLAVOR, IStoreSelector, MAIN_STORE, MASTER_FLAVOR)
2020
21from lp.buildmaster.interfaces.buildfarmjob import (21from lp.buildmaster.interfaces.buildfarmjob import BuildFarmJobType
22 BuildFarmJobType, ISpecificBuildFarmJobClass)
23from lp.buildmaster.model.buildfarmjob import BuildFarmJob
24from lp.buildmaster.interfaces.buildqueue import IBuildQueueSet22from lp.buildmaster.interfaces.buildqueue import IBuildQueueSet
23from lp.buildmaster.model.buildfarmjob import BuildFarmJobDerived
25from lp.buildmaster.model.buildqueue import BuildQueue24from lp.buildmaster.model.buildqueue import BuildQueue
26from lp.code.interfaces.branchjob import IRosettaUploadJobSource25from lp.code.interfaces.branchjob import IRosettaUploadJobSource
27from lp.buildmaster.interfaces.buildfarmbranchjob import IBuildFarmBranchJob26from lp.buildmaster.interfaces.buildfarmbranchjob import IBuildFarmBranchJob
@@ -31,17 +30,15 @@
31from lp.translations.pottery.detect_intltool import is_intltool_structure30from lp.translations.pottery.detect_intltool import is_intltool_structure
3231
3332
34class TranslationTemplatesBuildJob(BranchJobDerived, BuildFarmJob):33class TranslationTemplatesBuildJob(BuildFarmJobDerived, BranchJobDerived):
35 """An `IBuildFarmJob` implementation that generates templates.34 """An `IBuildFarmJob` implementation that generates templates.
3635
37 Implementation-wise, this is actually a `BranchJob`.36 Implementation-wise, this is actually a `BranchJob`.
38 """37 """
39 implements(IBuildFarmBranchJob)38 implements(IBuildFarmBranchJob)
40
41 class_job_type = BranchJobType.TRANSLATION_TEMPLATES_BUILD39 class_job_type = BranchJobType.TRANSLATION_TEMPLATES_BUILD
4240
43 classProvides(41 classProvides(ITranslationTemplatesBuildJobSource)
44 ISpecificBuildFarmJobClass, ITranslationTemplatesBuildJobSource)
4542
46 duration_estimate = timedelta(seconds=10)43 duration_estimate = timedelta(seconds=10)
4744
@@ -110,7 +107,6 @@
110 branch, BranchJobType.TRANSLATION_TEMPLATES_BUILD, metadata)107 branch, BranchJobType.TRANSLATION_TEMPLATES_BUILD, metadata)
111 store.add(branch_job)108 store.add(branch_job)
112 specific_job = TranslationTemplatesBuildJob(branch_job)109 specific_job = TranslationTemplatesBuildJob(branch_job)
113
114 duration_estimate = cls.duration_estimate110 duration_estimate = cls.duration_estimate
115 build_queue_entry = BuildQueue(111 build_queue_entry = BuildQueue(
116 estimated_duration=duration_estimate,112 estimated_duration=duration_estimate,
@@ -133,7 +129,10 @@
133129
134 @classmethod130 @classmethod
135 def getByJob(cls, job):131 def getByJob(cls, job):
136 """See `ISpecificBuildFarmJobClass`."""132 """See `IBuildFarmJobDerived`.
133
134 Overridden here to search via a BranchJob, rather than a Job.
135 """
137 store = getUtility(IStoreSelector).get(MAIN_STORE, DEFAULT_FLAVOR)136 store = getUtility(IStoreSelector).get(MAIN_STORE, DEFAULT_FLAVOR)
138 branch_job = store.find(BranchJob, BranchJob.job == job).one()137 branch_job = store.find(BranchJob, BranchJob.job == job).one()
139 if branch_job is None:138 if branch_job is None:
140139
=== modified file 'lib/lp/translations/tests/test_translationtemplatesbuildjob.py'
--- lib/lp/translations/tests/test_translationtemplatesbuildjob.py 2010-03-06 00:21:57 +0000
+++ lib/lp/translations/tests/test_translationtemplatesbuildjob.py 2010-04-21 11:53:24 +0000
@@ -19,7 +19,7 @@
19from lp.testing import TestCaseWithFactory19from lp.testing import TestCaseWithFactory
2020
21from lp.buildmaster.interfaces.buildfarmjob import (21from lp.buildmaster.interfaces.buildfarmjob import (
22 IBuildFarmJob, ISpecificBuildFarmJobClass)22 IBuildFarmJob, IBuildFarmJobDerived)
23from lp.buildmaster.interfaces.buildfarmjobbehavior import (23from lp.buildmaster.interfaces.buildfarmjobbehavior import (
24 IBuildFarmJobBehavior)24 IBuildFarmJobBehavior)
25from lp.buildmaster.interfaces.buildqueue import IBuildQueueSet25from lp.buildmaster.interfaces.buildqueue import IBuildQueueSet
@@ -54,14 +54,12 @@
54 self.specific_job = self.jobset.create(self.branch)54 self.specific_job = self.jobset.create(self.branch)
5555
56 def test_new_TranslationTemplatesBuildJob(self):56 def test_new_TranslationTemplatesBuildJob(self):
57 # TranslationTemplateBuildJob implements IBuildFarmJob and57 # TranslationTemplateBuildJob implements IBuildFarmJob,
58 # IBranchJob.58 # IBuildFarmJobDerived, and IBranchJob.
59 verifyObject(IBranchJob, self.specific_job)59 verifyObject(IBranchJob, self.specific_job)
60 verifyObject(IBuildFarmJobDerived, self.specific_job)
60 verifyObject(IBuildFarmJob, self.specific_job)61 verifyObject(IBuildFarmJob, self.specific_job)
6162
62 # The class also implements ISpecificBuildFarmJobClass.
63 verifyObject(ISpecificBuildFarmJobClass, TranslationTemplatesBuildJob)
64
65 # Each of these jobs knows the branch it will operate on.63 # Each of these jobs knows the branch it will operate on.
66 self.assertEqual(self.branch, self.specific_job.branch)64 self.assertEqual(self.branch, self.specific_job.branch)
6765
@@ -91,7 +89,7 @@
91 self.assertNotEqual(self.specific_job.getName(), other_job.getName())89 self.assertNotEqual(self.specific_job.getName(), other_job.getName())
9290
93 def test_getTitle(self):91 def test_getTitle(self):
94 other_job = self.jobset.create(self.branch)92 self.jobset.create(self.branch)
95 self.assertEqual(93 self.assertEqual(
96 '%s translation templates build' % self.branch.bzr_identity,94 '%s translation templates build' % self.branch.bzr_identity,
97 self.specific_job.getTitle())95 self.specific_job.getTitle())
@@ -191,7 +189,7 @@
191 # branch, generatesTemplates returns False.189 # branch, generatesTemplates returns False.
192 branch = self._makeTranslationBranch()190 branch = self._makeTranslationBranch()
193 self.assertFalse(self.jobsource.generatesTemplates(branch))191 self.assertFalse(self.jobsource.generatesTemplates(branch))
194 192
195 def test_branch_not_used(self):193 def test_branch_not_used(self):
196 # We don't generate templates branches not attached to series.194 # We don't generate templates branches not attached to series.
197 branch = self._makeTranslationBranch(fake_pottery_compatible=True)195 branch = self._makeTranslationBranch(fake_pottery_compatible=True)