Merge lp:~michael.nelson/launchpad/487009-db-generalise-ibuilder-1b into lp:launchpad/db-devel
- 487009-db-generalise-ibuilder-1b
- Merge into db-devel
Status: | Merged | ||||
---|---|---|---|---|---|
Approved by: | Michael Nelson | ||||
Approved revision: | not available | ||||
Merged at revision: | not available | ||||
Proposed branch: | lp:~michael.nelson/launchpad/487009-db-generalise-ibuilder-1b | ||||
Merge into: | lp:launchpad/db-devel | ||||
Diff against target: |
481 lines (+296/-7) 11 files modified
lib/lp/buildmaster/interfaces/buildfarmjobbehavior.py (+38/-0) lib/lp/buildmaster/model/buildfarmjobbehavior.py (+50/-0) lib/lp/soyuz/configure.zcml (+7/-0) lib/lp/soyuz/doc/builder.txt (+12/-0) lib/lp/soyuz/doc/buildqueue.txt (+10/-0) lib/lp/soyuz/interfaces/builder.py (+8/-2) lib/lp/soyuz/interfaces/buildqueue.py (+5/-1) lib/lp/soyuz/model/binarypackagebuildbehavior.py (+35/-0) lib/lp/soyuz/model/builder.py (+55/-4) lib/lp/soyuz/model/buildqueue.py (+7/-0) lib/lp/soyuz/tests/test_builder.py (+69/-0) |
||||
To merge this branch: | bzr merge lp:~michael.nelson/launchpad/487009-db-generalise-ibuilder-1b | ||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Graham Binns (community) | code | Approve | |
Review via email: mp+15477@code.launchpad.net |
Commit message
Description of the change
Michael Nelson (michael.nelson) wrote : | # |
Michael Nelson (michael.nelson) wrote : | # |
> == Tests ==
>
> bin/test -vv -t doc/builder.txt -t doc/buildqueue.txt -t
> TestCurrentBuil
Also include doc/buildd-
Graham Binns (gmb) wrote : | # |
Hi Michael,
Nice branch. Good work. I've got some stylistic nitpicks - our
guidelines gleefully discard PEP8, hurrah - and I'd like you to do a
strip-trailing-
much, but enough for me to notice).
Other than that, r=me.
> === added file 'lib/lp/
> --- lib/lp/
> +++ lib/lp/
> @@ -0,0 +1,38 @@
> +# Copyright 2009 Canonical Ltd. This software is licensed under the
> +# GNU Affero General Public License version 3 (see the file LICENSE).
> +
> +# pylint: disable-
> +
> +"""Interface for build farm job behaviors."""
> +
> +__metaclass__ = type
> +
> +__all__ = [
> + 'IBuildFarmJobB
> + ]
> +
> +from zope.interface import Interface
> +
> +
> +class BuildBehaviorMi
> + """
> + A general exception that can be raised when the builder's current behavior
> + does not match the expected behavior.
> + """
> +
> +
> +class IBuildFarmJobBe
> +
> + def set_builder(
> + """Sets the associated builder reference for this instance."""
> +
> + def log_start_
> + """Log the start of a specific build queue item.
> +
> + The form of the log message will vary depending on the type of build.
> + :param build_queue_item: A BuildQueueItem to build.
> + :param logger: A logger to be used to log diagnostic information.
> + """
> + # A number of other methods to go here that can be customised for each of
> + # the different build types (branch build, recipe build, translation
> + # build etc.)
>
> === added file 'lib/lp/
> --- lib/lp/
> +++ lib/lp/
> @@ -0,0 +1,53 @@
> +# Copyright 2009 Canonical Ltd. This software is licensed under the
> +# GNU Affero General Public License version 3 (see the file LICENSE).
> +
> +# pylint: disable-
> +
> +"""Base and idle BuildFarmJobBeh
> +
> +__metaclass__ = type
> +
> +__all__ = [
> + 'BuildFarmJobBe
> + 'IdleBuildBehavior'
> + ]
> +
> +from zope.interface import implements
> +
> +from lp.buildmaster.
> + BuildBehaviorMi
> +
> +
> +class BuildFarmJobBeh
> + """Ensures that all behaviors inherit the same initialisation.
> +
> + All build-farm job behaviors should inherit from this.
> + """
> +
> + def __init__(self, buildfarmjob):
> + """
> + Store a reference to the job_type with which we were created.
> + """
> + self.buildfarmjob = buildfarmjob
> + self._builder = None
> +
> + def set_builder(self, builder):
This should be setBuilder(), because who needs PEP8?
> + """The builder should be set once and not changed."""
> + self._builder = builde...
Michael Nelson (michael.nelson) wrote : | # |
On Tue, Dec 1, 2009 at 4:30 PM, Graham Binns <email address hidden> wrote:
> Review: Approve code
>
> Hi Michael,
>
> Nice branch. Good work. I've got some stylistic nitpicks - our
> guidelines gleefully discard PEP8, hurrah - and I'd like you to do a
>
gah, I'd thought I was cleaning up old code (too much lazrjs lately).
> strip-trailing-
> much, but enough for me to notice).
>
>
Sorry - switched editors recently and forgot to setup tailing whitespace
removal. I've updated my .rc file to automatically delete trailing spaces
and fixed all the files. Thanks.
> Other than that, r=me.
>
> > === added file 'lib/lp/
> > --- lib/lp/
> 00:00:00 +0000
> > +++ lib/lp/
> 10:00:36 +0000
> > @@ -0,0 +1,38 @@
> > +# Copyright 2009 Canonical Ltd. This software is licensed under the
> > +# GNU Affero General Public License version 3 (see the file LICENSE).
> > +
> > +# pylint: disable-
> > +
> > +"""Interface for build farm job behaviors."""
> > +
> > +__metaclass__ = type
> > +
> > +__all__ = [
> > + 'IBuildFarmJobB
> > + ]
> > +
> > +from zope.interface import Interface
> > +
> > +
> > +class BuildBehaviorMi
> > + """
> > + A general exception that can be raised when the builder's current
> behavior
> > + does not match the expected behavior.
> > + """
> > +
> > +
> > +class IBuildFarmJobBe
> > +
> > + def set_builder(
> > + """Sets the associated builder reference for this instance."""
> > +
> > + def log_start_
> > + """Log the start of a specific build queue item.
> > +
> > + The form of the log message will vary depending on the type of
> build.
> > + :param build_queue_item: A BuildQueueItem to build.
> > + :param logger: A logger to be used to log diagnostic
> information.
> > + """
> > + # A number of other methods to go here that can be customised for
> each of
> > + # the different build types (branch build, recipe build, translation
> > + # build etc.)
> >
> > === added file 'lib/lp/
> > --- lib/lp/
> +0000
> > +++ lib/lp/
> +0000
> > @@ -0,0 +1,53 @@
> > +# Copyright 2009 Canonical Ltd. This software is licensed under the
> > +# GNU Affero General Public License version 3 (see the file LICENSE).
> > +
> > +# pylint: disable-
> > +
> > +"""Base and idle BuildFarmJobBeh
> > +
> > +__metaclass__ = type
> > +
> > +__all__ = [
> > + 'BuildFarmJobBe
> > + 'IdleBuildBehavior'
> > + ]
> > +
> > +from zope.interface import implements
> > +
> > +from lp.buildmaster.
> > + BuildBehaviorMi
> > +
> > +
> > +class BuildFarmJobBeh
> > + """Ensures that all ...
1 | === modified file 'lib/lp/buildmaster/interfaces/buildfarmjobbehavior.py' |
2 | --- lib/lp/buildmaster/interfaces/buildfarmjobbehavior.py 2009-11-27 13:50:29 +0000 |
3 | +++ lib/lp/buildmaster/interfaces/buildfarmjobbehavior.py 2009-12-01 16:40:02 +0000 |
4 | @@ -23,10 +23,10 @@ |
5 | |
6 | class IBuildFarmJobBehavior(Interface): |
7 | |
8 | - def set_builder(builder): |
9 | + def setBuilder(builder): |
10 | """Sets the associated builder reference for this instance.""" |
11 | |
12 | - def log_start_build(build_queue_item, logger): |
13 | + def logStartBuild(build_queue_item, logger): |
14 | """Log the start of a specific build queue item. |
15 | |
16 | The form of the log message will vary depending on the type of build. |
17 | |
18 | === modified file 'lib/lp/buildmaster/model/buildfarmjobbehavior.py' |
19 | --- lib/lp/buildmaster/model/buildfarmjobbehavior.py 2009-12-01 09:43:41 +0000 |
20 | +++ lib/lp/buildmaster/model/buildfarmjobbehavior.py 2009-12-01 16:38:56 +0000 |
21 | @@ -25,13 +25,11 @@ |
22 | """ |
23 | |
24 | def __init__(self, buildfarmjob): |
25 | - """ |
26 | - Store a reference to the job_type with which we were created. |
27 | - """ |
28 | + """Store a reference to the job_type with which we were created.""" |
29 | self.buildfarmjob = buildfarmjob |
30 | self._builder = None |
31 | |
32 | - def set_builder(self, builder): |
33 | + def setBuilder(self, builder): |
34 | """The builder should be set once and not changed.""" |
35 | self._builder = builder |
36 | |
37 | @@ -41,9 +39,8 @@ |
38 | implements(IBuildFarmJobBehavior) |
39 | |
40 | def __init__(self): |
41 | - """ |
42 | - The idle behavior is special in that a buildfarmjob is not specified |
43 | - during initialisation. |
44 | + """The idle behavior is special in that a buildfarmjob is not |
45 | + specified during initialisation. |
46 | """ |
47 | super(IdleBuildBehavior, self).__init__(None) |
48 | |
49 | |
50 | === modified file 'lib/lp/soyuz/model/binarypackagebuildbehavior.py' |
51 | --- lib/lp/soyuz/model/binarypackagebuildbehavior.py 2009-12-01 09:02:14 +0000 |
52 | +++ lib/lp/soyuz/model/binarypackagebuildbehavior.py 2009-12-01 16:39:48 +0000 |
53 | @@ -26,8 +26,8 @@ |
54 | |
55 | implements(IBuildFarmJobBehavior) |
56 | |
57 | - def log_start_build(self, build_queue_item, logger): |
58 | - """See `IBuildFarmJobBehavior`.""" |
59 | + def logStartBuild(self, build_queue_item, logger): |
60 | + """See `IBuildFarmJobBehavior`.""" |
61 | build = getUtility(IBuildSet).getByQueueEntry(build_queue_item) |
62 | spr = build.sourcepackagerelease |
63 | |
64 | |
65 | === modified file 'lib/lp/soyuz/model/builder.py' |
66 | --- lib/lp/soyuz/model/builder.py 2009-12-01 09:38:05 +0000 |
67 | +++ lib/lp/soyuz/model/builder.py 2009-12-01 16:37:20 +0000 |
68 | @@ -142,7 +142,7 @@ |
69 | vm_host = StringCol(dbName='vm_host') |
70 | active = BoolCol(dbName='active', notNull=True, default=True) |
71 | |
72 | - def _get_current_build_behavior(self): |
73 | + def _getCurrentBuildBehavior(self): |
74 | """Return the current build behavior.""" |
75 | if not safe_hasattr(self, '_current_build_behavior'): |
76 | self._current_build_behavior = None |
77 | @@ -156,14 +156,14 @@ |
78 | # ...we'll set it based on our current job. |
79 | self._current_build_behavior = ( |
80 | currentjob.required_build_behavior) |
81 | - self._current_build_behavior.set_builder(self) |
82 | + self._current_build_behavior.setBuilder(self) |
83 | return self._current_build_behavior |
84 | elif self._current_build_behavior is None: |
85 | # If we don't have a current job or an idle behavior |
86 | # already set, then we just set the idle behavior |
87 | # before returning. |
88 | self._current_build_behavior = IdleBuildBehavior() |
89 | - return self._current_build_behavior |
90 | + return self._current_build_behavior |
91 | |
92 | else: |
93 | # We did have a current non-idle build behavior set, so |
94 | @@ -171,7 +171,7 @@ |
95 | return self._current_build_behavior |
96 | |
97 | |
98 | - def _set_current_build_behavior(self, new_behavior): |
99 | + def _setCurrentBuildBehavior(self, new_behavior): |
100 | """Set the current build behavior.""" |
101 | |
102 | if self.currentjob is not None: |
103 | @@ -182,10 +182,10 @@ |
104 | "exists.") |
105 | else: |
106 | self._current_build_behavior = new_behavior |
107 | - self._current_build_behavior.set_builder(self) |
108 | + self._current_build_behavior.setBuilder(self) |
109 | |
110 | current_build_behavior = property( |
111 | - _get_current_build_behavior, _set_current_build_behavior) |
112 | + _getCurrentBuildBehavior, _setCurrentBuildBehavior) |
113 | |
114 | def cacheFileOnSlave(self, logger, libraryfilealias): |
115 | """See `IBuilder`.""" |
116 | @@ -403,9 +403,9 @@ |
117 | |
118 | def startBuild(self, build_queue_item, logger): |
119 | """See IBuilder.""" |
120 | - # Set the build behavior depending on the provided build queue item. |
121 | + # Set the build behavior depending on the provided build queue item. |
122 | self.current_build_behavior = build_queue_item.required_build_behavior |
123 | - self.log_start_build(build_queue_item, logger) |
124 | + self.logStartBuild(build_queue_item, logger) |
125 | |
126 | # Make sure the request is valid; an exception is raised if it's not. |
127 | self._verifyBuildRequest(build_queue_item, logger) |
128 | |
129 | === modified file 'lib/lp/soyuz/tests/test_builder.py' |
130 | --- lib/lp/soyuz/tests/test_builder.py 2009-12-01 09:43:41 +0000 |
131 | +++ lib/lp/soyuz/tests/test_builder.py 2009-12-01 16:39:29 +0000 |
132 | @@ -221,8 +221,8 @@ |
133 | |
134 | |
135 | class TestCurrentBuildBehavior(TestCaseWithFactory): |
136 | - """ |
137 | - This test ensures the get/set behavior of Builder.current_build_behavior. |
138 | + """This test ensures the get/set behavior of IBuilder's |
139 | + current_build_behavior property. |
140 | """ |
141 | |
142 | layer = LaunchpadZopelessLayer |
143 | @@ -231,7 +231,7 @@ |
144 | """Create a new builder ready for testing.""" |
145 | super(TestCurrentBuildBehavior, self).setUp() |
146 | self.builder = self.factory.makeBuilder(name='builder') |
147 | - |
148 | + |
149 | # Have a publisher and a ppa handy for some of the tests below. |
150 | self.publisher = SoyuzTestPublisher() |
151 | self.publisher.prepareBreezyAutotest() |
152 | @@ -244,8 +244,7 @@ |
153 | self.buildfarmjob = self.build.buildqueue_record.specific_job |
154 | |
155 | def test_idle_behavior_when_no_current_build(self): |
156 | - """ |
157 | - We return an idle behavior when there is no behavior specified |
158 | + """We return an idle behavior when there is no behavior specified |
159 | nor a current build. |
160 | """ |
161 | self.assertIsInstance( |
162 | @@ -254,7 +253,7 @@ |
163 | def test_set_behavior_when_no_current_job(self): |
164 | """If a builder is idle then it is possible to set the behavior.""" |
165 | self.builder.current_build_behavior = IBuildFarmJobBehavior( |
166 | - self.buildfarmjob) |
167 | + self.buildfarmjob) |
168 | |
169 | self.assertIsInstance( |
170 | self.builder.current_build_behavior, BinaryPackageBuildBehavior) |
171 | @@ -269,9 +268,7 @@ |
172 | self.builder.current_build_behavior, BinaryPackageBuildBehavior) |
173 | |
174 | def test_set_behavior_when_current_job(self): |
175 | - """ |
176 | - If a builder has a current job then it's behavior cannot be |
177 | - set. |
178 | + """If a builder has a current job then it's behavior cannot be set. |
179 | """ |
180 | self.build.buildqueue_record.builder = self.builder |
181 | |
182 | @@ -280,7 +277,7 @@ |
183 | assertion_raised = False |
184 | try: |
185 | self.builder.current_build_behavior = IBuildFarmJobBehavior( |
186 | - self.buildfarmjob) |
187 | + self.buildfarmjob) |
188 | except BuildBehaviorMismatch, e: |
189 | assertion_raised = True |
190 |
Preview Diff
1 | === added file 'lib/lp/buildmaster/interfaces/buildfarmjobbehavior.py' |
2 | --- lib/lp/buildmaster/interfaces/buildfarmjobbehavior.py 1970-01-01 00:00:00 +0000 |
3 | +++ lib/lp/buildmaster/interfaces/buildfarmjobbehavior.py 2009-12-01 16:47:13 +0000 |
4 | @@ -0,0 +1,38 @@ |
5 | +# Copyright 2009 Canonical Ltd. This software is licensed under the |
6 | +# GNU Affero General Public License version 3 (see the file LICENSE). |
7 | + |
8 | +# pylint: disable-msg=E0211,E0213 |
9 | + |
10 | +"""Interface for build farm job behaviors.""" |
11 | + |
12 | +__metaclass__ = type |
13 | + |
14 | +__all__ = [ |
15 | + 'IBuildFarmJobBehavior', |
16 | + ] |
17 | + |
18 | +from zope.interface import Interface |
19 | + |
20 | + |
21 | +class BuildBehaviorMismatch(Exception): |
22 | + """ |
23 | + A general exception that can be raised when the builder's current behavior |
24 | + does not match the expected behavior. |
25 | + """ |
26 | + |
27 | + |
28 | +class IBuildFarmJobBehavior(Interface): |
29 | + |
30 | + def setBuilder(builder): |
31 | + """Sets the associated builder reference for this instance.""" |
32 | + |
33 | + def logStartBuild(build_queue_item, logger): |
34 | + """Log the start of a specific build queue item. |
35 | + |
36 | + The form of the log message will vary depending on the type of build. |
37 | + :param build_queue_item: A BuildQueueItem to build. |
38 | + :param logger: A logger to be used to log diagnostic information. |
39 | + """ |
40 | + # A number of other methods to go here that can be customised for each of |
41 | + # the different build types (branch build, recipe build, translation |
42 | + # build etc.) |
43 | |
44 | === added file 'lib/lp/buildmaster/model/buildfarmjobbehavior.py' |
45 | --- lib/lp/buildmaster/model/buildfarmjobbehavior.py 1970-01-01 00:00:00 +0000 |
46 | +++ lib/lp/buildmaster/model/buildfarmjobbehavior.py 2009-12-01 16:47:13 +0000 |
47 | @@ -0,0 +1,50 @@ |
48 | +# Copyright 2009 Canonical Ltd. This software is licensed under the |
49 | +# GNU Affero General Public License version 3 (see the file LICENSE). |
50 | + |
51 | +# pylint: disable-msg=E0211,E0213 |
52 | + |
53 | +"""Base and idle BuildFarmJobBehavior classes.""" |
54 | + |
55 | +__metaclass__ = type |
56 | + |
57 | +__all__ = [ |
58 | + 'BuildFarmJobBehaviorBase', |
59 | + 'IdleBuildBehavior' |
60 | + ] |
61 | + |
62 | +from zope.interface import implements |
63 | + |
64 | +from lp.buildmaster.interfaces.buildfarmjobbehavior import ( |
65 | + BuildBehaviorMismatch, IBuildFarmJobBehavior) |
66 | + |
67 | + |
68 | +class BuildFarmJobBehaviorBase: |
69 | + """Ensures that all behaviors inherit the same initialisation. |
70 | + |
71 | + All build-farm job behaviors should inherit from this. |
72 | + """ |
73 | + |
74 | + def __init__(self, buildfarmjob): |
75 | + """Store a reference to the job_type with which we were created.""" |
76 | + self.buildfarmjob = buildfarmjob |
77 | + self._builder = None |
78 | + |
79 | + def setBuilder(self, builder): |
80 | + """The builder should be set once and not changed.""" |
81 | + self._builder = builder |
82 | + |
83 | + |
84 | +class IdleBuildBehavior(BuildFarmJobBehaviorBase): |
85 | + |
86 | + implements(IBuildFarmJobBehavior) |
87 | + |
88 | + def __init__(self): |
89 | + """The idle behavior is special in that a buildfarmjob is not |
90 | + specified during initialisation. |
91 | + """ |
92 | + super(IdleBuildBehavior, self).__init__(None) |
93 | + |
94 | + def logStartBuild(self, build_queue_item, logger): |
95 | + """See `IBuildFarmJobBehavior`.""" |
96 | + raise BuildBehaviorMismatch( |
97 | + "Builder was idle when asked to log the start of a build.") |
98 | |
99 | === modified file 'lib/lp/soyuz/configure.zcml' |
100 | --- lib/lp/soyuz/configure.zcml 2009-11-16 22:06:14 +0000 |
101 | +++ lib/lp/soyuz/configure.zcml 2009-12-01 16:47:13 +0000 |
102 | @@ -892,4 +892,11 @@ |
103 | interface="lp.soyuz.interfaces.buildpackagejob.IBuildPackageJob"/> |
104 | </class> |
105 | |
106 | + <!-- BinaryPackageBuildBehavior --> |
107 | + <adapter |
108 | + for="lp.soyuz.interfaces.buildpackagejob.IBuildPackageJob" |
109 | + provides="lp.buildmaster.interfaces.buildfarmjobbehavior.IBuildFarmJobBehavior" |
110 | + factory="lp.soyuz.model.binarypackagebuildbehavior.BinaryPackageBuildBehavior" |
111 | + permission="zope.Public" /> |
112 | + |
113 | </configure> |
114 | |
115 | === modified file 'lib/lp/soyuz/doc/builder.txt' |
116 | --- lib/lp/soyuz/doc/builder.txt 2009-11-12 12:52:23 +0000 |
117 | +++ lib/lp/soyuz/doc/builder.txt 2009-12-01 16:47:13 +0000 |
118 | @@ -40,6 +40,18 @@ |
119 | >>> builder.builderok = True |
120 | >>> builder.failnotes = None |
121 | |
122 | +A builder provides a current_build_behavior attribute to which all the |
123 | +build-type specific behavior for the current build is delegated. For |
124 | +our sample data, the behavior is specifically a behavior for dealing |
125 | +with binary packages |
126 | + |
127 | + >>> from zope.security.proxy import isinstance |
128 | + >>> from lp.soyuz.model.binarypackagebuildbehavior import ( |
129 | + ... BinaryPackageBuildBehavior) |
130 | + >>> isinstance( |
131 | + ... builder.current_build_behavior, BinaryPackageBuildBehavior) |
132 | + True |
133 | + |
134 | In case of copy archives the status string will show both the copy |
135 | archive owner as well as the copy archive name. |
136 | |
137 | |
138 | === modified file 'lib/lp/soyuz/doc/buildqueue.txt' |
139 | --- lib/lp/soyuz/doc/buildqueue.txt 2009-11-13 19:34:17 +0000 |
140 | +++ lib/lp/soyuz/doc/buildqueue.txt 2009-12-01 16:47:13 +0000 |
141 | @@ -98,6 +98,16 @@ |
142 | (True, 1000) |
143 | |
144 | |
145 | +The BuildQueue item is responsible for providing the required build behavior |
146 | +for the item. |
147 | + |
148 | + >>> from zope.security.proxy import isinstance |
149 | + >>> from lp.soyuz.model.binarypackagebuildbehavior import ( |
150 | + ... BinaryPackageBuildBehavior) |
151 | + >>> isinstance(bq.required_build_behavior, BinaryPackageBuildBehavior) |
152 | + True |
153 | + |
154 | + |
155 | == Dispatching and Reseting jobs == |
156 | |
157 | The sampledata contains an active job, being built by the 'bob' |
158 | |
159 | === modified file 'lib/lp/soyuz/interfaces/builder.py' |
160 | --- lib/lp/soyuz/interfaces/builder.py 2009-11-20 18:06:28 +0000 |
161 | +++ lib/lp/soyuz/interfaces/builder.py 2009-12-01 16:47:13 +0000 |
162 | @@ -19,11 +19,13 @@ |
163 | ] |
164 | |
165 | from zope.interface import Interface, Attribute |
166 | -from zope.schema import Choice, TextLine, Text, Bool |
167 | +from zope.schema import Bool, Choice, Field, Text, TextLine |
168 | |
169 | from canonical.launchpad import _ |
170 | from canonical.launchpad.fields import Title, Description |
171 | from lp.registry.interfaces.role import IHasOwner |
172 | +from lp.buildmaster.interfaces.buildfarmjobbehavior import ( |
173 | + IBuildFarmJobBehavior) |
174 | from canonical.launchpad.validators.name import name_validator |
175 | from canonical.launchpad.validators.url import builder_url_validator |
176 | |
177 | @@ -57,7 +59,7 @@ |
178 | """The build slave has suffered an error and cannot be used.""" |
179 | |
180 | |
181 | -class IBuilder(IHasOwner): |
182 | +class IBuilder(IHasOwner, IBuildFarmJobBehavior): |
183 | """Build-slave information and state. |
184 | |
185 | Builder instance represents a single builder slave machine within the |
186 | @@ -138,6 +140,10 @@ |
187 | "new jobs. "), |
188 | required=False) |
189 | |
190 | + current_build_behavior = Field( |
191 | + title=u"The current behavior of the builder for the current job.", |
192 | + required=False) |
193 | + |
194 | def cacheFileOnSlave(logger, libraryfilealias): |
195 | """Ask the slave to cache a librarian file to its local disk. |
196 | |
197 | |
198 | === modified file 'lib/lp/soyuz/interfaces/buildqueue.py' |
199 | --- lib/lp/soyuz/interfaces/buildqueue.py 2009-11-20 18:06:28 +0000 |
200 | +++ lib/lp/soyuz/interfaces/buildqueue.py 2009-12-01 16:47:13 +0000 |
201 | @@ -13,7 +13,7 @@ |
202 | ] |
203 | |
204 | from zope.interface import Interface, Attribute |
205 | -from zope.schema import Choice, Datetime, Timedelta |
206 | +from zope.schema import Choice, Datetime, Field, Timedelta |
207 | |
208 | from lazr.restful.fields import Reference |
209 | |
210 | @@ -51,6 +51,10 @@ |
211 | title=_('Job type'), required=True, vocabulary=BuildFarmJobType, |
212 | description=_("The type of this job.")) |
213 | |
214 | + required_build_behavior = Field( |
215 | + title=_('The builder behavior required to run this job.'), |
216 | + required=False, readonly=True) |
217 | + |
218 | estimated_duration = Timedelta( |
219 | title=_("Estimated Job Duration"), required=True, |
220 | description=_("Estimated job duration interval.")) |
221 | |
222 | === added file 'lib/lp/soyuz/model/binarypackagebuildbehavior.py' |
223 | --- lib/lp/soyuz/model/binarypackagebuildbehavior.py 1970-01-01 00:00:00 +0000 |
224 | +++ lib/lp/soyuz/model/binarypackagebuildbehavior.py 2009-12-01 16:47:13 +0000 |
225 | @@ -0,0 +1,35 @@ |
226 | +# Copyright 2009 Canonical Ltd. This software is licensed under the |
227 | +# GNU Affero General Public License version 3 (see the file LICENSE). |
228 | + |
229 | +# pylint: disable-msg=E0211,E0213 |
230 | + |
231 | +"""Builder behavior for binary package builds.""" |
232 | + |
233 | +__metaclass__ = type |
234 | + |
235 | +__all__ = [ |
236 | + 'BinaryPackageBuildBehavior', |
237 | + ] |
238 | + |
239 | +from lp.buildmaster.interfaces.buildfarmjobbehavior import ( |
240 | + IBuildFarmJobBehavior) |
241 | +from lp.buildmaster.model.buildfarmjobbehavior import ( |
242 | + BuildFarmJobBehaviorBase) |
243 | +from lp.soyuz.interfaces.build import IBuildSet |
244 | + |
245 | +from zope.component import getUtility |
246 | +from zope.interface import implements |
247 | + |
248 | + |
249 | +class BinaryPackageBuildBehavior(BuildFarmJobBehaviorBase): |
250 | + """Define the behavior of binary package builds.""" |
251 | + |
252 | + implements(IBuildFarmJobBehavior) |
253 | + |
254 | + def logStartBuild(self, build_queue_item, logger): |
255 | + """See `IBuildFarmJobBehavior`.""" |
256 | + build = getUtility(IBuildSet).getByQueueEntry(build_queue_item) |
257 | + spr = build.sourcepackagerelease |
258 | + |
259 | + logger.info("startBuild(%s, %s, %s, %s)", self._builder.url, |
260 | + spr.name, spr.version, build.pocket.title) |
261 | |
262 | === modified file 'lib/lp/soyuz/model/builder.py' |
263 | --- lib/lp/soyuz/model/builder.py 2009-11-20 18:06:28 +0000 |
264 | +++ lib/lp/soyuz/model/builder.py 2009-12-01 16:47:13 +0000 |
265 | @@ -20,6 +20,8 @@ |
266 | import urllib2 |
267 | import xmlrpclib |
268 | |
269 | +from lazr.delegates import delegates |
270 | + |
271 | from zope.interface import implements |
272 | from zope.component import getUtility |
273 | |
274 | @@ -31,7 +33,10 @@ |
275 | from canonical.cachedproperty import cachedproperty |
276 | from canonical.config import config |
277 | from canonical.buildd.slave import BuilderStatus |
278 | +from lp.buildmaster.interfaces.buildfarmjobbehavior import ( |
279 | + BuildBehaviorMismatch, IBuildFarmJobBehavior) |
280 | from lp.buildmaster.master import BuilddMaster |
281 | +from lp.buildmaster.model.buildfarmjobbehavior import IdleBuildBehavior |
282 | from canonical.database.sqlbase import SQLBase, sqlvalues |
283 | from lp.soyuz.adapters.archivedependencies import ( |
284 | get_primary_current_component, get_sources_list_for_building) |
285 | @@ -54,6 +59,7 @@ |
286 | PackagePublishingStatus) |
287 | from lp.soyuz.model.buildpackagejob import BuildPackageJob |
288 | from canonical.launchpad.webapp import urlappend |
289 | +from canonical.lazr.utils import safe_hasattr |
290 | from canonical.librarian.utils import copy_and_close |
291 | |
292 | |
293 | @@ -114,6 +120,7 @@ |
294 | class Builder(SQLBase): |
295 | |
296 | implements(IBuilder, IHasBuildRecords) |
297 | + delegates(IBuildFarmJobBehavior, context="current_build_behavior") |
298 | _table = 'Builder' |
299 | |
300 | _defaultOrder = ['id'] |
301 | @@ -135,6 +142,51 @@ |
302 | vm_host = StringCol(dbName='vm_host') |
303 | active = BoolCol(dbName='active', notNull=True, default=True) |
304 | |
305 | + def _getCurrentBuildBehavior(self): |
306 | + """Return the current build behavior.""" |
307 | + if not safe_hasattr(self, '_current_build_behavior'): |
308 | + self._current_build_behavior = None |
309 | + |
310 | + if (self._current_build_behavior is None or |
311 | + isinstance(self._current_build_behavior, IdleBuildBehavior)): |
312 | + # If we don't currently have a current build behavior set, |
313 | + # or we are currently idle, then... |
314 | + currentjob = self.currentjob |
315 | + if currentjob is not None: |
316 | + # ...we'll set it based on our current job. |
317 | + self._current_build_behavior = ( |
318 | + currentjob.required_build_behavior) |
319 | + self._current_build_behavior.setBuilder(self) |
320 | + return self._current_build_behavior |
321 | + elif self._current_build_behavior is None: |
322 | + # If we don't have a current job or an idle behavior |
323 | + # already set, then we just set the idle behavior |
324 | + # before returning. |
325 | + self._current_build_behavior = IdleBuildBehavior() |
326 | + return self._current_build_behavior |
327 | + |
328 | + else: |
329 | + # We did have a current non-idle build behavior set, so |
330 | + # we just return it. |
331 | + return self._current_build_behavior |
332 | + |
333 | + |
334 | + def _setCurrentBuildBehavior(self, new_behavior): |
335 | + """Set the current build behavior.""" |
336 | + |
337 | + if self.currentjob is not None: |
338 | + # We do not allow the current build behavior to be reset if we |
339 | + # have a current job. |
340 | + raise BuildBehaviorMismatch( |
341 | + "Attempt to reset builder behavior while a current build " |
342 | + "exists.") |
343 | + else: |
344 | + self._current_build_behavior = new_behavior |
345 | + self._current_build_behavior.setBuilder(self) |
346 | + |
347 | + current_build_behavior = property( |
348 | + _getCurrentBuildBehavior, _setCurrentBuildBehavior) |
349 | + |
350 | def cacheFileOnSlave(self, logger, libraryfilealias): |
351 | """See `IBuilder`.""" |
352 | url = libraryfilealias.http_url |
353 | @@ -351,10 +403,9 @@ |
354 | |
355 | def startBuild(self, build_queue_item, logger): |
356 | """See IBuilder.""" |
357 | - build = getUtility(IBuildSet).getByQueueEntry(build_queue_item) |
358 | - spr = build.sourcepackagerelease |
359 | - logger.info("startBuild(%s, %s, %s, %s)", self.url, |
360 | - spr.name, spr.version, build.pocket.title) |
361 | + # Set the build behavior depending on the provided build queue item. |
362 | + self.current_build_behavior = build_queue_item.required_build_behavior |
363 | + self.logStartBuild(build_queue_item, logger) |
364 | |
365 | # Make sure the request is valid; an exception is raised if it's not. |
366 | self._verifyBuildRequest(build_queue_item, logger) |
367 | |
368 | === modified file 'lib/lp/soyuz/model/buildqueue.py' |
369 | --- lib/lp/soyuz/model/buildqueue.py 2009-11-20 18:06:28 +0000 |
370 | +++ lib/lp/soyuz/model/buildqueue.py 2009-12-01 16:47:13 +0000 |
371 | @@ -24,6 +24,8 @@ |
372 | from canonical.database.sqlbase import SQLBase, sqlvalues |
373 | from canonical.launchpad.webapp.interfaces import NotFoundError |
374 | from lp.buildmaster.interfaces.buildfarmjob import BuildFarmJobType |
375 | +from lp.buildmaster.interfaces.buildfarmjobbehavior import ( |
376 | + IBuildFarmJobBehavior) |
377 | from lp.services.job.interfaces.job import JobStatus |
378 | from lp.services.job.model.job import Job |
379 | from lp.soyuz.interfaces.build import BuildStatus, IBuildSet |
380 | @@ -49,6 +51,11 @@ |
381 | estimated_duration = IntervalCol() |
382 | |
383 | @property |
384 | + def required_build_behavior(self): |
385 | + """See `IBuildQueue`.""" |
386 | + return IBuildFarmJobBehavior(self.specific_job) |
387 | + |
388 | + @property |
389 | def specific_job(self): |
390 | """See `IBuildQueue`.""" |
391 | store = getUtility(IStoreSelector).get(MAIN_STORE, DEFAULT_FLAVOR) |
392 | |
393 | === modified file 'lib/lp/soyuz/tests/test_builder.py' |
394 | --- lib/lp/soyuz/tests/test_builder.py 2009-11-13 16:37:05 +0000 |
395 | +++ lib/lp/soyuz/tests/test_builder.py 2009-12-01 16:47:13 +0000 |
396 | @@ -8,10 +8,15 @@ |
397 | from zope.component import getUtility |
398 | |
399 | from canonical.testing import LaunchpadZopelessLayer |
400 | +from lp.buildmaster.interfaces.buildfarmjobbehavior import ( |
401 | + BuildBehaviorMismatch, IBuildFarmJobBehavior) |
402 | +from lp.buildmaster.model.buildfarmjobbehavior import IdleBuildBehavior |
403 | from lp.soyuz.interfaces.archive import ArchivePurpose |
404 | from lp.soyuz.interfaces.build import BuildStatus, IBuildSet |
405 | from lp.soyuz.interfaces.builder import IBuilderSet |
406 | from lp.soyuz.interfaces.publishing import PackagePublishingStatus |
407 | +from lp.soyuz.model.binarypackagebuildbehavior import ( |
408 | + BinaryPackageBuildBehavior) |
409 | from lp.soyuz.tests.test_publishing import SoyuzTestPublisher |
410 | from lp.testing import TestCaseWithFactory |
411 | |
412 | @@ -214,5 +219,69 @@ |
413 | self.failUnlessEqual('primary', build.archive.name) |
414 | self.failUnlessEqual('firefox', build.sourcepackagerelease.name) |
415 | |
416 | + |
417 | +class TestCurrentBuildBehavior(TestCaseWithFactory): |
418 | + """This test ensures the get/set behavior of IBuilder's |
419 | + current_build_behavior property. |
420 | + """ |
421 | + |
422 | + layer = LaunchpadZopelessLayer |
423 | + |
424 | + def setUp(self): |
425 | + """Create a new builder ready for testing.""" |
426 | + super(TestCurrentBuildBehavior, self).setUp() |
427 | + self.builder = self.factory.makeBuilder(name='builder') |
428 | + |
429 | + # Have a publisher and a ppa handy for some of the tests below. |
430 | + self.publisher = SoyuzTestPublisher() |
431 | + self.publisher.prepareBreezyAutotest() |
432 | + self.ppa_joe = self.factory.makeArchive(name="joesppa") |
433 | + |
434 | + self.build = self.publisher.getPubSource( |
435 | + sourcename="gedit", status=PackagePublishingStatus.PUBLISHED, |
436 | + archive=self.ppa_joe).createMissingBuilds()[0] |
437 | + |
438 | + self.buildfarmjob = self.build.buildqueue_record.specific_job |
439 | + |
440 | + def test_idle_behavior_when_no_current_build(self): |
441 | + """We return an idle behavior when there is no behavior specified |
442 | + nor a current build. |
443 | + """ |
444 | + self.assertIsInstance( |
445 | + self.builder.current_build_behavior, IdleBuildBehavior) |
446 | + |
447 | + def test_set_behavior_when_no_current_job(self): |
448 | + """If a builder is idle then it is possible to set the behavior.""" |
449 | + self.builder.current_build_behavior = IBuildFarmJobBehavior( |
450 | + self.buildfarmjob) |
451 | + |
452 | + self.assertIsInstance( |
453 | + self.builder.current_build_behavior, BinaryPackageBuildBehavior) |
454 | + |
455 | + def test_current_job_behavior(self): |
456 | + """The current behavior is set automatically from the current job.""" |
457 | + # Set the builder attribute on the buildqueue record so that our |
458 | + # builder will think it has a current build. |
459 | + self.build.buildqueue_record.builder = self.builder |
460 | + |
461 | + self.assertIsInstance( |
462 | + self.builder.current_build_behavior, BinaryPackageBuildBehavior) |
463 | + |
464 | + def test_set_behavior_when_current_job(self): |
465 | + """If a builder has a current job then it's behavior cannot be set. |
466 | + """ |
467 | + self.build.buildqueue_record.builder = self.builder |
468 | + |
469 | + # As we can't use assertRaises for a property, we use a try-except |
470 | + # instead. |
471 | + assertion_raised = False |
472 | + try: |
473 | + self.builder.current_build_behavior = IBuildFarmJobBehavior( |
474 | + self.buildfarmjob) |
475 | + except BuildBehaviorMismatch, e: |
476 | + assertion_raised = True |
477 | + |
478 | + self.failUnless(assertion_raised) |
479 | + |
480 | def test_suite(): |
481 | return unittest.TestLoader().loadTestsFromName(__name__) |
= Summary =
This branch creates the infrastructure to allow IBuilder to support different behaviors (BinaryPackageB uildBehavior currently, but later SourcePackageRe cipeBuildBehavi or etc.).
== Proposed fix ==
Create a general interface for build farm job behaviors that can be implemented by various classes, and allow the behavior to be an attribute of the builder to which all relevant calls will be delegated.
This branch begins the extraction of soyuz-specific build behavior for the [Binary] BuildPackageJob into a BinaryPackageBu ildBehavior. Subsequent branches (in a pipeline) will continue this.
I plan to re-base these to devel after the release when db-stable is merged back into devel.
== Pre-implementation notes ==
See the pre-implementation notes on bug 487009.
== Implementation details ==
== Tests ==
bin/test -vv -t doc/builder.txt -t doc/buildqueue.txt -t TestCurrentBuil dBehavior. txt
== Demo and Q/A ==
We will need to Q/A this on dogfood.
= Launchpad lint =
Checking for conflicts. and issues in doctests and templates.
Running jslint, xmllint, pyflakes, and pylint.
Using normal rules.
Linting changed files: soyuz/model/ builder. py soyuz/doc/ builder. txt soyuz/doc/ buildqueue. txt soyuz/configure .zcml soyuz/model/ buildqueue. py buildmaster/ model/buildfarm jobbehavior. py soyuz/interface s/buildqueue. py soyuz/tests/ test_builder. py soyuz/model/ binarypackagebu ildbehavior. py buildmaster/ interfaces/ buildfarmjobbeh avior.py soyuz/interface s/builder. py
lib/lp/
lib/lp/
lib/lp/
lib/lp/
lib/lp/
lib/lp/
lib/lp/
lib/lp/
lib/lp/
lib/lp/
lib/lp/
== Pylint notices ==
lib/lp/ soyuz/model/ builder. py
23: [F0401] Unable to import 'lazr.delegates' (No module named delegates)
lib/lp/ soyuz/interface s/buildqueue. py fields' (No module named restful)
18: [F0401] Unable to import 'lazr.restful.
--
Michael