Merge lp:~al-maisan/launchpad/refactoring-479079 into lp:launchpad/db-devel
- refactoring-479079
- Merge into db-devel
Status: | Merged |
---|---|
Approved by: | Julian Edwards |
Approved revision: | not available |
Merged at revision: | not available |
Proposed branch: | lp:~al-maisan/launchpad/refactoring-479079 |
Merge into: | lp:launchpad/db-devel |
Diff against target: |
3133 lines (+994/-560) 35 files modified
database/sampledata/current-dev.sql (+36/-2) database/sampledata/current.sql (+36/-2) database/schema/comments.sql (+3/-4) database/schema/patch-2207-11-0.sql (+87/-0) database/schema/security.cfg (+8/-0) lib/lp/buildmaster/buildergroup.py (+41/-31) lib/lp/buildmaster/interfaces/buildfarmjob.py (+71/-0) lib/lp/buildmaster/master.py (+4/-2) lib/lp/buildmaster/model/buildfarmjob.py (+40/-0) lib/lp/buildmaster/tests/queuebuilder.txt (+6/-5) lib/lp/buildmaster/tests/test_manager.py (+14/-10) lib/lp/registry/model/sourcepackage.py (+3/-1) lib/lp/services/job/tests/test_job.py (+22/-5) lib/lp/soyuz/browser/build.py (+2/-2) lib/lp/soyuz/browser/builder.py (+3/-3) lib/lp/soyuz/browser/tests/builder-views.txt (+9/-5) lib/lp/soyuz/configure.zcml (+7/-1) lib/lp/soyuz/doc/build-estimated-dispatch-time.txt (+6/-5) lib/lp/soyuz/doc/buildd-dispatching.txt (+20/-35) lib/lp/soyuz/doc/buildd-scoring.txt (+19/-11) lib/lp/soyuz/doc/buildd-slavescanner.txt (+94/-78) lib/lp/soyuz/doc/builder.txt (+3/-1) lib/lp/soyuz/doc/buildqueue.txt (+16/-36) lib/lp/soyuz/interfaces/build.py (+7/-0) lib/lp/soyuz/interfaces/buildpackagejob.py (+34/-0) lib/lp/soyuz/interfaces/buildqueue.py (+27/-44) lib/lp/soyuz/model/build.py (+47/-8) lib/lp/soyuz/model/builder.py (+51/-41) lib/lp/soyuz/model/buildpackagejob.py (+168/-0) lib/lp/soyuz/model/buildqueue.py (+72/-199) lib/lp/soyuz/stories/soyuz/xx-build-record.txt (+5/-8) lib/lp/soyuz/templates/build-index.pt (+2/-2) lib/lp/soyuz/templates/builder-index.pt (+10/-3) lib/lp/soyuz/templates/builds-list.pt (+2/-2) lib/lp/soyuz/tests/test_builder.py (+19/-14) |
To merge this branch: | bzr merge lp:~al-maisan/launchpad/refactoring-479079 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Julian Edwards (community) | code | Approve | |
Review via email: mp+14829@code.launchpad.net |
Commit message
Description of the change
Muharem Hrnjadovic (al-maisan) wrote : | # |
Julian Edwards (julian-edwards) wrote : | # |
Phew! What a change, thanks for staying late and getting this done Muharem.
There's a few things to fix; you're already aware of some that I mentioned on IRC. More inline!
> === modified file 'lib/lp/
> --- lib/lp/
> +++ lib/lp/
> @@ -130,8 +130,9 @@
> try:
> build = getUtility(
> queue_item = getUtility(
> - # Also check it build and buildqueue are properly related.
> - if queue_item.build.id != build.id:
> + queued_build = getUtility(
> + # Also check whether build and buildqueue are properly related.
> + if queued_build.id != build.id:
> raise BuildJobMismatc
>
> except (SQLObjectNotFound, NotFoundError, BuildJobMismatch), reason:
> @@ -159,9 +160,10 @@
>
> Invoke getFileFromSlave method with 'buildlog' identifier.
> """
> + build = getUtility(
> return queueItem.
> 'buildlog', queueItem.
> - queueItem.
> + build.archive.
>
> def updateBuild(self, queueItem):
> """Verify the current build job status.
> @@ -199,7 +201,7 @@
> "Unknown status code (%s) returned from status() probe."
> % builder_status)
> queueItem.builder = None
> - queueItem.
> + queueItem.
> self.commit()
> return
>
> @@ -261,17 +263,18 @@
>
> Store Buildlog, datebuilt, duration, dependencies.
> """
> - queueItem.
> - queueItem.
> - queueItem.
> + build = getUtility(
> + build.buildlog = self.getLogFrom
> + build.builder = queueItem.builder
> + build.dependencies = dependencies
> # XXX cprov 20060615 bug=120584: Currently buildduration includes
> # the scanner latency, it should really be asking the slave for
> # the duration spent building locally.
> - queueItem.
> + build.datebuilt = UTC_NOW
> # We need dynamic datetime.now() instance to be able to perform
> # the time operations for duration.
> RIGHT_NOW = datetime.
> - queueItem.
> + build.buildduration = RIGHT_NOW - queueItem.
Since you added buildqueue.
buildqueue.
> def buildStatus_
> @@ -287,7 +290,7 @@
> self.logger....
Muharem Hrnjadovic (al-maisan) wrote : | # |
Julian Edwards wrote:
> Review: Needs Fixing code
> Phew! What a change, thanks for staying late and getting this done
> Muharem. There's a few things to fix; you're already aware of some
> that I mentioned on IRC. More inline!
Hello Julian,
thanks for reviewing this monster branch :P
Please see my responses below as well as the enclosed incremental diff.
>> === modified file 'lib/lp/
>> --- lib/lp/
>> +++ lib/lp/
>> @@ -130,8 +130,9 @@
>> try:
>> build = getUtility(
>> queue_item = getUtility(
>> - # Also check it build and buildqueue are properly related.
>> - if queue_item.build.id != build.id:
>> + queued_build = getUtility(
>> + # Also check whether build and buildqueue are properly related.
>> + if queued_build.id != build.id:
>> raise BuildJobMismatc
>>
>> except (SQLObjectNotFound, NotFoundError, BuildJobMismatch), reason:
>> @@ -159,9 +160,10 @@
>>
>> Invoke getFileFromSlave method with 'buildlog' identifier.
>> """
>> + build = getUtility(
>> return queueItem.
>> 'buildlog', queueItem.
>> - queueItem.
>> + build.archive.
>>
>> def updateBuild(self, queueItem):
>> """Verify the current build job status.
>> @@ -199,7 +201,7 @@
>> "Unknown status code (%s) returned from status() probe."
>> % builder_status)
>> queueItem.builder = None
>> - queueItem.
>> + queueItem.
>> self.commit()
>> return
>>
>> @@ -261,17 +263,18 @@
>>
>> Store Buildlog, datebuilt, duration, dependencies.
>> """
>> - queueItem.
>> - queueItem.
>> - queueItem.
>> + build = getUtility(
>> + build.buildlog = self.getLogFrom
>> + build.builder = queueItem.builder
>> + build.dependencies = dependencies
>> # XXX cprov 20060615 bug=120584: Currently buildduration includes
>> # the scanner latency, it should really be asking the slave for
>> # the duration spent building locally.
>> - queueItem.
>> + build.datebuilt = UTC_NOW
>> # We need dynamic datetime.now() instance to be able to perform
>> # the time operations for duration.
>> RIGHT_NOW = datetime.
>> - queueItem.
>> + build.buildduration = RIGHT_NOW - queueItem.jo...
1 | === modified file 'lib/lp/buildmaster/buildergroup.py' |
2 | --- lib/lp/buildmaster/buildergroup.py 2009-11-13 09:00:59 +0000 |
3 | +++ lib/lp/buildmaster/buildergroup.py 2009-11-13 19:12:49 +0000 |
4 | @@ -274,7 +274,7 @@ |
5 | # We need dynamic datetime.now() instance to be able to perform |
6 | # the time operations for duration. |
7 | RIGHT_NOW = datetime.datetime.now(pytz.timezone('UTC')) |
8 | - build.buildduration = RIGHT_NOW - queueItem.job.date_started |
9 | + build.buildduration = RIGHT_NOW - queueItem.date_started |
10 | |
11 | |
12 | def buildStatus_OK(self, queueItem, librarian, buildid, |
13 | |
14 | === added directory 'lib/lp/buildmaster/interfaces' |
15 | === renamed file 'lib/lp/soyuz/interfaces/soyuzjob.py' => 'lib/lp/buildmaster/interfaces/buildfarmjob.py' |
16 | --- lib/lp/soyuz/interfaces/soyuzjob.py 2009-11-12 15:53:23 +0000 |
17 | +++ lib/lp/buildmaster/interfaces/buildfarmjob.py 2009-11-13 19:42:13 +0000 |
18 | @@ -8,15 +8,15 @@ |
19 | __metaclass__ = type |
20 | |
21 | __all__ = [ |
22 | - 'ISoyuzJob', |
23 | - 'SoyuzJobType', |
24 | + 'IBuildfarmJob', |
25 | + 'BuildfarmJobType', |
26 | ] |
27 | |
28 | from zope.interface import Interface |
29 | from lazr.enum import DBEnumeratedType, DBItem |
30 | |
31 | |
32 | -class SoyuzJobType(DBEnumeratedType): |
33 | +class BuildfarmJobType(DBEnumeratedType): |
34 | """Soyuz build farm job type. |
35 | |
36 | An enumeration with the types of jobs that may be run on the Soyuz build |
37 | @@ -48,7 +48,7 @@ |
38 | """) |
39 | |
40 | |
41 | -class ISoyuzJob(Interface): |
42 | +class IBuildfarmJob(Interface): |
43 | """Operations that Soyuz build farm jobs must implement.""" |
44 | |
45 | def score(): |
46 | |
47 | === added directory 'lib/lp/buildmaster/model' |
48 | === renamed file 'lib/lp/soyuz/model/soyuzjob.py' => 'lib/lp/buildmaster/model/buildfarmjob.py' |
49 | --- lib/lp/soyuz/model/soyuzjob.py 2009-11-12 15:53:23 +0000 |
50 | +++ lib/lp/buildmaster/model/buildfarmjob.py 2009-11-13 19:48:03 +0000 |
51 | @@ -2,39 +2,39 @@ |
52 | # GNU Affero General Public License version 3 (see the file LICENSE). |
53 | |
54 | __metaclass__ = type |
55 | -__all__ = ['SoyuzJob'] |
56 | +__all__ = ['BuildfarmJob'] |
57 | |
58 | |
59 | from zope.interface import implements |
60 | |
61 | -from lp.soyuz.interfaces.soyuzjob import ISoyuzJob |
62 | - |
63 | - |
64 | -class SoyuzJob: |
65 | - """Mix-in class for `ISoyuzJob` implementations.""" |
66 | - implements(ISoyuzJob) |
67 | +from lp.buildmaster.interfaces.buildfarmjob import IBuildfarmJob |
68 | + |
69 | + |
70 | +class BuildfarmJob: |
71 | + """Mix-in class for `IBuildfarmJob` implementations.""" |
72 | + implements(IBuildfarmJob) |
73 | |
74 | def score(self): |
75 | - """See `ISoyuzJob`.""" |
76 | + """See `IBuildfarmJob`.""" |
77 | raise NotImplementedError |
78 | |
79 | def getLogFileName(self): |
80 | - """See `ISoyuzJob`.""" |
81 | + """See `IBuildfarmJob`.""" |
82 | raise NotImplementedError |
83 | |
84 | def getName(self): |
85 | - """See `ISoyuzJob`.""" |
86 | + """See `IBuildfarmJob`.""" |
87 | raise NotImplementedError |
88 | |
89 | def jobStarted(self): |
90 | - """See `ISoyuzJob`.""" |
91 | + """See `IBuildfarmJob`.""" |
92 | pass |
93 | |
94 | def jobReset(self): |
95 | - """See `ISoyuzJob`.""" |
96 | + """See `IBuildfarmJob`.""" |
97 | pass |
98 | |
99 | def jobAborted(self): |
100 | - """See `ISoyuzJob`.""" |
101 | + """See `IBuildfarmJob`.""" |
102 | pass |
103 | |
104 | |
105 | === modified file 'lib/lp/buildmaster/tests/test_manager.py' |
106 | --- lib/lp/buildmaster/tests/test_manager.py 2009-11-12 13:54:36 +0000 |
107 | +++ lib/lp/buildmaster/tests/test_manager.py 2009-11-13 19:11:59 +0000 |
108 | @@ -494,7 +494,7 @@ |
109 | |
110 | self.assertTrue(job is not None) |
111 | self.assertEqual(job.builder, builder) |
112 | - self.assertTrue(job.job.date_started is not None) |
113 | + self.assertTrue(job.date_started is not None) |
114 | build = getUtility(IBuildSet).getByQueueEntry(job) |
115 | self.assertEqual(build.buildstate, BuildStatus.BUILDING) |
116 | self.assertEqual(job.logtail, logtail) |
117 | @@ -618,7 +618,7 @@ |
118 | |
119 | job = getUtility(IBuildQueueSet).get(job.id) |
120 | self.assertTrue(job.builder is None) |
121 | - self.assertTrue(job.job.date_started is None) |
122 | + self.assertTrue(job.date_started is None) |
123 | build = getUtility(IBuildSet).getByQueueEntry(job) |
124 | self.assertEqual(build.buildstate, BuildStatus.NEEDSBUILD) |
125 | |
126 | @@ -710,7 +710,7 @@ |
127 | |
128 | self.assertEqual('BUILDING', build.buildstate.name) |
129 | self.assertNotEqual(None, job.builder) |
130 | - self.assertNotEqual(None, job.job.date_started) |
131 | + self.assertNotEqual(None, job.date_started) |
132 | self.assertNotEqual(None, job.logtail) |
133 | |
134 | transaction.commit() |
135 | @@ -723,7 +723,7 @@ |
136 | build = getUtility(IBuildSet).getByQueueEntry(job) |
137 | self.assertEqual('NEEDSBUILD', build.buildstate.name) |
138 | self.assertEqual(None, job.builder) |
139 | - self.assertEqual(None, job.job.date_started) |
140 | + self.assertEqual(None, job.date_started) |
141 | self.assertEqual(None, job.logtail) |
142 | |
143 | def testResetDispatchResult(self): |
144 | |
145 | === modified file 'lib/lp/soyuz/browser/builder.py' |
146 | --- lib/lp/soyuz/browser/builder.py 2009-11-12 10:38:46 +0000 |
147 | +++ lib/lp/soyuz/browser/builder.py 2009-11-13 19:13:14 +0000 |
148 | @@ -237,11 +237,11 @@ |
149 | def current_build_duration(self): |
150 | """Return the delta representing the duration of the current job.""" |
151 | if (self.context.currentjob is None or |
152 | - self.context.currentjob.job.date_started is None): |
153 | + self.context.currentjob.date_started is None): |
154 | return None |
155 | else: |
156 | UTC = pytz.timezone('UTC') |
157 | - date_started = self.context.currentjob.job.date_started |
158 | + date_started = self.context.currentjob.date_started |
159 | return datetime.datetime.now(UTC) - date_started |
160 | |
161 | @property |
162 | |
163 | === modified file 'lib/lp/soyuz/browser/tests/builder-views.txt' |
164 | --- lib/lp/soyuz/browser/tests/builder-views.txt 2009-11-12 10:38:46 +0000 |
165 | +++ lib/lp/soyuz/browser/tests/builder-views.txt 2009-11-13 19:22:15 +0000 |
166 | @@ -215,7 +215,7 @@ |
167 | |
168 | >>> import datetime |
169 | >>> import pytz |
170 | - >>> private_job.job.date_started = ( |
171 | + >>> private_job.setDateStarted( |
172 | ... datetime.datetime.now(pytz.UTC) - datetime.timedelta(10)) |
173 | >>> print admin_view.current_build_duration |
174 | 10 days... |
175 | |
176 | === modified file 'lib/lp/soyuz/configure.zcml' |
177 | --- lib/lp/soyuz/configure.zcml 2009-11-13 16:37:05 +0000 |
178 | +++ lib/lp/soyuz/configure.zcml 2009-11-13 19:56:58 +0000 |
179 | @@ -560,7 +560,7 @@ |
180 | |
181 | <require |
182 | permission="zope.Public" |
183 | - set_attributes="lastscore builder logtail"/> |
184 | + set_attributes="lastscore builder logtail date_started"/> |
185 | </class> |
186 | |
187 | <!-- BuildQueueSet --> |
188 | |
189 | === modified file 'lib/lp/soyuz/doc/build-estimated-dispatch-time.txt' |
190 | --- lib/lp/soyuz/doc/build-estimated-dispatch-time.txt 2009-11-13 07:04:53 +0000 |
191 | +++ lib/lp/soyuz/doc/build-estimated-dispatch-time.txt 2009-11-13 19:14:25 +0000 |
192 | @@ -76,9 +76,9 @@ |
193 | |
194 | >>> from zope.security.proxy import removeSecurityProxy |
195 | >>> cur_bqueue.lastscore = 1111 |
196 | - >>> removeSecurityProxy(cur_bqueue.job).date_started = ( |
197 | + >>> cur_bqueue.setDateStarted( |
198 | ... datetime(2008, 4, 1, 10, 45, 39, tzinfo=UTC)) |
199 | - >>> print cur_bqueue.job.date_started |
200 | + >>> print cur_bqueue.date_started |
201 | 2008-04-01 10:45:39+00:00 |
202 | |
203 | Please note that the "estimated build duration" is an internal property |
204 | |
205 | === modified file 'lib/lp/soyuz/doc/buildd-dispatching.txt' |
206 | --- lib/lp/soyuz/doc/buildd-dispatching.txt 2009-11-13 09:14:30 +0000 |
207 | +++ lib/lp/soyuz/doc/buildd-dispatching.txt 2009-11-13 19:14:44 +0000 |
208 | @@ -140,7 +140,7 @@ |
209 | 'NEEDSBUILD' |
210 | >>> job.builder is None |
211 | True |
212 | - >>> job.job.date_started is None |
213 | + >>> job.date_started is None |
214 | True |
215 | >>> build.is_virtualized |
216 | False |
217 | @@ -204,7 +204,7 @@ |
218 | 3 |
219 | >>> ppa_job.builder == None |
220 | True |
221 | - >>> ppa_job.job.date_started == None |
222 | + >>> ppa_job.date_started == None |
223 | True |
224 | |
225 | The build job's archive requires virtualized builds. |
226 | @@ -317,7 +317,7 @@ |
227 | 4 |
228 | >>> print sec_job.builder |
229 | None |
230 | - >>> print sec_job.job.date_started |
231 | + >>> print sec_job.date_started |
232 | None |
233 | >>> sec_build.is_virtualized |
234 | False |
235 | |
236 | === modified file 'lib/lp/soyuz/doc/buildd-slavescanner.txt' |
237 | --- lib/lp/soyuz/doc/buildd-slavescanner.txt 2009-11-13 16:37:05 +0000 |
238 | +++ lib/lp/soyuz/doc/buildd-slavescanner.txt 2009-11-13 19:15:23 +0000 |
239 | @@ -593,7 +593,7 @@ |
240 | |
241 | >>> bqItem11.builder is None |
242 | True |
243 | - >>> bqItem11.job.date_started is None |
244 | + >>> bqItem11.date_started is None |
245 | True |
246 | >>> bqItem11.lastscore |
247 | 0 |
248 | @@ -962,7 +962,7 @@ |
249 | >>> a_builder.dispatchBuildCandidate(candidate) |
250 | ensurepresent called, url=... |
251 | ensurepresent called, |
252 | - url=http://localhost:58000/3/firefox-0.9.2.orig.tar.gz |
253 | + url=http://localhost:58000/3/firefox_0.9.2.orig.tar.gz |
254 | OkSlave BUILDING |
255 | Archives: |
256 | deb http://ftpmaster.internal/ubuntu hoary main |
257 | @@ -990,7 +990,7 @@ |
258 | >>> a_builder.dispatchBuildCandidate(candidate) |
259 | ensurepresent called, url=... |
260 | ensurepresent called, |
261 | - url=http://localhost:58000/3/firefox-0.9.2.orig.tar.gz |
262 | + url=http://localhost:58000/3/firefox_0.9.2.orig.tar.gz |
263 | OkSlave BUILDING |
264 | Archives: |
265 | deb http://ftpmaster.internal/ubuntu hoary main |
266 | @@ -1042,7 +1042,7 @@ |
267 | >>> a_builder.dispatchBuildCandidate(candidate) |
268 | ensurepresent called, url=... |
269 | ensurepresent called, |
270 | - url=http://localhost:58000/3/firefox-0.9.2.orig.tar.gz |
271 | + url=http://localhost:58000/3/firefox_0.9.2.orig.tar.gz |
272 | OkSlave BUILDING |
273 | Archives: |
274 | deb http://ftpmaster.internal/ubuntu hoary main restricted universe multiverse |
275 | @@ -1134,7 +1134,7 @@ |
276 | >>> a_builder.dispatchBuildCandidate(candidate) |
277 | ensurepresent called, url=... |
278 | ensurepresent called, |
279 | - url=http://localhost:58000/3/firefox-0.9.2.orig.tar.gz |
280 | + url=http://localhost:58000/3/firefox_0.9.2.orig.tar.gz |
281 | OkSlave BUILDING |
282 | Archives: |
283 | deb http://ftpmaster.internal/ubuntu hoary main restricted universe multiverse |
284 | @@ -1191,7 +1191,7 @@ |
285 | >>> a_builder.dispatchBuildCandidate(candidate) |
286 | ensurepresent called, url=... |
287 | ensurepresent called, |
288 | - url=http://private-ppa.launchpad.dev/cprov/ppa/ubuntu/pool/main/m/mozilla-firefox/firefox-0.9.2.orig.tar.gz |
289 | + url=http://private-ppa.launchpad.dev/cprov/ppa/ubuntu/pool/main/m/mozilla-firefox/firefox_0.9.2.orig.tar.gz |
290 | URL authorisation with buildd/secret |
291 | OkSlave BUILDING |
292 | Archives: |
293 | @@ -1311,7 +1311,7 @@ |
294 | >>> a_builder.dispatchBuildCandidate(candidate) |
295 | ensurepresent called, url=... |
296 | ensurepresent called, |
297 | - url=http://localhost:58000/3/firefox-0.9.2.orig.tar.gz |
298 | + url=http://localhost:58000/3/firefox_0.9.2.orig.tar.gz |
299 | OkSlave BUILDING |
300 | Archives: |
301 | deb http://ftpmaster.internal/ubuntu hoary main restricted universe multiverse |
302 | @@ -1340,7 +1340,7 @@ |
303 | >>> a_builder.dispatchBuildCandidate(candidate) |
304 | ensurepresent called, url=... |
305 | ensurepresent called, |
306 | - url=http://localhost:58000/3/firefox-0.9.2.orig.tar.gz |
307 | + url=http://localhost:58000/3/firefox_0.9.2.orig.tar.gz |
308 | OkSlave BUILDING |
309 | Archives: |
310 | deb http://ftpmaster.internal/ubuntu hoary main restricted universe multiverse |
311 | @@ -1410,7 +1410,7 @@ |
312 | >>> a_builder.dispatchBuildCandidate(bqItem3) |
313 | ensurepresent called, url=... |
314 | ensurepresent called, |
315 | - url=http://localhost:58000/3/firefox-0.9.2.orig.tar.gz |
316 | + url=http://localhost:58000/3/firefox_0.9.2.orig.tar.gz |
317 | OkSlave BUILDING |
318 | Archives: |
319 | deb http://ftpmaster.internal/ubuntu hoary main |
320 | @@ -1432,7 +1432,7 @@ |
321 | >>> a_builder.dispatchBuildCandidate(bqItem3) |
322 | ensurepresent called, url=... |
323 | ensurepresent called, |
324 | - url=http://localhost:58000/3/firefox-0.9.2.orig.tar.gz |
325 | + url=http://localhost:58000/3/firefox_0.9.2.orig.tar.gz |
326 | OkSlave BUILDING |
327 | Archives: |
328 | deb http://ftpmaster.internal/ubuntu hoary main |
329 | @@ -1455,7 +1455,7 @@ |
330 | >>> a_builder.dispatchBuildCandidate(bqItem3) |
331 | ensurepresent called, url=... |
332 | ensurepresent called, |
333 | - url=http://localhost:58000/3/firefox-0.9.2.orig.tar.gz |
334 | + url=http://localhost:58000/3/firefox_0.9.2.orig.tar.gz |
335 | OkSlave BUILDING |
336 | Archives: |
337 | deb http://ftpmaster.internal/ubuntu hoary main restricted universe multiverse |
338 | |
339 | === modified file 'lib/lp/soyuz/doc/buildqueue.txt' |
340 | --- lib/lp/soyuz/doc/buildqueue.txt 2009-11-12 13:09:37 +0000 |
341 | +++ lib/lp/soyuz/doc/buildqueue.txt 2009-11-13 19:15:43 +0000 |
342 | @@ -45,7 +45,7 @@ |
343 | >>> bq.job.date_created |
344 | datetime.datetime(2005, 6, 15, 9, 14, 12, 820778, tzinfo=<UTC>) |
345 | |
346 | - >>> bq.job.date_started |
347 | + >>> bq.date_started |
348 | datetime.datetime(2005, 6, 15, 9, 20, 12, 820778, tzinfo=<UTC>) |
349 | |
350 | Check Builder foreign key, which indicated which builder 'is processing' |
351 | @@ -110,7 +110,7 @@ |
352 | |
353 | >>> print job.builder.name |
354 | bob |
355 | - >>> job.job.date_started is not None |
356 | + >>> job.date_started is not None |
357 | True |
358 | >>> print job.logtail |
359 | Dummy sampledata entry, not processing |
360 | @@ -130,7 +130,7 @@ |
361 | |
362 | >>> print job.builder |
363 | None |
364 | - >>> print job.job.date_started |
365 | + >>> print job.date_started |
366 | None |
367 | >>> print job.logtail |
368 | None |
369 | @@ -149,7 +149,7 @@ |
370 | |
371 | >>> print job.builder.name |
372 | bob |
373 | - >>> job.job.date_started is not None |
374 | + >>> job.date_started is not None |
375 | True |
376 | >>> print build.buildstate.name |
377 | BUILDING |
378 | |
379 | === modified file 'lib/lp/soyuz/interfaces/buildpackagejob.py' |
380 | --- lib/lp/soyuz/interfaces/buildpackagejob.py 2009-11-13 10:26:22 +0000 |
381 | +++ lib/lp/soyuz/interfaces/buildpackagejob.py 2009-11-13 19:47:45 +0000 |
382 | @@ -15,20 +15,20 @@ |
383 | |
384 | from canonical.launchpad import _ |
385 | from lazr.restful.fields import Reference |
386 | +from lp.buildmaster.interfaces.buildfarmjob import IBuildfarmJob |
387 | from lp.services.job.interfaces.job import IJob |
388 | from lp.soyuz.interfaces.build import IBuild |
389 | -from lp.soyuz.interfaces.soyuzjob import ISoyuzJob |
390 | - |
391 | - |
392 | -class IBuildPackageJob(ISoyuzJob): |
393 | + |
394 | + |
395 | +class IBuildPackageJob(IBuildfarmJob): |
396 | """A read-only interface for build package jobs.""" |
397 | id = Int(title=_('ID'), required=True, readonly=True) |
398 | |
399 | job = Reference( |
400 | - IJob, title=_("General build job data"), required=True, readonly=True, |
401 | - description=_("General data about this build job.")) |
402 | + IJob, title=_("Job"), required=True, readonly=True, |
403 | + description=_("Data common to all job types.")) |
404 | |
405 | build = Reference( |
406 | - IBuild, title=_("Associated build record"), |
407 | + IBuild, title=_("Build"), |
408 | required=True,readonly=True, |
409 | - description=_("The build record associated with this job.")) |
410 | + description=_("Build record associated with this job.")) |
411 | |
412 | === modified file 'lib/lp/soyuz/interfaces/buildqueue.py' |
413 | --- lib/lp/soyuz/interfaces/buildqueue.py 2009-11-13 08:25:22 +0000 |
414 | +++ lib/lp/soyuz/interfaces/buildqueue.py 2009-11-13 19:53:36 +0000 |
415 | @@ -13,11 +13,14 @@ |
416 | ] |
417 | |
418 | from zope.interface import Interface, Attribute |
419 | -from zope.schema import Choice, Object |
420 | +from zope.schema import Choice, Datetime |
421 | + |
422 | +from lazr.restful.fields import Reference |
423 | |
424 | from canonical.launchpad import _ |
425 | +from lp.buildmaster.interfaces.buildfarmjob import ( |
426 | + IBuildfarmJob, BuildfarmJobType) |
427 | from lp.services.job.interfaces.job import IJob |
428 | -from lp.soyuz.interfaces.soyuzjob import SoyuzJobType |
429 | |
430 | |
431 | class IBuildQueue(Interface): |
432 | @@ -40,12 +43,12 @@ |
433 | lastscore = Attribute("Last score to be computed for this job") |
434 | manual = Attribute("Whether or not the job was manually scored") |
435 | |
436 | - job = Object( |
437 | - title=_("Generic job data"), schema=IJob, required=True, |
438 | - description=_("The generic data (time stamps etc.) about this job.")) |
439 | + job = Reference( |
440 | + IJob, title=_("Job"), required=True, readonly=True, |
441 | + description=_("Data common to all job types.")) |
442 | |
443 | job_type = Choice( |
444 | - title=_('Job type'), required=True, vocabulary=SoyuzJobType, |
445 | + title=_('Job type'), required=True, vocabulary=BuildfarmJobType, |
446 | description=_("The type of this job.")) |
447 | |
448 | def manualScore(value): |
449 | @@ -91,12 +94,17 @@ |
450 | Clean the builder for another jobs. |
451 | """ |
452 | |
453 | - specific_job = Attribute( |
454 | - "Object with data and behaviour specific to the job type at hand.") |
455 | + specific_job = Reference( |
456 | + IBuildfarmJob, title=_("Job"), |
457 | + description=_("Data and operations common to all build farm jobs.")) |
458 | |
459 | def setDateStarted(timestamp): |
460 | """Sets the date started property to the given value.""" |
461 | |
462 | + date_started = Datetime( |
463 | + title=_('Start time'), |
464 | + description=_('Time when the job started.')) |
465 | + |
466 | |
467 | class IBuildQueueSet(Interface): |
468 | """Launchpad Auto Build queue set handler and auxiliary methods.""" |
469 | |
470 | === modified file 'lib/lp/soyuz/model/build.py' |
471 | --- lib/lp/soyuz/model/build.py 2009-11-13 10:25:11 +0000 |
472 | +++ lib/lp/soyuz/model/build.py 2009-11-13 19:58:20 +0000 |
473 | @@ -45,6 +45,7 @@ |
474 | IStoreSelector, MAIN_STORE, DEFAULT_FLAVOR) |
475 | from canonical.launchpad.webapp.tales import DurationFormatterAPI |
476 | from lp.archivepublisher.utils import get_ppa_reference |
477 | +from lp.buildmaster.interfaces.buildfarmjob import BuildfarmJobType |
478 | from lp.registry.interfaces.pocket import PackagePublishingPocket |
479 | from lp.services.job.model.job import Job |
480 | from lp.soyuz.adapters.archivedependencies import get_components_for_building |
481 | @@ -53,7 +54,6 @@ |
482 | BuildStatus, BuildSetStatus, CannotBeRescored, IBuild, IBuildSet) |
483 | from lp.soyuz.interfaces.builder import IBuilderSet |
484 | from lp.soyuz.interfaces.publishing import active_publishing_status |
485 | -from lp.soyuz.interfaces.soyuzjob import SoyuzJobType |
486 | from lp.soyuz.model.binarypackagerelease import BinaryPackageRelease |
487 | from lp.soyuz.model.builder import Builder |
488 | from lp.soyuz.model.buildpackagejob import BuildPackageJob |
489 | @@ -630,7 +630,7 @@ |
490 | store.add(specific_job) |
491 | queue_entry = BuildQueue() |
492 | queue_entry.job = job.id |
493 | - queue_entry.job_type = SoyuzJobType.PACKAGEBUILD |
494 | + queue_entry.job_type = BuildfarmJobType.PACKAGEBUILD |
495 | store.add(queue_entry) |
496 | return queue_entry |
497 | |
498 | |
499 | === modified file 'lib/lp/soyuz/model/buildpackagejob.py' |
500 | --- lib/lp/soyuz/model/buildpackagejob.py 2009-11-12 15:53:23 +0000 |
501 | +++ lib/lp/soyuz/model/buildpackagejob.py 2009-11-13 20:04:38 +0000 |
502 | @@ -14,6 +14,7 @@ |
503 | |
504 | from canonical.database.constants import UTC_NOW |
505 | from canonical.launchpad.interfaces import SourcePackageUrgency |
506 | +from lp.buildmaster.interfaces.buildfarmjob import IBuildfarmJob |
507 | from lp.registry.interfaces.pocket import PackagePublishingPocket |
508 | from lp.soyuz.interfaces.archive import ArchivePurpose |
509 | from lp.soyuz.interfaces.build import BuildStatus |
510 | @@ -22,7 +23,7 @@ |
511 | |
512 | class BuildPackageJob(Storm): |
513 | """See `IBuildPackageJob`.""" |
514 | - implements(IBuildPackageJob) |
515 | + implements(IBuildfarmJob, IBuildPackageJob) |
516 | __storm_table__ = 'buildpackagejob' |
517 | id = Int(primary=True) |
518 | |
519 | @@ -33,7 +34,7 @@ |
520 | build = Reference(build_id, 'Build.id') |
521 | |
522 | def score(self): |
523 | - """See `ISoyuzJob`.""" |
524 | + """See `IBuildPackageJob`.""" |
525 | score_pocketname = { |
526 | PackagePublishingPocket.BACKPORTS: 0, |
527 | PackagePublishingPocket.RELEASE: 1500, |
528 | @@ -120,7 +121,7 @@ |
529 | return score |
530 | |
531 | def getLogFileName(self): |
532 | - """See `ISoyuzJob`.""" |
533 | + """See `IBuildPackageJob`.""" |
534 | sourcename = self.build.sourcepackagerelease.name |
535 | version = self.build.sourcepackagerelease.version |
536 | # we rely on previous storage of current buildstate |
537 | @@ -143,22 +144,22 @@ |
538 | )) |
539 | |
540 | def getName(self): |
541 | - """See `ISoyuzJob`.""" |
542 | + """See `IBuildPackageJob`.""" |
543 | return self.build.sourcepackagerelease.name |
544 | |
545 | def jobStarted(self): |
546 | - """See `ISoyuzJob`.""" |
547 | + """See `IBuildPackageJob`.""" |
548 | self.build.buildstate = BuildStatus.BUILDING |
549 | # The build started, set the start time if not set already. |
550 | if self.build.date_first_dispatched is None: |
551 | self.build.date_first_dispatched = UTC_NOW |
552 | |
553 | def jobReset(self): |
554 | - """See `ISoyuzJob`.""" |
555 | + """See `IBuildPackageJob`.""" |
556 | self.build.buildstate = BuildStatus.NEEDSBUILD |
557 | |
558 | def jobAborted(self): |
559 | - """See `ISoyuzJob`.""" |
560 | + """See `IBuildPackageJob`.""" |
561 | # XXX, al-maisan, Thu, 12 Nov 2009 16:38:52 +0100 |
562 | # The setting below was "inherited" from the previous code. We |
563 | # need to investigate whether and why this is really needed and |
564 | |
565 | === modified file 'lib/lp/soyuz/model/buildqueue.py' |
566 | --- lib/lp/soyuz/model/buildqueue.py 2009-11-13 08:49:14 +0000 |
567 | +++ lib/lp/soyuz/model/buildqueue.py 2009-11-13 20:00:40 +0000 |
568 | @@ -23,11 +23,11 @@ |
569 | from canonical.database.enumcol import EnumCol |
570 | from canonical.database.sqlbase import SQLBase, sqlvalues |
571 | from canonical.launchpad.webapp.interfaces import NotFoundError |
572 | +from lp.buildmaster.interfaces.buildfarmjob import BuildfarmJobType |
573 | from lp.services.job.interfaces.job import JobStatus |
574 | from lp.services.job.model.job import Job |
575 | from lp.soyuz.interfaces.build import BuildStatus, IBuildSet |
576 | from lp.soyuz.interfaces.buildqueue import IBuildQueue, IBuildQueueSet |
577 | -from lp.soyuz.interfaces.soyuzjob import SoyuzJobType |
578 | from lp.soyuz.model.buildpackagejob import BuildPackageJob |
579 | from canonical.launchpad.webapp.interfaces import ( |
580 | IStoreSelector, MAIN_STORE, DEFAULT_FLAVOR) |
581 | @@ -40,8 +40,8 @@ |
582 | |
583 | job = ForeignKey(dbName='job', foreignKey='Job', notNull=True) |
584 | job_type = EnumCol( |
585 | - enum=SoyuzJobType, notNull=True, default=SoyuzJobType.PACKAGEBUILD, |
586 | - dbName='job_type') |
587 | + enum=BuildfarmJobType, notNull=True, |
588 | + default=BuildfarmJobType.PACKAGEBUILD, dbName='job_type') |
589 | builder = ForeignKey(dbName='builder', foreignKey='Builder', default=None) |
590 | logtail = StringCol(dbName='logtail', default=None) |
591 | lastscore = IntCol(dbName='lastscore', default=0) |
592 | @@ -55,6 +55,11 @@ |
593 | BuildPackageJob, BuildPackageJob.job == self.job) |
594 | return result_set.one() |
595 | |
596 | + @property |
597 | + def date_started(self): |
598 | + """See `IBuildQueue`.""" |
599 | + return self.job.date_started |
600 | + |
601 | def manualScore(self, value): |
602 | """See `IBuildQueue`.""" |
603 | self.lastscore = value |
604 | @@ -71,14 +76,14 @@ |
605 | "%s (%d) MANUALLY RESCORED" % (name, self.lastscore)) |
606 | return |
607 | |
608 | - # Allow the `ISoyuzJob` instance with the data/logic specific to the |
609 | - # job at hand to calculate the score as appropriate. |
610 | + # Allow the `IBuildfarmJob` instance with the data/logic specific to |
611 | + # the job at hand to calculate the score as appropriate. |
612 | self.lastscore = self.specific_job.score() |
613 | |
614 | def getLogFileName(self): |
615 | """See `IBuildQueue`.""" |
616 | - # Allow the `ISoyuzJob` instance with the data/logic specific to the |
617 | - # job at hand to calculate the log file name as appropriate. |
618 | + # Allow the `IBuildfarmJob` instance with the data/logic specific to |
619 | + # the job at hand to calculate the log file name as appropriate. |
620 | return self.specific_job.getLogFileName() |
621 | |
622 | def markAsBuilding(self, builder): |
623 | @@ -189,7 +194,7 @@ |
624 | BuildPackageJob.build = build.id AND |
625 | BuildQueue.builder IS NULL |
626 | """ % sqlvalues( |
627 | - arch_ids, BuildStatus.NEEDSBUILD, SoyuzJobType.PACKAGEBUILD) |
628 | + arch_ids, BuildStatus.NEEDSBUILD, BuildfarmJobType.PACKAGEBUILD) |
629 | |
630 | candidates = BuildQueue.select( |
631 | query, clauseTables=['Build', 'BuildPackageJob'], |
Julian Edwards (julian-edwards) wrote : | # |
Nice work Muharem. Just a couple of things as I mentioned on IRC:
- you forgot to bzr add the __init__.py files in the new modules
- s/Buildfarm/
And then r=me! Land away on db-devel.
Preview Diff
1 | === modified file 'database/sampledata/current-dev.sql' |
2 | --- database/sampledata/current-dev.sql 2009-11-09 13:01:13 +0000 |
3 | +++ database/sampledata/current-dev.sql 2009-11-13 20:43:23 +0000 |
4 | @@ -745,6 +745,15 @@ |
5 | |
6 | |
7 | |
8 | + |
9 | + |
10 | + |
11 | + |
12 | + |
13 | + |
14 | + |
15 | + |
16 | + |
17 | ALTER TABLE account DISABLE TRIGGER ALL; |
18 | |
19 | INSERT INTO account (id, date_created, creation_rationale, status, date_status_set, displayname, openid_identifier, status_comment, old_openid_identifier) VALUES (1, '2005-06-06 08:59:51.591618', 8, 20, '2005-06-06 08:59:51.591618', 'Mark Shuttleworth', 'mark_oid', NULL, '123/mark'); |
20 | @@ -1695,10 +1704,19 @@ |
21 | ALTER TABLE builder ENABLE TRIGGER ALL; |
22 | |
23 | |
24 | +ALTER TABLE buildpackagejob DISABLE TRIGGER ALL; |
25 | + |
26 | +INSERT INTO buildpackagejob (id, job, build) VALUES (1, 1, 8); |
27 | +INSERT INTO buildpackagejob (id, job, build) VALUES (2, 2, 11); |
28 | + |
29 | + |
30 | +ALTER TABLE buildpackagejob ENABLE TRIGGER ALL; |
31 | + |
32 | + |
33 | ALTER TABLE buildqueue DISABLE TRIGGER ALL; |
34 | |
35 | -INSERT INTO buildqueue (id, build, builder, logtail, created, buildstart, lastscore, manual) VALUES (1, 8, 1, 'Dummy sampledata entry, not processing', '2005-06-15 09:14:12.820778', '2005-06-15 09:20:12.820778', 1, false); |
36 | -INSERT INTO buildqueue (id, build, builder, logtail, created, buildstart, lastscore, manual) VALUES (2, 11, NULL, NULL, '2005-06-15 10:14:12.820778', NULL, 10, false); |
37 | +INSERT INTO buildqueue (id, builder, logtail, lastscore, manual, job, job_type) VALUES (1, 1, 'Dummy sampledata entry, not processing', 1, false, 1, 1); |
38 | +INSERT INTO buildqueue (id, builder, logtail, lastscore, manual, job, job_type) VALUES (2, NULL, NULL, 10, false, 2, 1); |
39 | |
40 | |
41 | ALTER TABLE buildqueue ENABLE TRIGGER ALL; |
42 | @@ -2781,6 +2799,8 @@ |
43 | |
44 | ALTER TABLE job DISABLE TRIGGER ALL; |
45 | |
46 | +INSERT INTO job (id, requester, reason, status, progress, last_report_seen, next_report_due, attempt_count, max_retries, log, scheduled_start, lease_expires, date_created, date_started, date_finished) VALUES (1, NULL, NULL, 0, NULL, NULL, NULL, 0, 0, NULL, NULL, NULL, '2005-06-15 09:14:12.820778', '2005-06-15 09:20:12.820778', NULL); |
47 | +INSERT INTO job (id, requester, reason, status, progress, last_report_seen, next_report_due, attempt_count, max_retries, log, scheduled_start, lease_expires, date_created, date_started, date_finished) VALUES (2, NULL, NULL, 0, NULL, NULL, NULL, 0, 0, NULL, NULL, NULL, '2005-06-15 10:14:12.820778', NULL, NULL); |
48 | |
49 | |
50 | ALTER TABLE job ENABLE TRIGGER ALL; |
51 | @@ -4615,6 +4635,13 @@ |
52 | ALTER TABLE packageset ENABLE TRIGGER ALL; |
53 | |
54 | |
55 | +ALTER TABLE packagesetgroup DISABLE TRIGGER ALL; |
56 | + |
57 | + |
58 | + |
59 | +ALTER TABLE packagesetgroup ENABLE TRIGGER ALL; |
60 | + |
61 | + |
62 | ALTER TABLE packagesetinclusion DISABLE TRIGGER ALL; |
63 | |
64 | |
65 | @@ -8569,6 +8596,13 @@ |
66 | ALTER TABLE signedcodeofconduct ENABLE TRIGGER ALL; |
67 | |
68 | |
69 | +ALTER TABLE sourcepackageformatselection DISABLE TRIGGER ALL; |
70 | + |
71 | + |
72 | + |
73 | +ALTER TABLE sourcepackageformatselection ENABLE TRIGGER ALL; |
74 | + |
75 | + |
76 | ALTER TABLE sourcepackagename DISABLE TRIGGER ALL; |
77 | |
78 | INSERT INTO sourcepackagename (id, name) VALUES (1, 'mozilla-firefox'); |
79 | |
80 | === modified file 'database/sampledata/current.sql' |
81 | --- database/sampledata/current.sql 2009-11-05 10:51:36 +0000 |
82 | +++ database/sampledata/current.sql 2009-11-13 20:43:23 +0000 |
83 | @@ -745,6 +745,15 @@ |
84 | |
85 | |
86 | |
87 | + |
88 | + |
89 | + |
90 | + |
91 | + |
92 | + |
93 | + |
94 | + |
95 | + |
96 | ALTER TABLE account DISABLE TRIGGER ALL; |
97 | |
98 | INSERT INTO account (id, date_created, creation_rationale, status, date_status_set, displayname, openid_identifier, status_comment, old_openid_identifier) VALUES (11, '2005-06-06 08:59:51.591618', 8, 20, '2005-06-06 08:59:51.591618', 'Mark Shuttleworth', 'mark_oid', NULL, '123/mark'); |
99 | @@ -1677,10 +1686,19 @@ |
100 | ALTER TABLE builder ENABLE TRIGGER ALL; |
101 | |
102 | |
103 | +ALTER TABLE buildpackagejob DISABLE TRIGGER ALL; |
104 | + |
105 | +INSERT INTO buildpackagejob (id, job, build) VALUES (1, 1, 8); |
106 | +INSERT INTO buildpackagejob (id, job, build) VALUES (2, 2, 11); |
107 | + |
108 | + |
109 | +ALTER TABLE buildpackagejob ENABLE TRIGGER ALL; |
110 | + |
111 | + |
112 | ALTER TABLE buildqueue DISABLE TRIGGER ALL; |
113 | |
114 | -INSERT INTO buildqueue (id, build, builder, logtail, created, buildstart, lastscore, manual) VALUES (1, 8, 1, 'Dummy sampledata entry, not processing', '2005-06-15 09:14:12.820778', '2005-06-15 09:20:12.820778', 1, false); |
115 | -INSERT INTO buildqueue (id, build, builder, logtail, created, buildstart, lastscore, manual) VALUES (2, 11, NULL, NULL, '2005-06-15 10:14:12.820778', NULL, 10, false); |
116 | +INSERT INTO buildqueue (id, builder, logtail, lastscore, manual, job, job_type) VALUES (1, 1, 'Dummy sampledata entry, not processing', 1, false, 1, 1); |
117 | +INSERT INTO buildqueue (id, builder, logtail, lastscore, manual, job, job_type) VALUES (2, NULL, NULL, 10, false, 2, 1); |
118 | |
119 | |
120 | ALTER TABLE buildqueue ENABLE TRIGGER ALL; |
121 | @@ -2753,6 +2771,8 @@ |
122 | |
123 | ALTER TABLE job DISABLE TRIGGER ALL; |
124 | |
125 | +INSERT INTO job (id, requester, reason, status, progress, last_report_seen, next_report_due, attempt_count, max_retries, log, scheduled_start, lease_expires, date_created, date_started, date_finished) VALUES (1, NULL, NULL, 0, NULL, NULL, NULL, 0, 0, NULL, NULL, NULL, '2005-06-15 09:14:12.820778', '2005-06-15 09:20:12.820778', NULL); |
126 | +INSERT INTO job (id, requester, reason, status, progress, last_report_seen, next_report_due, attempt_count, max_retries, log, scheduled_start, lease_expires, date_created, date_started, date_finished) VALUES (2, NULL, NULL, 0, NULL, NULL, NULL, 0, 0, NULL, NULL, NULL, '2005-06-15 10:14:12.820778', NULL, NULL); |
127 | |
128 | |
129 | ALTER TABLE job ENABLE TRIGGER ALL; |
130 | @@ -4579,6 +4599,13 @@ |
131 | ALTER TABLE packageset ENABLE TRIGGER ALL; |
132 | |
133 | |
134 | +ALTER TABLE packagesetgroup DISABLE TRIGGER ALL; |
135 | + |
136 | + |
137 | + |
138 | +ALTER TABLE packagesetgroup ENABLE TRIGGER ALL; |
139 | + |
140 | + |
141 | ALTER TABLE packagesetinclusion DISABLE TRIGGER ALL; |
142 | |
143 | |
144 | @@ -8500,6 +8527,13 @@ |
145 | ALTER TABLE signedcodeofconduct ENABLE TRIGGER ALL; |
146 | |
147 | |
148 | +ALTER TABLE sourcepackageformatselection DISABLE TRIGGER ALL; |
149 | + |
150 | + |
151 | + |
152 | +ALTER TABLE sourcepackageformatselection ENABLE TRIGGER ALL; |
153 | + |
154 | + |
155 | ALTER TABLE sourcepackagename DISABLE TRIGGER ALL; |
156 | |
157 | INSERT INTO sourcepackagename (id, name) VALUES (1, 'mozilla-firefox'); |
158 | |
159 | === modified file 'database/schema/comments.sql' |
160 | --- database/schema/comments.sql 2009-11-02 15:33:35 +0000 |
161 | +++ database/schema/comments.sql 2009-11-13 20:43:23 +0000 |
162 | @@ -1531,14 +1531,13 @@ |
163 | COMMENT ON COLUMN Builder.active IS 'Whether to present or not the builder in the public list of builders avaialble. It is used to hide transient or defunct builders while they get fixed.'; |
164 | |
165 | -- BuildQueue |
166 | -COMMENT ON TABLE BuildQueue IS 'BuildQueue: The queue of builds in progress/scheduled to run. This table is the core of the build daemon master. It lists all builds in progress or scheduled to start.'; |
167 | -COMMENT ON COLUMN BuildQueue.build IS 'The build for which this queue item exists. This is how the buildd master will find all the files it needs to perform the build'; |
168 | +COMMENT ON TABLE BuildQueue IS 'BuildQueue: The queue of jobs in progress/scheduled to run on the Soyuz build farm.'; |
169 | COMMENT ON COLUMN BuildQueue.builder IS 'The builder assigned to this build. Some builds will have a builder assigned to queue them up; some will be building on the specified builder already; others will not have a builder yet (NULL) and will be waiting to be assigned into a builder''s queue'; |
170 | -COMMENT ON COLUMN BuildQueue.created IS 'The timestamp of the creation of this row. This is used by the buildd master scheduling algorithm to decide how soon to schedule a build to run on a given builder.'; |
171 | -COMMENT ON COLUMN BuildQueue.buildstart IS 'The timestamp of the start of the build run on the given builder. If this is NULL then the build is not running yet.'; |
172 | COMMENT ON COLUMN BuildQueue.logtail IS 'The tail end of the log of the current build. This is updated regularly as the buildd master polls the buildd slaves. Once the build is complete; the full log will be lodged with the librarian and linked into the build table.'; |
173 | COMMENT ON COLUMN BuildQueue.lastscore IS 'The last score ascribed to this build record. This can be used in the UI among other places.'; |
174 | COMMENT ON COLUMN BuildQueue.manual IS 'Indicates if the current record was or not rescored manually, if so it get skipped from the auto-score procedure.'; |
175 | +COMMENT ON COLUMN BuildQueue.job IS 'Foreign key to the `Job` table row with the generic job data.'; |
176 | +COMMENT ON COLUMN BuildQueue.job_type IS 'Type of job (enumeration value), enables us to find/query the correct table with the data specific to this type of job.'; |
177 | |
178 | -- Mirrors |
179 | |
180 | |
181 | === added file 'database/schema/patch-2207-11-0.sql' |
182 | --- database/schema/patch-2207-11-0.sql 1970-01-01 00:00:00 +0000 |
183 | +++ database/schema/patch-2207-11-0.sql 2009-11-13 20:43:23 +0000 |
184 | @@ -0,0 +1,87 @@ |
185 | +-- Copyright 2009 Canonical Ltd. This software is licensed under the |
186 | +-- GNU Affero General Public License version 3 (see the file LICENSE). |
187 | + |
188 | +SET client_min_messages=ERROR; |
189 | + |
190 | +-- The schema patch required for the Soyuz buildd generalisation, see |
191 | +-- https://dev.launchpad.net/Soyuz/Specs/BuilddGeneralisation for details. |
192 | +-- Bug #478919. |
193 | + |
194 | +-- Step 1 |
195 | +-- The `BuildPackageJob` table captures whatever data is required for |
196 | +-- "normal" Soyuz build farm jobs that build source packages. |
197 | + |
198 | +CREATE TABLE buildpackagejob ( |
199 | + id serial PRIMARY KEY, |
200 | + -- FK to the `Job` record with "generic" data about this source package |
201 | + -- build job. Please note that the corresponding `BuildQueue` row will |
202 | + -- have a FK referencing the same `Job` row. |
203 | + job integer NOT NULL CONSTRAINT buildpackagejob__job__fk REFERENCES job, |
204 | + -- FK to the associated `Build` record. |
205 | + build integer NOT NULL CONSTRAINT buildpackagejob__build__fk REFERENCES build |
206 | +); |
207 | + |
208 | +-- Step 2 |
209 | +-- Changes needed to the `BuildQueue` table. |
210 | + |
211 | +-- The 'job' and the 'job_type' columns will enable us to find the correct |
212 | +-- database rows that hold the generic and the specific data pertaining to |
213 | +-- the job respectively. |
214 | +ALTER TABLE ONLY buildqueue ADD COLUMN job integer; |
215 | +ALTER TABLE ONLY buildqueue ADD COLUMN job_type integer NOT NULL DEFAULT 1; |
216 | + |
217 | +-- Step 3 |
218 | +-- Data migration for the existing `BuildQueue` records. |
219 | +CREATE OR REPLACE FUNCTION migrate_buildqueue_rows() RETURNS integer |
220 | +LANGUAGE plpgsql AS |
221 | +$$ |
222 | +DECLARE |
223 | + queue_row RECORD; |
224 | + job_id integer; |
225 | + buildpackagejob_id integer; |
226 | + rows_migrated integer; |
227 | +BEGIN |
228 | + rows_migrated := 0; |
229 | + FOR queue_row IN SELECT * FROM buildqueue LOOP |
230 | + INSERT INTO job(status, date_created, date_started) VALUES(0, queue_row.created, queue_row.buildstart); |
231 | + -- Get the key of the `Job` row just inserted. |
232 | + SELECT currval('job_id_seq') INTO job_id; |
233 | + INSERT INTO buildpackagejob(job, build) VALUES(job_id, queue_row.build); |
234 | + -- Get the key of the `BuildPackageJob` row just inserted. |
235 | + SELECT currval('buildpackagejob_id_seq') INTO buildpackagejob_id; |
236 | + UPDATE buildqueue SET job=job_id WHERE id=queue_row.id; |
237 | + rows_migrated := rows_migrated + 1; |
238 | + END LOOP; |
239 | + RETURN rows_migrated; |
240 | +END; |
241 | +$$; |
242 | + |
243 | +-- Run the data migration function. |
244 | +SELECT * FROM migrate_buildqueue_rows(); |
245 | +-- The `BuildQueue` data is migrated at this point, we can get rid of the |
246 | +-- data migration function. |
247 | +DROP FUNCTION migrate_buildqueue_rows(); |
248 | + |
249 | +-- Now that the data was migrated we can make the 'job' column mandatory |
250 | +-- and define the foreign key constraint for it. |
251 | +ALTER TABLE ONLY buildqueue ALTER COLUMN job SET NOT NULL; |
252 | +ALTER TABLE ONLY buildqueue |
253 | + ADD CONSTRAINT buildqueue__job__fk |
254 | + FOREIGN KEY (job) REFERENCES job(id); |
255 | + |
256 | +-- Step 4 |
257 | +-- Now remove the obsolete columns, constraints and indexes from `BuildQueue`. |
258 | +-- The latter will from now on refer to the `Build` record via the |
259 | +-- `Job`/`BuildPackageJob` tables (and not directly any more). |
260 | +DROP INDEX buildqueue__build__idx; |
261 | +ALTER TABLE ONLY buildqueue DROP CONSTRAINT "$1"; |
262 | +ALTER TABLE ONLY buildqueue DROP COLUMN build; |
263 | +ALTER TABLE ONLY buildqueue DROP COLUMN created; |
264 | +ALTER TABLE ONLY buildqueue DROP COLUMN buildstart; |
265 | + |
266 | +-- Step 5 |
267 | +-- Add indexes for the new `BuildQueue` columns. |
268 | +CREATE INDEX buildqueue__job__idx ON buildqueue(job); |
269 | +CREATE INDEX buildqueue__job_type__idx ON buildqueue(job_type); |
270 | + |
271 | +INSERT INTO LaunchpadDatabaseRevision VALUES (2207, 11, 0); |
272 | |
273 | === modified file 'database/schema/security.cfg' |
274 | --- database/schema/security.cfg 2009-11-06 01:16:21 +0000 |
275 | +++ database/schema/security.cfg 2009-11-13 20:43:23 +0000 |
276 | @@ -837,6 +837,8 @@ |
277 | public.archivearch = SELECT, UPDATE |
278 | public.archivedependency = SELECT |
279 | public.buildqueue = SELECT, INSERT, UPDATE, DELETE |
280 | +public.job = SELECT, INSERT, UPDATE, DELETE |
281 | +public.buildpackagejob = SELECT, INSERT, UPDATE, DELETE |
282 | public.builder = SELECT, INSERT, UPDATE |
283 | public.build = SELECT, INSERT, UPDATE |
284 | public.distribution = SELECT, UPDATE |
285 | @@ -928,6 +930,8 @@ |
286 | public.build = SELECT, INSERT, UPDATE |
287 | public.builder = SELECT, INSERT, UPDATE |
288 | public.buildqueue = SELECT, INSERT, UPDATE, DELETE |
289 | +public.job = SELECT, INSERT, UPDATE, DELETE |
290 | +public.buildpackagejob = SELECT, INSERT, UPDATE, DELETE |
291 | public.component = SELECT, INSERT, UPDATE |
292 | public.componentselection = SELECT, INSERT, UPDATE |
293 | public.country = SELECT, INSERT, UPDATE |
294 | @@ -1114,6 +1118,8 @@ |
295 | public.pocketchroot = SELECT |
296 | public.build = SELECT, INSERT, UPDATE |
297 | public.buildqueue = SELECT, INSERT, UPDATE |
298 | +public.job = SELECT, INSERT, UPDATE |
299 | +public.buildpackagejob = SELECT, INSERT, UPDATE |
300 | |
301 | # Thusly the librarian |
302 | public.libraryfilecontent = SELECT, INSERT |
303 | @@ -1195,6 +1201,8 @@ |
304 | public.distrocomponentuploader = SELECT |
305 | public.build = SELECT, INSERT, UPDATE |
306 | public.buildqueue = SELECT, INSERT, UPDATE |
307 | +public.job = SELECT, INSERT, UPDATE |
308 | +public.buildpackagejob = SELECT, INSERT, UPDATE |
309 | public.pocketchroot = SELECT |
310 | public.sourcepackagerelease = SELECT, UPDATE |
311 | public.binarypackagerelease = SELECT, UPDATE |
312 | |
313 | === modified file 'lib/lp/buildmaster/buildergroup.py' |
314 | --- lib/lp/buildmaster/buildergroup.py 2009-08-16 12:38:12 +0000 |
315 | +++ lib/lp/buildmaster/buildergroup.py 2009-11-13 20:43:22 +0000 |
316 | @@ -130,8 +130,9 @@ |
317 | try: |
318 | build = getUtility(IBuildSet).getByBuildID(int(build_id)) |
319 | queue_item = getUtility(IBuildQueueSet).get(int(queue_item_id)) |
320 | - # Also check it build and buildqueue are properly related. |
321 | - if queue_item.build.id != build.id: |
322 | + queued_build = getUtility(IBuildSet).getByQueueEntry(queue_item) |
323 | + # Also check whether build and buildqueue are properly related. |
324 | + if queued_build.id != build.id: |
325 | raise BuildJobMismatch('Job build entry mismatch') |
326 | |
327 | except (SQLObjectNotFound, NotFoundError, BuildJobMismatch), reason: |
328 | @@ -159,9 +160,10 @@ |
329 | |
330 | Invoke getFileFromSlave method with 'buildlog' identifier. |
331 | """ |
332 | + build = getUtility(IBuildSet).getByQueueEntry(queueItem) |
333 | return queueItem.builder.transferSlaveFileToLibrarian( |
334 | 'buildlog', queueItem.getLogFileName(), |
335 | - queueItem.build.archive.private) |
336 | + build.archive.private) |
337 | |
338 | def updateBuild(self, queueItem): |
339 | """Verify the current build job status. |
340 | @@ -199,7 +201,7 @@ |
341 | "Unknown status code (%s) returned from status() probe." |
342 | % builder_status) |
343 | queueItem.builder = None |
344 | - queueItem.buildstart = None |
345 | + queueItem.setDateStarted(None) |
346 | self.commit() |
347 | return |
348 | |
349 | @@ -261,17 +263,18 @@ |
350 | |
351 | Store Buildlog, datebuilt, duration, dependencies. |
352 | """ |
353 | - queueItem.build.buildlog = self.getLogFromSlave(queueItem) |
354 | - queueItem.build.builder = queueItem.builder |
355 | - queueItem.build.dependencies = dependencies |
356 | + build = getUtility(IBuildSet).getByQueueEntry(queueItem) |
357 | + build.buildlog = self.getLogFromSlave(queueItem) |
358 | + build.builder = queueItem.builder |
359 | + build.dependencies = dependencies |
360 | # XXX cprov 20060615 bug=120584: Currently buildduration includes |
361 | # the scanner latency, it should really be asking the slave for |
362 | # the duration spent building locally. |
363 | - queueItem.build.datebuilt = UTC_NOW |
364 | + build.datebuilt = UTC_NOW |
365 | # We need dynamic datetime.now() instance to be able to perform |
366 | # the time operations for duration. |
367 | RIGHT_NOW = datetime.datetime.now(pytz.timezone('UTC')) |
368 | - queueItem.build.buildduration = RIGHT_NOW - queueItem.buildstart |
369 | + build.buildduration = RIGHT_NOW - queueItem.date_started |
370 | |
371 | |
372 | def buildStatus_OK(self, queueItem, librarian, buildid, |
373 | @@ -287,7 +290,7 @@ |
374 | self.logger.debug("Processing successful build %s" % buildid) |
375 | # Explode before collect a binary that is denied in this |
376 | # distroseries/pocket |
377 | - build = queueItem.build |
378 | + build = getUtility(IBuildSet).getByQueueEntry(queueItem) |
379 | if not build.archive.allowUpdatesToReleasePocket(): |
380 | assert build.distroseries.canUploadToPocket(build.pocket), ( |
381 | "%s (%s) can not be built for pocket %s: illegal status" |
382 | @@ -309,8 +312,9 @@ |
383 | # can be correctly found during the upload: |
384 | # <archive_id>/distribution_name |
385 | # for all destination archive types. |
386 | - archive = queueItem.build.archive |
387 | - distribution_name = queueItem.build.distribution.name |
388 | + build = getUtility(IBuildSet).getByQueueEntry(queueItem) |
389 | + archive = build.archive |
390 | + distribution_name = build.distribution.name |
391 | target_path = '%s/%s' % (archive.id, distribution_name) |
392 | upload_path = os.path.join(upload_dir, target_path) |
393 | os.makedirs(upload_path) |
394 | @@ -330,10 +334,10 @@ |
395 | # add extra arguments for processing a binary upload |
396 | extra_args = [ |
397 | "--log-file", "%s" % uploader_logfilename, |
398 | - "-d", "%s" % queueItem.build.distribution.name, |
399 | - "-s", "%s" % (queueItem.build.distroseries.name + |
400 | - pocketsuffix[queueItem.build.pocket]), |
401 | - "-b", "%s" % queueItem.build.id, |
402 | + "-d", "%s" % build.distribution.name, |
403 | + "-s", "%s" % (build.distroseries.name + |
404 | + pocketsuffix[build.pocket]), |
405 | + "-b", "%s" % build.id, |
406 | "-J", "%s" % upload_leaf, |
407 | "%s" % root, |
408 | ] |
409 | @@ -409,12 +413,11 @@ |
410 | # uploader about this occurrence. The failure notification will |
411 | # also contain the information required to manually reprocess the |
412 | # binary upload when it was the case. |
413 | - build = getUtility(IBuildSet).getByBuildID(queueItem.build.id) |
414 | + build = getUtility(IBuildSet).getByQueueEntry(queueItem) |
415 | if (build.buildstate != BuildStatus.FULLYBUILT or |
416 | build.binarypackages.count() == 0): |
417 | self.logger.debug("Build %s upload failed." % build.id) |
418 | - # update builder |
419 | - queueItem.build.buildstate = BuildStatus.FAILEDTOUPLOAD |
420 | + build.buildstate = BuildStatus.FAILEDTOUPLOAD |
421 | # Retrieve log file content. |
422 | possible_locations = ( |
423 | 'failed', 'failed-to-move', 'rejected', 'accepted') |
424 | @@ -434,11 +437,13 @@ |
425 | uploader_log_content = 'Could not find upload log file' |
426 | # Store the upload_log_contents in librarian so it can be |
427 | # accessed by anyone with permission to see the build. |
428 | - queueItem.build.storeUploadLog(uploader_log_content) |
429 | + build.storeUploadLog(uploader_log_content) |
430 | # Notify the build failure. |
431 | - queueItem.build.notify(extra_info=uploader_log_content) |
432 | + build.notify(extra_info=uploader_log_content) |
433 | else: |
434 | - self.logger.debug("Gathered build %s completely" % queueItem.name) |
435 | + self.logger.debug( |
436 | + "Gathered build %s completely" % |
437 | + build.sourcepackagerelease.name) |
438 | |
439 | # Release the builder for another job. |
440 | queueItem.builder.cleanSlave() |
441 | @@ -456,10 +461,11 @@ |
442 | set the job status as FAILEDTOBUILD, store available info and |
443 | remove Buildqueue entry. |
444 | """ |
445 | - queueItem.build.buildstate = BuildStatus.FAILEDTOBUILD |
446 | + build = getUtility(IBuildSet).getByQueueEntry(queueItem) |
447 | + build.buildstate = BuildStatus.FAILEDTOBUILD |
448 | self.storeBuildInfo(queueItem, librarian, buildid, dependencies) |
449 | queueItem.builder.cleanSlave() |
450 | - queueItem.build.notify() |
451 | + build.notify() |
452 | queueItem.destroySelf() |
453 | |
454 | def buildStatus_DEPFAIL(self, queueItem, librarian, buildid, |
455 | @@ -470,7 +476,8 @@ |
456 | MANUALDEPWAIT, store available information, remove BuildQueue |
457 | entry and release builder slave for another job. |
458 | """ |
459 | - queueItem.build.buildstate = BuildStatus.MANUALDEPWAIT |
460 | + build = getUtility(IBuildSet).getByQueueEntry(queueItem) |
461 | + build.buildstate = BuildStatus.MANUALDEPWAIT |
462 | self.storeBuildInfo(queueItem, librarian, buildid, dependencies) |
463 | self.logger.critical("***** %s is MANUALDEPWAIT *****" |
464 | % queueItem.builder.name) |
465 | @@ -485,12 +492,13 @@ |
466 | job as CHROOTFAIL, store available information, remove BuildQueue |
467 | and release the builder. |
468 | """ |
469 | - queueItem.build.buildstate = BuildStatus.CHROOTWAIT |
470 | + build = getUtility(IBuildSet).getByQueueEntry(queueItem) |
471 | + build.buildstate = BuildStatus.CHROOTWAIT |
472 | self.storeBuildInfo(queueItem, librarian, buildid, dependencies) |
473 | self.logger.critical("***** %s is CHROOTWAIT *****" % |
474 | queueItem.builder.name) |
475 | queueItem.builder.cleanSlave() |
476 | - queueItem.build.notify() |
477 | + build.notify() |
478 | queueItem.destroySelf() |
479 | |
480 | def buildStatus_BUILDERFAIL(self, queueItem, librarian, buildid, |
481 | @@ -507,10 +515,11 @@ |
482 | ("Builder returned BUILDERFAIL when asked " |
483 | "for its status")) |
484 | # simply reset job |
485 | - queueItem.build.buildstate = BuildStatus.NEEDSBUILD |
486 | + build = getUtility(IBuildSet).getByQueueEntry(queueItem) |
487 | + build.buildstate = BuildStatus.NEEDSBUILD |
488 | self.storeBuildInfo(queueItem, librarian, buildid, dependencies) |
489 | queueItem.builder = None |
490 | - queueItem.buildstart = None |
491 | + queueItem.setDateStarted(None) |
492 | |
493 | def buildStatus_GIVENBACK(self, queueItem, librarian, buildid, |
494 | filemap=None, dependencies=None): |
495 | @@ -522,7 +531,8 @@ |
496 | """ |
497 | self.logger.warning("***** %s is GIVENBACK by %s *****" |
498 | % (buildid, queueItem.builder.name)) |
499 | - queueItem.build.buildstate = BuildStatus.NEEDSBUILD |
500 | + build = getUtility(IBuildSet).getByQueueEntry(queueItem) |
501 | + build.buildstate = BuildStatus.NEEDSBUILD |
502 | self.storeBuildInfo(queueItem, librarian, buildid, dependencies) |
503 | # XXX cprov 2006-05-30: Currently this information is not |
504 | # properly presented in the Web UI. We will discuss it in |
505 | @@ -530,7 +540,7 @@ |
506 | # to use this content. For now we just ensure it's stored. |
507 | queueItem.builder.cleanSlave() |
508 | queueItem.builder = None |
509 | - queueItem.buildstart = None |
510 | + queueItem.setDateStarted(None) |
511 | queueItem.logtail = None |
512 | queueItem.lastscore = 0 |
513 | |
514 | |
515 | === added directory 'lib/lp/buildmaster/interfaces' |
516 | === added file 'lib/lp/buildmaster/interfaces/__init__.py' |
517 | === added file 'lib/lp/buildmaster/interfaces/buildfarmjob.py' |
518 | --- lib/lp/buildmaster/interfaces/buildfarmjob.py 1970-01-01 00:00:00 +0000 |
519 | +++ lib/lp/buildmaster/interfaces/buildfarmjob.py 2009-11-13 20:43:23 +0000 |
520 | @@ -0,0 +1,71 @@ |
521 | +# Copyright 2009 Canonical Ltd. This software is licensed under the |
522 | +# GNU Affero General Public License version 3 (see the file LICENSE). |
523 | + |
524 | +# pylint: disable-msg=E0211,E0213 |
525 | + |
526 | +"""Interface for Soyuz build farm jobs.""" |
527 | + |
528 | +__metaclass__ = type |
529 | + |
530 | +__all__ = [ |
531 | + 'IBuildFarmJob', |
532 | + 'BuildFarmJobType', |
533 | + ] |
534 | + |
535 | +from zope.interface import Interface |
536 | +from lazr.enum import DBEnumeratedType, DBItem |
537 | + |
538 | + |
539 | +class BuildFarmJobType(DBEnumeratedType): |
540 | + """Soyuz build farm job type. |
541 | + |
542 | + An enumeration with the types of jobs that may be run on the Soyuz build |
543 | + farm. |
544 | + """ |
545 | + |
546 | + PACKAGEBUILD = DBItem(1, """ |
547 | + PackageBuildJob |
548 | + |
549 | + Build a source package. |
550 | + """) |
551 | + |
552 | + BRANCHBUILD = DBItem(2, """ |
553 | + BranchBuildJob |
554 | + |
555 | + Build a package from a bazaar branch. |
556 | + """) |
557 | + |
558 | + RECIPEBRANCHBUILD = DBItem(3, """ |
559 | + RecipeBranchBuildJob |
560 | + |
561 | + Build a package from a bazaar branch and a recipe. |
562 | + """) |
563 | + |
564 | + TRANSLATION = DBItem(4, """ |
565 | + TranslationJob |
566 | + |
567 | + Perform a translation job. |
568 | + """) |
569 | + |
570 | + |
571 | +class IBuildFarmJob(Interface): |
572 | + """Operations that Soyuz build farm jobs must implement.""" |
573 | + |
574 | + def score(): |
575 | + """Calculate a job score appropriate for the job type in question.""" |
576 | + |
577 | + def getLogFileName(): |
578 | + """The preferred file name for the log of this Soyuz job.""" |
579 | + |
580 | + def getName(): |
581 | + """An appropriate name for this Soyuz job.""" |
582 | + |
583 | + def jobStarted(): |
584 | + """'Job started' life cycle event, handle as appropriate.""" |
585 | + |
586 | + def jobReset(): |
587 | + """'Job reset' life cycle event, handle as appropriate.""" |
588 | + |
589 | + def jobAborted(): |
590 | + """'Job aborted' life cycle event, handle as appropriate.""" |
591 | + |
592 | |
593 | === modified file 'lib/lp/buildmaster/master.py' |
594 | --- lib/lp/buildmaster/master.py 2009-10-26 18:40:04 +0000 |
595 | +++ lib/lp/buildmaster/master.py 2009-11-13 20:43:23 +0000 |
596 | @@ -280,8 +280,10 @@ |
597 | "scanActiveBuilders() found %d active build(s) to check" |
598 | % queueItems.count()) |
599 | |
600 | + build_set = getUtility(IBuildSet) |
601 | for job in queueItems: |
602 | - proc = job.archseries.processorfamily |
603 | + build = build_set.getByQueueEntry(job) |
604 | + proc = build.distroarchseries.processorfamily |
605 | try: |
606 | builders = notes[proc]["builders"] |
607 | except KeyError: |
608 | @@ -309,7 +311,7 @@ |
609 | % candidates.count()) |
610 | |
611 | for job in candidates: |
612 | - uptodate_build = getUtility(IBuildSet).getByBuildID(job.build.id) |
613 | + uptodate_build = getUtility(IBuildSet).getByQueueEntry(job) |
614 | if uptodate_build.buildstate != BuildStatus.NEEDSBUILD: |
615 | continue |
616 | job.score() |
617 | |
618 | === added directory 'lib/lp/buildmaster/model' |
619 | === added file 'lib/lp/buildmaster/model/__init__.py' |
620 | === added file 'lib/lp/buildmaster/model/buildfarmjob.py' |
621 | --- lib/lp/buildmaster/model/buildfarmjob.py 1970-01-01 00:00:00 +0000 |
622 | +++ lib/lp/buildmaster/model/buildfarmjob.py 2009-11-13 20:43:23 +0000 |
623 | @@ -0,0 +1,40 @@ |
624 | +# Copyright 2009 Canonical Ltd. This software is licensed under the |
625 | +# GNU Affero General Public License version 3 (see the file LICENSE). |
626 | + |
627 | +__metaclass__ = type |
628 | +__all__ = ['BuildFarmJob'] |
629 | + |
630 | + |
631 | +from zope.interface import implements |
632 | + |
633 | +from lp.buildmaster.interfaces.buildfarmjob import IBuildFarmJob |
634 | + |
635 | + |
636 | +class BuildFarmJob: |
637 | + """Mix-in class for `IBuildFarmJob` implementations.""" |
638 | + implements(IBuildFarmJob) |
639 | + |
640 | + def score(self): |
641 | + """See `IBuildFarmJob`.""" |
642 | + raise NotImplementedError |
643 | + |
644 | + def getLogFileName(self): |
645 | + """See `IBuildFarmJob`.""" |
646 | + raise NotImplementedError |
647 | + |
648 | + def getName(self): |
649 | + """See `IBuildFarmJob`.""" |
650 | + raise NotImplementedError |
651 | + |
652 | + def jobStarted(self): |
653 | + """See `IBuildFarmJob`.""" |
654 | + pass |
655 | + |
656 | + def jobReset(self): |
657 | + """See `IBuildFarmJob`.""" |
658 | + pass |
659 | + |
660 | + def jobAborted(self): |
661 | + """See `IBuildFarmJob`.""" |
662 | + pass |
663 | + |
664 | |
665 | === modified file 'lib/lp/buildmaster/tests/queuebuilder.txt' |
666 | --- lib/lp/buildmaster/tests/queuebuilder.txt 2009-10-26 18:40:04 +0000 |
667 | +++ lib/lp/buildmaster/tests/queuebuilder.txt 2009-11-13 20:43:23 +0000 |
668 | @@ -229,7 +229,7 @@ |
669 | >>> copied_pub = pub_failed.copyTo( |
670 | ... hoary, PackagePublishingPocket.RELEASE, warty.main_archive) |
671 | |
672 | - >>> from lp.soyuz.interfaces.build import BuildStatus |
673 | + >>> from lp.soyuz.interfaces.build import BuildStatus, IBuildSet |
674 | >>> failed_build = pub_failed.sourcepackagerelease.createBuild( |
675 | ... warty['i386'], PackagePublishingPocket.RELEASE, |
676 | ... warty.main_archive, status=BuildStatus.FAILEDTOBUILD) |
677 | @@ -343,7 +343,8 @@ |
678 | happen in parallel with build creation. |
679 | |
680 | >>> build_queue = active_jobs[0] |
681 | - >>> print build_queue.build.title |
682 | + >>> build = getUtility(IBuildSet).getByQueueEntry(build_queue) |
683 | + >>> print build.title |
684 | i386 build of test-buildd 667 in ubuntu hoary RELEASE |
685 | >>> build_queue.lastscore |
686 | 2505 |
687 | @@ -351,15 +352,15 @@ |
688 | Check the published component name retriever, they might be different, |
689 | i.e., the published component can be different than the original component. |
690 | |
691 | - >>> print build_queue.build.current_component.name |
692 | + >>> print build.current_component.name |
693 | main |
694 | - >>> print build_queue.build.sourcepackagerelease.component.name |
695 | + >>> print build.sourcepackagerelease.component.name |
696 | main |
697 | |
698 | Missing BuildQueue records, resulting from given-back builds, are |
699 | created in the last stage of the queue-builder script. |
700 | |
701 | - >>> given_back_build = build_queue.build |
702 | + >>> given_back_build = getUtility(IBuildSet).getByQueueEntry(build_queue) |
703 | >>> build_queue.destroySelf() |
704 | >>> flush_database_updates() |
705 | |
706 | |
707 | === modified file 'lib/lp/buildmaster/tests/test_manager.py' |
708 | --- lib/lp/buildmaster/tests/test_manager.py 2009-09-07 13:02:02 +0000 |
709 | +++ lib/lp/buildmaster/tests/test_manager.py 2009-11-13 20:43:23 +0000 |
710 | @@ -24,7 +24,7 @@ |
711 | from lp.buildmaster.tests.harness import BuilddManagerTestSetup |
712 | from canonical.launchpad.ftests import ANONYMOUS, login |
713 | from lp.soyuz.tests.soyuzbuilddhelpers import SaneBuildingSlave |
714 | -from lp.soyuz.interfaces.build import BuildStatus |
715 | +from lp.soyuz.interfaces.build import BuildStatus, IBuildSet |
716 | from lp.soyuz.interfaces.builder import IBuilderSet |
717 | from lp.soyuz.interfaces.buildqueue import IBuildQueueSet |
718 | from lp.registry.interfaces.distribution import IDistributionSet |
719 | @@ -494,8 +494,9 @@ |
720 | |
721 | self.assertTrue(job is not None) |
722 | self.assertEqual(job.builder, builder) |
723 | - self.assertTrue(job.buildstart is not None) |
724 | - self.assertEqual(job.build.buildstate, BuildStatus.BUILDING) |
725 | + self.assertTrue(job.date_started is not None) |
726 | + build = getUtility(IBuildSet).getByQueueEntry(job) |
727 | + self.assertEqual(build.buildstate, BuildStatus.BUILDING) |
728 | self.assertEqual(job.logtail, logtail) |
729 | |
730 | def _getManager(self): |
731 | @@ -617,8 +618,9 @@ |
732 | |
733 | job = getUtility(IBuildQueueSet).get(job.id) |
734 | self.assertTrue(job.builder is None) |
735 | - self.assertTrue(job.buildstart is None) |
736 | - self.assertEqual(job.build.buildstate, BuildStatus.NEEDSBUILD) |
737 | + self.assertTrue(job.date_started is None) |
738 | + build = getUtility(IBuildSet).getByQueueEntry(job) |
739 | + self.assertEqual(build.buildstate, BuildStatus.NEEDSBUILD) |
740 | |
741 | def testScanRescuesJobFromBrokenBuilder(self): |
742 | # The job assigned to a broken builder is rescued. |
743 | @@ -701,13 +703,14 @@ |
744 | builder.builderok = True |
745 | |
746 | job = builder.currentjob |
747 | + build = getUtility(IBuildSet).getByQueueEntry(job) |
748 | self.assertEqual( |
749 | 'i386 build of mozilla-firefox 0.9 in ubuntu hoary RELEASE', |
750 | - job.build.title) |
751 | + build.title) |
752 | |
753 | - self.assertEqual('BUILDING', job.build.buildstate.name) |
754 | + self.assertEqual('BUILDING', build.buildstate.name) |
755 | self.assertNotEqual(None, job.builder) |
756 | - self.assertNotEqual(None, job.buildstart) |
757 | + self.assertNotEqual(None, job.date_started) |
758 | self.assertNotEqual(None, job.logtail) |
759 | |
760 | transaction.commit() |
761 | @@ -717,9 +720,10 @@ |
762 | def assertJobIsClean(self, job_id): |
763 | """Re-fetch the `IBuildQueue` record and check if it's clean.""" |
764 | job = getUtility(IBuildQueueSet).get(job_id) |
765 | - self.assertEqual('NEEDSBUILD', job.build.buildstate.name) |
766 | + build = getUtility(IBuildSet).getByQueueEntry(job) |
767 | + self.assertEqual('NEEDSBUILD', build.buildstate.name) |
768 | self.assertEqual(None, job.builder) |
769 | - self.assertEqual(None, job.buildstart) |
770 | + self.assertEqual(None, job.date_started) |
771 | self.assertEqual(None, job.logtail) |
772 | |
773 | def testResetDispatchResult(self): |
774 | |
775 | === modified file 'lib/lp/registry/model/sourcepackage.py' |
776 | --- lib/lp/registry/model/sourcepackage.py 2009-10-26 18:40:04 +0000 |
777 | +++ lib/lp/registry/model/sourcepackage.py 2009-11-13 20:43:23 +0000 |
778 | @@ -554,8 +554,10 @@ |
779 | # It should present the builds in a more natural order. |
780 | if build_state in [BuildStatus.NEEDSBUILD, BuildStatus.BUILDING]: |
781 | orderBy = ["-BuildQueue.lastscore"] |
782 | + clauseTables.append('BuildPackageJob') |
783 | + condition_clauses.append('BuildPackageJob.build = Build.id') |
784 | clauseTables.append('BuildQueue') |
785 | - condition_clauses.append('BuildQueue.build = Build.id') |
786 | + condition_clauses.append('BuildQueue.job = BuildPackageJob.job') |
787 | elif build_state == BuildStatus.SUPERSEDED or build_state is None: |
788 | orderBy = ["-Build.datecreated"] |
789 | else: |
790 | |
791 | === modified file 'lib/lp/services/job/tests/test_job.py' |
792 | --- lib/lp/services/job/tests/test_job.py 2009-07-17 00:26:05 +0000 |
793 | +++ lib/lp/services/job/tests/test_job.py 2009-11-13 20:43:23 +0000 |
794 | @@ -8,6 +8,8 @@ |
795 | from unittest import TestLoader |
796 | |
797 | import pytz |
798 | +from zope.component import getUtility |
799 | + |
800 | from canonical.database.constants import UTC_NOW |
801 | from canonical.testing import LaunchpadZopelessLayer |
802 | from storm.locals import Store |
803 | @@ -17,6 +19,8 @@ |
804 | from lp.services.job.interfaces.job import IJob, JobStatus |
805 | from lp.testing import TestCase |
806 | from canonical.launchpad.webapp.testing import verifyObject |
807 | +from canonical.launchpad.webapp.interfaces import ( |
808 | + IStoreSelector, MAIN_STORE, DEFAULT_FLAVOR) |
809 | |
810 | |
811 | class TestJob(TestCase): |
812 | @@ -155,40 +159,53 @@ |
813 | |
814 | layer = LaunchpadZopelessLayer |
815 | |
816 | + def _sampleData(self): |
817 | + store = getUtility(IStoreSelector).get(MAIN_STORE, DEFAULT_FLAVOR) |
818 | + return list(store.execute(Job.ready_jobs)) |
819 | + |
820 | def test_ready_jobs(self): |
821 | """Job.ready_jobs should include new jobs.""" |
822 | + preexisting = self._sampleData() |
823 | job = Job() |
824 | self.assertEqual( |
825 | - [(job.id,)], list(Store.of(job).execute(Job.ready_jobs))) |
826 | + preexisting + [(job.id,)], |
827 | + list(Store.of(job).execute(Job.ready_jobs))) |
828 | |
829 | def test_ready_jobs_started(self): |
830 | """Job.ready_jobs should not jobs that have been started.""" |
831 | + preexisting = self._sampleData() |
832 | job = Job(_status=JobStatus.RUNNING) |
833 | self.assertEqual( |
834 | - [], list(Store.of(job).execute(Job.ready_jobs))) |
835 | + preexisting, list(Store.of(job).execute(Job.ready_jobs))) |
836 | |
837 | def test_ready_jobs_lease_expired(self): |
838 | """Job.ready_jobs should include jobs with expired leases.""" |
839 | + preexisting = self._sampleData() |
840 | UNIX_EPOCH = datetime.fromtimestamp(0, pytz.timezone('UTC')) |
841 | job = Job(lease_expires=UNIX_EPOCH) |
842 | self.assertEqual( |
843 | - [(job.id,)], list(Store.of(job).execute(Job.ready_jobs))) |
844 | + preexisting + [(job.id,)], |
845 | + list(Store.of(job).execute(Job.ready_jobs))) |
846 | |
847 | def test_ready_jobs_lease_in_future(self): |
848 | """Job.ready_jobs should not include jobs with active leases.""" |
849 | + preexisting = self._sampleData() |
850 | future = datetime.fromtimestamp( |
851 | time.time() + 1000, pytz.timezone('UTC')) |
852 | job = Job(lease_expires=future) |
853 | - self.assertEqual([], list(Store.of(job).execute(Job.ready_jobs))) |
854 | + self.assertEqual( |
855 | + preexisting, list(Store.of(job).execute(Job.ready_jobs))) |
856 | |
857 | def test_ready_jobs_not_jobs_scheduled_in_future(self): |
858 | """Job.ready_jobs does not included jobs scheduled for a time in the |
859 | future. |
860 | """ |
861 | + preexisting = self._sampleData() |
862 | future = datetime.fromtimestamp( |
863 | time.time() + 1000, pytz.timezone('UTC')) |
864 | job = Job(scheduled_start=future) |
865 | - self.assertEqual([], list(Store.of(job).execute(Job.ready_jobs))) |
866 | + self.assertEqual( |
867 | + preexisting, list(Store.of(job).execute(Job.ready_jobs))) |
868 | |
869 | def test_acquireLease(self): |
870 | """Job.acquireLease should set job.lease_expires.""" |
871 | |
872 | === modified file 'lib/lp/soyuz/browser/build.py' |
873 | --- lib/lp/soyuz/browser/build.py 2009-10-26 18:40:04 +0000 |
874 | +++ lib/lp/soyuz/browser/build.py 2009-11-13 20:43:23 +0000 |
875 | @@ -288,10 +288,10 @@ |
876 | prefetched_data = dict() |
877 | build_ids = [build.id for build in builds] |
878 | results = getUtility(IBuildQueueSet).getForBuilds(build_ids) |
879 | - for (buildqueue, builder) in results: |
880 | + for (buildqueue, _builder, build_job) in results: |
881 | # Get the build's id, 'buildqueue', 'sourcepackagerelease' and |
882 | # 'buildlog' (from the result set) respectively. |
883 | - prefetched_data[buildqueue.build.id] = buildqueue |
884 | + prefetched_data[build_job.build.id] = buildqueue |
885 | |
886 | complete_builds = [] |
887 | for build in builds: |
888 | |
889 | === modified file 'lib/lp/soyuz/browser/builder.py' |
890 | --- lib/lp/soyuz/browser/builder.py 2009-09-17 14:45:15 +0000 |
891 | +++ lib/lp/soyuz/browser/builder.py 2009-11-13 20:43:23 +0000 |
892 | @@ -237,12 +237,12 @@ |
893 | def current_build_duration(self): |
894 | """Return the delta representing the duration of the current job.""" |
895 | if (self.context.currentjob is None or |
896 | - self.context.currentjob.buildstart is None): |
897 | + self.context.currentjob.date_started is None): |
898 | return None |
899 | else: |
900 | UTC = pytz.timezone('UTC') |
901 | - buildstart = self.context.currentjob.buildstart |
902 | - return datetime.datetime.now(UTC) - buildstart |
903 | + date_started = self.context.currentjob.date_started |
904 | + return datetime.datetime.now(UTC) - date_started |
905 | |
906 | @property |
907 | def page_title(self): |
908 | |
909 | === modified file 'lib/lp/soyuz/browser/tests/builder-views.txt' |
910 | --- lib/lp/soyuz/browser/tests/builder-views.txt 2009-09-16 19:06:48 +0000 |
911 | +++ lib/lp/soyuz/browser/tests/builder-views.txt 2009-11-13 20:43:23 +0000 |
912 | @@ -1,7 +1,7 @@ |
913 | = Builder View Classes and Pages = |
914 | |
915 | >>> from zope.component import getMultiAdapter, getUtility |
916 | - >>> from canonical.launchpad.interfaces import IBuilderSet |
917 | + >>> from canonical.launchpad.interfaces import IBuildSet, IBuilderSet |
918 | >>> from canonical.launchpad.webapp.servers import LaunchpadTestRequest |
919 | |
920 | >>> builder = getUtility(IBuilderSet).get(1) |
921 | @@ -158,7 +158,8 @@ |
922 | >>> frog = getUtility(IBuilderSet)['frog'] |
923 | >>> frog.builderok = True |
924 | >>> private_build.builder = frog |
925 | - >>> private_job = BuildQueue(build=private_build, builder=frog) |
926 | + >>> private_job = private_build.createBuildQueueEntry() |
927 | + >>> private_job.builder = frog |
928 | >>> private_job_id = private_job.id |
929 | |
930 | >>> from canonical.database.sqlbase import flush_database_caches |
931 | @@ -175,7 +176,9 @@ |
932 | >>> print frog.builderok |
933 | True |
934 | |
935 | - >>> print frog.currentjob.build.title |
936 | + >>> build_set = getUtility(IBuildSet) |
937 | + >>> build = build_set.getByQueueEntry(frog.currentjob) |
938 | + >>> print build.title |
939 | i386 build of privacy-test 666 in ubuntutest breezy-autotest RELEASE |
940 | |
941 | >>> print frog.failnotes |
942 | @@ -199,7 +202,8 @@ |
943 | >>> print admin_view.context.builderok |
944 | True |
945 | |
946 | - >>> print admin_view.context.currentjob.build.title |
947 | + >>> build = build_set.getByQueueEntry(admin_view.context.currentjob) |
948 | + >>> print build.title |
949 | i386 build of privacy-test 666 in ubuntutest breezy-autotest RELEASE |
950 | |
951 | >>> print admin_view.context.failnotes |
952 | @@ -211,7 +215,7 @@ |
953 | |
954 | >>> import datetime |
955 | >>> import pytz |
956 | - >>> private_job.buildstart = ( |
957 | + >>> private_job.setDateStarted( |
958 | ... datetime.datetime.now(pytz.UTC) - datetime.timedelta(10)) |
959 | >>> print admin_view.current_build_duration |
960 | 10 days... |
961 | |
962 | === modified file 'lib/lp/soyuz/configure.zcml' |
963 | --- lib/lp/soyuz/configure.zcml 2009-11-09 17:59:18 +0000 |
964 | +++ lib/lp/soyuz/configure.zcml 2009-11-13 20:43:23 +0000 |
965 | @@ -560,7 +560,7 @@ |
966 | |
967 | <require |
968 | permission="zope.Public" |
969 | - set_attributes="lastscore builder buildstart logtail"/> |
970 | + set_attributes="lastscore builder logtail date_started"/> |
971 | </class> |
972 | |
973 | <!-- BuildQueueSet --> |
974 | @@ -863,5 +863,11 @@ |
975 | interface="lp.soyuz.interfaces.packagesetgroup.IPackagesetGroup"/> |
976 | </class> |
977 | |
978 | + <!-- BuildPackageJob --> |
979 | + <class |
980 | + class="lp.soyuz.model.buildpackagejob.BuildPackageJob"> |
981 | + <allow |
982 | + interface="lp.soyuz.interfaces.buildpackagejob.IBuildPackageJob"/> |
983 | + </class> |
984 | |
985 | </configure> |
986 | |
987 | === modified file 'lib/lp/soyuz/doc/build-estimated-dispatch-time.txt' |
988 | --- lib/lp/soyuz/doc/build-estimated-dispatch-time.txt 2009-08-28 07:34:44 +0000 |
989 | +++ lib/lp/soyuz/doc/build-estimated-dispatch-time.txt 2009-11-13 20:43:22 +0000 |
990 | @@ -59,7 +59,8 @@ |
991 | >>> UTC = pytz.timezone('UTC') |
992 | >>> bob_the_builder = builder_set.get(1) |
993 | >>> cur_bqueue = bob_the_builder.currentjob |
994 | - >>> cur_build = cur_bqueue.build |
995 | + >>> from lp.soyuz.interfaces.build import IBuildSet |
996 | + >>> cur_build = getUtility(IBuildSet).getByQueueEntry(cur_bqueue) |
997 | |
998 | Make sure the job at hand is currently being built. |
999 | |
1000 | @@ -73,16 +74,16 @@ |
1001 | of job N in the build queue. These values will now be set for the job |
1002 | that is currently building. |
1003 | |
1004 | + >>> from zope.security.proxy import removeSecurityProxy |
1005 | >>> cur_bqueue.lastscore = 1111 |
1006 | - >>> cur_bqueue.buildstart = datetime(2008, 4, 1, 10, 45, 39, |
1007 | - ... tzinfo=UTC) |
1008 | - >>> print cur_bqueue.buildstart |
1009 | + >>> cur_bqueue.setDateStarted( |
1010 | + ... datetime(2008, 4, 1, 10, 45, 39, tzinfo=UTC)) |
1011 | + >>> print cur_bqueue.date_started |
1012 | 2008-04-01 10:45:39+00:00 |
1013 | |
1014 | Please note that the "estimated build duration" is an internal property |
1015 | and not meant to be viewed or modified by an end user. |
1016 | |
1017 | - >>> from zope.security.proxy import removeSecurityProxy |
1018 | >>> naked_build = removeSecurityProxy(cur_build) |
1019 | >>> naked_build.estimated_build_duration = timedelta(minutes=56) |
1020 | |
1021 | |
1022 | === modified file 'lib/lp/soyuz/doc/buildd-dispatching.txt' |
1023 | --- lib/lp/soyuz/doc/buildd-dispatching.txt 2009-10-14 08:20:40 +0000 |
1024 | +++ lib/lp/soyuz/doc/buildd-dispatching.txt 2009-11-13 20:43:23 +0000 |
1025 | @@ -134,18 +134,20 @@ |
1026 | |
1027 | >>> job.id |
1028 | 2 |
1029 | - >>> job.build.buildstate.name |
1030 | + >>> from lp.soyuz.interfaces.build import IBuildSet |
1031 | + >>> build = getUtility(IBuildSet).getByQueueEntry(job) |
1032 | + >>> build.buildstate.name |
1033 | 'NEEDSBUILD' |
1034 | >>> job.builder is None |
1035 | True |
1036 | - >>> job.buildstart is None |
1037 | + >>> job.date_started is None |
1038 | True |
1039 | - >>> job.is_virtualized |
1040 | + >>> build.is_virtualized |
1041 | False |
1042 | |
1043 | The build start time is not set yet either. |
1044 | |
1045 | - >>> print job.build.date_first_dispatched |
1046 | + >>> print build.date_first_dispatched |
1047 | None |
1048 | |
1049 | Update the SourcePackageReleaseFile corresponding to this job: |
1050 | @@ -154,7 +156,7 @@ |
1051 | >>> alias_id = librarian_client.addFile( |
1052 | ... 'foo.dsc', len(content), StringIO(content), 'application/dsc') |
1053 | |
1054 | - >>> sprf = job.build.sourcepackagerelease.files[0] |
1055 | + >>> sprf = build.sourcepackagerelease.files[0] |
1056 | >>> from zope.security.proxy import removeSecurityProxy |
1057 | >>> naked_sprf = removeSecurityProxy(sprf) |
1058 | >>> naked_sprf.libraryfile = getUtility(ILibraryFileAliasSet)[alias_id] |
1059 | @@ -167,35 +169,20 @@ |
1060 | |
1061 | Verify if the job (BuildQueue) was updated appropriately: |
1062 | |
1063 | - >>> def checkTimes(expected, actual): |
1064 | - ... if expected != actual: |
1065 | - ... return "expected: %s, actual: %s" % (expected, actual) |
1066 | - ... else: |
1067 | - ... return "OK" |
1068 | - |
1069 | >>> job.builder.id == bob_builder.id |
1070 | True |
1071 | |
1072 | - >>> job.build.buildstate.name |
1073 | + >>> build = getUtility(IBuildSet).getByQueueEntry(job) |
1074 | + >>> build.buildstate.name |
1075 | 'BUILDING' |
1076 | |
1077 | - >>> from canonical.database.sqlbase import get_transaction_timestamp |
1078 | - >>> checkTimes(get_transaction_timestamp(), job.buildstart) |
1079 | - 'OK' |
1080 | - |
1081 | -The build start time will be set to the same value. |
1082 | - |
1083 | - >>> checkTimes(get_transaction_timestamp(), |
1084 | - ... job.build.date_first_dispatched) |
1085 | - 'OK' |
1086 | - |
1087 | Shutdown builder, mark the build record as failed and remove the |
1088 | buildqueue record, so the build was eliminated: |
1089 | |
1090 | >>> BuilddSlaveTestSetup().tearDown() |
1091 | |
1092 | >>> from lp.soyuz.interfaces.build import BuildStatus |
1093 | - >>> job.build.buildstate = BuildStatus.FAILEDTOBUILD |
1094 | + >>> build.buildstate = BuildStatus.FAILEDTOBUILD |
1095 | >>> job.destroySelf() |
1096 | >>> flush_database_updates() |
1097 | |
1098 | @@ -217,12 +204,13 @@ |
1099 | 3 |
1100 | >>> ppa_job.builder == None |
1101 | True |
1102 | - >>> ppa_job.buildstart == None |
1103 | + >>> ppa_job.date_started == None |
1104 | True |
1105 | |
1106 | The build job's archive requires virtualized builds. |
1107 | |
1108 | - >>> ppa_job.build.archive.require_virtualized |
1109 | + >>> build = getUtility(IBuildSet).getByQueueEntry(ppa_job) |
1110 | + >>> build.archive.require_virtualized |
1111 | True |
1112 | |
1113 | But the builder is not virtualized. |
1114 | @@ -249,10 +237,10 @@ |
1115 | >>> from lp.soyuz.model.publishing import ( |
1116 | ... SourcePackagePublishingHistory) |
1117 | >>> [old_pub] = SourcePackagePublishingHistory.selectBy( |
1118 | - ... distroseries=ppa_job.build.distroseries, |
1119 | - ... sourcepackagerelease=ppa_job.build.sourcepackagerelease) |
1120 | + ... distroseries=build.distroseries, |
1121 | + ... sourcepackagerelease=build.sourcepackagerelease) |
1122 | >>> new_pub = old_pub.copyTo( |
1123 | - ... old_pub.distroseries, old_pub.pocket, ppa_job.build.archive) |
1124 | + ... old_pub.distroseries, old_pub.pocket, build.archive) |
1125 | |
1126 | >>> bob_builder.virtualized = True |
1127 | >>> syncUpdate(bob_builder) |
1128 | @@ -293,19 +281,16 @@ |
1129 | >>> ppa_job.builder.name |
1130 | u'bob' |
1131 | |
1132 | - >>> ppa_job.build.buildstate.name |
1133 | + >>> build.buildstate.name |
1134 | 'BUILDING' |
1135 | |
1136 | - >>> ppa_job.buildstart == get_transaction_timestamp() |
1137 | - True |
1138 | - |
1139 | Shutdown builder slave, mark the ppa build record as failed, remove the |
1140 | buildqueue record and make 'bob' builder non-virtual again, so the |
1141 | environment is back to the initial state. |
1142 | |
1143 | >>> BuilddSlaveTestSetup().tearDown() |
1144 | |
1145 | - >>> ppa_job.build.buildstate = BuildStatus.FAILEDTOBUILD |
1146 | + >>> build.buildstate = BuildStatus.FAILEDTOBUILD |
1147 | >>> ppa_job.destroySelf() |
1148 | >>> bob_builder.virtualized = False |
1149 | >>> flush_database_updates() |
1150 | @@ -332,9 +317,9 @@ |
1151 | 4 |
1152 | >>> print sec_job.builder |
1153 | None |
1154 | - >>> print sec_job.buildstart |
1155 | + >>> print sec_job.date_started |
1156 | None |
1157 | - >>> sec_job.is_virtualized |
1158 | + >>> sec_build.is_virtualized |
1159 | False |
1160 | |
1161 | In normal conditions the next available candidate would be the job |
1162 | |
1163 | === modified file 'lib/lp/soyuz/doc/buildd-scoring.txt' |
1164 | --- lib/lp/soyuz/doc/buildd-scoring.txt 2009-08-30 23:57:41 +0000 |
1165 | +++ lib/lp/soyuz/doc/buildd-scoring.txt 2009-11-13 20:43:23 +0000 |
1166 | @@ -49,7 +49,7 @@ |
1167 | >>> def setUpBuildQueueEntry( |
1168 | ... component_name='main', urgency=SourcePackageUrgency.HIGH, |
1169 | ... pocket=PackagePublishingPocket.RELEASE, |
1170 | - ... date_created=LOCAL_NOW, manual=False): |
1171 | + ... date_created=LOCAL_NOW, manual=False, archive=None): |
1172 | ... global version |
1173 | ... commit() |
1174 | ... LaunchpadZopelessLayer.switchDbUser('launchpad') |
1175 | @@ -57,7 +57,7 @@ |
1176 | ... sourcename='test-build', version=str(version), |
1177 | ... distroseries=hoary, component=component_name, |
1178 | ... urgency=urgency, pocket=pocket, |
1179 | - ... status=PackagePublishingStatus.PUBLISHED) |
1180 | + ... status=PackagePublishingStatus.PUBLISHED, archive=archive) |
1181 | ... commit() |
1182 | ... LaunchpadZopelessLayer.switchDbUser(test_dbuser) |
1183 | ... version += 1 |
1184 | @@ -65,7 +65,7 @@ |
1185 | ... hoary386, pub.pocket, pub.archive) |
1186 | ... |
1187 | ... build_queue = build.createBuildQueueEntry() |
1188 | - ... build_queue.created = date_created |
1189 | + ... build_queue.job.date_created = date_created |
1190 | ... build_queue.manual = manual |
1191 | ... |
1192 | ... return build_queue |
1193 | @@ -86,8 +86,10 @@ |
1194 | |
1195 | >>> commit() |
1196 | >>> LaunchpadZopelessLayer.switchDbUser('launchpad') |
1197 | - >>> bq0.build.archive.buildd_secret = "secret" |
1198 | - >>> bq0.build.archive.private = True |
1199 | + >>> from lp.soyuz.interfaces.build import IBuildSet |
1200 | + >>> build = getUtility(IBuildSet).getByQueueEntry(bq0) |
1201 | + >>> build.archive.buildd_secret = "secret" |
1202 | + >>> build.archive.private = True |
1203 | >>> bq0.score() |
1204 | >>> bq0.lastscore |
1205 | 12515 |
1206 | @@ -96,19 +98,19 @@ |
1207 | IArchive.relative_build_score to boost by 100 changes the lastscore value |
1208 | appropriately. |
1209 | |
1210 | - >>> bq0.build.archive.relative_build_score = 100 |
1211 | + >>> build.archive.relative_build_score = 100 |
1212 | >>> bq0.score() |
1213 | >>> bq0.lastscore |
1214 | 12615 |
1215 | |
1216 | The delta can also be negative. |
1217 | |
1218 | - >>> bq0.build.archive.relative_build_score = -100 |
1219 | + >>> build.archive.relative_build_score = -100 |
1220 | >>> bq0.score() |
1221 | >>> bq0.lastscore |
1222 | 12415 |
1223 | |
1224 | - >>> bq0.build.archive.relative_build_score = 0 |
1225 | + >>> build.archive.relative_build_score = 0 |
1226 | >>> LaunchpadZopelessLayer.switchDbUser(test_dbuser) |
1227 | |
1228 | |
1229 | @@ -250,9 +252,15 @@ |
1230 | they all have a fixed score of -10. They will get built in the order |
1231 | they were created. |
1232 | |
1233 | - >>> from canonical.launchpad.interfaces import ArchivePurpose |
1234 | - >>> bqc = setUpBuildQueueEntry() |
1235 | - >>> bqc.build.archive.purpose = ArchivePurpose.COPY |
1236 | + >>> LaunchpadZopelessLayer.switchDbUser('launchpad') |
1237 | + >>> from canonical.launchpad.interfaces import ( |
1238 | + ... ArchivePurpose, IArchiveSet) |
1239 | + >>> copy = getUtility(IArchiveSet).new( |
1240 | + ... owner=ubuntu.owner, purpose=ArchivePurpose.COPY, |
1241 | + ... name='test-rebuild') |
1242 | + |
1243 | + >>> bqc = setUpBuildQueueEntry(archive=copy) |
1244 | + >>> build = getUtility(IBuildSet).getByQueueEntry(bqc) |
1245 | >>> bqc.score() |
1246 | >>> bqc.lastscore |
1247 | -10 |
1248 | |
1249 | === modified file 'lib/lp/soyuz/doc/buildd-slavescanner.txt' |
1250 | --- lib/lp/soyuz/doc/buildd-slavescanner.txt 2009-11-05 10:51:36 +0000 |
1251 | +++ lib/lp/soyuz/doc/buildd-slavescanner.txt 2009-11-13 20:43:23 +0000 |
1252 | @@ -188,10 +188,11 @@ |
1253 | To make testing easier we provide a convenience function to put a BuildQueue |
1254 | object into a preset fixed state: |
1255 | |
1256 | + >>> from zope.security.proxy import removeSecurityProxy |
1257 | >>> default_start = datetime.datetime(2005, 1, 1, 8, 0, 0, tzinfo=UTC) |
1258 | >>> def setupBuildQueue(build_queue, builder): |
1259 | ... build_queue.builder = builder |
1260 | - ... build_queue.buildstart = default_start |
1261 | + ... build_queue.setDateStarted(default_start) |
1262 | |
1263 | Remove any previous buildmaster ROOT directory, to avoid any garbage |
1264 | lock conflict (it would be recreated automatically if necessary) |
1265 | @@ -216,7 +217,7 @@ |
1266 | >>> from canonical.launchpad.ftests import syncUpdate |
1267 | >>> if a_builder.currentjob is not None: |
1268 | ... currentjob = a_builder.currentjob |
1269 | - ... currentjob.buildstart = None |
1270 | + ... currentjob.setDateStarted(None) |
1271 | ... currentjob.builder = None |
1272 | ... syncUpdate(currentjob) |
1273 | |
1274 | @@ -236,17 +237,18 @@ |
1275 | Do the test execution: |
1276 | |
1277 | >>> buildergroup.updateBuild(bqItem3) |
1278 | - >>> bqItem3.build.builder is not None |
1279 | - True |
1280 | - >>> bqItem3.build.datebuilt is not None |
1281 | - True |
1282 | - >>> bqItem3.build.buildduration is not None |
1283 | - True |
1284 | - >>> bqItem3.build.buildlog is not None |
1285 | + >>> build = getUtility(IBuildSet).getByQueueEntry(bqItem3) |
1286 | + >>> build.builder is not None |
1287 | + True |
1288 | + >>> build.datebuilt is not None |
1289 | + True |
1290 | + >>> build.buildduration is not None |
1291 | + True |
1292 | + >>> build.buildlog is not None |
1293 | True |
1294 | >>> check_mail_sent(last_stub_mail_count) |
1295 | True |
1296 | - >>> bqItem3.build.buildstate.title |
1297 | + >>> build.buildstate.title |
1298 | 'Failed to build' |
1299 | |
1300 | Cleanup in preparation for the next test: |
1301 | @@ -270,19 +272,20 @@ |
1302 | |
1303 | >>> buildergroup.updateBuild(bqItem4) |
1304 | CRITICAL:root:***** bob is MANUALDEPWAIT ***** |
1305 | - >>> bqItem4.build.builder is not None |
1306 | - True |
1307 | - >>> bqItem4.build.datebuilt is not None |
1308 | - True |
1309 | - >>> bqItem4.build.buildduration is not None |
1310 | - True |
1311 | - >>> bqItem4.build.buildlog is not None |
1312 | + >>> build = getUtility(IBuildSet).getByQueueEntry(bqItem4) |
1313 | + >>> build.builder is not None |
1314 | + True |
1315 | + >>> build.datebuilt is not None |
1316 | + True |
1317 | + >>> build.buildduration is not None |
1318 | + True |
1319 | + >>> build.buildlog is not None |
1320 | True |
1321 | >>> check_mail_sent(last_stub_mail_count) |
1322 | False |
1323 | - >>> bqItem4.build.dependencies |
1324 | + >>> build.dependencies |
1325 | u'baz (>= 1.0.1)' |
1326 | - >>> bqItem4.build.buildstate.title |
1327 | + >>> build.buildstate.title |
1328 | 'Dependency wait' |
1329 | |
1330 | Cleanup in preparation for the next test: |
1331 | @@ -302,17 +305,18 @@ |
1332 | ... WaitingSlave('BuildStatus.CHROOTFAIL')) |
1333 | >>> buildergroup.updateBuild(bqItem5) |
1334 | CRITICAL:root:***** bob is CHROOTWAIT ***** |
1335 | - >>> bqItem5.build.builder is not None |
1336 | - True |
1337 | - >>> bqItem5.build.datebuilt is not None |
1338 | - True |
1339 | - >>> bqItem5.build.buildduration is not None |
1340 | - True |
1341 | - >>> bqItem5.build.buildlog is not None |
1342 | + >>> build = getUtility(IBuildSet).getByQueueEntry(bqItem5) |
1343 | + >>> build.builder is not None |
1344 | + True |
1345 | + >>> build.datebuilt is not None |
1346 | + True |
1347 | + >>> build.buildduration is not None |
1348 | + True |
1349 | + >>> build.buildlog is not None |
1350 | True |
1351 | >>> check_mail_sent(last_stub_mail_count) |
1352 | True |
1353 | - >>> bqItem5.build.buildstate.title |
1354 | + >>> build.buildstate.title |
1355 | 'Chroot problem' |
1356 | |
1357 | Cleanup in preparation for the next test: |
1358 | @@ -343,7 +347,8 @@ |
1359 | True |
1360 | >>> check_mail_sent(last_stub_mail_count) |
1361 | False |
1362 | - >>> bqItem6.build.buildstate.title |
1363 | + >>> build = getUtility(IBuildSet).getByQueueEntry(bqItem6) |
1364 | + >>> build.buildstate.title |
1365 | 'Needs building' |
1366 | |
1367 | Cleanup in preparation for the next test: |
1368 | @@ -384,6 +389,8 @@ |
1369 | >>> setupBuildQueue(bqItem8, a_builder) |
1370 | >>> last_stub_mail_count = len(stub.test_emails) |
1371 | |
1372 | + >>> bqItem8.builder.setSlaveForTesting(BuildingSlave()) |
1373 | + >>> buildergroup.updateBuild(bqItem8) |
1374 | >>> bqItem8.builder.setSlaveForTesting(AbortedSlave()) |
1375 | >>> bqItem8.builder.name |
1376 | u'bob' |
1377 | @@ -445,17 +452,18 @@ |
1378 | FAILEDTOUPLOAD: |
1379 | |
1380 | >>> buildergroup.updateBuild(bqItem10) |
1381 | - >>> bqItem10.build.builder is not None |
1382 | - True |
1383 | - >>> bqItem10.build.datebuilt is not None |
1384 | - True |
1385 | - >>> bqItem10.build.buildduration is not None |
1386 | - True |
1387 | - >>> bqItem10.build.buildlog is not None |
1388 | + >>> build = getUtility(IBuildSet).getByQueueEntry(bqItem10) |
1389 | + >>> build.builder is not None |
1390 | + True |
1391 | + >>> build.datebuilt is not None |
1392 | + True |
1393 | + >>> build.buildduration is not None |
1394 | + True |
1395 | + >>> build.buildlog is not None |
1396 | True |
1397 | >>> check_mail_sent(last_stub_mail_count) |
1398 | True |
1399 | - >>> bqItem10.build.buildstate.title |
1400 | + >>> build.buildstate.title |
1401 | 'Failed to upload' |
1402 | |
1403 | Let's check the emails generated by this 'failure' |
1404 | @@ -493,7 +501,7 @@ |
1405 | output is both emailed in an immediate notification, and stored in the |
1406 | librarian for future reference. |
1407 | |
1408 | - >>> bqItem10.build.upload_log is not None |
1409 | + >>> build.upload_log is not None |
1410 | True |
1411 | |
1412 | What we can clearly notice is that the buildlog is still containing |
1413 | @@ -514,16 +522,16 @@ |
1414 | |
1415 | >>> bqItem10 = getUtility(IBuildSet).getByBuildID( |
1416 | ... 6).createBuildQueueEntry() |
1417 | + >>> build = getUtility(IBuildSet).getByQueueEntry(bqItem10) |
1418 | |
1419 | XXX: The pocket attribute is not intended to be changed in regular code, but |
1420 | for this test we want to change it on the fly. An alternative would be to add |
1421 | new sample data for a build that can be uploaded with binary packages attached |
1422 | to it. |
1423 | |
1424 | - >>> from zope.security.proxy import removeSecurityProxy |
1425 | >>> from lp.registry.interfaces.pocket import PackagePublishingPocket |
1426 | >>> removeSecurityProxy( |
1427 | - ... bqItem10.build).pocket = PackagePublishingPocket.UPDATES |
1428 | + ... build).pocket = PackagePublishingPocket.UPDATES |
1429 | >>> setupBuildQueue(bqItem10, a_builder) |
1430 | >>> last_stub_mail_count = len(stub.test_emails) |
1431 | |
1432 | @@ -535,22 +543,22 @@ |
1433 | the build record to FULLYBUILT, as the process-upload would do: |
1434 | |
1435 | >>> from canonical.launchpad.interfaces import BuildStatus |
1436 | - >>> bqItem10.build.buildstate = BuildStatus.FULLYBUILT |
1437 | + >>> build.buildstate = BuildStatus.FULLYBUILT |
1438 | |
1439 | Now the updateBuild should recognize this build record as a |
1440 | Successfully built and uploaded procedure, not sending any |
1441 | notification and updating the build information: |
1442 | |
1443 | >>> buildergroup.updateBuild(bqItem10) |
1444 | - >>> bqItem10.build.builder is not None |
1445 | - True |
1446 | - >>> bqItem10.build.datebuilt is not None |
1447 | - True |
1448 | - >>> bqItem10.build.buildduration is not None |
1449 | - True |
1450 | - >>> bqItem10.build.buildlog is not None |
1451 | - True |
1452 | - >>> bqItem10.build.buildstate.title |
1453 | + >>> build.builder is not None |
1454 | + True |
1455 | + >>> build.datebuilt is not None |
1456 | + True |
1457 | + >>> build.buildduration is not None |
1458 | + True |
1459 | + >>> build.buildlog is not None |
1460 | + True |
1461 | + >>> build.buildstate.title |
1462 | 'Successfully built' |
1463 | >>> check_mail_sent(last_stub_mail_count) |
1464 | False |
1465 | @@ -558,7 +566,7 @@ |
1466 | We do not store any build log information when the binary upload |
1467 | processing succeeded. |
1468 | |
1469 | - >>> bqItem10.build.upload_log is None |
1470 | + >>> build.upload_log is None |
1471 | True |
1472 | |
1473 | Cleanup in preparation for the next test: |
1474 | @@ -585,13 +593,14 @@ |
1475 | |
1476 | >>> bqItem11.builder is None |
1477 | True |
1478 | - >>> bqItem11.buildstart is None |
1479 | + >>> bqItem11.date_started is None |
1480 | True |
1481 | >>> bqItem11.lastscore |
1482 | 0 |
1483 | >>> check_mail_sent(last_stub_mail_count) |
1484 | False |
1485 | - >>> bqItem11.build.buildstate.title |
1486 | + >>> build = getUtility(IBuildSet).getByQueueEntry(bqItem11) |
1487 | + >>> build.buildstate.title |
1488 | 'Needs building' |
1489 | |
1490 | Cleanup in preparation for the next test: |
1491 | @@ -790,11 +799,11 @@ |
1492 | tests. |
1493 | |
1494 | >>> current_job = a_builder.currentjob |
1495 | - >>> resurrect_build = current_job.build |
1496 | + >>> resurrect_build = getUtility(IBuildSet).getByQueueEntry(current_job) |
1497 | >>> resurrect_build.buildstate = BuildStatus.NEEDSBUILD |
1498 | >>> syncUpdate(resurrect_build) |
1499 | >>> current_job.builder = None |
1500 | - >>> current_job.buildstart = None |
1501 | + >>> current_job.setDateStarted(None) |
1502 | >>> syncUpdate(current_job) |
1503 | |
1504 | IBuilder.findCandidate also identifies if there are builds for |
1505 | @@ -802,7 +811,8 @@ |
1506 | corresponding build record as SUPERSEDED. |
1507 | |
1508 | >>> old_candidate = a_builder.findBuildCandidate() |
1509 | - >>> print old_candidate.build.buildstate.name |
1510 | + >>> build = getUtility(IBuildSet).getByQueueEntry(old_candidate) |
1511 | + >>> print build.buildstate.name |
1512 | NEEDSBUILD |
1513 | |
1514 | The 'candidate' is constant until we dispatch it. |
1515 | @@ -814,7 +824,7 @@ |
1516 | Now let's disable the archive of the associated build record and see |
1517 | whether the candidate will still be found. |
1518 | |
1519 | - >>> old_candidate.build.archive.enabled = False |
1520 | + >>> build.archive.enabled = False |
1521 | >>> new_candidate = a_builder.findBuildCandidate() |
1522 | >>> new_candidate is None |
1523 | True |
1524 | @@ -823,7 +833,7 @@ |
1525 | archives are ignored. Now let's re-enable that archive and the build |
1526 | candidate will be found again. |
1527 | |
1528 | - >>> old_candidate.build.archive.enabled = True |
1529 | + >>> build.archive.enabled = True |
1530 | >>> new_candidate = a_builder.findBuildCandidate() |
1531 | >>> new_candidate.id == old_candidate.id |
1532 | True |
1533 | @@ -836,9 +846,9 @@ |
1534 | >>> from canonical.launchpad.interfaces import PackagePublishingStatus |
1535 | >>> from canonical.testing.layers import LaunchpadZopelessLayer |
1536 | |
1537 | - >>> spr = old_candidate.build.sourcepackagerelease |
1538 | + >>> spr = build.sourcepackagerelease |
1539 | >>> secure_pub = removeSecurityProxy( |
1540 | - ... old_candidate).build.current_source_publication.secure_record |
1541 | + ... build).current_source_publication.secure_record |
1542 | >>> commit() |
1543 | >>> LaunchpadZopelessLayer.switchDbUser('launchpad') |
1544 | >>> secure_pub.status = PackagePublishingStatus.SUPERSEDED |
1545 | @@ -854,7 +864,7 @@ |
1546 | Because the 'previous' candidate was marked as superseded, so it's not |
1547 | part of the candidates list anymore. |
1548 | |
1549 | - >>> print old_candidate.build.buildstate.name |
1550 | + >>> print build.buildstate.name |
1551 | SUPERSEDED |
1552 | |
1553 | If the candidate is for a private build whose source has not been |
1554 | @@ -862,9 +872,10 @@ |
1555 | published. We need to tweak the status of the publishing record again |
1556 | to demonstrate this, and also make the archive private: |
1557 | |
1558 | - >>> source = new_candidate.build.sourcepackagerelease |
1559 | + >>> build = getUtility(IBuildSet).getByQueueEntry(new_candidate) |
1560 | + >>> source = build.sourcepackagerelease |
1561 | >>> secure_pub = removeSecurityProxy( |
1562 | - ... new_candidate).build.current_source_publication.secure_record |
1563 | + ... build).current_source_publication.secure_record |
1564 | >>> commit() |
1565 | >>> LaunchpadZopelessLayer.switchDbUser('launchpad') |
1566 | >>> secure_pub.status = PackagePublishingStatus.PENDING |
1567 | @@ -903,22 +914,23 @@ |
1568 | |
1569 | >>> LaunchpadZopelessLayer.switchDbUser('launchpad') |
1570 | >>> secure_pub = removeSecurityProxy( |
1571 | - ... new_candidate).build.current_source_publication.secure_record |
1572 | + ... build).current_source_publication.secure_record |
1573 | >>> secure_pub.status = PackagePublishingStatus.DELETED |
1574 | >>> secure_pub = removeSecurityProxy( |
1575 | - ... new_candidate).build.current_source_publication.secure_record |
1576 | + ... build).current_source_publication.secure_record |
1577 | >>> secure_pub.status = PackagePublishingStatus.SUPERSEDED |
1578 | >>> commit() |
1579 | >>> LaunchpadZopelessLayer.switchDbUser(config.builddmaster.dbuser) |
1580 | |
1581 | - >>> print current_job.build.buildstate.name |
1582 | + >>> build = getUtility(IBuildSet).getByQueueEntry(current_job) |
1583 | + >>> print build.buildstate.name |
1584 | NEEDSBUILD |
1585 | |
1586 | >>> another_candidate = a_builder.findBuildCandidate() |
1587 | >>> print another_candidate |
1588 | None |
1589 | |
1590 | - >>> print current_job.build.buildstate.name |
1591 | + >>> print build.buildstate.name |
1592 | SUPERSEDED |
1593 | |
1594 | We'll reset the archive back to non-private for further tests: |
1595 | @@ -1147,7 +1159,8 @@ |
1596 | >>> cprov_archive.private = True |
1597 | >>> cprov_archive.buildd_secret = "secret" |
1598 | >>> cprov_archive.require_virtualized = False |
1599 | - >>> for build_file in candidate.files: |
1600 | + >>> build = getUtility(IBuildSet).getByQueueEntry(candidate) |
1601 | + >>> for build_file in build.sourcepackagerelease.files: |
1602 | ... removeSecurityProxy(build_file).libraryfile.restricted = True |
1603 | >>> commit() |
1604 | >>> LaunchpadZopelessLayer.switchDbUser(test_dbuser) |
1605 | @@ -1169,7 +1182,8 @@ |
1606 | archive and not the one from the PPA, which on the absence of ancestry |
1607 | defaults to 'universe'. |
1608 | |
1609 | - >>> print candidate.build.current_component.name |
1610 | + >>> build = getUtility(IBuildSet).getByQueueEntry(candidate) |
1611 | + >>> print build.current_component.name |
1612 | main |
1613 | |
1614 | This is so that the mangling tools will run over the built packages. |
1615 | @@ -1196,7 +1210,7 @@ |
1616 | We will create an ancestry in the primary archive target to the 'main' |
1617 | component and this time the dispatching will follow that component. |
1618 | |
1619 | - >>> sourcename = candidate.build.sourcepackagerelease.name |
1620 | + >>> sourcename = build.sourcepackagerelease.name |
1621 | |
1622 | >>> LaunchpadZopelessLayer.switchDbUser('launchpad') |
1623 | >>> login('foo.bar@canonical.com') |
1624 | @@ -1227,14 +1241,14 @@ |
1625 | |
1626 | >>> candidate = a_build.createBuildQueueEntry() |
1627 | >>> setupBuildQueue(candidate, a_builder) |
1628 | - >>> candidate.build.upload_log = None |
1629 | + >>> build.upload_log = None |
1630 | >>> candidate.builder.setSlaveForTesting(WaitingSlave('BuildStatus.OK')) |
1631 | >>> buildergroup.updateBuild(candidate) |
1632 | |
1633 | - >>> candidate.build.archive.private |
1634 | + >>> build.archive.private |
1635 | True |
1636 | |
1637 | - >>> lfa = candidate.build.buildlog |
1638 | + >>> lfa = build.buildlog |
1639 | >>> lfa.restricted |
1640 | True |
1641 | >>> print lfa.filename |
1642 | @@ -1269,7 +1283,8 @@ |
1643 | |
1644 | >>> cprov_archive.private = False |
1645 | >>> cprov_archive.require_virtualized = True |
1646 | - >>> for build_file in candidate.files: |
1647 | + >>> build = getUtility(IBuildSet).getByQueueEntry(candidate) |
1648 | + >>> for build_file in build.sourcepackagerelease.files: |
1649 | ... removeSecurityProxy(build_file).libraryfile.restricted = False |
1650 | >>> mark_archive = getUtility(IPersonSet).getByName('mark').archive |
1651 | |
1652 | @@ -1388,7 +1403,8 @@ |
1653 | >>> a_builder.currentjob.destroySelf() |
1654 | |
1655 | >>> bqItem3 = a_build.createBuildQueueEntry() |
1656 | - >>> removeSecurityProxy(bqItem3.build).pocket = ( |
1657 | + >>> build = getUtility(IBuildSet).getByQueueEntry(bqItem3) |
1658 | + >>> removeSecurityProxy(build).pocket = ( |
1659 | ... PackagePublishingPocket.UPDATES) |
1660 | >>> last_stub_mail_count = len(stub.test_emails) |
1661 | >>> a_builder.dispatchBuildCandidate(bqItem3) |
1662 | @@ -1410,7 +1426,7 @@ |
1663 | >>> a_builder.currentjob.destroySelf() |
1664 | |
1665 | >>> bqItem3 = a_build.createBuildQueueEntry() |
1666 | - >>> removeSecurityProxy(bqItem3.build).pocket = ( |
1667 | + >>> removeSecurityProxy(build).pocket = ( |
1668 | ... PackagePublishingPocket.PROPOSED) |
1669 | >>> last_stub_mail_count = len(stub.test_emails) |
1670 | >>> a_builder.dispatchBuildCandidate(bqItem3) |
1671 | @@ -1433,7 +1449,7 @@ |
1672 | >>> a_builder.currentjob.destroySelf() |
1673 | |
1674 | >>> bqItem3 = a_build.createBuildQueueEntry() |
1675 | - >>> removeSecurityProxy(bqItem3.build).pocket = ( |
1676 | + >>> removeSecurityProxy(build).pocket = ( |
1677 | ... PackagePublishingPocket.BACKPORTS) |
1678 | >>> last_stub_mail_count = len(stub.test_emails) |
1679 | >>> a_builder.dispatchBuildCandidate(bqItem3) |
1680 | @@ -1456,9 +1472,9 @@ |
1681 | >>> a_builder.currentjob.destroySelf() |
1682 | |
1683 | >>> bqItem3 = a_build.createBuildQueueEntry() |
1684 | - >>> removeSecurityProxy(bqItem3.build).buildstate = ( |
1685 | + >>> removeSecurityProxy(build).buildstate = ( |
1686 | ... BuildStatus.NEEDSBUILD) |
1687 | - >>> removeSecurityProxy(bqItem3.build).pocket = ( |
1688 | + >>> removeSecurityProxy(build).pocket = ( |
1689 | ... PackagePublishingPocket.SECURITY) |
1690 | >>> last_stub_mail_count = len(stub.test_emails) |
1691 | |
1692 | |
1693 | === modified file 'lib/lp/soyuz/doc/builder.txt' |
1694 | --- lib/lp/soyuz/doc/builder.txt 2009-08-27 19:09:44 +0000 |
1695 | +++ lib/lp/soyuz/doc/builder.txt 2009-11-13 20:43:23 +0000 |
1696 | @@ -45,8 +45,10 @@ |
1697 | |
1698 | >>> from lp.soyuz.interfaces.archive import ArchivePurpose |
1699 | >>> from zope.security.proxy import removeSecurityProxy |
1700 | + >>> from lp.soyuz.interfaces.build import IBuildSet |
1701 | + >>> build = getUtility(IBuildSet).getByQueueEntry(builder.currentjob) |
1702 | >>> builder_archive = removeSecurityProxy( |
1703 | - ... builder.currentjob.build.archive) |
1704 | + ... build.archive) |
1705 | >>> saved_purpose = builder_archive.purpose |
1706 | >>> builder_archive.purpose = ArchivePurpose.COPY |
1707 | |
1708 | |
1709 | === modified file 'lib/lp/soyuz/doc/buildqueue.txt' |
1710 | --- lib/lp/soyuz/doc/buildqueue.txt 2009-08-28 07:34:44 +0000 |
1711 | +++ lib/lp/soyuz/doc/buildqueue.txt 2009-11-13 20:43:23 +0000 |
1712 | @@ -31,19 +31,21 @@ |
1713 | The IBuild record related to this job is provided by the 'build' |
1714 | attribute: |
1715 | |
1716 | - >>> bq.build.id |
1717 | + >>> from lp.soyuz.interfaces.build import IBuildSet |
1718 | + >>> build = getUtility(IBuildSet).getByQueueEntry(bq) |
1719 | + >>> build.id |
1720 | 8 |
1721 | - >>> bq.build.buildstate.name |
1722 | + >>> build.buildstate.name |
1723 | 'BUILDING' |
1724 | |
1725 | The static timestamps, representing when the record was initialised |
1726 | (inserted) and when the job was dispatched are provided as datetime |
1727 | instances: |
1728 | |
1729 | - >>> bq.created |
1730 | + >>> bq.job.date_created |
1731 | datetime.datetime(2005, 6, 15, 9, 14, 12, 820778, tzinfo=<UTC>) |
1732 | |
1733 | - >>> bq.buildstart |
1734 | + >>> bq.date_started |
1735 | datetime.datetime(2005, 6, 15, 9, 20, 12, 820778, tzinfo=<UTC>) |
1736 | |
1737 | Check Builder foreign key, which indicated which builder 'is processing' |
1738 | @@ -77,29 +79,6 @@ |
1739 | >>> bq.manual |
1740 | False |
1741 | |
1742 | -BuildQueue provides a property which calculates the partial duration |
1743 | -of the build procedure (NOW - buildstart), it's mainly used in the UI. |
1744 | - |
1745 | - >>> bq.buildduration |
1746 | - datetime.timedelta(...) |
1747 | - |
1748 | -Some local properties inherited from related content classes: |
1749 | - |
1750 | - >>> bq.archseries.id == bq.build.distroarchseries.id |
1751 | - True |
1752 | - >>> bq.urgency == bq.build.sourcepackagerelease.urgency |
1753 | - True |
1754 | - >>> bq.archhintlist == bq.build.sourcepackagerelease.architecturehintlist |
1755 | - True |
1756 | - >>> bq.name == bq.build.sourcepackagerelease.name |
1757 | - True |
1758 | - >>> bq.version == bq.build.sourcepackagerelease.version |
1759 | - True |
1760 | - >>> bq.files.count() == bq.build.sourcepackagerelease.files.count() |
1761 | - True |
1762 | - >>> bq.builddependsindep == bq.build.sourcepackagerelease.builddependsindep |
1763 | - True |
1764 | - |
1765 | BuildQueue provides the name for the logfile resulting from the build: |
1766 | |
1767 | >>> bq.getLogFileName() |
1768 | @@ -131,11 +110,12 @@ |
1769 | |
1770 | >>> print job.builder.name |
1771 | bob |
1772 | - >>> job.buildstart is not None |
1773 | + >>> job.date_started is not None |
1774 | True |
1775 | >>> print job.logtail |
1776 | Dummy sampledata entry, not processing |
1777 | - >>> print job.build.buildstate.name |
1778 | + >>> build = getUtility(IBuildSet).getByQueueEntry(job) |
1779 | + >>> print build.buildstate.name |
1780 | BUILDING |
1781 | >>> print job.lastscore |
1782 | 1 |
1783 | @@ -150,11 +130,11 @@ |
1784 | |
1785 | >>> print job.builder |
1786 | None |
1787 | - >>> print job.buildstart |
1788 | + >>> print job.date_started |
1789 | None |
1790 | >>> print job.logtail |
1791 | None |
1792 | - >>> print job.build.buildstate.name |
1793 | + >>> print build.buildstate.name |
1794 | NEEDSBUILD |
1795 | >>> print job.lastscore |
1796 | 1 |
1797 | @@ -169,9 +149,9 @@ |
1798 | |
1799 | >>> print job.builder.name |
1800 | bob |
1801 | - >>> job.buildstart is not None |
1802 | + >>> job.date_started is not None |
1803 | True |
1804 | - >>> print job.build.buildstate.name |
1805 | + >>> print build.buildstate.name |
1806 | BUILDING |
1807 | |
1808 | |
1809 | @@ -266,7 +246,7 @@ |
1810 | and restricted |
1811 | |
1812 | >>> for bq in bqset.calculateCandidates(archseries): |
1813 | - ... build = bq.build |
1814 | + ... build = getUtility(IBuildSet).getByQueueEntry(bq) |
1815 | ... print "%s (%s, %d)" % (build.title, bq.lastscore, bq.id) |
1816 | hppa build of pmount 0.1-2 in ubuntu hoary RELEASE (1500, 4) |
1817 | i386 build of alsa-utils 1.0.9a-4ubuntu1 in ubuntu hoary RELEASE (1000, 2) |
1818 | @@ -298,7 +278,7 @@ |
1819 | as intended. |
1820 | |
1821 | >>> for bq in bqset.calculateCandidates(archseries): |
1822 | - ... build = bq.build |
1823 | + ... build = getUtility(IBuildSet).getByQueueEntry(bq) |
1824 | ... print "%s (%s, %d)" % (build.title, bq.lastscore, bq.id) |
1825 | hppa build of pmount 0.1-2 in ubuntu hoary RELEASE (1500, 4) |
1826 | i386 build of alsa-utils 1.0.9a-4ubuntu1 in ubuntu hoary RELEASE (1000, 2) |
1827 | @@ -310,7 +290,7 @@ |
1828 | |
1829 | >>> archseries = [hoary['hppa']] |
1830 | >>> for bq in bqset.calculateCandidates(archseries): |
1831 | - ... build = bq.build |
1832 | + ... build = getUtility(IBuildSet).getByQueueEntry(bq) |
1833 | ... print "%s (%s, %d)" % (build.title, bq.lastscore, bq.id) |
1834 | hppa build of pmount 0.1-2 in ubuntu hoary RELEASE (1500, 4) |
1835 | hppa build of alsa-utils 1.0.9a-4 in ubuntu hoary RELEASE (500, 3) |
1836 | |
1837 | === modified file 'lib/lp/soyuz/interfaces/build.py' |
1838 | --- lib/lp/soyuz/interfaces/build.py 2009-10-26 18:40:04 +0000 |
1839 | +++ lib/lp/soyuz/interfaces/build.py 2009-11-13 20:43:23 +0000 |
1840 | @@ -524,6 +524,13 @@ |
1841 | :rtype: ``dict``. |
1842 | """ |
1843 | |
1844 | + def getByQueueEntry(queue_entry): |
1845 | + """Return an IBuild instance for the given build queue entry. |
1846 | + |
1847 | + Retrieve the only one possible build record associated with the given |
1848 | + build queue entry. If not found, return None. |
1849 | + """ |
1850 | + |
1851 | |
1852 | class IBuildRescoreForm(Interface): |
1853 | """Form for rescoring a build.""" |
1854 | |
1855 | === added file 'lib/lp/soyuz/interfaces/buildpackagejob.py' |
1856 | --- lib/lp/soyuz/interfaces/buildpackagejob.py 1970-01-01 00:00:00 +0000 |
1857 | +++ lib/lp/soyuz/interfaces/buildpackagejob.py 2009-11-13 20:43:23 +0000 |
1858 | @@ -0,0 +1,34 @@ |
1859 | +# Copyright 2009 Canonical Ltd. This software is licensed under the |
1860 | +# GNU Affero General Public License version 3 (see the file LICENSE). |
1861 | + |
1862 | +# pylint: disable-msg=E0211,E0213 |
1863 | + |
1864 | +"""BuildPackageJob interfaces.""" |
1865 | + |
1866 | +__metaclass__ = type |
1867 | + |
1868 | +__all__ = [ |
1869 | + 'IBuildPackageJob', |
1870 | + ] |
1871 | + |
1872 | +from zope.schema import Int |
1873 | + |
1874 | +from canonical.launchpad import _ |
1875 | +from lazr.restful.fields import Reference |
1876 | +from lp.buildmaster.interfaces.buildfarmjob import IBuildFarmJob |
1877 | +from lp.services.job.interfaces.job import IJob |
1878 | +from lp.soyuz.interfaces.build import IBuild |
1879 | + |
1880 | + |
1881 | +class IBuildPackageJob(IBuildFarmJob): |
1882 | + """A read-only interface for build package jobs.""" |
1883 | + id = Int(title=_('ID'), required=True, readonly=True) |
1884 | + |
1885 | + job = Reference( |
1886 | + IJob, title=_("Job"), required=True, readonly=True, |
1887 | + description=_("Data common to all job types.")) |
1888 | + |
1889 | + build = Reference( |
1890 | + IBuild, title=_("Build"), |
1891 | + required=True,readonly=True, |
1892 | + description=_("Build record associated with this job.")) |
1893 | |
1894 | === modified file 'lib/lp/soyuz/interfaces/buildqueue.py' |
1895 | --- lib/lp/soyuz/interfaces/buildqueue.py 2009-06-25 04:06:00 +0000 |
1896 | +++ lib/lp/soyuz/interfaces/buildqueue.py 2009-11-13 20:43:23 +0000 |
1897 | @@ -13,6 +13,14 @@ |
1898 | ] |
1899 | |
1900 | from zope.interface import Interface, Attribute |
1901 | +from zope.schema import Choice, Datetime |
1902 | + |
1903 | +from lazr.restful.fields import Reference |
1904 | + |
1905 | +from canonical.launchpad import _ |
1906 | +from lp.buildmaster.interfaces.buildfarmjob import ( |
1907 | + IBuildFarmJob, BuildFarmJobType) |
1908 | +from lp.services.job.interfaces.job import IJob |
1909 | |
1910 | |
1911 | class IBuildQueue(Interface): |
1912 | @@ -30,59 +38,24 @@ |
1913 | """ |
1914 | |
1915 | id = Attribute("Job identifier") |
1916 | - build = Attribute("The IBuild record that originated this job") |
1917 | builder = Attribute("The IBuilder instance processing this job") |
1918 | - created = Attribute("The datetime that the queue entry was created") |
1919 | - buildstart = Attribute("The datetime of the last build attempt") |
1920 | logtail = Attribute("The current tail of the log of the build") |
1921 | lastscore = Attribute("Last score to be computed for this job") |
1922 | manual = Attribute("Whether or not the job was manually scored") |
1923 | |
1924 | - # properties inherited from related Content classes. |
1925 | - archseries = Attribute( |
1926 | - "DistroArchSeries target of the IBuild releated to this job.") |
1927 | - name = Attribute( |
1928 | - "Name of the ISourcePackageRelease releated to this job.") |
1929 | - version = Attribute( |
1930 | - "Version of the ISourcePackageRelease releated to this job.") |
1931 | - files = Attribute( |
1932 | - "Collection of files related to the ISourcePackageRelease " |
1933 | - "releated to this job.") |
1934 | - urgency = Attribute( |
1935 | - "Urgency of the ISourcePackageRelease releated to this job.") |
1936 | - archhintlist = Attribute( |
1937 | - "architecturehintlist of the ISourcePackageRelease releated " |
1938 | - "to this job.") |
1939 | - builddependsindep = Attribute( |
1940 | - "builddependsindep of the ISourcePackageRelease releated to " |
1941 | - "this job.") |
1942 | - buildduration = Attribute( |
1943 | - "Duration of the job, calculated on-the-fly based on buildstart.") |
1944 | - is_virtualized = Attribute("See IBuild.is_virtualized.") |
1945 | + job = Reference( |
1946 | + IJob, title=_("Job"), required=True, readonly=True, |
1947 | + description=_("Data common to all job types.")) |
1948 | + |
1949 | + job_type = Choice( |
1950 | + title=_('Job type'), required=True, vocabulary=BuildFarmJobType, |
1951 | + description=_("The type of this job.")) |
1952 | |
1953 | def manualScore(value): |
1954 | """Manually set a score value to a queue item and lock it.""" |
1955 | |
1956 | def score(): |
1957 | - """Perform scoring based on heuristic values. |
1958 | - |
1959 | - Creates a 'score' (priority) value based on: |
1960 | - |
1961 | - * Component: main component gets higher values |
1962 | - (main, 1000, restricted, 750, universe, 250, multiverse, 0) |
1963 | - |
1964 | - * Urgency: EMERGENCY sources gets higher values |
1965 | - (EMERGENCY, 20, HIGH, 15, MEDIUM, 10, LOW, 5) |
1966 | - |
1967 | - * Queue time: old records gets a relative higher priority |
1968 | - (The rate against component is something like: a 'multiverse' |
1969 | - build will be as important as a 'main' after 40 hours in queue) |
1970 | - |
1971 | - This method automatically updates IBuildQueue.lastscore value and |
1972 | - skips 'manually-scored' records. |
1973 | - |
1974 | - This method use any logger available in the standard logging system. |
1975 | - """ |
1976 | + """The job score calculated for the job type in question.""" |
1977 | |
1978 | def destroySelf(): |
1979 | """Delete this entry from the database.""" |
1980 | @@ -121,6 +94,17 @@ |
1981 | Clean the builder for another jobs. |
1982 | """ |
1983 | |
1984 | + specific_job = Reference( |
1985 | + IBuildFarmJob, title=_("Job"), |
1986 | + description=_("Data and operations common to all build farm jobs.")) |
1987 | + |
1988 | + def setDateStarted(timestamp): |
1989 | + """Sets the date started property to the given value.""" |
1990 | + |
1991 | + date_started = Datetime( |
1992 | + title=_('Start time'), |
1993 | + description=_('Time when the job started.')) |
1994 | + |
1995 | |
1996 | class IBuildQueueSet(Interface): |
1997 | """Launchpad Auto Build queue set handler and auxiliary methods.""" |
1998 | @@ -165,4 +149,3 @@ |
1999 | Retrieve the build queue and related builder rows associated with the |
2000 | builds in question where they exist. |
2001 | """ |
2002 | - |
2003 | |
2004 | === modified file 'lib/lp/soyuz/model/build.py' |
2005 | --- lib/lp/soyuz/model/build.py 2009-10-26 18:40:04 +0000 |
2006 | +++ lib/lp/soyuz/model/build.py 2009-11-13 20:43:23 +0000 |
2007 | @@ -18,7 +18,6 @@ |
2008 | from zope.security.proxy import removeSecurityProxy |
2009 | from storm.expr import ( |
2010 | Desc, In, Join, LeftJoin) |
2011 | -from storm.references import Reference |
2012 | from storm.store import Store |
2013 | from sqlobject import ( |
2014 | StringCol, ForeignKey, IntervalCol, SQLObjectNotFound) |
2015 | @@ -46,7 +45,9 @@ |
2016 | IStoreSelector, MAIN_STORE, DEFAULT_FLAVOR) |
2017 | from canonical.launchpad.webapp.tales import DurationFormatterAPI |
2018 | from lp.archivepublisher.utils import get_ppa_reference |
2019 | +from lp.buildmaster.interfaces.buildfarmjob import BuildFarmJobType |
2020 | from lp.registry.interfaces.pocket import PackagePublishingPocket |
2021 | +from lp.services.job.model.job import Job |
2022 | from lp.soyuz.adapters.archivedependencies import get_components_for_building |
2023 | from lp.soyuz.interfaces.archive import ArchivePurpose |
2024 | from lp.soyuz.interfaces.build import ( |
2025 | @@ -55,6 +56,7 @@ |
2026 | from lp.soyuz.interfaces.publishing import active_publishing_status |
2027 | from lp.soyuz.model.binarypackagerelease import BinaryPackageRelease |
2028 | from lp.soyuz.model.builder import Builder |
2029 | +from lp.soyuz.model.buildpackagejob import BuildPackageJob |
2030 | from lp.soyuz.model.buildqueue import BuildQueue |
2031 | from lp.soyuz.model.files import BinaryPackageFile |
2032 | from lp.soyuz.model.publishing import SourcePackagePublishingHistory |
2033 | @@ -88,8 +90,6 @@ |
2034 | archive = ForeignKey(foreignKey='Archive', dbName='archive', notNull=True) |
2035 | estimated_build_duration = IntervalCol(default=None) |
2036 | |
2037 | - buildqueue_record = Reference("<primary key>", BuildQueue.buildID, |
2038 | - on_remote=True) |
2039 | date_first_dispatched = UtcDateTimeCol(dbName='date_first_dispatched') |
2040 | |
2041 | upload_log = ForeignKey( |
2042 | @@ -105,6 +105,16 @@ |
2043 | return proxied_file.http_url |
2044 | |
2045 | @property |
2046 | + def buildqueue_record(self): |
2047 | + """See `IBuild`.""" |
2048 | + store = Store.of(self) |
2049 | + results = store.find( |
2050 | + BuildQueue, |
2051 | + BuildPackageJob.job == BuildQueue.jobID, |
2052 | + BuildPackageJob.build == self.id) |
2053 | + return results.one() |
2054 | + |
2055 | + @property |
2056 | def upload_log_url(self): |
2057 | """See `IBuild`.""" |
2058 | if self.upload_log is None: |
2059 | @@ -351,8 +361,10 @@ |
2060 | Archive |
2061 | JOIN Build ON |
2062 | Build.archive = Archive.id |
2063 | + JOIN BuildPackageJob ON |
2064 | + Build.id = BuildPackageJob.build |
2065 | JOIN BuildQueue ON |
2066 | - Build.id = BuildQueue.build |
2067 | + BuildPackageJob.job = BuildQueue.job |
2068 | WHERE |
2069 | Build.buildstate = 0 AND |
2070 | Build.processor = %s AND |
2071 | @@ -412,16 +424,20 @@ |
2072 | SELECT |
2073 | CAST (EXTRACT(EPOCH FROM |
2074 | (Build.estimated_build_duration - |
2075 | - (NOW() - BuildQueue.buildstart))) AS INTEGER) |
2076 | + (NOW() - Job.date_started))) AS INTEGER) |
2077 | AS remainder |
2078 | FROM |
2079 | Archive |
2080 | JOIN Build ON |
2081 | Build.archive = Archive.id |
2082 | + JOIN BuildPackageJob ON |
2083 | + Build.id = BuildPackageJob.build |
2084 | JOIN BuildQueue ON |
2085 | - Build.id = BuildQueue.build |
2086 | + BuildQueue.job = BuildPackageJob.job |
2087 | JOIN Builder ON |
2088 | Builder.id = BuildQueue.builder |
2089 | + JOIN Job ON |
2090 | + Job.id = BuildPackageJob.job |
2091 | WHERE |
2092 | Archive.require_virtualized = %s AND |
2093 | Archive.enabled = TRUE AND |
2094 | @@ -605,7 +621,18 @@ |
2095 | |
2096 | def createBuildQueueEntry(self): |
2097 | """See `IBuild`""" |
2098 | - return BuildQueue(build=self) |
2099 | + store = Store.of(self) |
2100 | + job = Job() |
2101 | + store.add(job) |
2102 | + specific_job = BuildPackageJob() |
2103 | + specific_job.build = self.id |
2104 | + specific_job.job = job.id |
2105 | + store.add(specific_job) |
2106 | + queue_entry = BuildQueue() |
2107 | + queue_entry.job = job.id |
2108 | + queue_entry.job_type = BuildFarmJobType.PACKAGEBUILD |
2109 | + store.add(queue_entry) |
2110 | + return queue_entry |
2111 | |
2112 | def notify(self, extra_info=None): |
2113 | """See `IBuild`""" |
2114 | @@ -966,7 +993,9 @@ |
2115 | if status in [BuildStatus.NEEDSBUILD, BuildStatus.BUILDING]: |
2116 | orderBy = ["-BuildQueue.lastscore", "Build.id"] |
2117 | clauseTables.append('BuildQueue') |
2118 | - condition_clauses.append('BuildQueue.build = Build.id') |
2119 | + clauseTables.append('BuildPackageJob') |
2120 | + condition_clauses.append('BuildPackageJob.build = Build.id') |
2121 | + condition_clauses.append('BuildPackageJob.job = BuildQueue.job') |
2122 | elif status == BuildStatus.SUPERSEDED or status is None: |
2123 | orderBy = ["-Build.datecreated"] |
2124 | else: |
2125 | @@ -1144,3 +1173,13 @@ |
2126 | # this (pre_iter_hook()) method that will iterate over the |
2127 | # result set and force the query execution that way. |
2128 | return list(result_set) |
2129 | + |
2130 | + def getByQueueEntry(self, queue_entry): |
2131 | + """See `IBuildSet`.""" |
2132 | + store = getUtility(IStoreSelector).get(MAIN_STORE, DEFAULT_FLAVOR) |
2133 | + result_set = store.find( |
2134 | + Build, |
2135 | + BuildPackageJob.build == Build.id, |
2136 | + BuildPackageJob.job == queue_entry.job) |
2137 | + |
2138 | + return result_set.one() |
2139 | |
2140 | === modified file 'lib/lp/soyuz/model/builder.py' |
2141 | --- lib/lp/soyuz/model/builder.py 2009-11-11 10:43:07 +0000 |
2142 | +++ lib/lp/soyuz/model/builder.py 2009-11-13 20:43:22 +0000 |
2143 | @@ -52,6 +52,7 @@ |
2144 | from lp.soyuz.interfaces.buildqueue import IBuildQueueSet |
2145 | from lp.soyuz.interfaces.publishing import ( |
2146 | PackagePublishingStatus) |
2147 | +from lp.soyuz.model.buildpackagejob import BuildPackageJob |
2148 | from canonical.launchpad.webapp import urlappend |
2149 | from canonical.librarian.utils import copy_and_close |
2150 | |
2151 | @@ -151,11 +152,11 @@ |
2152 | # Avoid circular imports. |
2153 | from lp.soyuz.model.publishing import makePoolPath |
2154 | |
2155 | - build = build_queue_item.build |
2156 | + build = getUtility(IBuildSet).getByQueueEntry(build_queue_item) |
2157 | archive = build.archive |
2158 | archive_url = archive.archive_url |
2159 | component_name = build.current_component.name |
2160 | - for source_file in build_queue_item.files: |
2161 | + for source_file in build.sourcepackagerelease.files: |
2162 | file_name = source_file.libraryfile.filename |
2163 | sha1 = source_file.libraryfile.content.sha1 |
2164 | source_name = build.sourcepackagerelease.sourcepackagename.name |
2165 | @@ -264,8 +265,8 @@ |
2166 | * Ensure that the build pocket allows builds for the current |
2167 | distroseries state. |
2168 | """ |
2169 | - assert not (not self.virtualized and |
2170 | - build_queue_item.is_virtualized), ( |
2171 | + build = getUtility(IBuildSet).getByQueueEntry(build_queue_item) |
2172 | + assert not (not self.virtualized and build.is_virtualized), ( |
2173 | "Attempt to build non-virtual item on a virtual builder.") |
2174 | |
2175 | # Assert that we are not silently building SECURITY jobs. |
2176 | @@ -274,27 +275,27 @@ |
2177 | # XXX Julian 2007-12-18 spec=security-in-soyuz: This is being |
2178 | # addressed in the work on the blueprint: |
2179 | # https://blueprints.launchpad.net/soyuz/+spec/security-in-soyuz |
2180 | - target_pocket = build_queue_item.build.pocket |
2181 | + target_pocket = build.pocket |
2182 | assert target_pocket != PackagePublishingPocket.SECURITY, ( |
2183 | "Soyuz is not yet capable of building SECURITY uploads.") |
2184 | |
2185 | # Ensure build has the needed chroot |
2186 | - chroot = build_queue_item.archseries.getChroot() |
2187 | + build = getUtility(IBuildSet).getByQueueEntry(build_queue_item) |
2188 | + chroot = build.distroarchseries.getChroot() |
2189 | if chroot is None: |
2190 | raise CannotBuild( |
2191 | "Missing CHROOT for %s/%s/%s" % ( |
2192 | - build_queue_item.build.distroseries.distribution.name, |
2193 | - build_queue_item.build.distroseries.name, |
2194 | - build_queue_item.build.distroarchseries.architecturetag) |
2195 | + build.distroseries.distribution.name, |
2196 | + build.distroseries.name, |
2197 | + build.distroarchseries.architecturetag) |
2198 | ) |
2199 | |
2200 | # The main distribution has policies to prevent uploads to some |
2201 | # pockets (e.g. security) during different parts of the distribution |
2202 | # series lifecycle. These do not apply to PPA builds nor any archive |
2203 | # that allows release pocket updates. |
2204 | - if (build_queue_item.build.archive.purpose != ArchivePurpose.PPA and |
2205 | - not build_queue_item.build.archive.allowUpdatesToReleasePocket()): |
2206 | - build = build_queue_item.build |
2207 | + if (build.archive.purpose != ArchivePurpose.PPA and |
2208 | + not build.archive.allowUpdatesToReleasePocket()): |
2209 | # XXX Robert Collins 2007-05-26: not an explicit CannotBuild |
2210 | # exception yet because the callers have not been audited |
2211 | assert build.distroseries.canUploadToPocket(build.pocket), ( |
2212 | @@ -306,7 +307,8 @@ |
2213 | def _dispatchBuildToSlave(self, build_queue_item, args, buildid, logger): |
2214 | """Start the build on the slave builder.""" |
2215 | # Send chroot. |
2216 | - chroot = build_queue_item.archseries.getChroot() |
2217 | + build = getUtility(IBuildSet).getByQueueEntry(build_queue_item) |
2218 | + chroot = build.distroarchseries.getChroot() |
2219 | self.cacheFileOnSlave(logger, chroot) |
2220 | |
2221 | # Build filemap structure with the files required in this build |
2222 | @@ -314,11 +316,11 @@ |
2223 | # If the build is private we tell the slave to get the files from the |
2224 | # archive instead of the librarian because the slaves cannot |
2225 | # access the restricted librarian. |
2226 | - private = build_queue_item.build.archive.private |
2227 | + private = build.archive.private |
2228 | if private: |
2229 | self.cachePrivateSourceOnSlave(logger, build_queue_item) |
2230 | filemap = {} |
2231 | - for source_file in build_queue_item.files: |
2232 | + for source_file in build.sourcepackagerelease.files: |
2233 | lfa = source_file.libraryfile |
2234 | filemap[lfa.filename] = lfa.content.sha1 |
2235 | if not private: |
2236 | @@ -349,9 +351,10 @@ |
2237 | |
2238 | def startBuild(self, build_queue_item, logger): |
2239 | """See IBuilder.""" |
2240 | + build = getUtility(IBuildSet).getByQueueEntry(build_queue_item) |
2241 | + spr = build.sourcepackagerelease |
2242 | logger.info("startBuild(%s, %s, %s, %s)", self.url, |
2243 | - build_queue_item.name, build_queue_item.version, |
2244 | - build_queue_item.build.pocket.title) |
2245 | + spr.name, spr.version, build.pocket.title) |
2246 | |
2247 | # Make sure the request is valid; an exception is raised if it's not. |
2248 | self._verifyBuildRequest(build_queue_item, logger) |
2249 | @@ -365,39 +368,39 @@ |
2250 | # turn 'arch_indep' ON only if build is archindep or if |
2251 | # the specific architecture is the nominatedarchindep for |
2252 | # this distroseries (in case it requires any archindep source) |
2253 | - args['arch_indep'] = build_queue_item.archseries.isNominatedArchIndep |
2254 | + build = getUtility(IBuildSet).getByQueueEntry(build_queue_item) |
2255 | + args['arch_indep'] = build.distroarchseries.isNominatedArchIndep |
2256 | |
2257 | - suite = build_queue_item.build.distroarchseries.distroseries.name |
2258 | - if build_queue_item.build.pocket != PackagePublishingPocket.RELEASE: |
2259 | - suite += "-%s" % (build_queue_item.build.pocket.name.lower()) |
2260 | + suite = build.distroarchseries.distroseries.name |
2261 | + if build.pocket != PackagePublishingPocket.RELEASE: |
2262 | + suite += "-%s" % (build.pocket.name.lower()) |
2263 | args['suite'] = suite |
2264 | |
2265 | - archive_purpose = build_queue_item.build.archive.purpose |
2266 | + archive_purpose = build.archive.purpose |
2267 | if (archive_purpose == ArchivePurpose.PPA and |
2268 | - not build_queue_item.build.archive.require_virtualized): |
2269 | + not build.archive.require_virtualized): |
2270 | # If we're building a non-virtual PPA, override the purpose |
2271 | # to PRIMARY and use the primary component override. |
2272 | # This ensures that the package mangling tools will run over |
2273 | # the built packages. |
2274 | args['archive_purpose'] = ArchivePurpose.PRIMARY.name |
2275 | args["ogrecomponent"] = ( |
2276 | - get_primary_current_component(build_queue_item.build)) |
2277 | + get_primary_current_component(build)) |
2278 | else: |
2279 | args['archive_purpose'] = archive_purpose.name |
2280 | args["ogrecomponent"] = ( |
2281 | - build_queue_item.build.current_component.name) |
2282 | + build.current_component.name) |
2283 | |
2284 | - args['archives'] = get_sources_list_for_building( |
2285 | - build_queue_item.build) |
2286 | + args['archives'] = get_sources_list_for_building(build) |
2287 | |
2288 | # Let the build slave know whether this is a build in a private |
2289 | # archive. |
2290 | - args['archive_private'] = build_queue_item.build.archive.private |
2291 | + args['archive_private'] = build.archive.private |
2292 | |
2293 | # Generate a string which can be used to cross-check when obtaining |
2294 | # results so we know we are referring to the right database object in |
2295 | # subsequent runs. |
2296 | - buildid = "%s-%s" % (build_queue_item.build.id, build_queue_item.id) |
2297 | + buildid = "%s-%s" % (build.id, build_queue_item.id) |
2298 | logger.debug("Initiating build %s on %s" % (buildid, self.url)) |
2299 | |
2300 | # Do it. |
2301 | @@ -421,8 +424,9 @@ |
2302 | if currentjob is None: |
2303 | return 'Idle' |
2304 | |
2305 | - msg = 'Building %s' % currentjob.build.title |
2306 | - archive = currentjob.build.archive |
2307 | + build = getUtility(IBuildSet).getByQueueEntry(currentjob) |
2308 | + msg = 'Building %s' % build.title |
2309 | + archive = build.archive |
2310 | if not archive.owner.private and (archive.is_ppa or archive.is_copy): |
2311 | return '%s [%s/%s]' % (msg, archive.owner.name, archive.name) |
2312 | else: |
2313 | @@ -553,7 +557,8 @@ |
2314 | SourcePackagePublishingHistory.status IN %s)) |
2315 | OR |
2316 | archive.private IS FALSE) AND |
2317 | - buildqueue.build = build.id AND |
2318 | + buildqueue.job = buildpackagejob.job AND |
2319 | + buildpackagejob.build = build.id AND |
2320 | build.distroarchseries = distroarchseries.id AND |
2321 | build.archive = archive.id AND |
2322 | archive.enabled = TRUE AND |
2323 | @@ -563,7 +568,8 @@ |
2324 | """ % sqlvalues( |
2325 | private_statuses, BuildStatus.NEEDSBUILD, self.processor.family)] |
2326 | |
2327 | - clauseTables = ['Build', 'DistroArchSeries', 'Archive'] |
2328 | + clauseTables = [ |
2329 | + 'Build', 'BuildPackageJob', 'DistroArchSeries', 'Archive'] |
2330 | |
2331 | clauses.append(""" |
2332 | archive.require_virtualized = %s |
2333 | @@ -605,7 +611,7 @@ |
2334 | |
2335 | query = " AND ".join(clauses) |
2336 | candidate = BuildQueue.selectFirst( |
2337 | - query, clauseTables=clauseTables, prejoins=['build'], |
2338 | + query, clauseTables=clauseTables, |
2339 | orderBy=['-buildqueue.lastscore', 'build.id']) |
2340 | |
2341 | return candidate |
2342 | @@ -629,26 +635,28 @@ |
2343 | # Builds in those situation should not be built because they will |
2344 | # be wasting build-time, the former case already has a newer source |
2345 | # and the latter could not be built in DAK. |
2346 | + build_set = getUtility(IBuildSet) |
2347 | while candidate is not None: |
2348 | - if candidate.build.pocket == PackagePublishingPocket.SECURITY: |
2349 | + build = build_set.getByQueueEntry(candidate) |
2350 | + if build.pocket == PackagePublishingPocket.SECURITY: |
2351 | # We never build anything in the security pocket. |
2352 | logger.debug( |
2353 | "Build %s FAILEDTOBUILD, queue item %s REMOVED" |
2354 | - % (candidate.build.id, candidate.id)) |
2355 | - candidate.build.buildstate = BuildStatus.FAILEDTOBUILD |
2356 | + % (build.id, candidate.id)) |
2357 | + build.buildstate = BuildStatus.FAILEDTOBUILD |
2358 | candidate.destroySelf() |
2359 | candidate = self._findBuildCandidate() |
2360 | continue |
2361 | |
2362 | - publication = candidate.build.current_source_publication |
2363 | + publication = build.current_source_publication |
2364 | |
2365 | if publication is None: |
2366 | # The build should be superseded if it no longer has a |
2367 | # current publishing record. |
2368 | logger.debug( |
2369 | "Build %s SUPERSEDED, queue item %s REMOVED" |
2370 | - % (candidate.build.id, candidate.id)) |
2371 | - candidate.build.buildstate = BuildStatus.SUPERSEDED |
2372 | + % (build.id, candidate.id)) |
2373 | + build.buildstate = BuildStatus.SUPERSEDED |
2374 | candidate.destroySelf() |
2375 | candidate = self._findBuildCandidate() |
2376 | continue |
2377 | @@ -751,13 +759,15 @@ |
2378 | origin = ( |
2379 | Archive, |
2380 | Build, |
2381 | + BuildPackageJob, |
2382 | BuildQueue, |
2383 | DistroArchSeries, |
2384 | Processor, |
2385 | ) |
2386 | queue = store.using(*origin).find( |
2387 | BuildQueue, |
2388 | - BuildQueue.build == Build.id, |
2389 | + BuildPackageJob.job == BuildQueue.jobID, |
2390 | + BuildPackageJob.build == Build.id, |
2391 | Build.distroarchseries == DistroArchSeries.id, |
2392 | Build.archive == Archive.id, |
2393 | DistroArchSeries.processorfamilyID == Processor.familyID, |
2394 | |
2395 | === added file 'lib/lp/soyuz/model/buildpackagejob.py' |
2396 | --- lib/lp/soyuz/model/buildpackagejob.py 1970-01-01 00:00:00 +0000 |
2397 | +++ lib/lp/soyuz/model/buildpackagejob.py 2009-11-13 20:43:23 +0000 |
2398 | @@ -0,0 +1,168 @@ |
2399 | +# Copyright 2009 Canonical Ltd. This software is licensed under the |
2400 | +# GNU Affero General Public License version 3 (see the file LICENSE). |
2401 | + |
2402 | +__metaclass__ = type |
2403 | +__all__ = ['BuildPackageJob'] |
2404 | + |
2405 | + |
2406 | +from datetime import datetime |
2407 | +import pytz |
2408 | + |
2409 | +from storm.locals import Int, Reference, Storm |
2410 | + |
2411 | +from zope.interface import implements |
2412 | + |
2413 | +from canonical.database.constants import UTC_NOW |
2414 | +from canonical.launchpad.interfaces import SourcePackageUrgency |
2415 | +from lp.buildmaster.interfaces.buildfarmjob import IBuildFarmJob |
2416 | +from lp.registry.interfaces.pocket import PackagePublishingPocket |
2417 | +from lp.soyuz.interfaces.archive import ArchivePurpose |
2418 | +from lp.soyuz.interfaces.build import BuildStatus |
2419 | +from lp.soyuz.interfaces.buildpackagejob import IBuildPackageJob |
2420 | + |
2421 | + |
2422 | +class BuildPackageJob(Storm): |
2423 | + """See `IBuildPackageJob`.""" |
2424 | + implements(IBuildFarmJob, IBuildPackageJob) |
2425 | + __storm_table__ = 'buildpackagejob' |
2426 | + id = Int(primary=True) |
2427 | + |
2428 | + job_id = Int(name='job', allow_none=False) |
2429 | + job = Reference(job_id, 'Job.id') |
2430 | + |
2431 | + build_id = Int(name='build', allow_none=False) |
2432 | + build = Reference(build_id, 'Build.id') |
2433 | + |
2434 | + def score(self): |
2435 | + """See `IBuildPackageJob`.""" |
2436 | + score_pocketname = { |
2437 | + PackagePublishingPocket.BACKPORTS: 0, |
2438 | + PackagePublishingPocket.RELEASE: 1500, |
2439 | + PackagePublishingPocket.PROPOSED: 3000, |
2440 | + PackagePublishingPocket.UPDATES: 3000, |
2441 | + PackagePublishingPocket.SECURITY: 4500, |
2442 | + } |
2443 | + |
2444 | + score_componentname = { |
2445 | + 'multiverse': 0, |
2446 | + 'universe': 250, |
2447 | + 'restricted': 750, |
2448 | + 'main': 1000, |
2449 | + 'partner' : 1250, |
2450 | + } |
2451 | + |
2452 | + score_urgency = { |
2453 | + SourcePackageUrgency.LOW: 5, |
2454 | + SourcePackageUrgency.MEDIUM: 10, |
2455 | + SourcePackageUrgency.HIGH: 15, |
2456 | + SourcePackageUrgency.EMERGENCY: 20, |
2457 | + } |
2458 | + |
2459 | + # Define a table we'll use to calculate the score based on the time |
2460 | + # in the build queue. The table is a sorted list of (upper time |
2461 | + # limit in seconds, score) tuples. |
2462 | + queue_time_scores = [ |
2463 | + (14400, 100), |
2464 | + (7200, 50), |
2465 | + (3600, 20), |
2466 | + (1800, 15), |
2467 | + (900, 10), |
2468 | + (300, 5), |
2469 | + ] |
2470 | + |
2471 | + private_archive_increment = 10000 |
2472 | + |
2473 | + # For build jobs in rebuild archives a score value of -1 |
2474 | + # was chosen because their priority is lower than build retries |
2475 | + # or language-packs. They should be built only when there is |
2476 | + # nothing else to build. |
2477 | + rebuild_archive_score = -10 |
2478 | + |
2479 | + score = 0 |
2480 | + |
2481 | + # Please note: the score for language packs is to be zero because |
2482 | + # they unduly delay the building of packages in the main component |
2483 | + # otherwise. |
2484 | + if self.build.sourcepackagerelease.section.name == 'translations': |
2485 | + pass |
2486 | + elif self.build.archive.purpose == ArchivePurpose.COPY: |
2487 | + score = rebuild_archive_score |
2488 | + else: |
2489 | + # Calculates the urgency-related part of the score. |
2490 | + urgency = score_urgency[self.build.sourcepackagerelease.urgency] |
2491 | + score += urgency |
2492 | + |
2493 | + # Calculates the pocket-related part of the score. |
2494 | + score_pocket = score_pocketname[self.build.pocket] |
2495 | + score += score_pocket |
2496 | + |
2497 | + # Calculates the component-related part of the score. |
2498 | + score_component = score_componentname[ |
2499 | + self.build.current_component.name] |
2500 | + score += score_component |
2501 | + |
2502 | + # Calculates the build queue time component of the score. |
2503 | + right_now = datetime.now(pytz.timezone('UTC')) |
2504 | + eta = right_now - self.job.date_created |
2505 | + for limit, dep_score in queue_time_scores: |
2506 | + if eta.seconds > limit: |
2507 | + score += dep_score |
2508 | + break |
2509 | + |
2510 | + # Private builds get uber score. |
2511 | + if self.build.archive.private: |
2512 | + score += private_archive_increment |
2513 | + |
2514 | + # Lastly, apply the archive score delta. This is to boost |
2515 | + # or retard build scores for any build in a particular |
2516 | + # archive. |
2517 | + score += self.build.archive.relative_build_score |
2518 | + |
2519 | + return score |
2520 | + |
2521 | + def getLogFileName(self): |
2522 | + """See `IBuildPackageJob`.""" |
2523 | + sourcename = self.build.sourcepackagerelease.name |
2524 | + version = self.build.sourcepackagerelease.version |
2525 | + # we rely on previous storage of current buildstate |
2526 | + # in the state handling methods. |
2527 | + state = self.build.buildstate.name |
2528 | + |
2529 | + dar = self.build.distroarchseries |
2530 | + distroname = dar.distroseries.distribution.name |
2531 | + distroseriesname = dar.distroseries.name |
2532 | + archname = dar.architecturetag |
2533 | + |
2534 | + # logfilename format: |
2535 | + # buildlog_<DISTRIBUTION>_<DISTROSeries>_<ARCHITECTURE>_\ |
2536 | + # <SOURCENAME>_<SOURCEVERSION>_<BUILDSTATE>.txt |
2537 | + # as: |
2538 | + # buildlog_ubuntu_dapper_i386_foo_1.0-ubuntu0_FULLYBUILT.txt |
2539 | + # it fix request from bug # 30617 |
2540 | + return ('buildlog_%s-%s-%s.%s_%s_%s.txt' % ( |
2541 | + distroname, distroseriesname, archname, sourcename, version, state |
2542 | + )) |
2543 | + |
2544 | + def getName(self): |
2545 | + """See `IBuildPackageJob`.""" |
2546 | + return self.build.sourcepackagerelease.name |
2547 | + |
2548 | + def jobStarted(self): |
2549 | + """See `IBuildPackageJob`.""" |
2550 | + self.build.buildstate = BuildStatus.BUILDING |
2551 | + # The build started, set the start time if not set already. |
2552 | + if self.build.date_first_dispatched is None: |
2553 | + self.build.date_first_dispatched = UTC_NOW |
2554 | + |
2555 | + def jobReset(self): |
2556 | + """See `IBuildPackageJob`.""" |
2557 | + self.build.buildstate = BuildStatus.NEEDSBUILD |
2558 | + |
2559 | + def jobAborted(self): |
2560 | + """See `IBuildPackageJob`.""" |
2561 | + # XXX, al-maisan, Thu, 12 Nov 2009 16:38:52 +0100 |
2562 | + # The setting below was "inherited" from the previous code. We |
2563 | + # need to investigate whether and why this is really needed and |
2564 | + # fix it. |
2565 | + self.build.buildstate = BuildStatus.BUILDING |
2566 | + |
2567 | |
2568 | === modified file 'lib/lp/soyuz/model/buildqueue.py' |
2569 | --- lib/lp/soyuz/model/buildqueue.py 2009-08-28 06:39:38 +0000 |
2570 | +++ lib/lp/soyuz/model/buildqueue.py 2009-11-13 20:43:23 +0000 |
2571 | @@ -10,27 +10,25 @@ |
2572 | 'BuildQueueSet' |
2573 | ] |
2574 | |
2575 | -from datetime import datetime |
2576 | import logging |
2577 | -import pytz |
2578 | |
2579 | from zope.component import getUtility |
2580 | from zope.interface import implements |
2581 | |
2582 | from sqlobject import ( |
2583 | StringCol, ForeignKey, BoolCol, IntCol, SQLObjectNotFound) |
2584 | -from storm.expr import In, LeftJoin |
2585 | +from storm.expr import In, Join, LeftJoin |
2586 | |
2587 | from canonical import encoding |
2588 | -from canonical.database.constants import UTC_NOW |
2589 | -from canonical.database.datetimecol import UtcDateTimeCol |
2590 | +from canonical.database.enumcol import EnumCol |
2591 | from canonical.database.sqlbase import SQLBase, sqlvalues |
2592 | from canonical.launchpad.webapp.interfaces import NotFoundError |
2593 | -from lp.registry.interfaces.sourcepackage import SourcePackageUrgency |
2594 | -from lp.soyuz.interfaces.archive import ArchivePurpose |
2595 | -from lp.soyuz.interfaces.build import BuildStatus |
2596 | +from lp.buildmaster.interfaces.buildfarmjob import BuildFarmJobType |
2597 | +from lp.services.job.interfaces.job import JobStatus |
2598 | +from lp.services.job.model.job import Job |
2599 | +from lp.soyuz.interfaces.build import BuildStatus, IBuildSet |
2600 | from lp.soyuz.interfaces.buildqueue import IBuildQueue, IBuildQueueSet |
2601 | -from lp.registry.interfaces.pocket import PackagePublishingPocket |
2602 | +from lp.soyuz.model.buildpackagejob import BuildPackageJob |
2603 | from canonical.launchpad.webapp.interfaces import ( |
2604 | IStoreSelector, MAIN_STORE, DEFAULT_FLAVOR) |
2605 | |
2606 | @@ -40,229 +38,85 @@ |
2607 | _table = "BuildQueue" |
2608 | _defaultOrder = "id" |
2609 | |
2610 | - build = ForeignKey(dbName='build', foreignKey='Build', notNull=True) |
2611 | + job = ForeignKey(dbName='job', foreignKey='Job', notNull=True) |
2612 | + job_type = EnumCol( |
2613 | + enum=BuildFarmJobType, notNull=True, |
2614 | + default=BuildFarmJobType.PACKAGEBUILD, dbName='job_type') |
2615 | builder = ForeignKey(dbName='builder', foreignKey='Builder', default=None) |
2616 | - created = UtcDateTimeCol(dbName='created', default=UTC_NOW) |
2617 | - buildstart = UtcDateTimeCol(dbName='buildstart', default= None) |
2618 | logtail = StringCol(dbName='logtail', default=None) |
2619 | lastscore = IntCol(dbName='lastscore', default=0) |
2620 | manual = BoolCol(dbName='manual', default=False) |
2621 | |
2622 | + @property |
2623 | + def specific_job(self): |
2624 | + """See `IBuildQueue`.""" |
2625 | + store = getUtility(IStoreSelector).get(MAIN_STORE, DEFAULT_FLAVOR) |
2626 | + result_set = store.find( |
2627 | + BuildPackageJob, BuildPackageJob.job == self.job) |
2628 | + return result_set.one() |
2629 | + |
2630 | + @property |
2631 | + def date_started(self): |
2632 | + """See `IBuildQueue`.""" |
2633 | + return self.job.date_started |
2634 | + |
2635 | def manualScore(self, value): |
2636 | """See `IBuildQueue`.""" |
2637 | self.lastscore = value |
2638 | self.manual = True |
2639 | |
2640 | - @property |
2641 | - def archseries(self): |
2642 | - """See `IBuildQueue`.""" |
2643 | - return self.build.distroarchseries |
2644 | - |
2645 | - @property |
2646 | - def urgency(self): |
2647 | - """See `IBuildQueue`.""" |
2648 | - return self.build.sourcepackagerelease.urgency |
2649 | - |
2650 | - @property |
2651 | - def archhintlist(self): |
2652 | - """See `IBuildQueue`.""" |
2653 | - return self.build.sourcepackagerelease.architecturehintlist |
2654 | - |
2655 | - @property |
2656 | - def name(self): |
2657 | - """See `IBuildQueue`.""" |
2658 | - return self.build.sourcepackagerelease.name |
2659 | - |
2660 | - @property |
2661 | - def version(self): |
2662 | - """See `IBuildQueue`.""" |
2663 | - return self.build.sourcepackagerelease.version |
2664 | - |
2665 | - @property |
2666 | - def files(self): |
2667 | - """See `IBuildQueue`.""" |
2668 | - return self.build.sourcepackagerelease.files |
2669 | - |
2670 | - @property |
2671 | - def builddependsindep(self): |
2672 | - """See `IBuildQueue`.""" |
2673 | - return self.build.sourcepackagerelease.builddependsindep |
2674 | - |
2675 | - @property |
2676 | - def buildduration(self): |
2677 | - """See `IBuildQueue`.""" |
2678 | - if self.buildstart: |
2679 | - UTC = pytz.timezone('UTC') |
2680 | - now = datetime.now(UTC) |
2681 | - return now - self.buildstart |
2682 | - return None |
2683 | - |
2684 | - @property |
2685 | - def is_virtualized(self): |
2686 | - """See `IBuildQueue`.""" |
2687 | - return self.build.is_virtualized |
2688 | - |
2689 | def score(self): |
2690 | """See `IBuildQueue`.""" |
2691 | # Grab any logger instance available. |
2692 | logger = logging.getLogger() |
2693 | + name = self.specific_job.getName() |
2694 | |
2695 | if self.manual: |
2696 | logger.debug( |
2697 | - "%s (%d) MANUALLY RESCORED" % (self.name, self.lastscore)) |
2698 | + "%s (%d) MANUALLY RESCORED" % (name, self.lastscore)) |
2699 | return |
2700 | |
2701 | - # XXX Al-maisan, 2008-05-14 (bug #230330): |
2702 | - # We keep touching the code here whenever a modification to the |
2703 | - # scoring parameters/weights is needed. Maybe the latter can be |
2704 | - # externalized? |
2705 | - |
2706 | - score_pocketname = { |
2707 | - PackagePublishingPocket.BACKPORTS: 0, |
2708 | - PackagePublishingPocket.RELEASE: 1500, |
2709 | - PackagePublishingPocket.PROPOSED: 3000, |
2710 | - PackagePublishingPocket.UPDATES: 3000, |
2711 | - PackagePublishingPocket.SECURITY: 4500, |
2712 | - } |
2713 | - |
2714 | - score_componentname = { |
2715 | - 'multiverse': 0, |
2716 | - 'universe': 250, |
2717 | - 'restricted': 750, |
2718 | - 'main': 1000, |
2719 | - 'partner' : 1250, |
2720 | - } |
2721 | - |
2722 | - score_urgency = { |
2723 | - SourcePackageUrgency.LOW: 5, |
2724 | - SourcePackageUrgency.MEDIUM: 10, |
2725 | - SourcePackageUrgency.HIGH: 15, |
2726 | - SourcePackageUrgency.EMERGENCY: 20, |
2727 | - } |
2728 | - |
2729 | - # Define a table we'll use to calculate the score based on the time |
2730 | - # in the build queue. The table is a sorted list of (upper time |
2731 | - # limit in seconds, score) tuples. |
2732 | - queue_time_scores = [ |
2733 | - (14400, 100), |
2734 | - (7200, 50), |
2735 | - (3600, 20), |
2736 | - (1800, 15), |
2737 | - (900, 10), |
2738 | - (300, 5), |
2739 | - ] |
2740 | - |
2741 | - private_archive_increment = 10000 |
2742 | - |
2743 | - # For build jobs in rebuild archives a score value of -1 |
2744 | - # was chosen because their priority is lower than build retries |
2745 | - # or language-packs. They should be built only when there is |
2746 | - # nothing else to build. |
2747 | - rebuild_archive_score = -10 |
2748 | - |
2749 | - score = 0 |
2750 | - msg = "%s (%d) -> " % (self.build.title, self.lastscore) |
2751 | - |
2752 | - # Please note: the score for language packs is to be zero because |
2753 | - # they unduly delay the building of packages in the main component |
2754 | - # otherwise. |
2755 | - if self.build.sourcepackagerelease.section.name == 'translations': |
2756 | - msg += "LPack => score zero" |
2757 | - elif self.build.archive.purpose == ArchivePurpose.COPY: |
2758 | - score = rebuild_archive_score |
2759 | - msg += "Rebuild archive => -10" |
2760 | - else: |
2761 | - # Calculates the urgency-related part of the score. |
2762 | - urgency = score_urgency[self.urgency] |
2763 | - score += urgency |
2764 | - msg += "U+%d " % urgency |
2765 | - |
2766 | - # Calculates the pocket-related part of the score. |
2767 | - score_pocket = score_pocketname[self.build.pocket] |
2768 | - score += score_pocket |
2769 | - msg += "P+%d " % score_pocket |
2770 | - |
2771 | - # Calculates the component-related part of the score. |
2772 | - score_component = score_componentname[ |
2773 | - self.build.current_component.name] |
2774 | - score += score_component |
2775 | - msg += "C+%d " % score_component |
2776 | - |
2777 | - # Calculates the build queue time component of the score. |
2778 | - right_now = datetime.now(pytz.timezone('UTC')) |
2779 | - eta = right_now - self.created |
2780 | - for limit, dep_score in queue_time_scores: |
2781 | - if eta.seconds > limit: |
2782 | - score += dep_score |
2783 | - msg += "T+%d " % dep_score |
2784 | - break |
2785 | - else: |
2786 | - msg += "T+0 " |
2787 | - |
2788 | - # Private builds get uber score. |
2789 | - if self.build.archive.private: |
2790 | - score += private_archive_increment |
2791 | - |
2792 | - # Lastly, apply the archive score delta. This is to boost |
2793 | - # or retard build scores for any build in a particular |
2794 | - # archive. |
2795 | - score += self.build.archive.relative_build_score |
2796 | - |
2797 | - # Store current score value. |
2798 | - self.lastscore = score |
2799 | - |
2800 | - logger.debug("%s= %d" % (msg, self.lastscore)) |
2801 | + # Allow the `IBuildFarmJob` instance with the data/logic specific to |
2802 | + # the job at hand to calculate the score as appropriate. |
2803 | + self.lastscore = self.specific_job.score() |
2804 | |
2805 | def getLogFileName(self): |
2806 | """See `IBuildQueue`.""" |
2807 | - sourcename = self.build.sourcepackagerelease.name |
2808 | - version = self.build.sourcepackagerelease.version |
2809 | - # we rely on previous storage of current buildstate |
2810 | - # in the state handling methods. |
2811 | - state = self.build.buildstate.name |
2812 | - |
2813 | - dar = self.build.distroarchseries |
2814 | - distroname = dar.distroseries.distribution.name |
2815 | - distroseriesname = dar.distroseries.name |
2816 | - archname = dar.architecturetag |
2817 | - |
2818 | - # logfilename format: |
2819 | - # buildlog_<DISTRIBUTION>_<DISTROSeries>_<ARCHITECTURE>_\ |
2820 | - # <SOURCENAME>_<SOURCEVERSION>_<BUILDSTATE>.txt |
2821 | - # as: |
2822 | - # buildlog_ubuntu_dapper_i386_foo_1.0-ubuntu0_FULLYBUILT.txt |
2823 | - # it fix request from bug # 30617 |
2824 | - return ('buildlog_%s-%s-%s.%s_%s_%s.txt' % ( |
2825 | - distroname, distroseriesname, archname, sourcename, version, state |
2826 | - )) |
2827 | + # Allow the `IBuildFarmJob` instance with the data/logic specific to |
2828 | + # the job at hand to calculate the log file name as appropriate. |
2829 | + return self.specific_job.getLogFileName() |
2830 | |
2831 | def markAsBuilding(self, builder): |
2832 | """See `IBuildQueue`.""" |
2833 | self.builder = builder |
2834 | - self.buildstart = UTC_NOW |
2835 | - self.build.buildstate = BuildStatus.BUILDING |
2836 | - # The build started, set the start time if not set already. |
2837 | - if self.build.date_first_dispatched is None: |
2838 | - self.build.date_first_dispatched = UTC_NOW |
2839 | + if self.job.status != JobStatus.RUNNING: |
2840 | + self.job.start() |
2841 | + self.specific_job.jobStarted() |
2842 | |
2843 | def reset(self): |
2844 | """See `IBuildQueue`.""" |
2845 | self.builder = None |
2846 | - self.buildstart = None |
2847 | + if self.job.status != JobStatus.WAITING: |
2848 | + self.job.queue() |
2849 | + self.job.date_started = None |
2850 | + self.job.date_finished = None |
2851 | self.logtail = None |
2852 | - self.build.buildstate = BuildStatus.NEEDSBUILD |
2853 | + self.specific_job.jobReset() |
2854 | |
2855 | def updateBuild_IDLE(self, build_id, build_status, logtail, |
2856 | filemap, dependencies, logger): |
2857 | """See `IBuildQueue`.""" |
2858 | + build = getUtility(IBuildSet).getByQueueEntry(self) |
2859 | logger.warn( |
2860 | "Builder %s forgot about build %s -- resetting buildqueue record" |
2861 | - % (self.builder.url, self.build.title)) |
2862 | + % (self.builder.url, build.title)) |
2863 | self.reset() |
2864 | |
2865 | def updateBuild_BUILDING(self, build_id, build_status, |
2866 | logtail, filemap, dependencies, logger): |
2867 | """See `IBuildQueue`.""" |
2868 | + if self.job.status != JobStatus.RUNNING: |
2869 | + self.job.start() |
2870 | self.logtail = encoding.guess(str(logtail)) |
2871 | |
2872 | def updateBuild_ABORTING(self, buildid, build_status, |
2873 | @@ -275,8 +129,15 @@ |
2874 | """See `IBuildQueue`.""" |
2875 | self.builder.cleanSlave() |
2876 | self.builder = None |
2877 | - self.buildstart = None |
2878 | - self.build.buildstate = BuildStatus.BUILDING |
2879 | + if self.job.status != JobStatus.FAILED: |
2880 | + self.job.fail() |
2881 | + self.job.date_started = None |
2882 | + self.job.date_finished = None |
2883 | + self.specific_job.jobAborted() |
2884 | + |
2885 | + def setDateStarted(self, timestamp): |
2886 | + """See `IBuildQueue`.""" |
2887 | + self.job.date_started = timestamp |
2888 | |
2889 | |
2890 | class BuildQueueSet(object): |
2891 | @@ -311,7 +172,12 @@ |
2892 | |
2893 | def getActiveBuildJobs(self): |
2894 | """See `IBuildQueueSet`.""" |
2895 | - return BuildQueue.select('buildstart is not null') |
2896 | + store = getUtility(IStoreSelector).get(MAIN_STORE, DEFAULT_FLAVOR) |
2897 | + result_set = store.find( |
2898 | + BuildQueue, |
2899 | + BuildQueue.job == Job.id, |
2900 | + Job.date_started != None) |
2901 | + return result_set |
2902 | |
2903 | def calculateCandidates(self, archseries): |
2904 | """See `IBuildQueueSet`.""" |
2905 | @@ -323,30 +189,37 @@ |
2906 | query = """ |
2907 | Build.distroarchseries IN %s AND |
2908 | Build.buildstate = %s AND |
2909 | - BuildQueue.build = build.id AND |
2910 | + BuildQueue.job_type = %s AND |
2911 | + BuildQueue.job = BuildPackageJob.job AND |
2912 | + BuildPackageJob.build = build.id AND |
2913 | BuildQueue.builder IS NULL |
2914 | - """ % sqlvalues(arch_ids, BuildStatus.NEEDSBUILD) |
2915 | + """ % sqlvalues( |
2916 | + arch_ids, BuildStatus.NEEDSBUILD, BuildFarmJobType.PACKAGEBUILD) |
2917 | |
2918 | candidates = BuildQueue.select( |
2919 | - query, clauseTables=['Build'], orderBy=['-BuildQueue.lastscore']) |
2920 | + query, clauseTables=['Build', 'BuildPackageJob'], |
2921 | + orderBy=['-BuildQueue.lastscore']) |
2922 | |
2923 | return candidates |
2924 | |
2925 | def getForBuilds(self, build_ids): |
2926 | """See `IBuildQueueSet`.""" |
2927 | # Avoid circular import problem. |
2928 | + from lp.soyuz.model.build import Build |
2929 | from lp.soyuz.model.builder import Builder |
2930 | |
2931 | store = getUtility(IStoreSelector).get(MAIN_STORE, DEFAULT_FLAVOR) |
2932 | |
2933 | origin = ( |
2934 | - BuildQueue, |
2935 | + BuildPackageJob, |
2936 | + Join(BuildQueue, BuildPackageJob.job == BuildQueue.jobID), |
2937 | + Join(Build, BuildPackageJob.build == Build.id), |
2938 | LeftJoin( |
2939 | Builder, |
2940 | BuildQueue.builderID == Builder.id), |
2941 | ) |
2942 | result_set = store.using(*origin).find( |
2943 | - (BuildQueue, Builder), |
2944 | - In(BuildQueue.buildID, build_ids)) |
2945 | + (BuildQueue, Builder, BuildPackageJob), |
2946 | + In(Build.id, build_ids)) |
2947 | |
2948 | return result_set |
2949 | |
2950 | === modified file 'lib/lp/soyuz/stories/soyuz/xx-build-record.txt' |
2951 | --- lib/lp/soyuz/stories/soyuz/xx-build-record.txt 2009-09-23 16:38:10 +0000 |
2952 | +++ lib/lp/soyuz/stories/soyuz/xx-build-record.txt 2009-11-13 20:43:23 +0000 |
2953 | @@ -23,8 +23,9 @@ |
2954 | >>> bob_builder.builderok = True |
2955 | |
2956 | # Set a known duration for the current job. |
2957 | - >>> in_progress_build = removeSecurityProxy( |
2958 | - ... bob_builder.currentjob.build) |
2959 | + >>> from lp.soyuz.interfaces.build import IBuildSet |
2960 | + >>> build2 = getUtility(IBuildSet).getByQueueEntry(bob_builder.currentjob) |
2961 | + >>> in_progress_build = removeSecurityProxy(build2) |
2962 | >>> one_minute = datetime.timedelta(seconds=60) |
2963 | >>> in_progress_build.estimated_build_duration = one_minute |
2964 | |
2965 | @@ -122,12 +123,8 @@ |
2966 | >>> login('foo.bar@canonical.com') |
2967 | >>> from canonical.database.constants import UTC_NOW |
2968 | >>> from lp.soyuz.interfaces.build import BuildStatus |
2969 | - >>> in_progress_build.buildstate = BuildStatus.NEEDSBUILD |
2970 | - >>> in_progress_build.buildqueue_record.buildstart = None |
2971 | - >>> in_progress_build.buildqueue_record.builder = None |
2972 | - >>> build.buildstate = BuildStatus.BUILDING |
2973 | - >>> build.buildqueue_record.buildstart = UTC_NOW |
2974 | - >>> build.buildqueue_record.builder = bob_builder |
2975 | + >>> in_progress_build.buildqueue_record.reset() |
2976 | + >>> build.buildqueue_record.markAsBuilding(bob_builder) |
2977 | >>> build.buildqueue_record.logtail = 'one line\nanother line' |
2978 | >>> logout() |
2979 | |
2980 | |
2981 | === modified file 'lib/lp/soyuz/templates/build-index.pt' |
2982 | --- lib/lp/soyuz/templates/build-index.pt 2009-09-17 12:08:45 +0000 |
2983 | +++ lib/lp/soyuz/templates/build-index.pt 2009-11-13 20:43:23 +0000 |
2984 | @@ -161,8 +161,8 @@ |
2985 | <tal:building condition="context/buildstate/enumvalue:BUILDING"> |
2986 | <li> |
2987 | Started |
2988 | - <span tal:attributes="title view/buildqueue/buildstart/fmt:datetime" |
2989 | - tal:content="view/buildqueue/buildstart/fmt:approximatedate" |
2990 | + <span tal:attributes="title view/buildqueue/job/date_started/fmt:datetime" |
2991 | + tal:content="view/buildqueue/job/date_started/fmt:approximatedate" |
2992 | >5 minutes ago</span> |
2993 | </li> |
2994 | </tal:building> |
2995 | |
2996 | === modified file 'lib/lp/soyuz/templates/builder-index.pt' |
2997 | --- lib/lp/soyuz/templates/builder-index.pt 2009-09-16 19:06:48 +0000 |
2998 | +++ lib/lp/soyuz/templates/builder-index.pt 2009-11-13 20:43:23 +0000 |
2999 | @@ -104,9 +104,14 @@ |
3000 | </tal:buildernok> |
3001 | </tal:no_job> |
3002 | |
3003 | + <tal:comment replace="nothing"> |
3004 | + In the very near future, 'job' will not just be a Build job. |
3005 | + The template needs to cope with that as and when new job types are |
3006 | + added. |
3007 | + </tal:comment> |
3008 | <tal:job condition="job"> |
3009 | <span class="sortkey" tal:content="job/id" /> |
3010 | - <tal:build define="build job/build"> |
3011 | + <tal:build define="build job/specific_job/build"> |
3012 | <tal:visible condition="build/required:launchpad.View"> |
3013 | <tal:icon replace="structure build/image:icon" /> |
3014 | Building |
3015 | @@ -153,10 +158,12 @@ |
3016 | |
3017 | <tal:job condition="job"> |
3018 | <p class="sprite">Started |
3019 | - <span tal:attributes="title job/buildstart/fmt:datetime" |
3020 | + <span tal:attributes="title job/job/date_started/fmt:datetime" |
3021 | tal:content="view/current_build_duration/fmt:exactduration" |
3022 | /> ago.</p> |
3023 | - <tal:visible condition="job/build/required:launchpad.View"> |
3024 | + <tal:visible |
3025 | + define="build job/specific_job/build" |
3026 | + condition="build/required:launchpad.View"> |
3027 | <tal:logtail condition="job/logtail"> |
3028 | <h3>Buildlog</h3> |
3029 | <div tal:content="structure job/logtail/fmt:text-to-html" |
3030 | |
3031 | === modified file 'lib/lp/soyuz/templates/builds-list.pt' |
3032 | --- lib/lp/soyuz/templates/builds-list.pt 2009-08-18 12:33:37 +0000 |
3033 | +++ lib/lp/soyuz/templates/builds-list.pt 2009-11-13 20:43:23 +0000 |
3034 | @@ -101,8 +101,8 @@ |
3035 | <tal:building condition="bq/builder"> |
3036 | Build started |
3037 | <span |
3038 | - tal:attributes="title bq/buildstart/fmt:datetime" |
3039 | - tal:content="bq/buildstart/fmt:displaydate" /> |
3040 | + tal:attributes="title bq/job/date_started/fmt:datetime" |
3041 | + tal:content="bq/job/date_started/fmt:displaydate" /> |
3042 | on |
3043 | <a tal:content="bq/builder/title" |
3044 | tal:attributes="href bq/builder/fmt:url"/> |
3045 | |
3046 | === modified file 'lib/lp/soyuz/tests/test_builder.py' |
3047 | --- lib/lp/soyuz/tests/test_builder.py 2009-11-11 10:43:07 +0000 |
3048 | +++ lib/lp/soyuz/tests/test_builder.py 2009-11-13 20:43:23 +0000 |
3049 | @@ -9,8 +9,8 @@ |
3050 | |
3051 | from canonical.testing import LaunchpadZopelessLayer |
3052 | from lp.soyuz.interfaces.archive import ArchivePurpose |
3053 | +from lp.soyuz.interfaces.build import BuildStatus, IBuildSet |
3054 | from lp.soyuz.interfaces.builder import IBuilderSet |
3055 | -from lp.soyuz.interfaces.build import BuildStatus |
3056 | from lp.soyuz.interfaces.publishing import PackagePublishingStatus |
3057 | from lp.soyuz.tests.test_publishing import SoyuzTestPublisher |
3058 | from lp.testing import TestCaseWithFactory |
3059 | @@ -77,14 +77,16 @@ |
3060 | |
3061 | # Asking frog to find a candidate should give us the joesppa build. |
3062 | next_job = self.frog_builder.findBuildCandidate() |
3063 | - self.assertEqual('joesppa', next_job.build.archive.name) |
3064 | + build = getUtility(IBuildSet).getByQueueEntry(next_job) |
3065 | + self.assertEqual('joesppa', build.archive.name) |
3066 | |
3067 | # If bob is in a failed state the joesppa build is still |
3068 | # returned. |
3069 | self.bob_builder.builderok = False |
3070 | self.bob_builder.manual = False |
3071 | next_job = self.frog_builder.findBuildCandidate() |
3072 | - self.assertEqual('joesppa', next_job.build.archive.name) |
3073 | + build = getUtility(IBuildSet).getByQueueEntry(next_job) |
3074 | + self.assertEqual('joesppa', build.archive.name) |
3075 | |
3076 | |
3077 | class TestFindBuildCandidatePPA(TestFindBuildCandidateBase): |
3078 | @@ -156,14 +158,16 @@ |
3079 | # A PPA cannot start a build if it would use 80% or more of the |
3080 | # builders. |
3081 | next_job = self.builder4.findBuildCandidate() |
3082 | - self.failIfEqual('joesppa', next_job.build.archive.name) |
3083 | + build = getUtility(IBuildSet).getByQueueEntry(next_job) |
3084 | + self.failIfEqual('joesppa', build.archive.name) |
3085 | |
3086 | def test_findBuildCandidate_first_build_finished(self): |
3087 | # When joe's first ppa build finishes, his fourth i386 build |
3088 | # will be the next build candidate. |
3089 | self.joe_builds[0].buildstate = BuildStatus.FAILEDTOBUILD |
3090 | next_job = self.builder4.findBuildCandidate() |
3091 | - self.failUnlessEqual('joesppa', next_job.build.archive.name) |
3092 | + build = getUtility(IBuildSet).getByQueueEntry(next_job) |
3093 | + self.failUnlessEqual('joesppa', build.archive.name) |
3094 | |
3095 | def test_findBuildCandidate_for_private_ppa(self): |
3096 | # If a ppa is private it will be able to have parallel builds |
3097 | @@ -171,7 +175,8 @@ |
3098 | self.ppa_joe.private = True |
3099 | self.ppa_joe.buildd_secret = 'sekrit' |
3100 | next_job = self.builder4.findBuildCandidate() |
3101 | - self.failUnlessEqual('joesppa', next_job.build.archive.name) |
3102 | + build = getUtility(IBuildSet).getByQueueEntry(next_job) |
3103 | + self.failUnlessEqual('joesppa', build.archive.name) |
3104 | |
3105 | |
3106 | class TestFindBuildCandidateDistroArchive(TestFindBuildCandidateBase): |
3107 | @@ -196,18 +201,18 @@ |
3108 | # arch. |
3109 | |
3110 | next_job = self.builder2.findBuildCandidate() |
3111 | - self.failUnlessEqual('primary', next_job.build.archive.name) |
3112 | - self.failUnlessEqual( |
3113 | - 'gedit', next_job.build.sourcepackagerelease.name) |
3114 | + build = getUtility(IBuildSet).getByQueueEntry(next_job) |
3115 | + self.failUnlessEqual('primary', build.archive.name) |
3116 | + self.failUnlessEqual('gedit', build.sourcepackagerelease.name) |
3117 | |
3118 | # Now even if we set the build building, we'll still get the |
3119 | # second non-ppa build for the same archive as the next candidate. |
3120 | - next_job.build.buildstate = BuildStatus.BUILDING |
3121 | - next_job.build.builder = self.builder2 |
3122 | + build.buildstate = BuildStatus.BUILDING |
3123 | + build.builder = self.builder2 |
3124 | next_job = self.builder2.findBuildCandidate() |
3125 | - self.failUnlessEqual('primary', next_job.build.archive.name) |
3126 | - self.failUnlessEqual( |
3127 | - 'firefox', next_job.build.sourcepackagerelease.name) |
3128 | + build = getUtility(IBuildSet).getByQueueEntry(next_job) |
3129 | + self.failUnlessEqual('primary', build.archive.name) |
3130 | + self.failUnlessEqual('firefox', build.sourcepackagerelease.name) |
3131 | |
3132 | def test_suite(): |
3133 | return unittest.TestLoader().loadTestsFromName(__name__) |
Hello there!
This is a follow-up branch to the schema (and sample data) changes required
for the Soyuz buildd generalisation. It refactors the code in the python
domain to cope with the schema changes.
For more details on the Soyuz buildd generalisation /dev.launchpad. net/Soyuz/ Specs/BuilddGen eralisation.
please see: https:/
Pre-implementation call, assistance and intermediate reviews by Julian E.
Tests to run:
bin/test -vv -t build
No pertinent lint errors or warnings.
This branch depends on the schema patch branch (lp:~al-maisan/launchpad/builddsc-478919). Just in case the diff includes the schema patch: the *real* diff is here: http:// pastebin. ubuntu. com/317945/