Merge lp:~michael.nelson/launchpad/567922-binarypackagebuild-new-table-5 into lp:launchpad/db-devel

Proposed by Michael Nelson
Status: Merged
Approved by: Michael Nelson
Approved revision: no longer in the source branch.
Merged at revision: 9405
Proposed branch: lp:~michael.nelson/launchpad/567922-binarypackagebuild-new-table-5
Merge into: lp:launchpad/db-devel
Prerequisite: lp:~michael.nelson/launchpad/567922-binarypackagebuild-new-table-4
Diff against target: 970 lines (+248/-179) (has conflicts)
10 files modified
lib/canonical/launchpad/security.py (+45/-27)
lib/lp/buildmaster/configure.zcml (+19/-12)
lib/lp/buildmaster/model/buildfarmjob.py (+5/-3)
lib/lp/buildmaster/model/packagebuild.py (+8/-2)
lib/lp/buildmaster/tests/test_buildfarmjob.py (+38/-6)
lib/lp/buildmaster/tests/test_packagebuild.py (+43/-1)
lib/lp/soyuz/doc/binarypackagebuild.txt (+50/-104)
lib/lp/soyuz/doc/buildd-mass-retry.txt (+1/-1)
lib/lp/soyuz/model/binarypackagebuild.py (+38/-22)
lib/lp/soyuz/stories/webservice/xx-builds.txt (+1/-1)
Text conflict in lib/lp/buildmaster/interfaces/buildbase.py
Text conflict in lib/lp/buildmaster/model/buildbase.py
Text conflict in lib/lp/buildmaster/tests/test_buildbase.py
Text conflict in lib/lp/code/model/sourcepackagerecipebuild.py
To merge this branch: bzr merge lp:~michael.nelson/launchpad/567922-binarypackagebuild-new-table-5
Reviewer Review Type Date Requested Status
Eleanor Berger (community) code Approve
Review via email: mp+25239@code.launchpad.net

Description of the change

This branch is part of a pipeline for

https://blueprints.edge.launchpad.net/soyuz/+spec/build-generalisation
https://dev.launchpad.net/LEP/GeneralBuildHistories

**Note**: If it's possible, please ignore the conflicts with db-devel - it's due to a reversion of some work that was in db-devel and that I'd already pumped through the pipeline, and I'm waiting for that work to land again on db-devel before re-merging and pumping.

The actual diff of this branch from the previous is:
http://pastebin.ubuntu.com/432830/

Overview
========
This branch continues the work to switch our BinaryPackageBuild class to the new binarypackagebuild table (using the delegated PackageBuild/BuildFarmJob).

This branch gets just renames build.txt => binarypackagebuild.txt and updates the test and code to pass.

Note: Some parts of the doctest were removed in favour of new unit tests.

This branch is dependent on the pending schema patch in a previous branch.

To test
=======

First update the test db schema (required as the db patch still needs to be updated to remove the old build table):
psql launchpad_ftest_template -f database/schema/pending/michaeln-build-generalisation.sql
bin/py database/schema/security.py -d launchpad_ftest_template

And then:
bin/test -vv -t test_buildfarmjob -t test_packagebuild -t doc/binarypackagebuild.txt

The next branch will continue getting the remaining soyuz doctests passing with the new model.

To post a comment you must log in.
Revision history for this message
Eleanor Berger (intellectronica) :
review: Approve (code)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'lib/canonical/launchpad/security.py'
2--- lib/canonical/launchpad/security.py 2010-05-13 15:56:00 +0000
3+++ lib/canonical/launchpad/security.py 2010-05-13 15:56:21 +0000
4@@ -39,7 +39,9 @@
5 from lp.bugs.interfaces.bugtracker import IBugTracker
6 from lp.buildmaster.interfaces.builder import IBuilder, IBuilderSet
7 from lp.buildmaster.interfaces.buildfarmbranchjob import IBuildFarmBranchJob
8-from lp.buildmaster.interfaces.buildfarmjob import IBuildFarmJob
9+from lp.buildmaster.interfaces.buildfarmjob import (
10+ IBuildFarmJob, IBuildFarmJobOld)
11+from lp.buildmaster.interfaces.packagebuild import IPackageBuild
12 from lp.code.interfaces.codeimport import ICodeImport
13 from lp.code.interfaces.codeimportjob import (
14 ICodeImportJobSet, ICodeImportJobWorkflow)
15@@ -1446,10 +1448,29 @@
16
17
18 class AdminBuildRecord(AdminByBuilddAdmin):
19- usedfor = IBinaryPackageBuild
20-
21-
22-class EditBuildRecord(AdminByBuilddAdmin):
23+ usedfor = IBuildFarmJob
24+
25+
26+class EditBuildFarmJob(AdminByBuilddAdmin):
27+ permission = 'launchpad.Edit'
28+ usedfor = IBuildFarmJob
29+
30+
31+class EditPackageBuild(EditBuildFarmJob):
32+ usedfor = IPackageBuild
33+
34+ def checkAuthenticated(self, user):
35+ """Check if the user has access to edit the archive."""
36+ if EditBuildFarmJob.checkAuthenticated(self, user):
37+ return True
38+
39+ # If the user is in the owning team for the archive,
40+ # then they have access to edit the builds.
41+ # If it's a PPA or a copy archive only allow its owner.
42+ return (self.obj.archive.owner and
43+ user.inTeam(self.obj.archive.owner))
44+
45+class EditBinaryPackageBuild(EditPackageBuild):
46 permission = 'launchpad.Edit'
47 usedfor = IBinaryPackageBuild
48
49@@ -1462,29 +1483,26 @@
50 * users with upload permissions (for the respective distribution)
51 otherwise.
52 """
53- if AdminByBuilddAdmin.checkAuthenticated(self, user):
54+ if EditPackageBuild.checkAuthenticated(self, user):
55 return True
56
57- # If it's a PPA or a copy archive only allow its owner.
58- if self.obj.archive.is_ppa or self.obj.archive.is_copy:
59- return (self.obj.archive.owner and
60- user.inTeam(self.obj.archive.owner))
61-
62 # Primary or partner section here: is the user in question allowed
63 # to upload to the respective component, packageset or package? Allow
64 # user to retry build if so.
65 # strict_component is True because the source package already exists,
66 # otherwise, how can they give it back?
67- check_perms = check_upload_to_archive(
68- user.person, self.obj.distro_series,
69- self.obj.source_package_release.sourcepackagename,
70- self.obj.archive,
71- self.obj.current_component, self.obj.pocket,
72- strict_component=True)
73- return check_perms == None
74-
75-
76-class ViewBuildRecord(EditBuildRecord):
77+ if self.obj.archive.is_main:
78+ check_perms = check_upload_to_archive(
79+ user.person, self.obj.distro_series,
80+ self.obj.source_package_release.sourcepackagename,
81+ self.obj.archive,
82+ self.obj.current_component, self.obj.pocket,
83+ strict_component=True)
84+ return check_perms == None
85+ return False
86+
87+
88+class ViewBinaryPackageBuild(EditBinaryPackageBuild):
89 permission = 'launchpad.View'
90
91 # This code MUST match the logic in
92@@ -1509,7 +1527,7 @@
93 # privacy since the source package is published publicly.
94 # This happens when copy-package is used to re-publish a private
95 # package in the primary archive.
96- auth_spr = ViewSourcePackageRelease(self.obj.sourcepackagerelease)
97+ auth_spr = ViewSourcePackageRelease(self.obj.source_package_release)
98 if auth_spr.checkAuthenticated(user):
99 return True
100
101@@ -1522,18 +1540,18 @@
102 return True
103
104 # See comment above.
105- auth_spr = ViewSourcePackageRelease(self.obj.sourcepackagerelease)
106+ auth_spr = ViewSourcePackageRelease(self.obj.source_package_release)
107 return auth_spr.checkUnauthenticated()
108
109
110-class ViewBuildFarmJob(AuthorizationBase):
111- """Permission to view an `IBuildFarmJob`.
112+class ViewBuildFarmJobOld(AuthorizationBase):
113+ """Permission to view an `IBuildFarmJobOld`.
114
115 This permission is based entirely on permission to view the
116 associated `IBinaryPackageBuild` and/or `IBranch`.
117 """
118 permission = 'launchpad.View'
119- usedfor = IBuildFarmJob
120+ usedfor = IBuildFarmJobOld
121
122 def _getBranch(self):
123 """Get `IBranch` associated with this job, if any."""
124@@ -1551,7 +1569,7 @@
125
126 def _checkBuildPermission(self, user=None):
127 """Check access to `IBuildBase` for this job."""
128- permission = ViewBuildRecord(self.obj.build)
129+ permission = ViewBinaryPackageBuild(self.obj.build)
130 if user is None:
131 return permission.checkUnauthenticated()
132 else:
133
134=== modified file 'lib/lp/buildmaster/configure.zcml'
135--- lib/lp/buildmaster/configure.zcml 2010-05-13 15:56:00 +0000
136+++ lib/lp/buildmaster/configure.zcml 2010-05-13 15:56:21 +0000
137@@ -47,6 +47,9 @@
138 class="lp.buildmaster.model.buildfarmjob.BuildFarmJob">
139 <allow
140 interface="lp.buildmaster.interfaces.buildfarmjob.IBuildFarmJob" />
141+ <require
142+ permission="launchpad.Edit"
143+ set_attributes="status"/>
144 </class>
145 <securedutility
146 component="lp.buildmaster.model.buildfarmjob.BuildFarmJob"
147@@ -56,6 +59,22 @@
148 interface="lp.buildmaster.interfaces.buildfarmjob.IBuildFarmJobSource" />
149 </securedutility>
150
151+ <!-- PackageBuild -->
152+ <class
153+ class="lp.buildmaster.model.packagebuild.PackageBuild">
154+ <allow
155+ interface="lp.buildmaster.interfaces.packagebuild.IPackageBuild" />
156+ <require
157+ permission="launchpad.Edit"
158+ set_attributes="dependencies"/>
159+ </class>
160+
161+ <securedutility
162+ component="lp.buildmaster.model.packagebuild.PackageBuild"
163+ provides="lp.buildmaster.interfaces.packagebuild.IPackageBuildSource">
164+ <allow
165+ interface="lp.buildmaster.interfaces.packagebuild.IPackageBuildSource" />
166+ </securedutility>
167
168 <!-- BuildQueue -->
169 <class
170@@ -80,17 +99,5 @@
171 interface="lp.buildmaster.interfaces.buildqueue.IBuildQueueSet"/>
172 </securedutility>
173
174- <class
175- class="lp.buildmaster.model.packagebuild.PackageBuild">
176- <allow
177- interface="lp.buildmaster.interfaces.packagebuild.IPackageBuild" />
178- </class>
179-
180- <securedutility
181- component="lp.buildmaster.model.packagebuild.PackageBuild"
182- provides="lp.buildmaster.interfaces.packagebuild.IPackageBuildSource">
183- <allow
184- interface="lp.buildmaster.interfaces.packagebuild.IPackageBuildSource" />
185- </securedutility>
186
187 </configure>
188
189=== modified file 'lib/lp/buildmaster/model/buildfarmjob.py'
190--- lib/lp/buildmaster/model/buildfarmjob.py 2010-05-13 15:56:00 +0000
191+++ lib/lp/buildmaster/model/buildfarmjob.py 2010-05-13 15:56:21 +0000
192@@ -195,7 +195,7 @@
193 name='job_type', allow_none=False, enum=BuildFarmJobType)
194
195 def __init__(self, job_type, status=BuildStatus.NEEDSBUILD,
196- processor=None, virtualized=None):
197+ processor=None, virtualized=None, date_created=None):
198 super(BuildFarmJob, self).__init__()
199 self.job_type, self.status, self.processor, self.virtualized = (
200 job_type,
201@@ -203,13 +203,15 @@
202 processor,
203 virtualized,
204 )
205+ if date_created is not None:
206+ self.date_created = date_created
207
208 @classmethod
209 def new(cls, job_type, status=BuildStatus.NEEDSBUILD, processor=None,
210- virtualized=None):
211+ virtualized=None, date_created=None):
212 """See `IBuildFarmJobSource`."""
213 build_farm_job = BuildFarmJob(
214- job_type, status, processor, virtualized)
215+ job_type, status, processor, virtualized, date_created)
216
217 store = IMasterStore(BuildFarmJob)
218 store.add(build_farm_job)
219
220=== modified file 'lib/lp/buildmaster/model/packagebuild.py'
221--- lib/lp/buildmaster/model/packagebuild.py 2010-05-13 15:56:00 +0000
222+++ lib/lp/buildmaster/model/packagebuild.py 2010-05-13 15:56:21 +0000
223@@ -75,14 +75,15 @@
224
225 @classmethod
226 def new(cls, job_type, virtualized, archive, pocket,
227- processor=None, status=BuildStatus.NEEDSBUILD, dependencies=None):
228+ processor=None, status=BuildStatus.NEEDSBUILD, dependencies=None,
229+ date_created=None):
230 """See `IPackageBuildSource`."""
231 store = IMasterStore(PackageBuild)
232
233 # Create the BuildFarmJob to which the new PackageBuild
234 # will delegate.
235 build_farm_job = getUtility(IBuildFarmJobSource).new(
236- job_type, status, processor, virtualized)
237+ job_type, status, processor, virtualized, date_created)
238
239 package_build = cls(build_farm_job, archive, pocket, dependencies)
240 store.add(package_build)
241@@ -107,6 +108,11 @@
242 return None
243 return ProxiedLibraryFileAlias(self.log, self).http_url
244
245+ @property
246+ def is_private(self):
247+ """See `IBuildBase`"""
248+ return self.archive.private
249+
250 def getUploadDirLeaf(self, build_cookie, now=None):
251 """See `IPackageBuild`."""
252 return BuildBase.getUploadDirLeaf(build_cookie, now)
253
254=== modified file 'lib/lp/buildmaster/tests/test_buildfarmjob.py'
255--- lib/lp/buildmaster/tests/test_buildfarmjob.py 2010-05-13 15:56:00 +0000
256+++ lib/lp/buildmaster/tests/test_buildfarmjob.py 2010-05-13 15:56:21 +0000
257@@ -11,6 +11,7 @@
258
259 from storm.store import Store
260 from zope.component import getUtility
261+from zope.security.interfaces import Unauthorized
262 from zope.security.proxy import removeSecurityProxy
263
264 from canonical.database.sqlbase import flush_database_updates
265@@ -20,23 +21,26 @@
266 from lp.buildmaster.interfaces.buildfarmjob import (
267 BuildFarmJobType, IBuildFarmJob, IBuildFarmJobSource)
268 from lp.buildmaster.model.buildfarmjob import BuildFarmJob
269-from lp.testing import TestCaseWithFactory
270-
271-
272-class TestBuildFarmJob(TestCaseWithFactory):
273- """Tests for the build farm job object."""
274+from lp.testing import login, TestCaseWithFactory
275+
276+
277+class TestBuildFarmJobBase(TestCaseWithFactory):
278
279 layer = DatabaseFunctionalLayer
280
281 def setUp(self):
282 """Create a build farm job with which to test."""
283- super(TestBuildFarmJob, self).setUp()
284+ super(TestBuildFarmJobBase, self).setUp()
285 self.build_farm_job = self.makeBuildFarmJob()
286
287 def makeBuildFarmJob(self):
288 return getUtility(IBuildFarmJobSource).new(
289 job_type=BuildFarmJobType.PACKAGEBUILD)
290
291+
292+class TestBuildFarmJob(TestBuildFarmJobBase):
293+ """Tests for the build farm job object."""
294+
295 def test_providesInterface(self):
296 # BuildFarmJob provides IBuildFarmJob
297 self.assertProvides(self.build_farm_job, IBuildFarmJob)
298@@ -136,6 +140,34 @@
299 naked_bfj.date_finished = now + duration
300 self.failUnlessEqual(duration, self.build_farm_job.duration)
301
302+ def test_date_created(self):
303+ # date_created can be passed optionally when creating a
304+ # bulid farm job to ensure we don't get identical timestamps
305+ # when transactions are committed.
306+ ten_years_ago = datetime.now(pytz.UTC) - timedelta(365*10)
307+ build_farm_job = getUtility(IBuildFarmJobSource).new(
308+ job_type=BuildFarmJobType.PACKAGEBUILD,
309+ date_created=ten_years_ago)
310+ self.failUnlessEqual(ten_years_ago, build_farm_job.date_created)
311+
312+
313+class TestBuildFarmJobSecurity(TestBuildFarmJobBase):
314+
315+ def test_view_build_farm_job(self):
316+ # Anonymous access can read public builds, but not edit.
317+ self.failUnlessEqual(
318+ BuildStatus.NEEDSBUILD, self.build_farm_job.status)
319+ self.assertRaises(
320+ Unauthorized, setattr, self.build_farm_job,
321+ 'status', BuildStatus.FULLYBUILT)
322+
323+ def test_edit_build_farm_job(self):
324+ # Users with edit access can update attributes.
325+ login('admin@canonical.com')
326+ self.build_farm_job.status = BuildStatus.FULLYBUILT
327+ self.failUnlessEqual(
328+ BuildStatus.FULLYBUILT, self.build_farm_job.status)
329+
330
331 def test_suite():
332 return unittest.TestLoader().loadTestsFromName(__name__)
333
334=== modified file 'lib/lp/buildmaster/tests/test_packagebuild.py'
335--- lib/lp/buildmaster/tests/test_packagebuild.py 2010-05-13 15:56:00 +0000
336+++ lib/lp/buildmaster/tests/test_packagebuild.py 2010-05-13 15:56:21 +0000
337@@ -10,6 +10,7 @@
338
339 from storm.store import Store
340 from zope.component import getUtility
341+from zope.security.interfaces import Unauthorized
342 from zope.security.proxy import removeSecurityProxy
343
344 from canonical.testing.layers import LaunchpadFunctionalLayer
345@@ -20,7 +21,7 @@
346 from lp.buildmaster.model.packagebuild import PackageBuild
347 from lp.buildmaster.tests.test_buildbase import TestBuildBaseMixin
348 from lp.registry.interfaces.pocket import PackagePublishingPocket
349-from lp.testing import TestCaseWithFactory
350+from lp.testing import login, login_person, TestCaseWithFactory
351
352
353 class TestPackageBuildBase(TestCaseWithFactory):
354@@ -121,6 +122,16 @@
355 hashlib.sha1("Some content").hexdigest(),
356 self.package_build.upload_log.content.sha1)
357
358+ def test_storeUploadLog_private(self):
359+ # A private package build will store the upload log on the
360+ # restricted librarian.
361+ login('admin@canonical.com')
362+ self.package_build.archive.buildd_secret = 'sekrit'
363+ self.package_build.archive.private = True
364+ self.failUnless(self.package_build.is_private)
365+ self.package_build.storeUploadLog("Some content")
366+ self.failUnless(self.package_build.upload_log.restricted)
367+
368 def test_upload_log_url(self):
369 # The url of the upload log file is determined by the PackageBuild.
370 Store.of(self.package_build).flush()
371@@ -133,6 +144,37 @@
372 build_id, build_id),
373 log_url)
374
375+ def test_view_package_build(self):
376+ # Anonymous access can read public builds, but not edit.
377+ self.failUnlessEqual(
378+ None, self.package_build.dependencies)
379+ self.assertRaises(
380+ Unauthorized, setattr, self.package_build,
381+ 'dependencies', u'my deps')
382+
383+ def test_edit_package_build(self):
384+ # An authenticated user who belongs to the owning archive team
385+ # can edit the build.
386+ login_person(self.package_build.archive.owner)
387+ self.package_build.dependencies = u'My deps'
388+ self.failUnlessEqual(
389+ u'My deps', self.package_build.dependencies)
390+
391+ # But other users cannot.
392+ other_person = self.factory.makePerson()
393+ login_person(other_person)
394+ self.assertRaises(
395+ Unauthorized, setattr, self.package_build,
396+ 'dependencies', u'my deps')
397+
398+
399+ def test_admin_package_build(self):
400+ # Users with edit access can update attributes.
401+ login('admin@canonical.com')
402+ self.package_build.dependencies = u'My deps'
403+ self.failUnlessEqual(
404+ u'My deps', self.package_build.dependencies)
405+
406
407 def test_suite():
408 return unittest.TestLoader().loadTestsFromName(__name__)
409
410=== renamed file 'lib/lp/soyuz/doc/build.txt' => 'lib/lp/soyuz/doc/binarypackagebuild.txt'
411--- lib/lp/soyuz/doc/build.txt 2010-05-13 15:56:00 +0000
412+++ lib/lp/soyuz/doc/binarypackagebuild.txt 2010-05-13 15:56:21 +0000
413@@ -39,10 +39,10 @@
414 >>> print firefox_build.distribution.displayname
415 ubuntutest
416
417- >>> print firefox_build.distroseries.displayname
418+ >>> print firefox_build.distro_series.displayname
419 Breezy Badger Autotest
420
421- >>> print firefox_build.distroarchseries.displayname
422+ >>> print firefox_build.distro_arch_series.displayname
423 ubuntutest Breezy Badger Autotest i386
424
425 >>> firefox_build.pocket
426@@ -54,7 +54,7 @@
427 >>> firefox_build.is_virtualized
428 False
429
430- >>> print firefox_build.sourcepackagerelease.title
431+ >>> print firefox_build.source_package_release.title
432 mozilla-firefox - 0.9
433
434 A build has an state that represents in which stage it is in a
435@@ -62,12 +62,12 @@
436 of the intermediate failed states (FAILEDTOBUILD, MANUALDEPWAIT,
437 CHROOTWAIT, SUPERSEDED and FAILEDTOUPLOAD).
438
439- >>> firefox_build.buildstate
440+ >>> firefox_build.status
441 <DBItem BuildStatus.FULLYBUILT, (1) Successfully built>
442
443 Builds which were already processed also offer additional information
444 about its process such as the time it was started and finished and its
445-'buildlog' and 'upload_changesfile' as librarian files.
446+'log' and 'upload_changesfile' as librarian files.
447
448 >>> firefox_build.was_built
449 True
450@@ -75,16 +75,16 @@
451 >>> firefox_build.date_started
452 datetime.datetime(...)
453
454- >>> firefox_build.datebuilt
455+ >>> firefox_build.date_finished
456 datetime.datetime(...)
457
458- >>> firefox_build.buildduration
459+ >>> firefox_build.duration
460 datetime.timedelta(...)
461
462- >>> print firefox_build.buildlog.filename
463+ >>> print firefox_build.log.filename
464 buildlog_ubuntutest-breezy-autotest-i386.mozilla-firefox_0.9_FULLYBUILT.txt.gz
465
466- >>> print firefox_build.build_log_url
467+ >>> print firefox_build.log_url
468 http://launchpad.dev/ubuntutest/+source/mozilla-firefox/0.9/+build/.../+files/buildlog_ubuntutest-breezy-autotest-i386.mozilla-firefox_0.9_FULLYBUILT.txt.gz
469
470 >>> print firefox_build.upload_changesfile.filename
471@@ -119,7 +119,7 @@
472
473 It is not necessarily the same as:
474
475- >>> print firefox_build.sourcepackagerelease.component.name
476+ >>> print firefox_build.source_package_release.component.name
477 main
478
479 which is the component the source was originally uploaded to, before
480@@ -151,7 +151,7 @@
481 >>> frozen_build = getUtility(IBinaryPackageBuildSet).getByBuildID(9)
482 >>> frozen_build.title
483 u'i386 build of pmount 0.1-1 in ubuntu warty RELEASE'
484- >>> frozen_build.buildstate.title
485+ >>> frozen_build.status.title
486 'Failed to build'
487 >>> frozen_build.can_be_retried
488 False
489@@ -166,13 +166,13 @@
490 >>> print active_build.title
491 i386 build of pmount 0.1-1 in ubuntu warty RELEASE
492
493- >>> print active_build.buildstate.name
494+ >>> print active_build.status.name
495 FAILEDTOBUILD
496
497 >>> print active_build.builder.name
498 bob
499
500- >>> print active_build.buildlog.filename
501+ >>> print active_build.log.filename
502 netapplet-1.0.0.tar.gz
503
504 At this point, it's also convenient to test if any content can be
505@@ -210,54 +210,7 @@
506 sample upload log.
507
508 The 'upload_log' library file privacy is set according to the build
509-target archive.
510-
511- >>> print active_build.archive.private
512- False
513-
514- >>> print active_build.upload_log.restricted
515- False
516-
517-Transforming ubuntu primary archive in a private archive makes
518-storeUploadLog() upload the given content as a restricted file.
519-
520- >>> login('foo.bar@canonical.com')
521- >>> original_archive = active_build.archive
522- >>> private_ppa = factory.makeArchive(private=True)
523- >>> removeSecurityProxy(active_build).archive = private_ppa
524- >>> login(ANONYMOUS)
525-
526-Simply changing the archive privacy after the 'upload_log' is stored
527-doesn't make it restricted. The archive privacy will be respected in
528-the next upload attempt only.
529-
530- >>> print active_build.upload_log.restricted
531- False
532-
533-In order to call storeUploadLog() again for the same build, we have to
534-remove the previously stored 'upload_log'. See the check below in
535-'AssertionErrors in IBinaryPackageBuild' for more detail.
536-
537- >>> login('foo.bar@canonical.com')
538- >>> active_build.upload_log = None
539- >>> login(ANONYMOUS)
540-
541-Once targeted to a private archive the 'upload_log' gets stored in the
542-restricted librarian instance.
543-
544- >>> print active_build.archive.private
545- True
546-
547- >>> active_build.storeUploadLog('private upload log.')
548- >>> print active_build.upload_log.restricted
549- True
550-
551-Restore ubuntu main archive as the target to not affect the rest of the
552-tests.
553-
554- >>> login('foo.bar@canonical.com')
555- >>> removeSecurityProxy(active_build).archive = original_archive
556- >>> login(ANONYMOUS)
557+target archive. For an example, see lp.buildmaster.tests.test_packagebuild
558
559 Since ubuntu/warty is already released the failed build can't be
560 retried.
561@@ -318,18 +271,18 @@
562 >>> print active_build.builder
563 None
564
565- >>> print active_build.buildstate.name
566+ >>> print active_build.status.name
567 NEEDSBUILD
568
569 >>> print active_build.buildqueue_record
570 <...BuildQueue...>
571
572-'buildlog' and 'upload_log' librarian references were removed when the
573+'log' and 'upload_log' librarian references were removed when the
574 build was retried. They will be garbage-collected later by
575 'librariangc' and replaced by new ones when the build re-attempt
576 finishes.
577
578- >>> print active_build.buildlog
579+ >>> print active_build.log
580 None
581
582 >>> print active_build.upload_log
583@@ -353,8 +306,8 @@
584 >>> description = 'Descripppppppption'
585 >>> from canonical.launchpad.interfaces import BinaryPackageFormat
586 >>> binpackageformat = BinaryPackageFormat.DEB
587- >>> component = firefox_build.sourcepackagerelease.component.id
588- >>> section = firefox_build.sourcepackagerelease.section.id
589+ >>> component = firefox_build.source_package_release.component.id
590+ >>> section = firefox_build.source_package_release.section.id
591 >>> from canonical.launchpad.interfaces import PackagePublishingPriority
592 >>> priority = PackagePublishingPriority.STANDARD
593 >>> shlibdeps = None
594@@ -565,7 +518,8 @@
595 ... return row[0].id
596 >>> for row in sorted(rset, key=sort_result_key):
597 ... (sourcepackagerelease, buildlog,
598- ... sourcepackagename, buildlog_content, builder) = row
599+ ... sourcepackagename, buildlog_content, builder,
600+ ... package_build, build_farm_job) = row
601 ... print(
602 ... 'builder: %s, spr: %s, log: %s' %
603 ... (id_or_none(builder),
604@@ -662,7 +616,7 @@
605 >>> [deleted_build, superseded_build] == list(old_source_builds)
606 True
607
608- >>> deleted_build.datecreated > superseded_build.datecreated
609+ >>> deleted_build.date_created > superseded_build.date_created
610 True
611
612 Builds records for the exactly the same `SourcePackageRelease`s may
613@@ -699,9 +653,9 @@
614 >>> ubuntu.getBuildRecords().count()
615 17
616
617- >>> L = ubuntu.getBuildRecords(build_state=BuildStatus.FULLYBUILT)
618- >>> for l in L:
619- ... print l.datebuilt, l.id, l.buildstate.value
620+ >>> builds = ubuntu.getBuildRecords(build_state=BuildStatus.FULLYBUILT)
621+ >>> for build in builds:
622+ ... print build.date_finished, build.id, build.status.value
623 2007-08-10 00:00:14+00:00 30 1
624 2007-08-09 23:59:59+00:00 29 1
625 2005-03-25 00:00:03+00:00 7 1
626@@ -727,7 +681,7 @@
627 Note that they are ordered by DESC lastscore, as expected:
628
629 >>> for b in builds:
630- ... b.id, b.buildstate.value, b.buildqueue_record.lastscore
631+ ... b.id, b.status.value, b.buildqueue_record.lastscore
632 (11, 0, 10)
633 (9, 0, 0)
634
635@@ -906,14 +860,6 @@
636 >>> gina_build.was_built
637 True
638
639-this method is protected by an assertion on valid buildduration and
640-datebuilt, it makes the diagnosis of problems in current DB easier.
641-
642- >>> gina_build.date_started
643- Traceback (most recent call last):
644- ...
645- AssertionError: value is not suitable for this build record (10)
646-
647 Only builds in failed_states (FAILEDTOBUILD, MANUALDEPWAIT and
648 CHROOTWAIT) can be retried. We must check if Soyuz is able to accept
649 its result in case of success, i.e., we should not be able to retry a
650@@ -927,7 +873,7 @@
651 >>> failed_build.title
652 u'i386 build of foobar 1.0 in ubuntu warty RELEASE'
653
654- >>> failed_build.buildstate.name
655+ >>> failed_build.status.name
656 'FAILEDTOBUILD'
657
658 >>> failed_build.can_be_retried
659@@ -1024,12 +970,12 @@
660 See also bug 177827.
661
662 >>> login('foo.bar@canonical.com')
663- >>> depwait_build.dependencies = 'pmount'
664+ >>> depwait_build.dependencies = u'pmount'
665 >>> flush_database_updates()
666
667 'pmount' in hoary/i386 is published in the 'universe' component:
668
669- >>> hoary_i386 = depwait_build.distroarchseries
670+ >>> hoary_i386 = depwait_build.distro_arch_series
671 >>> pmount_pub = hoary_i386[
672 ... 'pmount'].currentrelease.current_publishing_record
673 >>> print pmount_pub.component.name
674@@ -1059,7 +1005,7 @@
675 >>> from lp.soyuz.interfaces.component import IComponentSet
676 >>> main_component = getUtility(IComponentSet)['main']
677 >>> pmount_pub.component = main_component
678- >>> depwait_build.dependencies = 'mozilla-firefox, pmount'
679+ >>> depwait_build.dependencies = u'mozilla-firefox, pmount'
680 >>> from canonical.database.sqlbase import flush_database_caches
681 >>> flush_database_caches()
682 >>> login(ANONYMOUS)
683@@ -1080,7 +1026,7 @@
684
685
686 >>> login('foo.bar@canonical.com')
687- >>> depwait_build.dependencies = 'biscuit, pmount'
688+ >>> depwait_build.dependencies = u'biscuit, pmount'
689 >>> universe_component = getUtility(IComponentSet)['universe']
690 >>> pmount_pub.component = universe_component
691 >>> removeSecurityProxy(depwait_build).archive = cprov.archive
692@@ -1112,16 +1058,16 @@
693 for performing the mentioned auto-depwait procedure we have a utility
694 in IBinaryPackageBuildSet called retryDepWaiting().
695
696- >>> print depwait_build.buildstate.name
697+ >>> print depwait_build.status.name
698 MANUALDEPWAIT
699- >>> print depwait_build.distroarchseries.title
700+ >>> print depwait_build.distro_arch_series.title
701 The Hoary Hedgehog Release for i386 (x86)
702
703 In order to allow depwait_build to be retried we will forge a
704 'fully-satisfiable' dependencies field.
705
706 >>> login('foo.bar@canonical.com')
707- >>> depwait_build.dependencies = 'pmount'
708+ >>> depwait_build.dependencies = u'pmount'
709 >>> login(ANONYMOUS)
710 >>> flush_database_updates()
711
712@@ -1130,7 +1076,7 @@
713
714 >>> getUtility(IBinaryPackageBuildSet).retryDepWaiting(hoaryi386)
715
716- >>> print depwait_build.buildstate.name
717+ >>> print depwait_build.status.name
718 NEEDSBUILD
719
720 >>> depwait_build.buildqueue_record.lastscore
721@@ -1165,7 +1111,7 @@
722 If a callsite tries to rescore a build that is not in the NEEDSBUILD state,
723 a CannotBeRescored exception is raised.
724
725- >>> depwait_build.buildstate = BuildStatus.FAILEDTOUPLOAD
726+ >>> depwait_build.status = BuildStatus.FAILEDTOUPLOAD
727 >>> depwait_build.rescore(1000)
728 Traceback (most recent call last):
729 ...
730@@ -1246,12 +1192,12 @@
731 ... print "Did not fail when expected setting %s" % property
732 >>> from canonical.database.constants import UTC_NOW
733 >>> properties = {
734- ... 'buildlog': 1,
735- ... 'datebuilt': UTC_NOW,
736- ... 'buildduration': None,
737+ ... 'log': 1,
738+ ... 'date_finished': UTC_NOW,
739+ ... 'date_started': None,
740 ... 'builder': bob,
741- ... 'buildstate': BuildStatus.FAILEDTOUPLOAD,
742- ... 'dependencies': 'whatever',
743+ ... 'status': BuildStatus.FAILEDTOUPLOAD,
744+ ... 'dependencies': u'whatever',
745 ... 'upload_log': 1,
746 ... }
747
748@@ -1295,8 +1241,8 @@
749 ... PackagePublishingPocket.UPDATES,
750 ... test_publisher.breezy_autotest.main_archive,
751 ... status=BuildStatus.FULLYBUILT)
752- >>> oldest_build.buildduration = timedelta(minutes=72)
753- >>> oldest_build.datebuilt = datetime(2008, 4, 1, 10, 45, 39, tzinfo=UTC)
754+ >>> oldest_build.date_finished = datetime(2008, 4, 1, 10, 45, 39, tzinfo=UTC)
755+ >>> oldest_build.date_started = oldest_build.date_finished - timedelta(minutes=72)
756
757 Check that the oldest build instance's 'estimated_duration'
758 is initialized based on its package size. Since the latter is very
759@@ -1320,8 +1266,8 @@
760 ... PackagePublishingPocket.UPDATES,
761 ... test_publisher.breezy_autotest.main_archive,
762 ... status=BuildStatus.FULLYBUILT)
763- >>> medium_build.buildduration = timedelta(minutes=60)
764- >>> medium_build.datebuilt = datetime(2008, 4, 2, 11, 56, 33, tzinfo=UTC)
765+ >>> medium_build.date_finished = datetime(2008, 4, 2, 11, 56, 33, tzinfo=UTC)
766+ >>> medium_build.date_started = medium_build.date_finished - timedelta(minutes=60)
767
768 Check whether the intermediate build instance's 'estimated_duration'
769 value equals the oldest instance's 'buildduration' (72 minutes equals 4320
770@@ -1408,7 +1354,7 @@
771 ... source_ids)
772 >>> import operator
773 >>> for build in sorted(builds, key=operator.attrgetter("id")):
774- ... print build.title, build.buildstate.name
775+ ... print build.title, build.status.name
776 hppa build of sourceone 666 in ubuntutest breezy-autotest RELEASE
777 FULLYBUILT
778 hppa build of sourcetwo 666 in ubuntutest breezy-autotest RELEASE
779@@ -1419,7 +1365,7 @@
780 >>> builds = removeSecurityProxy(bs).getBuildsBySourcePackageRelease(
781 ... source_ids, buildstate=BuildStatus.FULLYBUILT)
782 >>> for build in sorted(builds, key=operator.attrgetter("id")):
783- ... print build.title, build.buildstate.name
784+ ... print build.title, build.status.name
785 hppa build of sourceone 666 in ubuntutest breezy-autotest RELEASE
786 FULLYBUILT
787
788@@ -1463,13 +1409,13 @@
789 >>> bob_builder = getUtility(IBuilderSet)['bob']
790
791 >>> earlier_builds = src_pkg_earlier.createMissingBuilds()
792- >>> eg_build_date = earlier_builds[0].datecreated
793+ >>> eg_build_date = earlier_builds[0].date_created
794 >>> for build in earlier_builds:
795- ... build.datebuilt = eg_build_date - timedelta(1)
796+ ... build.date_finished = eg_build_date - timedelta(1)
797
798 >>> later_builds = src_pkg_later.createMissingBuilds()
799 >>> for build in later_builds:
800- ... build.datebuilt = eg_build_date
801+ ... build.date_finished = eg_build_date
802
803 Ensure that the i386 builds are created by the 'frog' builder,
804 while the hppa builds are created by 'bob' the builder:
805
806=== modified file 'lib/lp/soyuz/doc/buildd-mass-retry.txt'
807--- lib/lp/soyuz/doc/buildd-mass-retry.txt 2010-04-21 11:13:11 +0000
808+++ lib/lp/soyuz/doc/buildd-mass-retry.txt 2010-05-13 15:56:21 +0000
809@@ -25,7 +25,7 @@
810
811 The script provides dry-run mode (-N).
812
813-See build.txt for more information about IBuild.retry().
814+See binarypackagebuild.txt for more information about IBuild.retry().
815
816 Passing only suite, request retry on all failed states:
817
818
819=== modified file 'lib/lp/soyuz/model/binarypackagebuild.py'
820--- lib/lp/soyuz/model/binarypackagebuild.py 2010-05-13 15:56:00 +0000
821+++ lib/lp/soyuz/model/binarypackagebuild.py 2010-05-13 15:56:21 +0000
822@@ -12,6 +12,8 @@
823 import operator
824
825 from storm.locals import Int, Reference
826+from canonical.launchpad.webapp.interfaces import (
827+ IStoreSelector, MAIN_STORE, DEFAULT_FLAVOR)
828
829 from zope.interface import implements
830 from zope.component import getUtility
831@@ -185,11 +187,6 @@
832 return self.archive.require_virtualized
833
834 @property
835- def is_private(self):
836- """See `IBuildBase`"""
837- return self.archive.private
838-
839- @property
840 def title(self):
841 """See `IBuild`"""
842 return '%s build of %s %s in %s %s %s' % (
843@@ -212,7 +209,7 @@
844
845 @property
846 def log_url(self):
847- """See `IBuildFarmJob`.
848+ """See `IPackageBuild`.
849
850 Overridden here for the case of builds for distro archives,
851 currently only supported for binary package builds.
852@@ -222,6 +219,17 @@
853 return ProxiedLibraryFileAlias(self.log, self).http_url
854
855 @property
856+ def upload_log_url(self):
857+ """See `IPackageBuild`.
858+
859+ Overridden here for the case of builds for distro archives,
860+ currently only supported for binary package builds.
861+ """
862+ if self.upload_log is None:
863+ return None
864+ return ProxiedLibraryFileAlias(self.upload_log, self).http_url
865+
866+ @property
867 def distributionsourcepackagerelease(self):
868 """See `IBuild`."""
869 from lp.soyuz.model.distributionsourcepackagerelease \
870@@ -284,10 +292,10 @@
871 """See `IBuild`."""
872 assert self.can_be_retried, "Build %s cannot be retried" % self.id
873 self.status = BuildStatus.NEEDSBUILD
874- self.datebuilt = None
875- self.buildduration = None
876+ self.date_finished = None
877+ self.date_started = None
878 self.builder = None
879- self.buildlog = None
880+ self.log = None
881 self.upload_log = None
882 self.dependencies = None
883 self.queueBuild()
884@@ -700,7 +708,7 @@
885 package_build = getUtility(IPackageBuildSource).new(
886 BinaryPackageBuild.build_farm_job_type,
887 archive.require_virtualized, archive, pocket, processor,
888- status) #, date_created)
889+ status, date_created=date_created)
890
891 binary_package_build = BinaryPackageBuild(
892 package_build=package_build,
893@@ -711,8 +719,9 @@
894 def getBuildBySRAndArchtag(self, sourcepackagereleaseID, archtag):
895 """See `IBinaryPackageBuildSet`"""
896 clauseTables = ['DistroArchSeries']
897- query = ('Build.sourcepackagerelease = %s '
898- 'AND Build.distroarchseries = DistroArchSeries.id '
899+ query = ('BinaryPackageBuild.source_package_release = %s '
900+ 'AND BinaryPackageBuild.distro_arch_series = '
901+ 'DistroArchSeries.id '
902 'AND DistroArchSeries.architecturetag = %s'
903 % sqlvalues(sourcepackagereleaseID, archtag)
904 )
905@@ -896,7 +905,7 @@
906 # * FULLYBUILT & FAILURES by -datebuilt
907 # It should present the builds in a more natural order.
908 if status in [BuildStatus.NEEDSBUILD, BuildStatus.BUILDING]:
909- orderBy = ["-BuildQueue.lastscore", "Build.id"]
910+ orderBy = ["-BuildQueue.lastscore", "BinaryPackageBuild.id"]
911 clauseTables.append('BuildQueue')
912 clauseTables.append('BuildPackageJob')
913 condition_clauses.append(
914@@ -939,9 +948,14 @@
915 logger = logging.getLogger('retry-depwait')
916
917 # Get the MANUALDEPWAIT records for all archives.
918- candidates = BinaryPackageBuild.selectBy(
919- status=BuildStatus.MANUALDEPWAIT,
920- distro_arch_series=distroarchseries)
921+ store = getUtility(IStoreSelector).get(MAIN_STORE, DEFAULT_FLAVOR)
922+
923+ candidates = store.find(
924+ BinaryPackageBuild,
925+ BinaryPackageBuild.distro_arch_series == distroarchseries,
926+ BinaryPackageBuild.package_build == PackageBuild.id,
927+ PackageBuild.build_farm_job == BuildFarmJob.id,
928+ BuildFarmJob.status == BuildStatus.MANUALDEPWAIT)
929
930 candidates_count = candidates.count()
931 if candidates_count == 0:
932@@ -971,17 +985,19 @@
933 return []
934
935 query = """
936- sourcepackagerelease IN %s AND
937- archive.id = build.archive AND
938- archive.purpose != %s
939+ source_package_release IN %s AND
940+ package_build = packagebuild.id AND
941+ archive.id = packagebuild.archive AND
942+ archive.purpose != %s AND
943+ packagebuild.build_farm_job = buildfarmjob.id
944 """ % sqlvalues(sourcepackagerelease_ids, ArchivePurpose.PPA)
945
946 if buildstate is not None:
947- query += "AND buildstate = %s" % sqlvalues(buildstate)
948+ query += "AND buildfarmjob.status = %s" % sqlvalues(buildstate)
949
950 return BinaryPackageBuild.select(
951- query, orderBy=["-datecreated", "id"],
952- clauseTables=["Archive"])
953+ query, orderBy=["-buildfarmjob.date_created", "id"],
954+ clauseTables=["Archive", "PackageBuild", "BuildFarmJob"])
955
956 def getStatusSummaryForBuilds(self, builds):
957 """See `IBinaryPackageBuildSet`."""
958
959=== modified file 'lib/lp/soyuz/stories/webservice/xx-builds.txt'
960--- lib/lp/soyuz/stories/webservice/xx-builds.txt 2010-04-09 15:46:09 +0000
961+++ lib/lp/soyuz/stories/webservice/xx-builds.txt 2010-05-13 15:56:21 +0000
962@@ -92,7 +92,7 @@
963
964 If a build is in a retry-able state, the retry method can be invoked
965 to cause a new build request for that build. The caller must also have
966-permission to retry the build. See doc/build.txt and
967+permission to retry the build. See doc/binarypackagebuild.txt and
968 stories/soyuz/xx-build-record.txt for more information.
969
970 >>> a_build = builds['entries'][0]

Subscribers

People subscribed via source and target branches

to status/vote changes: