launchpad-reviewers team mailing list archive
-
launchpad-reviewers team
-
Mailing list archive
-
Message #00255
[Merge] lp:~abentley/launchpad/package-build-recipe into lp:launchpad
Aaron Bentley has proposed merging lp:~abentley/launchpad/package-build-recipe into lp:launchpad.
Requested reviews:
Stuart Bishop (stub): db
Launchpad code reviewers (launchpad-reviewers): code
Related bugs:
#609266 sourcepackagerecipebuilds should be packagebuilds
https://bugs.launchpad.net/bugs/609266
Summary: Fix bug Bug 609266 sourcepackagerecipebuilds should be packagebuilds.
Changes: Add a foreign key reference from sourcepackagerecipebuild to packagebuild. Drop all columns from sourcepackagerecipe that are now provided by packagebuild or buildfarmjob. Update the model and calling code.
Preimplementation was with stub and noodles.
Lint omitted because there's way too much of it-- all kinds of places were affected by this change.
--
https://code.launchpad.net/~abentley/launchpad/package-build-recipe/+merge/30818
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~abentley/launchpad/package-build-recipe into lp:launchpad.
=== modified file 'database/sampledata/current-dev.sql'
--- database/sampledata/current-dev.sql 2010-07-23 09:04:18 +0000
+++ database/sampledata/current-dev.sql 2010-07-23 19:32:55 +0000
@@ -4321,6 +4321,13 @@
ALTER TABLE featuredproject ENABLE TRIGGER ALL;
+ALTER TABLE featureflag DISABLE TRIGGER ALL;
+
+
+
+ALTER TABLE featureflag ENABLE TRIGGER ALL;
+
+
ALTER TABLE flatpackagesetinclusion DISABLE TRIGGER ALL;
=== modified file 'database/sampledata/current.sql'
--- database/sampledata/current.sql 2010-07-23 09:04:18 +0000
+++ database/sampledata/current.sql 2010-07-23 19:32:55 +0000
@@ -4259,6 +4259,13 @@
ALTER TABLE featuredproject ENABLE TRIGGER ALL;
+ALTER TABLE featureflag DISABLE TRIGGER ALL;
+
+
+
+ALTER TABLE featureflag ENABLE TRIGGER ALL;
+
+
ALTER TABLE flatpackagesetinclusion DISABLE TRIGGER ALL;
=== modified file 'database/schema/comments.sql'
--- database/schema/comments.sql 2010-07-23 09:04:18 +0000
+++ database/schema/comments.sql 2010-07-23 19:32:55 +0000
@@ -1384,19 +1384,10 @@
COMMENT ON TABLE SourcePackageRecipeBuild IS 'The build record for the process of building a source package as described by a recipe.';
COMMENT ON COLUMN SourcePackageRecipeBuild.distroseries IS 'The distroseries the build was for.';
-COMMENT ON COLUMN SourcePackageRecipeBuild.build_state IS 'The state of the build.';
-COMMENT ON COLUMN SourcePackageRecipeBuild.date_built IS 'When the build record was processed.';
-COMMENT ON COLUMN SourcePackageRecipeBuild.build_duration IS 'How long this build took to be processed.';
-COMMENT ON COLUMN SourcePackageRecipeBuild.build_log IS 'Points to the build_log file stored in librarian.';
-COMMENT ON COLUMN SourcePackageRecipeBuild.builder IS 'Points to the builder which has once processed it.';
-COMMENT ON COLUMN SourcePackageRecipeBuild.date_first_dispatched IS 'The instant the build was dispatched the first time. This value will not get overridden if the build is retried.';
+COMMENT ON COLUMN SourcePackageRecipeBuild.package_build IS 'The package_build with the base information about this build.';
COMMENT ON COLUMN SourcePackageRecipeBuild.requester IS 'Who requested the build.';
COMMENT ON COLUMN SourcePackageRecipeBuild.recipe IS 'The recipe being processed.';
COMMENT ON COLUMN SourcePackageRecipeBuild.manifest IS 'The evaluated recipe that was built.';
-COMMENT ON COLUMN SourcePackageRecipeBuild.archive IS 'The archive the source package will be built in and uploaded to.';
-COMMENT ON COLUMN SourcePackageRecipeBuild.pocket IS 'The pocket the source package will be built in and uploaded to.';
-COMMENT ON COLUMN SourcePackageRecipeBuild.dependencies IS 'The missing build dependencies, if any.';
-COMMENT ON COLUMN SourcePackageRecipeBuild.upload_log IS 'The output from uploading the source package to the archive.';
-- SourcePackageRecipeBuildJob
=== added file 'database/schema/patch-2207-99-0.sql'
--- database/schema/patch-2207-99-0.sql 1970-01-01 00:00:00 +0000
+++ database/schema/patch-2207-99-0.sql 2010-07-23 19:32:55 +0000
@@ -0,0 +1,29 @@
+-- Copyright 2010 Canonical Ltd. This software is licensed under the
+-- GNU Affero General Public License version 3 (see the file LICENSE).
+
+SET client_min_messages=ERROR;
+
+CREATE TEMPORARY TABLE NewBuildFarmJob AS SELECT
+ nextval('buildfarmjob_id_seq') AS id, 1 AS processor, True AS virtualized, date_created, date_built - build_duration AS date_started, date_built AS date_finished, date_first_dispatched, builder, build_state, build_log, 3 AS job_type, id AS sprb_id FROM SourcePackageRecipeBuild;
+
+INSERT INTO BuildFarmJob SELECT id, processor, virtualized, date_created, date_started, date_finished, date_first_dispatched, builder, build_state, build_log, job_type FROM NewBuildFarmJob;
+
+CREATE TEMPORARY TABLE NewPackageBuild AS SELECT
+ nextval('packagebuild_id_seq') AS id, NewBuildFarmJob.id AS new_build_farm_job, archive, pocket, upload_log, dependencies, SourcePackageRecipeBuild.id AS sprb_id FROM SourcePackageRecipeBuild, NewBuildFarmJob;
+
+ALTER TABLE SourcePackageRecipeBuild
+ ADD COLUMN package_build INTEGER REFERENCES PackageBuild NOT NULL;
+
+UPDATE SourcePackageRecipebuild
+ SET package_build=NewPackageBuild.id
+ FROM NewPackageBuild
+ WHERE sprb_id = SourcePackageRecipeBuild.id;
+
+ALTER TABLE SourcePackageRecipeBuild
+ ALTER COLUMN package_build SET NOT NULL, DROP COLUMN date_created,
+ DROP COLUMN build_duration, DROP COLUMN date_built,
+ DROP COLUMN date_first_dispatched, DROP COLUMN builder,
+ DROP COLUMN build_state, DROP COLUMN build_log, DROP COLUMN archive,
+ DROP COLUMN pocket, DROP COLUMN upload_log, DROP COLUMN dependencies;
+
+INSERT INTO LaunchpadDatabaseRevision VALUES (2207, 99, 0);
=== modified file 'database/schema/security.cfg'
--- database/schema/security.cfg 2010-07-23 09:04:18 +0000
+++ database/schema/security.cfg 2010-07-23 19:32:55 +0000
@@ -700,12 +700,14 @@
public.archivepermission = SELECT
public.buildqueue = SELECT, INSERT, UPDATE
public.branch = SELECT
+public.buildfarmjob = SELECT, INSERT
public.component = SELECT
public.distribution = SELECT
public.distroseries = SELECT
public.distroarchseries = SELECT
public.job = SELECT, INSERT
public.person = SELECT
+public.packagebuild = SELECT, INSERT
public.processor = SELECT
public.processorfamily = SELECT
public.sourcepackagerecipe = SELECT, UPDATE
=== modified file 'lib/lp/archiveuploader/dscfile.py'
--- lib/lp/archiveuploader/dscfile.py 2010-07-15 11:30:58 +0000
+++ lib/lp/archiveuploader/dscfile.py 2010-07-23 19:32:55 +0000
@@ -573,7 +573,7 @@
build = getUtility(ISourcePackageRecipeBuildSource).getById(build_id)
# The master verifies the status to confirm successful upload.
- build.buildstate = BuildStatus.FULLYBUILT
+ build.status = BuildStatus.FULLYBUILT
# If this upload is successful, any existing log is wrong and
# unuseful.
build.upload_log = None
=== modified file 'lib/lp/archiveuploader/tests/test_recipeuploads.py'
--- lib/lp/archiveuploader/tests/test_recipeuploads.py 2010-07-18 00:26:33 +0000
+++ lib/lp/archiveuploader/tests/test_recipeuploads.py 2010-07-23 19:32:55 +0000
@@ -49,7 +49,7 @@
# Ensure that the upload processor correctly links the SPR to
# the SPRB, and that the status is set properly.
# This test depends on write access being granted to anybody
- # (it does not matter who) on SPRB.{buildstate,upload_log}.
+ # (it does not matter who) on SPRB.{status,upload_log}.
self.assertIs(None, self.build.source_package_release)
self.assertEqual(False, self.build.verifySuccessfulUpload())
self.queueUpload('bar_1.0-1', '%d/ubuntu' % self.build.archive.id)
@@ -67,5 +67,5 @@
spr = queue_item.sources[0].sourcepackagerelease
self.assertEqual(self.build, spr.source_package_recipe_build)
self.assertEqual(spr, self.build.source_package_release)
- self.assertEqual(BuildStatus.FULLYBUILT, self.build.buildstate)
+ self.assertEqual(BuildStatus.FULLYBUILT, self.build.status)
self.assertEqual(True, self.build.verifySuccessfulUpload())
=== modified file 'lib/lp/buildmaster/interfaces/packagebuild.py'
--- lib/lp/buildmaster/interfaces/packagebuild.py 2010-06-14 08:11:33 +0000
+++ lib/lp/buildmaster/interfaces/packagebuild.py 2010-07-23 19:32:55 +0000
@@ -106,7 +106,7 @@
stored.
"""
- def getLogFromSlave():
+ def getLogFromSlave(package_build):
"""Get last buildlog from slave. """
def getUploadLogContent(root, leaf):
@@ -120,7 +120,7 @@
def estimateDuration():
"""Estimate the build duration."""
- def storeBuildInfo(librarian, slave_status):
+ def storeBuildInfo(package_build, librarian, slave_status):
"""Store available information for the build job.
Derived classes can override this as needed, and call it from
@@ -193,4 +193,3 @@
will be returned.
:return: a `ResultSet` representing the requested package builds.
"""
-
=== modified file 'lib/lp/code/browser/sourcepackagerecipebuild.py'
--- lib/lp/code/browser/sourcepackagerecipebuild.py 2010-07-14 10:27:35 +0000
+++ lib/lp/code/browser/sourcepackagerecipebuild.py 2010-07-23 19:32:55 +0000
@@ -64,7 +64,7 @@
@property
def status(self):
"""A human-friendly status string."""
- if (self.context.buildstate == BuildStatus.NEEDSBUILD
+ if (self.context.status == BuildStatus.NEEDSBUILD
and self.eta is None):
return 'No suitable builders'
return {
@@ -77,7 +77,7 @@
BuildStatus.SUPERSEDED: (
'Could not build because source package was superseded'),
BuildStatus.FAILEDTOUPLOAD: 'Could not be uploaded correctly',
- }.get(self.context.buildstate, self.context.buildstate.title)
+ }.get(self.context.status, self.context.status.title)
@property
def eta(self):
@@ -103,12 +103,12 @@
"""The date when the build completed or is estimated to complete."""
if self.estimate:
return self.eta
- return self.context.datebuilt
+ return self.context.date_finished
@property
def estimate(self):
"""If true, the date value is an estimate."""
- if self.context.datebuilt is not None:
+ if self.context.date_finished is not None:
return False
return self.eta is not None
=== modified file 'lib/lp/code/browser/tests/test_sourcepackagerecipe.py'
--- lib/lp/code/browser/tests/test_sourcepackagerecipe.py 2010-07-22 08:39:05 +0000
+++ lib/lp/code/browser/tests/test_sourcepackagerecipe.py 2010-07-23 19:32:55 +0000
@@ -28,8 +28,13 @@
from lp.code.interfaces.sourcepackagerecipe import MINIMAL_RECIPE_TEXT
from lp.registry.interfaces.pocket import PackagePublishingPocket
from lp.soyuz.model.processor import ProcessorFamily
+<<<<<<< TREE
from lp.testing import ANONYMOUS, BrowserTestCase, login, logout
from lp.testing.factory import remove_security_proxy_and_shout_at_engineer
+=======
+from lp.testing import (
+ ANONYMOUS, BrowserTestCase, login, logout)
+>>>>>>> MERGE-SOURCE
class TestCaseForRecipe(BrowserTestCase):
@@ -450,8 +455,8 @@
recipe = self.makeRecipe()
build = removeSecurityProxy(self.factory.makeSourcePackageRecipeBuild(
recipe=recipe, distroseries=self.squirrel, archive=self.ppa))
- build.buildstate = BuildStatus.FULLYBUILT
- build.datebuilt = datetime(2010, 03, 16, tzinfo=utc)
+ build.status = BuildStatus.FULLYBUILT
+ build.date_finished = datetime(2010, 03, 16, tzinfo=utc)
self.assertTextMatchesExpressionIgnoreWhitespace("""\
Master Chef Recipes cake_recipe
@@ -532,7 +537,7 @@
set(view.builds))
def set_day(build, day):
- removeSecurityProxy(build).datebuilt = datetime(
+ removeSecurityProxy(build).date_finished = datetime(
2010, 03, day, tzinfo=utc)
set_day(build1, 16)
set_day(build2, 15)
@@ -617,7 +622,7 @@
for x in range(5):
build = recipe.requestBuild(
self.ppa, self.chef, woody, PackagePublishingPocket.RELEASE)
- removeSecurityProxy(build).buildstate = BuildStatus.FULLYBUILT
+ removeSecurityProxy(build).status = BuildStatus.FULLYBUILT
browser = self.getViewBrowser(recipe, '+request-builds')
browser.getControl('Woody').click()
@@ -658,7 +663,7 @@
self.user = self.factory.makePerson(
displayname='Owner', name='build-owner', password='test')
- def makeBuild(self, buildstate=None):
+ def makeBuild(self):
"""Make a build suitabe for testing."""
archive = self.factory.makeArchive(name='build',
owner=self.user)
@@ -683,7 +688,7 @@
self.assertTrue(view.estimate)
view.context.buildqueue_record.job.start()
self.assertTrue(view.estimate)
- removeSecurityProxy(view.context).datebuilt = datetime.now(utc)
+ removeSecurityProxy(view.context).date_finished = datetime.now(utc)
self.assertFalse(view.estimate)
def test_eta(self):
@@ -739,11 +744,12 @@
release = self.makeBuildAndRelease()
self.makeBinaryBuild(release, 'itanic')
naked_build = removeSecurityProxy(release.source_package_recipe_build)
- naked_build.buildstate = BuildStatus.FULLYBUILT
- naked_build.buildduration = timedelta(minutes=1)
- naked_build.datebuilt = datetime(2009, 1, 1, tzinfo=utc)
+ naked_build.status = BuildStatus.FULLYBUILT
+ naked_build.date_finished = datetime(2009, 1, 1, tzinfo=utc)
+ naked_build.date_started = (
+ naked_build.date_finished - timedelta(minutes=1))
naked_build.buildqueue_record.destroySelf()
- naked_build.buildlog = self.factory.makeLibraryFileAlias(
+ naked_build.log = self.factory.makeLibraryFileAlias(
content='buildlog')
naked_build.upload_log = self.factory.makeLibraryFileAlias(
content='upload_log')
@@ -805,10 +811,10 @@
build.buildqueue_record.builder = self.factory.makeBuilder()
main_text = self.getMainText(build, '+index')
self.assertNotIn('Logs have no tails!', main_text)
- removeSecurityProxy(build).buildstate = BuildStatus.BUILDING
+ removeSecurityProxy(build).status = BuildStatus.BUILDING
main_text = self.getMainText(build, '+index')
self.assertIn('Logs have no tails!', main_text)
- removeSecurityProxy(build).buildstate = BuildStatus.FULLYBUILT
+ removeSecurityProxy(build).status = BuildStatus.FULLYBUILT
self.assertIn('Logs have no tails!', main_text)
def getMainText(self, build, view_name=None):
@@ -819,12 +825,11 @@
def test_buildlog(self):
"""A link to the build log is shown if available."""
build = self.makeBuild()
- removeSecurityProxy(build).buildlog = (
+ removeSecurityProxy(build).log = (
self.factory.makeLibraryFileAlias())
- build_log_url = build.build_log_url
browser = self.getViewBrowser(build)
link = browser.getLink('buildlog')
- self.assertEqual(build_log_url, link.url)
+ self.assertEqual(build.log_url, link.url)
def test_uploadlog(self):
"""A link to the upload log is shown if available."""
=== modified file 'lib/lp/code/configure.zcml'
--- lib/lp/code/configure.zcml 2010-07-23 01:53:05 +0000
+++ lib/lp/code/configure.zcml 2010-07-23 19:32:55 +0000
@@ -920,7 +920,7 @@
<require permission="launchpad.View" interface="lp.code.interfaces.sourcepackagerecipebuild.ISourcePackageRecipeBuild"/>
<!-- This is needed for UploadProcessor to run. The permission isn't
important; launchpad.Edit isn't actually held by anybody. -->
- <require permission="launchpad.Edit" set_attributes="buildstate upload_log" />
+ <require permission="launchpad.Edit" set_attributes="status upload_log" />
</class>
<securedutility
=== modified file 'lib/lp/code/interfaces/sourcepackagerecipebuild.py'
--- lib/lp/code/interfaces/sourcepackagerecipebuild.py 2010-07-14 08:42:01 +0000
+++ lib/lp/code/interfaces/sourcepackagerecipebuild.py 2010-07-23 19:32:55 +0000
@@ -17,11 +17,11 @@
from lazr.restful.declarations import export_as_webservice_entry
from zope.interface import Interface
-from zope.schema import Bool, Datetime, Int, Object
+from zope.schema import Bool, Int, Object
from canonical.launchpad import _
-from lp.buildmaster.interfaces.buildbase import IBuildBase
+from lp.buildmaster.interfaces.packagebuild import IPackageBuild
from lp.soyuz.interfaces.binarypackagebuild import IBinaryPackageBuild
from lp.soyuz.interfaces.buildfarmbuildjob import IBuildFarmBuildJob
from lp.code.interfaces.sourcepackagerecipe import (
@@ -32,7 +32,7 @@
from lp.soyuz.interfaces.sourcepackagerelease import ISourcePackageRelease
-class ISourcePackageRecipeBuild(IBuildBase):
+class ISourcePackageRecipeBuild(IPackageBuild):
"""A build of a source package."""
export_as_webservice_entry()
@@ -42,15 +42,9 @@
Reference(IBinaryPackageBuild),
title=_("The binary builds that resulted from this."), readonly=True)
- datestarted = Datetime(title=u'The time the build started.')
-
distroseries = Reference(
IDistroSeries, title=_("The distroseries being built for"),
readonly=True)
- # XXX michaeln 2010-05-18 bug=567922
- # Temporarily alias distro_series until SPRecipeBuild is
- # implementing IPackageBuild.
- distro_series = distroseries
requester = Object(
schema=IPerson, required=False,
@@ -89,7 +83,8 @@
def new(distroseries, recipe, requester, archive, date_created=None):
"""Create an `ISourcePackageRecipeBuild`.
- :param distroseries: The `IDistroSeries` that this is building against.
+ :param distroseries: The `IDistroSeries` that this is building
+ against.
:param recipe: The `ISourcePackageRecipe` that this is building.
:param requester: The `IPerson` who wants to build it.
:param date_created: The date this build record was created. If not
=== modified file 'lib/lp/code/mail/sourcepackagerecipebuild.py'
--- lib/lp/code/mail/sourcepackagerecipebuild.py 2010-06-09 20:24:11 +0000
+++ lib/lp/code/mail/sourcepackagerecipebuild.py 2010-07-23 19:32:55 +0000
@@ -50,7 +50,7 @@
params = super(
SourcePackageRecipeBuildMailer, self)._getTemplateParams(email)
params.update({
- 'status': self.build.buildstate.title,
+ 'status': self.build.status.title,
'distroseries': self.build.distroseries.name,
'recipe': self.build.recipe.name,
'recipe_owner': self.build.recipe.owner.name,
=== modified file 'lib/lp/code/model/sourcepackagerecipe.py'
--- lib/lp/code/model/sourcepackagerecipe.py 2010-07-21 14:41:26 +0000
+++ lib/lp/code/model/sourcepackagerecipe.py 2010-07-23 19:32:55 +0000
@@ -26,6 +26,8 @@
from canonical.launchpad.interfaces.lpstorm import IMasterStore, IStore
from lp.buildmaster.interfaces.buildbase import BuildStatus
+from lp.buildmaster.model.buildfarmjob import BuildFarmJob
+from lp.buildmaster.model.packagebuild import PackageBuild
from lp.code.errors import (BuildAlreadyPending, BuildNotAllowedForDistro,
TooManyBuilds)
from lp.code.interfaces.sourcepackagerecipe import (
@@ -217,14 +219,16 @@
pending = IStore(self).find(SourcePackageRecipeBuild,
SourcePackageRecipeBuild.recipe_id == self.id,
SourcePackageRecipeBuild.distroseries_id == distroseries.id,
- SourcePackageRecipeBuild.archive_id == archive.id,
- SourcePackageRecipeBuild.buildstate == BuildStatus.NEEDSBUILD)
+ PackageBuild.archive_id == archive.id,
+ PackageBuild.id == SourcePackageRecipeBuild.package_build_id,
+ BuildFarmJob.id == PackageBuild.build_farm_job_id,
+ BuildFarmJob.status == BuildStatus.NEEDSBUILD)
if pending.any() is not None:
raise BuildAlreadyPending(self, distroseries)
build = getUtility(ISourcePackageRecipeBuildSource).new(distroseries,
self, requester, archive)
- build.queueBuild(build)
+ build.queueBuild()
if manual:
build.buildqueue_record.manualScore(1000)
return build
@@ -232,32 +236,41 @@
def getBuilds(self, pending=False):
"""See `ISourcePackageRecipe`."""
if pending:
- clauses = [SourcePackageRecipeBuild.datebuilt == None]
+ clauses = [BuildFarmJob.date_finished == None]
else:
- clauses = [SourcePackageRecipeBuild.datebuilt != None]
+ clauses = [BuildFarmJob.date_finished != None]
result = Store.of(self).find(
- SourcePackageRecipeBuild, SourcePackageRecipeBuild.recipe==self,
+ SourcePackageRecipeBuild,
+ SourcePackageRecipeBuild.recipe==self,
+ SourcePackageRecipeBuild.package_build_id == PackageBuild.id,
+ PackageBuild.build_farm_job_id == BuildFarmJob.id,
*clauses)
- result.order_by(Desc(SourcePackageRecipeBuild.datebuilt))
+ result.order_by(Desc(BuildFarmJob.date_finished))
return result
def getLastBuild(self):
"""See `ISourcePackageRecipeBuild`."""
store = Store.of(self)
result = store.find(
- SourcePackageRecipeBuild, SourcePackageRecipeBuild.recipe == self)
- result.order_by(Desc(SourcePackageRecipeBuild.datebuilt))
+ (SourcePackageRecipeBuild),
+ SourcePackageRecipeBuild.recipe == self,
+ SourcePackageRecipeBuild.package_build_id == PackageBuild.id,
+ PackageBuild.build_farm_job_id == BuildFarmJob.id)
+ result.order_by(Desc(BuildFarmJob.date_finished))
return result.first()
def getMedianBuildDuration(self):
"""Return the median duration of builds of this recipe."""
store = IStore(self)
result = store.find(
- SourcePackageRecipeBuild.buildduration,
- SourcePackageRecipeBuild.recipe==self.id,
- SourcePackageRecipeBuild.buildduration != None)
- result.order_by(Desc(SourcePackageRecipeBuild.buildduration))
- count = result.count()
- if count == 0:
+ BuildFarmJob,
+ SourcePackageRecipeBuild.recipe == self.id,
+ BuildFarmJob.date_finished != None,
+ BuildFarmJob.id == PackageBuild.build_farm_job_id,
+ SourcePackageRecipeBuild.package_build_id == PackageBuild.id)
+ durations = [build.date_finished - build.date_started for build in
+ result]
+ if len(durations) == 0:
return None
- return result[count/2]
+ durations.sort(reverse=True)
+ return durations[len(durations) / 2]
=== modified file 'lib/lp/code/model/sourcepackagerecipebuild.py'
--- lib/lp/code/model/sourcepackagerecipebuild.py 2010-07-14 09:35:20 +0000
+++ lib/lp/code/model/sourcepackagerecipebuild.py 2010-07-23 19:32:55 +0000
@@ -16,19 +16,22 @@
from pytz import utc
from canonical.database.constants import UTC_NOW
-from canonical.database.datetimecol import UtcDateTimeCol
-from canonical.database.enumcol import DBEnum
+from canonical.launchpad.browser.librarian import (
+ ProxiedLibraryFileAlias)
from canonical.launchpad.interfaces.lpstorm import IMasterStore, IStore
from canonical.launchpad.interfaces.launchpad import NotFoundError
-from storm.locals import Int, Reference, Storm, TimeDelta, Unicode
+from psycopg2 import ProgrammingError
+from storm.locals import Int, Reference, Storm
from storm.store import Store
from zope.component import getUtility
from zope.interface import classProvides, implements
from canonical.launchpad.webapp import errorlog
-from lp.buildmaster.interfaces.buildbase import BuildStatus, IBuildBase
+from lp.buildmaster.model.packagebuild import (
+ PackageBuild, PackageBuildDerived)
+from lp.buildmaster.interfaces.buildbase import BuildStatus
from lp.buildmaster.interfaces.buildfarmjob import BuildFarmJobType
from lp.buildmaster.model.buildbase import BuildBase
from lp.buildmaster.model.buildqueue import BuildQueue
@@ -50,23 +53,24 @@
from lp.soyuz.model.sourcepackagerelease import SourcePackageRelease
-class SourcePackageRecipeBuild(BuildBase, Storm):
+class SourcePackageRecipeBuild(PackageBuildDerived, Storm):
+
__storm_table__ = 'SourcePackageRecipeBuild'
policy_name = 'recipe'
- implements(IBuildBase, ISourcePackageRecipeBuild)
+ implements(ISourcePackageRecipeBuild)
classProvides(ISourcePackageRecipeBuildSource)
+ package_build_id = Int(name='package_build', allow_none=False)
+ package_build = Reference(package_build_id, 'PackageBuild.id')
+
build_farm_job_type = BuildFarmJobType.RECIPEBRANCHBUILD
id = Int(primary=True)
is_private = False
- archive_id = Int(name='archive', allow_none=False)
- archive = Reference(archive_id, 'Archive.id')
-
@property
def binary_builds(self):
"""See `ISourcePackageRecipeBuild`."""
@@ -75,53 +79,10 @@
SourcePackageRelease.id,
SourcePackageRelease.source_package_recipe_build==self.id)
- buildduration = TimeDelta(name='build_duration', default=None)
-
- builder_id = Int(name='builder', allow_none=True)
- builder = Reference(builder_id, 'Builder.id')
-
- buildlog_id = Int(name='build_log', allow_none=True)
- buildlog = Reference(buildlog_id, 'LibraryFileAlias.id')
-
- buildstate = DBEnum(enum=BuildStatus, name='build_state')
- dependencies = Unicode(allow_none=True)
-
- upload_log_id = Int(name='upload_log', allow_none=True)
- upload_log = Reference(upload_log_id, 'LibraryFileAlias.id')
-
@property
def current_component(self):
return getUtility(IComponentSet)[default_component_dependency_name]
- datecreated = UtcDateTimeCol(notNull=True, dbName='date_created')
- datebuilt = UtcDateTimeCol(notNull=False, dbName='date_built')
-
- # See `IBuildBase` - the following attributes are aliased
- # to allow a shared implementation of the handleStatus methods
- # until IBuildBase is removed.
- status = buildstate
- date_finished = datebuilt
- log = buildlog
-
- @property
- def datestarted(self):
- """See `IBuild`."""
- # datestarted is not stored on Build. It can be calculated from
- # self.datebuilt and self.buildduration, if both are set. This does
- # not happen until the build is complete.
- #
- # Before the build is complete, there will be a buildqueue_record.
- # If buildqueue_record is set, buildqueue_record.job.date_started can
- # be used. Otherwise, None is returned.
- if None not in (self.datebuilt, self.buildduration):
- return self.datebuilt - self.buildduration
- queue_record = self.buildqueue_record
- if queue_record is None:
- return None
- return queue_record.job.date_started
-
- date_first_dispatched = UtcDateTimeCol(notNull=False)
-
distroseries_id = Int(name='distroseries', allow_none=True)
distroseries = Reference(distroseries_id, 'DistroSeries.id')
distro_series = distroseries
@@ -133,8 +94,6 @@
is_virtualized = True
- pocket = DBEnum(enum=PackagePublishingPocket)
-
recipe_id = Int(name='recipe', allow_none=False)
recipe = Reference(recipe_id, 'SourcePackageRecipe.id')
@@ -180,22 +139,10 @@
def title(self):
return '%s recipe build' % self.recipe.base_branch.unique_name
- def __init__(self, distroseries, recipe, requester,
- archive, pocket, date_created=None,
- date_first_dispatched=None, date_built=None, builder=None,
- build_state=BuildStatus.NEEDSBUILD, build_log=None,
- build_duration=None):
+ def __init__(self, package_build, distroseries, recipe, requester):
"""Construct a SourcePackageRecipeBuild."""
super(SourcePackageRecipeBuild, self).__init__()
- self.archive = archive
- self.pocket = pocket
- self.buildduration = build_duration
- self.buildlog = build_log
- self.builder = builder
- self.buildstate = build_state
- self.datebuilt = date_built
- self.datecreated = date_created
- self.date_first_dispatched = date_first_dispatched
+ self.package_build = package_build
self.distroseries = distroseries
self.recipe = recipe
self.requester = requester
@@ -209,13 +156,13 @@
pocket = PackagePublishingPocket.RELEASE
if date_created is None:
date_created = UTC_NOW
+ packagebuild = PackageBuild.new(cls.build_farm_job_type,
+ True, archive, pocket, date_created=date_created)
spbuild = cls(
+ packagebuild,
distroseries,
recipe,
- requester,
- archive,
- pocket,
- date_created=date_created)
+ requester)
store.add(spbuild)
return spbuild
@@ -232,6 +179,8 @@
distroseries, PackagePublishingPocket.RELEASE)
except BuildAlreadyPending:
continue
+ except ProgrammingError:
+ raise
except:
info = sys.exc_info()
errorlog.globalErrorUtility.raising(info)
@@ -269,13 +218,16 @@
@classmethod
def getRecentBuilds(cls, requester, recipe, distroseries, _now=None):
+ from lp.buildmaster.model.buildfarmjob import BuildFarmJob
if _now is None:
_now = datetime.datetime.now(utc)
store = IMasterStore(SourcePackageRecipeBuild)
old_threshold = _now - datetime.timedelta(days=1)
return store.find(cls, cls.distroseries_id == distroseries.id,
cls.requester_id == requester.id, cls.recipe_id == recipe.id,
- cls.datecreated > old_threshold)
+ BuildFarmJob.date_created > old_threshold,
+ BuildFarmJob.id == PackageBuild.build_farm_job_id,
+ PackageBuild.id == cls.package_build_id)
def makeJob(self):
"""See `ISourcePackageRecipeBuildJob`."""
@@ -301,10 +253,35 @@
mailer = SourcePackageRecipeBuildMailer.forStatus(self)
mailer.sendAll()
+ def lfaUrl(self, lfa):
+ """Return the URL for a LibraryFileAlias, in the context of self.
+ """
+ if lfa is None:
+ return None
+ return ProxiedLibraryFileAlias(lfa, self).http_url
+
+ @property
+ def log_url(self):
+ """See `IPackageBuild`.
+
+ Overridden here so that it uses the SourcePackageRecipeBuild as
+ context.
+ """
+ return self.lfaUrl(self.log)
+
+ @property
+ def upload_log_url(self):
+ """See `IPackageBuild`.
+
+ Overridden here so that it uses the SourcePackageRecipeBuild as
+ context.
+ """
+ return self.lfaUrl(self.upload_log)
+
def getFileByName(self, filename):
"""See `ISourcePackageRecipeBuild`."""
files = dict((lfa.filename, lfa)
- for lfa in [self.buildlog, self.upload_log]
+ for lfa in [self.log, self.upload_log]
if lfa is not None)
try:
return files[filename]
=== modified file 'lib/lp/code/model/tests/test_sourcepackagerecipe.py'
--- lib/lp/code/model/tests/test_sourcepackagerecipe.py 2010-07-22 08:39:05 +0000
+++ lib/lp/code/model/tests/test_sourcepackagerecipe.py 2010-07-23 19:32:55 +0000
@@ -304,7 +304,7 @@
def request_build():
build = recipe.requestBuild(archive, requester, series,
PackagePublishingPocket.RELEASE)
- removeSecurityProxy(build).buildstate = BuildStatus.FULLYBUILT
+ removeSecurityProxy(build).status = BuildStatus.FULLYBUILT
[request_build() for num in range(5)]
e = self.assertRaises(TooManyBuilds, request_build)
self.assertIn(
@@ -331,7 +331,7 @@
recipe.requestBuild(archive, recipe.owner,
new_distroseries, PackagePublishingPocket.RELEASE)
# Changing status of old build allows new build.
- removeSecurityProxy(old_build).buildstate = BuildStatus.FULLYBUILT
+ removeSecurityProxy(old_build).status = BuildStatus.FULLYBUILT
recipe.requestBuild(archive, recipe.owner, series,
PackagePublishingPocket.RELEASE)
@@ -425,18 +425,21 @@
SourcePackageRecipe.findStaleDailyBuilds())
def test_getMedianBuildDuration(self):
+ def set_duration(build, minutes):
+ duration = timedelta(minutes=minutes)
+ build = removeSecurityProxy(build)
+ build.date_started = self.factory.getUniqueDate()
+ build.date_finished = build.date_started + duration
recipe = removeSecurityProxy(self.factory.makeSourcePackageRecipe())
self.assertIs(None, recipe.getMedianBuildDuration())
- build = removeSecurityProxy(
- self.factory.makeSourcePackageRecipeBuild(recipe=recipe))
- build.buildduration = timedelta(minutes=10)
+ build = self.factory.makeSourcePackageRecipeBuild(recipe=recipe)
+ set_duration(build, 10)
self.assertEqual(
timedelta(minutes=10), recipe.getMedianBuildDuration())
def addBuild(minutes):
- build = removeSecurityProxy(
- self.factory.makeSourcePackageRecipeBuild(recipe=recipe))
- build.buildduration = timedelta(minutes=minutes)
+ build = self.factory.makeSourcePackageRecipeBuild(recipe=recipe)
+ set_duration(build, minutes)
addBuild(20)
self.assertEqual(
timedelta(minutes=10), recipe.getMedianBuildDuration())
=== modified file 'lib/lp/code/model/tests/test_sourcepackagerecipebuild.py'
--- lib/lp/code/model/tests/test_sourcepackagerecipebuild.py 2010-07-22 08:15:29 +0000
+++ lib/lp/code/model/tests/test_sourcepackagerecipebuild.py 2010-07-23 19:32:55 +0000
@@ -11,7 +11,6 @@
import re
import unittest
-from pytz import utc
import transaction
from storm.locals import Store
from zope.component import getUtility
@@ -23,7 +22,7 @@
from canonical.launchpad.interfaces.lpstorm import IStore
from canonical.launchpad.webapp.authorization import check_permission
from canonical.launchpad.webapp.testing import verifyObject
-from lp.buildmaster.interfaces.buildbase import BuildStatus, IBuildBase
+from lp.buildmaster.interfaces.buildbase import BuildStatus
from lp.buildmaster.interfaces.buildqueue import IBuildQueue
from lp.buildmaster.tests.test_buildbase import (
TestGetUploadMethodsMixin, TestHandleStatusMixin)
@@ -69,7 +68,6 @@
# SourcePackageRecipeBuild provides IBuildBase and
# ISourcePackageRecipeBuild.
spb = self.makeSourcePackageRecipeBuild()
- self.assertProvides(spb, IBuildBase)
self.assertProvides(spb, ISourcePackageRecipeBuild)
def test_implements_interface(self):
@@ -156,44 +154,28 @@
def test_estimateDuration(self):
# If there are no successful builds, estimate 10 minutes.
spb = self.makeSourcePackageRecipeBuild()
+ cur_date = self.factory.getUniqueDate()
self.assertEqual(
datetime.timedelta(minutes=10), spb.estimateDuration())
for minutes in [20, 5, 1]:
build = removeSecurityProxy(
self.factory.makeSourcePackageRecipeBuild(recipe=spb.recipe))
- build.buildduration = datetime.timedelta(minutes=minutes)
+ build.date_started = cur_date
+ build.date_finished = (
+ cur_date + datetime.timedelta(minutes=minutes))
self.assertEqual(
datetime.timedelta(minutes=5), spb.estimateDuration())
- def test_datestarted(self):
- """Datestarted is taken from job if not specified in the build.
-
- Specifying datestarted in the build requires datebuilt and
- buildduration to be specified.
- """
- spb = self.makeSourcePackageRecipeBuild()
- self.assertIs(None, spb.datestarted)
- job = self.factory.makeSourcePackageRecipeBuildJob(
- recipe_build=spb).job
- job.start()
- self.assertEqual(job.date_started, spb.datestarted)
- now = datetime.datetime.now(utc)
- removeSecurityProxy(spb).datebuilt = now
- self.assertEqual(job.date_started, spb.datestarted)
- duration = datetime.timedelta(minutes=1)
- removeSecurityProxy(spb).buildduration = duration
- self.assertEqual(now - duration, spb.datestarted)
-
def test_getFileByName(self):
"""getFileByName returns the logs when requested by name."""
spb = self.factory.makeSourcePackageRecipeBuild()
- removeSecurityProxy(spb).buildlog = (
+ removeSecurityProxy(spb).log = (
self.factory.makeLibraryFileAlias(filename='buildlog.txt.gz'))
- self.assertEqual(spb.buildlog, spb.getFileByName('buildlog.txt.gz'))
+ self.assertEqual(spb.log, spb.getFileByName('buildlog.txt.gz'))
self.assertRaises(NotFoundError, spb.getFileByName, 'foo')
- removeSecurityProxy(spb).buildlog = (
+ removeSecurityProxy(spb).log = (
self.factory.makeLibraryFileAlias(filename='foo'))
- self.assertEqual(spb.buildlog, spb.getFileByName('foo'))
+ self.assertEqual(spb.log, spb.getFileByName('foo'))
self.assertRaises(NotFoundError, spb.getFileByName, 'buildlog.txt.gz')
removeSecurityProxy(spb).upload_log = (
self.factory.makeLibraryFileAlias(filename='upload.txt.gz'))
@@ -287,7 +269,7 @@
date_created=yesterday)
self.assertContentEqual([], get_recent())
a_second = datetime.timedelta(seconds=1)
- removeSecurityProxy(recent_build).datecreated += a_second
+ removeSecurityProxy(recent_build).date_created += a_second
self.assertContentEqual([recent_build], get_recent())
def test_destroySelf(self):
@@ -320,7 +302,7 @@
secret = self.factory.makeDistroSeries(name=u'distroseries')
build = self.factory.makeSourcePackageRecipeBuild(
recipe=cake, distroseries=secret, archive=pantry)
- removeSecurityProxy(build).buildstate = BuildStatus.FULLYBUILT
+ removeSecurityProxy(build).status = BuildStatus.FULLYBUILT
IStore(build).flush()
build.notify()
(message, ) = pop_notifications()
@@ -342,7 +324,7 @@
def prepare_build():
queue_record = self.factory.makeSourcePackageRecipeBuildJob()
build = queue_record.specific_job.build
- removeSecurityProxy(build).buildstate = BuildStatus.FULLYBUILT
+ removeSecurityProxy(build).status = BuildStatus.FULLYBUILT
queue_record.builder = self.factory.makeBuilder()
slave = WaitingSlave('BuildStatus.OK')
queue_record.builder.setSlaveForTesting(slave)
=== modified file 'lib/lp/code/templates/sourcepackagerecipebuild-index.pt'
--- lib/lp/code/templates/sourcepackagerecipebuild-index.pt 2010-07-21 10:48:23 +0000
+++ lib/lp/code/templates/sourcepackagerecipebuild-index.pt 2010-07-23 19:32:55 +0000
@@ -12,8 +12,8 @@
<tal:registering metal:fill-slot="registering">
<p>
created
- <span tal:content="context/datecreated/fmt:displaydate"
- tal:attributes="title context/datecreated/fmt:datetime"
+ <span tal:content="context/date_created/fmt:displaydate"
+ tal:attributes="title context/date_created/fmt:datetime"
>on 2005-01-01</span>
</p>
</tal:registering>
@@ -37,7 +37,7 @@
</div> <!-- yui-g -->
<div id="buildlog" class="portlet"
- tal:condition="context/buildstate/enumvalue:BUILDING">
+ tal:condition="context/status/enumvalue:BUILDING">
<div metal:use-macro="template/macros/buildlog" />
</div>
@@ -95,9 +95,9 @@
<p>
<span tal:replace="structure context/image:icon" />
<span tal:attributes="
- class string:buildstatus${context/buildstate/name};"
- tal:content="context/buildstate/title">Fully built</span>
- <tal:building condition="context/buildstate/enumvalue:BUILDING">
+ class string:buildstatus${context/status/name};"
+ tal:content="context/status/title">Fully built</span>
+ <tal:building condition="context/status/enumvalue:BUILDING">
on <a tal:content="context/buildqueue_record/builder/title"
tal:attributes="href context/buildqueue_record/builder/fmt:url"/>
</tal:building>
@@ -120,33 +120,33 @@
</li>
</tal:pending>
</tal:reallypending>
- <tal:started condition="context/datestarted">
- <li tal:condition="context/datestarted">
+ <tal:started condition="context/date_started">
+ <li tal:condition="context/date_started">
Started <span
- tal:define="start context/datestarted"
+ tal:define="start context/date_started"
tal:attributes="title start/fmt:datetime"
tal:content="start/fmt:displaydate">2008-01-01</span>
</li>
</tal:started>
- <tal:finish condition="not: context/datebuilt">
+ <tal:finish condition="not: context/date_finished">
<li tal:define="eta view/eta" tal:condition="view/eta">
Estimated finish <tal:eta
replace="eta/fmt:approximatedate">in 3 hours</tal:eta>
</li>
</tal:finish>
- <li tal:condition="context/datebuilt">
+ <li tal:condition="context/date_finished">
Finished <span
- tal:attributes="title context/datebuilt/fmt:datetime"
- tal:content="context/datebuilt/fmt:displaydate">2008-01-01</span>
- <tal:duration condition="context/buildduration">
- (took <span tal:replace="context/buildduration/fmt:exactduration"/>)
+ tal:attributes="title context/date_finished/fmt:datetime"
+ tal:content="context/date_finished/fmt:displaydate">2008-01-01</span>
+ <tal:duration condition="context/duration">
+ (took <span tal:replace="context/duration/fmt:exactduration"/>)
</tal:duration>
</li>
- <li tal:define="file context/buildlog"
+ <li tal:define="file context/log"
tal:condition="file">
<a class="sprite download"
- tal:attributes="href context/build_log_url">buildlog</a>
+ tal:attributes="href context/log_url">buildlog</a>
(<span tal:replace="file/content/filesize/fmt:bytes" />)
</li>
<li tal:define="file context/upload_log"
=== modified file 'lib/lp/testing/factory.py'
--- lib/lp/testing/factory.py 2010-07-22 14:06:45 +0000
+++ lib/lp/testing/factory.py 2010-07-23 19:32:55 +0000
@@ -158,7 +158,6 @@
ANONYMOUS,
login,
login_as,
- logout,
run_with_login,
temp_dir,
time_counter,
@@ -1864,7 +1863,7 @@
requester=requester,
pocket=pocket,
date_created=date_created)
- removeSecurityProxy(spr_build).buildstate = status
+ removeSecurityProxy(spr_build).status = status
return spr_build
def makeSourcePackageRecipeBuildJob(