Merge lp:~michael.nelson/launchpad/delegate-to-buildfarmjob into lp:launchpad
- delegate-to-buildfarmjob
- Merge into devel
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 | ||||
Related bugs: |
|
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_translatio
Pre-implementation:
This is part of the LEP https:/
Preview Diff
1 | === modified file 'lib/lp/buildmaster/doc/buildfarmjob.txt' |
2 | --- lib/lp/buildmaster/doc/buildfarmjob.txt 2010-01-14 09:55:06 +0000 |
3 | +++ lib/lp/buildmaster/doc/buildfarmjob.txt 2010-04-21 11:53:24 +0000 |
4 | @@ -1,20 +1,43 @@ |
5 | -= BuildFarmJob = |
6 | +BuildFarmJob |
7 | +============ |
8 | |
9 | >>> from lp.buildmaster.interfaces.buildfarmjob import IBuildFarmJob |
10 | - >>> from lp.buildmaster.model.buildfarmjob import BuildFarmJob |
11 | + >>> from lp.buildmaster.model.buildfarmjob import ( |
12 | + ... BuildFarmJob, BuildFarmJobDerived) |
13 | |
14 | BuildFarmJob provides a basic implementation of IBuildFarmJob. The |
15 | -specific build farm job classes should inherit from it. |
16 | +specific build farm job classes will automatically delegate to |
17 | +BuildFarmJob by inheriting BuildFarmJobDerived. |
18 | |
19 | >>> buildfarmjob = BuildFarmJob() |
20 | - >>> verifyObject(IBuildFarmJob, buildfarmjob) |
21 | + >>> verifyObject(IBuildFarmJob, buildfarmjob) |
22 | True |
23 | |
24 | -As a class, it also provides ISpecificBuildFarmJobClass so that |
25 | -BuildQueue can find the instance of a specific build-farm job |
26 | -implementation associated with a given Job instance. |
27 | +The BuildFarmJob class does not (yet) do a lot itself, other than |
28 | +providing default implementations for its methods. |
29 | + |
30 | + >>> print buildfarmjob.getLogFileName() |
31 | + buildlog.txt |
32 | + |
33 | + >>> buildfarmjob.getName() |
34 | + Traceback (most recent call last): |
35 | + ... |
36 | + NotImplementedError |
37 | + |
38 | + |
39 | +BuildFarmJobDerived |
40 | +=================== |
41 | + |
42 | +BuildFarmJobDerived exists to encapsulate the functionality required |
43 | +by classes delegating IBuildFarmJob. |
44 | |
45 | >>> from lp.buildmaster.interfaces.buildfarmjob import ( |
46 | - ... ISpecificBuildFarmJobClass) |
47 | - >>> verifyObject(ISpecificBuildFarmJobClass, BuildFarmJob) |
48 | + ... IBuildFarmJobDerived) |
49 | + >>> verifyObject(IBuildFarmJobDerived, BuildFarmJobDerived()) |
50 | True |
51 | + |
52 | +This class also includes the getByJob() class method used to find the |
53 | +instance of a specific build-farm job implementation associated with a |
54 | +given Job instance which must be called in the context of a concrete |
55 | +derived class. See lp.buildmaster.tests.test_buildqueue for examples. |
56 | + |
57 | |
58 | === modified file 'lib/lp/buildmaster/interfaces/buildfarmbranchjob.py' |
59 | --- lib/lp/buildmaster/interfaces/buildfarmbranchjob.py 2010-03-17 05:58:22 +0000 |
60 | +++ lib/lp/buildmaster/interfaces/buildfarmbranchjob.py 2010-04-21 11:53:24 +0000 |
61 | @@ -8,11 +8,10 @@ |
62 | 'IBuildFarmBranchJob' |
63 | ] |
64 | |
65 | -from lp.buildmaster.interfaces.buildfarmjob import IBuildFarmJob |
66 | from lp.code.interfaces.branchjob import IBranchJob |
67 | |
68 | |
69 | -class IBuildFarmBranchJob(IBuildFarmJob, IBranchJob): |
70 | +class IBuildFarmBranchJob(IBranchJob): |
71 | """An `IBuildFarmJob` that's also an `IBranchJob`. |
72 | |
73 | Use this interface for `IBuildFarmJob` implementations that do not |
74 | |
75 | === modified file 'lib/lp/buildmaster/interfaces/buildfarmjob.py' |
76 | --- lib/lp/buildmaster/interfaces/buildfarmjob.py 2010-04-12 05:52:01 +0000 |
77 | +++ lib/lp/buildmaster/interfaces/buildfarmjob.py 2010-04-21 11:53:24 +0000 |
78 | @@ -9,8 +9,7 @@ |
79 | |
80 | __all__ = [ |
81 | 'IBuildFarmJob', |
82 | - 'IBuildFarmCandidateJobSelection', |
83 | - 'ISpecificBuildFarmJobClass', |
84 | + 'IBuildFarmJobDerived', |
85 | 'BuildFarmJobType', |
86 | ] |
87 | |
88 | @@ -57,16 +56,6 @@ |
89 | class IBuildFarmJob(Interface): |
90 | """Operations that jobs for the build farm must implement.""" |
91 | |
92 | - def generateSlaveBuildCookie(): |
93 | - """Produce a cookie for the slave as a token of the job it's doing. |
94 | - |
95 | - The cookie need not be unique, but should be hard for a |
96 | - compromised slave to guess. |
97 | - |
98 | - :return: a hard-to-guess ASCII string that can be reproduced |
99 | - accurately based on this job's properties. |
100 | - """ |
101 | - |
102 | def score(): |
103 | """Calculate a job score appropriate for the job type in question.""" |
104 | |
105 | @@ -101,11 +90,10 @@ |
106 | "return None.")) |
107 | |
108 | |
109 | -class ISpecificBuildFarmJobClass(Interface): |
110 | - """Class interface provided by `IBuildFarmJob` classes. |
111 | +class IBuildFarmJobDerived(Interface): |
112 | + """Common functionality required by classes delegating IBuildFarmJob. |
113 | |
114 | - Used by the `BuildQueue` to find the specific build-farm job objects |
115 | - it needs to dispatch to builders. |
116 | + An implementation of this class must setup the necessary delagation. |
117 | """ |
118 | |
119 | def getByJob(job): |
120 | @@ -115,15 +103,6 @@ |
121 | has an entry associated with `job`. |
122 | """ |
123 | |
124 | - |
125 | -class IBuildFarmCandidateJobSelection(Interface): |
126 | - """Operations for refining candidate job selection (optional). |
127 | - |
128 | - Job type classes that do *not* need to refine candidate job selection may |
129 | - be derived from `BuildFarmJob` which provides a base implementation of |
130 | - this interface. |
131 | - """ |
132 | - |
133 | def addCandidateSelectionCriteria(processor, virtualized): |
134 | """Provide a sub-query to refine the candidate job selection. |
135 | |
136 | @@ -159,3 +138,14 @@ |
137 | :return: True if the candidate job should be dispatched |
138 | to a builder, False otherwise. |
139 | """ |
140 | + |
141 | + def generateSlaveBuildCookie(): |
142 | + """Produce a cookie for the slave as a token of the job it's doing. |
143 | + |
144 | + The cookie need not be unique, but should be hard for a |
145 | + compromised slave to guess. |
146 | + |
147 | + :return: a hard-to-guess ASCII string that can be reproduced |
148 | + accurately based on this job's properties. |
149 | + """ |
150 | + |
151 | |
152 | === modified file 'lib/lp/buildmaster/model/buildfarmjob.py' |
153 | --- lib/lp/buildmaster/model/buildfarmjob.py 2010-04-12 05:52:01 +0000 |
154 | +++ lib/lp/buildmaster/model/buildfarmjob.py 2010-04-21 11:53:24 +0000 |
155 | @@ -2,48 +2,31 @@ |
156 | # GNU Affero General Public License version 3 (see the file LICENSE). |
157 | |
158 | __metaclass__ = type |
159 | -__all__ = ['BuildFarmJob'] |
160 | - |
161 | +__all__ = [ |
162 | + 'BuildFarmJob', |
163 | + 'BuildFarmJobDerived', |
164 | + ] |
165 | + |
166 | + |
167 | +from lazr.delegates import delegates |
168 | |
169 | import hashlib |
170 | |
171 | from zope.component import getUtility |
172 | -from zope.interface import classProvides, implements |
173 | +from zope.interface import implements |
174 | from zope.security.proxy import removeSecurityProxy |
175 | |
176 | from canonical.launchpad.webapp.interfaces import ( |
177 | DEFAULT_FLAVOR, IStoreSelector, MAIN_STORE) |
178 | + |
179 | from lp.buildmaster.interfaces.buildfarmjob import ( |
180 | - IBuildFarmJob, IBuildFarmCandidateJobSelection, |
181 | - ISpecificBuildFarmJobClass) |
182 | + IBuildFarmJob, IBuildFarmJobDerived) |
183 | from lp.buildmaster.interfaces.buildqueue import IBuildQueueSet |
184 | |
185 | |
186 | class BuildFarmJob: |
187 | - """Mix-in class for `IBuildFarmJob` implementations.""" |
188 | + """A base implementation for `IBuildFarmJob` classes.""" |
189 | implements(IBuildFarmJob) |
190 | - classProvides( |
191 | - IBuildFarmCandidateJobSelection, ISpecificBuildFarmJobClass) |
192 | - |
193 | - def generateSlaveBuildCookie(self): |
194 | - """See `IBuildFarmJob`.""" |
195 | - buildqueue = getUtility(IBuildQueueSet).getByJob(self.job) |
196 | - |
197 | - if buildqueue.processor is None: |
198 | - processor = '*' |
199 | - else: |
200 | - processor = repr(buildqueue.processor.id) |
201 | - |
202 | - contents = ';'.join([ |
203 | - repr(removeSecurityProxy(self.job).id), |
204 | - self.job.date_created.isoformat(), |
205 | - repr(buildqueue.id), |
206 | - buildqueue.job_type.name, |
207 | - processor, |
208 | - self.getName(), |
209 | - ]) |
210 | - |
211 | - return hashlib.sha1(contents).hexdigest() |
212 | |
213 | def score(self): |
214 | """See `IBuildFarmJob`.""" |
215 | @@ -83,22 +66,66 @@ |
216 | """See `IBuildFarmJob`.""" |
217 | return None |
218 | |
219 | - @staticmethod |
220 | - def addCandidateSelectionCriteria(processor, virtualized): |
221 | - """See `IBuildFarmCandidateJobSelection`.""" |
222 | - return ('') |
223 | + |
224 | +class BuildFarmJobDerived: |
225 | + """See `IBuildFarmJobDerived`.""" |
226 | + implements(IBuildFarmJobDerived) |
227 | + delegates(IBuildFarmJob, context='_build_farm_job') |
228 | + |
229 | + def __init__(self, *args, **kwargs): |
230 | + """Ensure the instance to which we delegate is set on creation.""" |
231 | + self._set_build_farm_job() |
232 | + super(BuildFarmJobDerived, self).__init__(*args, **kwargs) |
233 | + |
234 | + def __storm_loaded__(self): |
235 | + """Set the attribute for our IBuildFarmJob delegation. |
236 | + |
237 | + This is needed here as __init__() is not called when a storm object |
238 | + is loaded from the database. |
239 | + """ |
240 | + self._set_build_farm_job() |
241 | + |
242 | + def _set_build_farm_job(self): |
243 | + """Set the build farm job to which we will delegate. |
244 | + |
245 | + Sub-classes can override as required. |
246 | + """ |
247 | + self._build_farm_job = BuildFarmJob() |
248 | |
249 | @classmethod |
250 | def getByJob(cls, job): |
251 | - """See `ISpecificBuildFarmJobClass`. |
252 | - This base implementation should work for most build farm job |
253 | - types, but some need to override it. |
254 | - """ |
255 | + """See `IBuildFarmJobDerived`.""" |
256 | store = getUtility(IStoreSelector).get(MAIN_STORE, DEFAULT_FLAVOR) |
257 | return store.find(cls, cls.job == job).one() |
258 | |
259 | @staticmethod |
260 | + def addCandidateSelectionCriteria(processor, virtualized): |
261 | + """See `IBuildFarmJobDerived`.""" |
262 | + return ('') |
263 | + |
264 | + @staticmethod |
265 | def postprocessCandidate(job, logger): |
266 | - """See `IBuildFarmCandidateJobSelection`.""" |
267 | + """See `IBuildFarmJobDerived`.""" |
268 | return True |
269 | |
270 | + def generateSlaveBuildCookie(self): |
271 | + """See `IBuildFarmJobDerived`.""" |
272 | + buildqueue = getUtility(IBuildQueueSet).getByJob(self.job) |
273 | + |
274 | + if buildqueue.processor is None: |
275 | + processor = '*' |
276 | + else: |
277 | + processor = repr(buildqueue.processor.id) |
278 | + |
279 | + contents = ';'.join([ |
280 | + repr(removeSecurityProxy(self.job).id), |
281 | + self.job.date_created.isoformat(), |
282 | + repr(buildqueue.id), |
283 | + buildqueue.job_type.name, |
284 | + processor, |
285 | + self.getName(), |
286 | + ]) |
287 | + |
288 | + return hashlib.sha1(contents).hexdigest() |
289 | + |
290 | + |
291 | |
292 | === modified file 'lib/lp/buildmaster/model/packagebuildfarmjob.py' |
293 | --- lib/lp/buildmaster/model/packagebuildfarmjob.py 2010-03-25 14:38:25 +0000 |
294 | +++ lib/lp/buildmaster/model/packagebuildfarmjob.py 2010-04-21 11:53:24 +0000 |
295 | @@ -2,17 +2,32 @@ |
296 | # GNU Affero General Public License version 3 (see the file LICENSE). |
297 | |
298 | __metaclass__ = type |
299 | -__all__ = ['PackageBuildFarmJob'] |
300 | +__all__ = [ |
301 | + 'PackageBuildFarmJob', |
302 | + 'PackageBuildFarmJobDerived', |
303 | + ] |
304 | |
305 | |
306 | from canonical.database.constants import UTC_NOW |
307 | |
308 | from lp.buildmaster.interfaces.buildbase import BuildStatus |
309 | -from lp.buildmaster.model.buildfarmjob import BuildFarmJob |
310 | +from lp.buildmaster.model.buildfarmjob import ( |
311 | + BuildFarmJob, BuildFarmJobDerived) |
312 | |
313 | |
314 | class PackageBuildFarmJob(BuildFarmJob): |
315 | - """Mix-in class for `IBuildFarmJob` implementations for package builds.""" |
316 | + """An implementation of `IBuildFarmJob` for package builds.""" |
317 | + |
318 | + def __init__(self, build): |
319 | + """Store the build for this package build farm job. |
320 | + |
321 | + XXX 2010-04-12 michael.nelson bug=536700 |
322 | + The build param will no longer be necessary once BuildFarmJob is |
323 | + itself a concrete class. This class (PackageBuildFarmJob) |
324 | + will also be renamed PackageBuild and turned into a concrete class. |
325 | + """ |
326 | + super(PackageBuildFarmJob, self).__init__() |
327 | + self.build = build |
328 | |
329 | def getTitle(self): |
330 | """See `IBuildFarmJob`.""" |
331 | @@ -32,3 +47,14 @@ |
332 | def jobAborted(self): |
333 | """See `IBuildFarmJob`.""" |
334 | self.build.buildstate = BuildStatus.NEEDSBUILD |
335 | + |
336 | + |
337 | +class PackageBuildFarmJobDerived(BuildFarmJobDerived): |
338 | + """Override the base delegate. |
339 | + |
340 | + Ensure that we use a build farm job specific to packages. |
341 | + """ |
342 | + def _set_build_farm_job(self): |
343 | + self._build_farm_job = PackageBuildFarmJob(self.build) |
344 | + |
345 | + |
346 | |
347 | === modified file 'lib/lp/buildmaster/tests/test_buildqueue.py' |
348 | --- lib/lp/buildmaster/tests/test_buildqueue.py 2010-04-12 08:29:02 +0000 |
349 | +++ lib/lp/buildmaster/tests/test_buildqueue.py 2010-04-21 11:53:24 +0000 |
350 | @@ -8,7 +8,8 @@ |
351 | from pytz import utc |
352 | from unittest import TestLoader |
353 | |
354 | -from zope.component import getUtility |
355 | +from zope import component |
356 | +from zope.component import getGlobalSiteManager, getUtility |
357 | from zope.interface.verify import verifyObject |
358 | |
359 | from canonical.launchpad.webapp.interfaces import ( |
360 | @@ -17,10 +18,11 @@ |
361 | |
362 | from lp.buildmaster.interfaces.buildbase import BuildStatus |
363 | from lp.buildmaster.interfaces.builder import IBuilderSet |
364 | -from lp.buildmaster.interfaces.buildfarmjob import BuildFarmJobType |
365 | +from lp.buildmaster.interfaces.buildfarmjob import ( |
366 | + BuildFarmJobType, IBuildFarmJob) |
367 | from lp.buildmaster.interfaces.buildqueue import IBuildQueueSet |
368 | from lp.buildmaster.model.builder import specific_job_classes |
369 | -from lp.buildmaster.model.buildfarmjob import BuildFarmJob |
370 | +from lp.buildmaster.model.buildfarmjob import BuildFarmJobDerived |
371 | from lp.buildmaster.model.buildqueue import BuildQueue, get_builder_data |
372 | from lp.services.job.model.job import Job |
373 | from lp.soyuz.interfaces.archive import ArchivePurpose |
374 | @@ -885,9 +887,7 @@ |
375 | |
376 | def test_OtherTypeClasses(self): |
377 | """Other job type classes are picked up as well.""" |
378 | - from zope import component |
379 | - from lp.buildmaster.interfaces.buildfarmjob import IBuildFarmJob |
380 | - class FakeBranchBuild(BuildFarmJob): |
381 | + class FakeBranchBuild(BuildFarmJobDerived): |
382 | pass |
383 | |
384 | _build, bq = find_job(self, 'gedit') |
385 | @@ -896,17 +896,24 @@ |
386 | self.assertTrue( |
387 | specific_job_classes().get(BuildFarmJobType.BRANCHBUILD) is None) |
388 | |
389 | - # Pretend that our `FakeBranchBuild` class implements the |
390 | - # `IBuildFarmJob` interface. |
391 | - component.provideUtility( |
392 | - FakeBranchBuild, IBuildFarmJob, 'BRANCHBUILD') |
393 | - |
394 | - # Now we should see the `FakeBranchBuild` class "registered" in the |
395 | - # `specific_job_classes` dictionary under the 'BRANCHBUILD' key. |
396 | - self.assertEqual( |
397 | - specific_job_classes()[BuildFarmJobType.BRANCHBUILD], |
398 | - FakeBranchBuild) |
399 | - |
400 | + try: |
401 | + # Pretend that our `FakeBranchBuild` class implements the |
402 | + # `IBuildFarmJob` interface. |
403 | + component.provideUtility( |
404 | + FakeBranchBuild, IBuildFarmJob, 'BRANCHBUILD') |
405 | + |
406 | + # Now we should see the `FakeBranchBuild` class "registered" |
407 | + # in the `specific_job_classes` dictionary under the |
408 | + # 'BRANCHBUILD' key. |
409 | + self.assertEqual( |
410 | + specific_job_classes()[BuildFarmJobType.BRANCHBUILD], |
411 | + FakeBranchBuild) |
412 | + finally: |
413 | + # Just de-register the utility so we don't affect other |
414 | + # tests. |
415 | + site_manager = getGlobalSiteManager() |
416 | + site_manager.unregisterUtility( |
417 | + FakeBranchBuild, IBuildFarmJob, 'BRANCHBUILD') |
418 | |
419 | class TestPlatformData(TestCaseWithFactory): |
420 | """Tests covering the processor/virtualized properties.""" |
421 | |
422 | === modified file 'lib/lp/code/configure.zcml' |
423 | --- lib/lp/code/configure.zcml 2010-04-20 06:42:29 +0000 |
424 | +++ lib/lp/code/configure.zcml 2010-04-21 11:53:24 +0000 |
425 | @@ -31,7 +31,7 @@ |
426 | |
427 | <class class="lp.code.model.codereviewvote.CodeReviewVoteReference"> |
428 | <allow interface="lp.code.interfaces.codereviewvote.ICodeReviewVoteReferencePublic"/> |
429 | - <require |
430 | + <require |
431 | permission="launchpad.Edit" |
432 | interface="lp.code.interfaces.codereviewvote.ICodeReviewVoteReferenceEdit"/> |
433 | </class> |
434 | @@ -988,6 +988,7 @@ |
435 | <class |
436 | class="lp.code.model.sourcepackagerecipebuild.SourcePackageRecipeBuildJob"> |
437 | <allow interface="lp.code.interfaces.sourcepackagerecipebuild.ISourcePackageRecipeBuildJob"/> |
438 | + <allow interface="lp.buildmaster.interfaces.buildfarmjob.IBuildFarmJobDerived"/> |
439 | </class> |
440 | |
441 | <securedutility |
442 | |
443 | === modified file 'lib/lp/code/model/sourcepackagerecipebuild.py' |
444 | --- lib/lp/code/model/sourcepackagerecipebuild.py 2010-04-19 03:36:27 +0000 |
445 | +++ lib/lp/code/model/sourcepackagerecipebuild.py 2010-04-21 11:53:24 +0000 |
446 | @@ -27,7 +27,8 @@ |
447 | from lp.buildmaster.interfaces.buildfarmjob import BuildFarmJobType |
448 | from lp.buildmaster.model.buildbase import BuildBase |
449 | from lp.buildmaster.model.buildqueue import BuildQueue |
450 | -from lp.buildmaster.model.packagebuildfarmjob import PackageBuildFarmJob |
451 | +from lp.buildmaster.model.packagebuildfarmjob import ( |
452 | + PackageBuildFarmJobDerived) |
453 | from lp.code.interfaces.sourcepackagerecipebuild import ( |
454 | ISourcePackageRecipeBuildJob, ISourcePackageRecipeBuildJobSource, |
455 | ISourcePackageRecipeBuild, ISourcePackageRecipeBuildSource) |
456 | @@ -198,7 +199,7 @@ |
457 | return |
458 | |
459 | |
460 | -class SourcePackageRecipeBuildJob(PackageBuildFarmJob, Storm): |
461 | +class SourcePackageRecipeBuildJob(PackageBuildFarmJobDerived, Storm): |
462 | classProvides(ISourcePackageRecipeBuildJobSource) |
463 | implements(ISourcePackageRecipeBuildJob) |
464 | |
465 | @@ -217,15 +218,15 @@ |
466 | virtualized = True |
467 | |
468 | def __init__(self, build, job): |
469 | - super(SourcePackageRecipeBuildJob, self).__init__() |
470 | self.build = build |
471 | self.job = job |
472 | + super(SourcePackageRecipeBuildJob, self).__init__() |
473 | |
474 | @classmethod |
475 | def new(cls, build, job): |
476 | """See `ISourcePackageRecipeBuildJobSource`.""" |
477 | specific_job = cls(build, job) |
478 | - store = IMasterStore(SourcePackageRecipeBuildJob) |
479 | + store = IMasterStore(cls) |
480 | store.add(specific_job) |
481 | return specific_job |
482 | |
483 | |
484 | === modified file 'lib/lp/soyuz/configure.zcml' |
485 | --- lib/lp/soyuz/configure.zcml 2010-04-12 11:37:48 +0000 |
486 | +++ lib/lp/soyuz/configure.zcml 2010-04-21 11:53:24 +0000 |
487 | @@ -848,6 +848,8 @@ |
488 | class="lp.soyuz.model.buildpackagejob.BuildPackageJob"> |
489 | <allow |
490 | interface="lp.soyuz.interfaces.buildpackagejob.IBuildPackageJob"/> |
491 | + <allow |
492 | + interface="lp.buildmaster.interfaces.buildfarmjob.IBuildFarmJobDerived"/> |
493 | </class> |
494 | <!-- |
495 | The registration below is used to discover all build farm job classes |
496 | |
497 | === modified file 'lib/lp/soyuz/model/binarypackagebuild.py' |
498 | --- lib/lp/soyuz/model/binarypackagebuild.py 2010-04-09 15:46:09 +0000 |
499 | +++ lib/lp/soyuz/model/binarypackagebuild.py 2010-04-21 11:53:24 +0000 |
500 | @@ -313,9 +313,7 @@ |
501 | store = Store.of(self) |
502 | job = Job() |
503 | store.add(job) |
504 | - specific_job = BuildPackageJob() |
505 | - specific_job.build = self.id |
506 | - specific_job.job = job.id |
507 | + specific_job = BuildPackageJob(build=self, job=job) |
508 | store.add(specific_job) |
509 | return specific_job |
510 | |
511 | |
512 | === modified file 'lib/lp/soyuz/model/buildpackagejob.py' |
513 | --- lib/lp/soyuz/model/buildpackagejob.py 2010-04-12 11:37:48 +0000 |
514 | +++ lib/lp/soyuz/model/buildpackagejob.py 2010-04-21 11:53:24 +0000 |
515 | @@ -12,13 +12,14 @@ |
516 | |
517 | from storm.locals import Int, Reference, Storm |
518 | |
519 | +from zope.component import getUtility |
520 | from zope.interface import implements |
521 | -from zope.component import getUtility |
522 | |
523 | from canonical.database.sqlbase import sqlvalues |
524 | |
525 | from lp.buildmaster.interfaces.buildbase import BuildStatus |
526 | -from lp.buildmaster.model.packagebuildfarmjob import PackageBuildFarmJob |
527 | +from lp.buildmaster.model.packagebuildfarmjob import ( |
528 | + PackageBuildFarmJobDerived) |
529 | from lp.registry.interfaces.sourcepackage import SourcePackageUrgency |
530 | from lp.registry.interfaces.pocket import PackagePublishingPocket |
531 | from lp.soyuz.interfaces.archive import ArchivePurpose |
532 | @@ -27,7 +28,7 @@ |
533 | from lp.soyuz.interfaces.publishing import PackagePublishingStatus |
534 | |
535 | |
536 | -class BuildPackageJob(PackageBuildFarmJob, Storm): |
537 | +class BuildPackageJob(PackageBuildFarmJobDerived, Storm): |
538 | """See `IBuildPackageJob`.""" |
539 | implements(IBuildPackageJob) |
540 | |
541 | @@ -40,6 +41,11 @@ |
542 | build_id = Int(name='build', allow_none=False) |
543 | build = Reference(build_id, 'BinaryPackageBuild.id') |
544 | |
545 | + def __init__(self, build, job): |
546 | + """ Setup the IBuildFarmJob delegation when new items are created.""" |
547 | + self.build, self.job = build, job |
548 | + super(BuildPackageJob, self).__init__() |
549 | + |
550 | def score(self): |
551 | """See `IBuildPackageJob`.""" |
552 | score_pocketname = { |
553 | @@ -166,7 +172,7 @@ |
554 | |
555 | @staticmethod |
556 | def addCandidateSelectionCriteria(processor, virtualized): |
557 | - """See `IBuildFarmCandidateJobSelection`.""" |
558 | + """See `IBuildFarmJob`.""" |
559 | # Avoiding circular import. |
560 | from lp.buildmaster.model.builder import Builder |
561 | |
562 | @@ -236,7 +242,7 @@ |
563 | |
564 | @staticmethod |
565 | def postprocessCandidate(job, logger): |
566 | - """See `IBuildFarmCandidateJobSelection`.""" |
567 | + """See `IBuildFarmJob`.""" |
568 | # Mark build records targeted to old source versions as SUPERSEDED |
569 | # and build records target to SECURITY pocket as FAILEDTOBUILD. |
570 | # Builds in those situation should not be built because they will |
571 | |
572 | === modified file 'lib/lp/soyuz/tests/test_buildpackagejob.py' |
573 | --- lib/lp/soyuz/tests/test_buildpackagejob.py 2010-04-12 08:29:02 +0000 |
574 | +++ lib/lp/soyuz/tests/test_buildpackagejob.py 2010-04-21 11:53:24 +0000 |
575 | @@ -13,7 +13,10 @@ |
576 | |
577 | from lp.buildmaster.interfaces.buildbase import BuildStatus |
578 | from lp.buildmaster.interfaces.builder import IBuilderSet |
579 | +from lp.buildmaster.interfaces.buildfarmjob import ( |
580 | + IBuildFarmJob, IBuildFarmJobDerived) |
581 | from lp.soyuz.interfaces.archive import ArchivePurpose |
582 | +from lp.soyuz.interfaces.buildpackagejob import IBuildPackageJob |
583 | from lp.soyuz.interfaces.publishing import PackagePublishingStatus |
584 | from lp.soyuz.model.binarypackagebuild import BinaryPackageBuild |
585 | from lp.soyuz.model.processor import ProcessorFamilySet |
586 | @@ -225,3 +228,13 @@ |
587 | # Test that BuildPackageJob returns the title of the build. |
588 | build, bq = find_job(self, 'gcc', '386') |
589 | self.assertEqual(bq.specific_job.getTitle(), build.title) |
590 | + |
591 | + def test_providesInterfaces(self): |
592 | + # Ensure that a BuildPackageJob generates an appropriate cookie. |
593 | + build, bq = find_job(self, 'gcc', '386') |
594 | + build_farm_job = bq.specific_job |
595 | + self.assertProvides(build_farm_job, IBuildPackageJob) |
596 | + self.assertProvides(build_farm_job, IBuildFarmJob) |
597 | + self.assertProvides(build_farm_job, IBuildFarmJobDerived) |
598 | + |
599 | + |
600 | |
601 | === modified file 'lib/lp/translations/configure.zcml' |
602 | --- lib/lp/translations/configure.zcml 2010-02-17 11:19:42 +0000 |
603 | +++ lib/lp/translations/configure.zcml 2010-04-21 11:53:24 +0000 |
604 | @@ -579,6 +579,8 @@ |
605 | interface="lp.code.interfaces.branchjob.IBranchJob"/> |
606 | <allow |
607 | interface="lp.buildmaster.interfaces.buildfarmjob.IBuildFarmJob"/> |
608 | + <allow |
609 | + interface="lp.buildmaster.interfaces.buildfarmjob.IBuildFarmJobDerived"/> |
610 | </class> |
611 | <securedutility |
612 | component="lp.translations.model.translationtemplatesbuildjob.TranslationTemplatesBuildJob" |
613 | |
614 | === modified file 'lib/lp/translations/model/translationtemplatesbuildjob.py' |
615 | --- lib/lp/translations/model/translationtemplatesbuildjob.py 2010-03-18 12:25:36 +0000 |
616 | +++ lib/lp/translations/model/translationtemplatesbuildjob.py 2010-04-21 11:53:24 +0000 |
617 | @@ -18,10 +18,9 @@ |
618 | from canonical.launchpad.webapp.interfaces import ( |
619 | DEFAULT_FLAVOR, IStoreSelector, MAIN_STORE, MASTER_FLAVOR) |
620 | |
621 | -from lp.buildmaster.interfaces.buildfarmjob import ( |
622 | - BuildFarmJobType, ISpecificBuildFarmJobClass) |
623 | -from lp.buildmaster.model.buildfarmjob import BuildFarmJob |
624 | +from lp.buildmaster.interfaces.buildfarmjob import BuildFarmJobType |
625 | from lp.buildmaster.interfaces.buildqueue import IBuildQueueSet |
626 | +from lp.buildmaster.model.buildfarmjob import BuildFarmJobDerived |
627 | from lp.buildmaster.model.buildqueue import BuildQueue |
628 | from lp.code.interfaces.branchjob import IRosettaUploadJobSource |
629 | from lp.buildmaster.interfaces.buildfarmbranchjob import IBuildFarmBranchJob |
630 | @@ -31,17 +30,15 @@ |
631 | from lp.translations.pottery.detect_intltool import is_intltool_structure |
632 | |
633 | |
634 | -class TranslationTemplatesBuildJob(BranchJobDerived, BuildFarmJob): |
635 | +class TranslationTemplatesBuildJob(BuildFarmJobDerived, BranchJobDerived): |
636 | """An `IBuildFarmJob` implementation that generates templates. |
637 | |
638 | Implementation-wise, this is actually a `BranchJob`. |
639 | """ |
640 | implements(IBuildFarmBranchJob) |
641 | - |
642 | class_job_type = BranchJobType.TRANSLATION_TEMPLATES_BUILD |
643 | |
644 | - classProvides( |
645 | - ISpecificBuildFarmJobClass, ITranslationTemplatesBuildJobSource) |
646 | + classProvides(ITranslationTemplatesBuildJobSource) |
647 | |
648 | duration_estimate = timedelta(seconds=10) |
649 | |
650 | @@ -110,7 +107,6 @@ |
651 | branch, BranchJobType.TRANSLATION_TEMPLATES_BUILD, metadata) |
652 | store.add(branch_job) |
653 | specific_job = TranslationTemplatesBuildJob(branch_job) |
654 | - |
655 | duration_estimate = cls.duration_estimate |
656 | build_queue_entry = BuildQueue( |
657 | estimated_duration=duration_estimate, |
658 | @@ -133,7 +129,10 @@ |
659 | |
660 | @classmethod |
661 | def getByJob(cls, job): |
662 | - """See `ISpecificBuildFarmJobClass`.""" |
663 | + """See `IBuildFarmJobDerived`. |
664 | + |
665 | + Overridden here to search via a BranchJob, rather than a Job. |
666 | + """ |
667 | store = getUtility(IStoreSelector).get(MAIN_STORE, DEFAULT_FLAVOR) |
668 | branch_job = store.find(BranchJob, BranchJob.job == job).one() |
669 | if branch_job is None: |
670 | |
671 | === modified file 'lib/lp/translations/tests/test_translationtemplatesbuildjob.py' |
672 | --- lib/lp/translations/tests/test_translationtemplatesbuildjob.py 2010-03-06 00:21:57 +0000 |
673 | +++ lib/lp/translations/tests/test_translationtemplatesbuildjob.py 2010-04-21 11:53:24 +0000 |
674 | @@ -19,7 +19,7 @@ |
675 | from lp.testing import TestCaseWithFactory |
676 | |
677 | from lp.buildmaster.interfaces.buildfarmjob import ( |
678 | - IBuildFarmJob, ISpecificBuildFarmJobClass) |
679 | + IBuildFarmJob, IBuildFarmJobDerived) |
680 | from lp.buildmaster.interfaces.buildfarmjobbehavior import ( |
681 | IBuildFarmJobBehavior) |
682 | from lp.buildmaster.interfaces.buildqueue import IBuildQueueSet |
683 | @@ -54,14 +54,12 @@ |
684 | self.specific_job = self.jobset.create(self.branch) |
685 | |
686 | def test_new_TranslationTemplatesBuildJob(self): |
687 | - # TranslationTemplateBuildJob implements IBuildFarmJob and |
688 | - # IBranchJob. |
689 | + # TranslationTemplateBuildJob implements IBuildFarmJob, |
690 | + # IBuildFarmJobDerived, and IBranchJob. |
691 | verifyObject(IBranchJob, self.specific_job) |
692 | + verifyObject(IBuildFarmJobDerived, self.specific_job) |
693 | verifyObject(IBuildFarmJob, self.specific_job) |
694 | |
695 | - # The class also implements ISpecificBuildFarmJobClass. |
696 | - verifyObject(ISpecificBuildFarmJobClass, TranslationTemplatesBuildJob) |
697 | - |
698 | # Each of these jobs knows the branch it will operate on. |
699 | self.assertEqual(self.branch, self.specific_job.branch) |
700 | |
701 | @@ -91,7 +89,7 @@ |
702 | self.assertNotEqual(self.specific_job.getName(), other_job.getName()) |
703 | |
704 | def test_getTitle(self): |
705 | - other_job = self.jobset.create(self.branch) |
706 | + self.jobset.create(self.branch) |
707 | self.assertEqual( |
708 | '%s translation templates build' % self.branch.bzr_identity, |
709 | self.specific_job.getTitle()) |
710 | @@ -191,7 +189,7 @@ |
711 | # branch, generatesTemplates returns False. |
712 | branch = self._makeTranslationBranch() |
713 | self.assertFalse(self.jobsource.generatesTemplates(branch)) |
714 | - |
715 | + |
716 | def test_branch_not_used(self): |
717 | # We don't generate templates branches not attached to series. |
718 | branch = self._makeTranslationBranch(fake_pottery_compatible=True) |
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.