← Back to team overview

launchpad-reviewers team mailing list archive

[Merge] lp:~wgrant/launchpad/flatten-bfj-1-populate into lp:launchpad

 

William Grant has proposed merging lp:~wgrant/launchpad/flatten-bfj-1-populate into lp:launchpad with lp:~wgrant/launchpad/flatten-bfj-0-db as a prerequisite.

Requested reviews:
  Launchpad code reviewers (launchpad-reviewers)
Related bugs:
  Bug #758258 in Launchpad itself: "buildfarmjob schema is inefficient for reporting"
  https://bugs.launchpad.net/launchpad/+bug/758258

For more details, see:
https://code.launchpad.net/~wgrant/launchpad/flatten-bfj-1-populate/+merge/145541

The build farm job schema is being reworked to improve performance. Columns from PackageBuild and BuildFarmJob are being merged into tables that previously delegated to them. The PackageBuild table will end up dying entirely, but BuildFarmJob will remain, a shadow of its former self, to answer questions about Archive:+builds and Builder:+history. Additionally, BinaryPackageBuild is growing new distribution, distroseries, sourcepackagename and is_distro_archive columns to make searches even faster.

This is the first non-DB component: altering the app to set the new columns on BPB/SPRB/TTB as well as the old columns on BFJ/PB. Values are still only ever read from BFJ/PB, as the new columns won't be fully populated yet.
-- 
https://code.launchpad.net/~wgrant/launchpad/flatten-bfj-1-populate/+merge/145541
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~wgrant/launchpad/flatten-bfj-1-populate into lp:launchpad.
=== modified file 'lib/lp/buildmaster/interfaces/packagebuild.py'
--- lib/lp/buildmaster/interfaces/packagebuild.py	2013-01-22 08:31:09 +0000
+++ lib/lp/buildmaster/interfaces/packagebuild.py	2013-02-01 02:04:26 +0000
@@ -133,20 +133,12 @@
 class IPackageBuildSource(Interface):
     """A utility of this interface used to create _things_."""
 
-    def new(job_type, virtualized, archive, pocket, processor=None,
-            status=BuildStatus.NEEDSBUILD, dependencies=None, builder=None):
+    def new(build_farm_job, archive, pocket):
         """Create a new `IPackageBuild`.
 
-        :param job_type: A `BuildFarmJobType` item.
-        :param virtualized: A boolean indicating whether this build was
-            virtualized.
+        :param build_farm_job: An `IBuildFarmJob`.
         :param archive: An `IArchive`.
         :param pocket: An item of `PackagePublishingPocket`.
-        :param processor: An `IProcessor` required to run this build farm
-            job. Default is None (processor-independent).
-        :param status: A `BuildStatus` item defaulting to NEEDSBUILD.
-        :param dependencies: An optional debian-like dependency line.
-        :parma builder: An optional `IBuilder`.
         """
 
 

=== modified file 'lib/lp/buildmaster/model/buildfarmjob.py'
--- lib/lp/buildmaster/model/buildfarmjob.py	2013-01-30 07:49:52 +0000
+++ lib/lp/buildmaster/model/buildfarmjob.py	2013-02-01 02:04:26 +0000
@@ -196,23 +196,28 @@
 
     failure_count = Int(name='failure_count', allow_none=False)
 
+    archive_id = Int(name='archive')
+    archive = Reference(archive_id, 'Archive.id')
+
     dependencies = None
 
     def __init__(self, job_type, status=BuildStatus.NEEDSBUILD,
                  processor=None, virtualized=None, date_created=None,
-                 builder=None):
+                 builder=None, archive=None):
         super(BuildFarmJob, self).__init__()
         (self.job_type, self.status, self.processor, self.virtualized,
-         self.builder) = (job_type, status, processor, virtualized, builder)
+         self.builder, self.archive) = (
+             job_type, status, processor, virtualized, builder, archive)
         if date_created is not None:
             self.date_created = date_created
 
     @classmethod
     def new(cls, job_type, status=BuildStatus.NEEDSBUILD, processor=None,
-            virtualized=None, date_created=None, builder=None):
+            virtualized=None, date_created=None, builder=None, archive=None):
         """See `IBuildFarmJobSource`."""
         build_farm_job = BuildFarmJob(
-            job_type, status, processor, virtualized, date_created, builder)
+            job_type, status, processor, virtualized, date_created, builder,
+            archive)
         store = IMasterStore(BuildFarmJob)
         store.add(build_farm_job)
         return build_farm_job
@@ -319,29 +324,30 @@
 
     def setLog(self, log):
         """See `IBuildFarmJob`."""
-        self.build_farm_job.log = log
+        self.build_farm_job.log = self._new_log = log
 
     def updateStatus(self, status, builder=None, slave_status=None,
                      date_started=None, date_finished=None):
         """See `IBuildFarmJob`."""
-        self.build_farm_job.status = status
+        self.build_farm_job.status = self._new_status = status
 
         # If there's a builder provided, set it if we don't already have
         # one, or otherwise crash if it's different from the one we
         # expected.
         if builder is not None:
             if self.builder is None:
-                self.build_farm_job.builder = builder
+                self.build_farm_job.builder = self._new_builder = builder
             else:
                 assert self.builder == builder
 
         # If we're starting to build, set date_started and
         # date_first_dispatched if required.
         if self.date_started is None and status == BuildStatus.BUILDING:
-            self.build_farm_job.date_started = (
+            self.build_farm_job.date_started = self._new_date_started = (
                 date_started or datetime.datetime.now(pytz.UTC))
             if self.date_first_dispatched is None:
                 self.build_farm_job.date_first_dispatched = self.date_started
+                self._new_date_first_dispatched = self.date_started
 
         # If we're in a final build state (or UPLOADING, which sort of
         # is), set date_finished if date_started is.
@@ -352,12 +358,13 @@
             # XXX cprov 20060615 bug=120584: Currently buildduration includes
             # the scanner latency, it should really be asking the slave for
             # the duration spent building locally.
-            self.build_farm_job.date_finished = (
+            self.build_farm_job.date_finished = self._new_date_finished = (
                 date_finished or datetime.datetime.now(pytz.UTC))
 
     def gotFailure(self):
         """See `IBuildFarmJob`."""
         self.build_farm_job.failure_count += 1
+        self._new_failure_count += 1
 
 
 class BuildFarmJobSet:

=== modified file 'lib/lp/buildmaster/model/packagebuild.py'
--- lib/lp/buildmaster/model/packagebuild.py	2013-01-30 07:49:52 +0000
+++ lib/lp/buildmaster/model/packagebuild.py	2013-02-01 02:04:26 +0000
@@ -84,8 +84,7 @@
     distribution = None
     distro_series = None
 
-    def __init__(self, build_farm_job, archive, pocket,
-                 dependencies=None):
+    def __init__(self, build_farm_job, archive, pocket, dependencies=None):
         """Construct a PackageBuild."""
         super(PackageBuild, self).__init__()
         self.build_farm_job = build_farm_job
@@ -94,18 +93,10 @@
         self.dependencies = dependencies
 
     @classmethod
-    def new(cls, job_type, virtualized, archive, pocket, processor=None,
-            status=BuildStatus.NEEDSBUILD, dependencies=None,
-            date_created=None, builder=None):
+    def new(cls, build_farm_job, archive, pocket):
         """See `IPackageBuildSource`."""
         store = IMasterStore(PackageBuild)
-
-        # Create the BuildFarmJob to which the new PackageBuild
-        # will delegate.
-        build_farm_job = getUtility(IBuildFarmJobSource).new(
-            job_type, status, processor, virtualized, date_created, builder)
-
-        package_build = cls(build_farm_job, archive, pocket, dependencies)
+        package_build = cls(build_farm_job, archive, pocket)
         store.add(package_build)
         return package_build
 
@@ -174,10 +165,10 @@
 
         if (status == BuildStatus.MANUALDEPWAIT and slave_status is not None
             and slave_status.get('dependencies') is not None):
-            self.package_build.dependencies = (
+            self.package_build.dependencies = self._new_dependencies = (
                 unicode(slave_status.get('dependencies')))
         else:
-            self.package_build.dependencies = None
+            self.package_build.dependencies = self._new_dependencies = None
 
     def verifySuccessfulUpload(self):
         """See `IPackageBuild`."""
@@ -213,7 +204,7 @@
         """See `IPackageBuild`."""
         filename = "upload_%s_log.txt" % self.id
         library_file = self.createUploadLog(content, filename=filename)
-        self.package_build.upload_log = library_file
+        self.package_build.upload_log = self._new_upload_log = library_file
 
     def notify(self, extra_info=None):
         """See `IPackageBuild`."""

=== modified file 'lib/lp/buildmaster/tests/test_packagebuild.py'
--- lib/lp/buildmaster/tests/test_packagebuild.py	2013-01-30 07:29:46 +0000
+++ lib/lp/buildmaster/tests/test_packagebuild.py	2013-02-01 02:04:26 +0000
@@ -16,6 +16,7 @@
     BuildFarmJobType,
     BuildStatus,
     )
+from lp.buildmaster.interfaces.buildfarmjob import IBuildFarmJobSource
 from lp.buildmaster.interfaces.packagebuild import (
     IPackageBuild,
     IPackageBuildSet,
@@ -46,9 +47,9 @@
         if archive is None:
             archive = self.factory.makeArchive()
 
-        return getUtility(IPackageBuildSource).new(
-            job_type=job_type, virtualized=True, archive=archive,
-            status=status, pocket=pocket)
+        bfj = getUtility(IBuildFarmJobSource).new(
+            job_type, virtualized=True, status=status)
+        return getUtility(IPackageBuildSource).new(bfj, archive, pocket)
 
 
 class TestPackageBuild(TestPackageBuildBase):

=== modified file 'lib/lp/code/model/sourcepackagerecipebuild.py'
--- lib/lp/code/model/sourcepackagerecipebuild.py	2013-01-30 07:49:52 +0000
+++ lib/lp/code/model/sourcepackagerecipebuild.py	2013-02-01 02:04:26 +0000
@@ -15,11 +15,14 @@
 import logging
 
 from psycopg2 import ProgrammingError
-from pytz import utc
+import pytz
 from storm.locals import (
+    Bool,
+    DateTime,
     Int,
     Reference,
     Storm,
+    Unicode,
     )
 from storm.store import (
     EmptyResultSet,
@@ -36,7 +39,12 @@
     BuildFarmJobType,
     BuildStatus,
     )
-from lp.buildmaster.model.buildfarmjob import BuildFarmJobOld
+from lp.buildmaster.interfaces.buildfarmjob import IBuildFarmJobSource
+from lp.buildmaster.interfaces.packagebuild import IPackageBuildSource
+from lp.buildmaster.model.buildfarmjob import (
+    BuildFarmJob,
+    BuildFarmJobOld,
+    )
 from lp.buildmaster.model.buildqueue import BuildQueue
 from lp.buildmaster.model.packagebuild import (
     PackageBuild,
@@ -61,6 +69,7 @@
 from lp.services.database.bulk import load_related
 from lp.services.database.constants import UTC_NOW
 from lp.services.database.decoratedresultset import DecoratedResultSet
+from lp.services.database.enumcol import DBEnum
 from lp.services.database.lpstorm import (
     IMasterStore,
     IStore,
@@ -140,6 +149,45 @@
     requester_id = Int(name='requester', allow_none=False)
     requester = Reference(requester_id, 'Person.id')
 
+    # Migrating from PackageBuild
+    _new_build_farm_job_id = Int(name='build_farm_job')
+    _new_build_farm_job = Reference(_new_build_farm_job_id, BuildFarmJob.id)
+
+    _new_archive_id = Int(name='archive')
+    _new_archive = Reference(_new_archive_id, 'Archive.id')
+
+    _new_pocket = DBEnum(name='pocket', enum=PackagePublishingPocket)
+
+    _new_upload_log_id = Int(name='upload_log')
+    _new_upload_log = Reference(_new_upload_log_id, 'LibraryFileAlias.id')
+
+    _new_dependencies = Unicode(name='dependencies')
+
+    # Migrating from BuildFarmJob.
+    _new_processor_id = Int(name='processor')
+    _new_processor = Reference(_new_processor_id, 'Processor.id')
+
+    _new_virtualized = Bool(name='virtualized')
+
+    _new_date_created = DateTime(name='date_created', tzinfo=pytz.UTC)
+
+    _new_date_started = DateTime(name='date_started', tzinfo=pytz.UTC)
+
+    _new_date_finished = DateTime(name='date_finished', tzinfo=pytz.UTC)
+
+    _new_date_first_dispatched = DateTime(
+        name='date_first_dispatched', tzinfo=pytz.UTC)
+
+    _new_builder_id = Int(name='builder')
+    _new_builder = Reference(_new_builder_id, 'Builder.id')
+
+    _new_status = DBEnum(name='status', enum=BuildStatus)
+
+    _new_log_id = Int(name='log')
+    _new_log = Reference(_new_log_id, 'LibraryFileAlias.id')
+
+    _new_failure_count = Int(name='failure_count')
+
     @property
     def buildqueue_record(self):
         """See `IBuildFarmJob`."""
@@ -164,13 +212,21 @@
             branch_name = self.recipe.base_branch.unique_name
             return '%s recipe build' % branch_name
 
-    def __init__(self, package_build, distroseries, recipe, requester):
+    def __init__(self, build_farm_job, package_build, distroseries, recipe,
+                 requester, archive, pocket, date_created):
         """Construct a SourcePackageRecipeBuild."""
         super(SourcePackageRecipeBuild, self).__init__()
+        self._new_build_farm_job = build_farm_job
         self.package_build = package_build
         self.distroseries = distroseries
         self.recipe = recipe
         self.requester = requester
+        self._new_archive = archive
+        self._new_pocket = pocket
+        self._new_status = BuildStatus.NEEDSBUILD
+        self._new_virtualized = True
+        if date_created is not None:
+            self._new_date_created = date_created
 
     @classmethod
     def new(cls, distroseries, recipe, requester, archive, pocket=None,
@@ -181,13 +237,14 @@
             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)
+        build_farm_job = getUtility(IBuildFarmJobSource).new(
+            cls.build_farm_job_type, BuildStatus.NEEDSBUILD, None, True,
+            date_created, None, archive)
+        packagebuild = getUtility(IPackageBuildSource).new(
+            build_farm_job, archive, pocket)
         spbuild = cls(
-            packagebuild,
-            distroseries,
-            recipe,
-            requester)
+            build_farm_job, packagebuild, distroseries, recipe, requester,
+            archive, pocket, date_created)
         store.add(spbuild)
         return spbuild
 
@@ -310,7 +367,7 @@
     def getRecentBuilds(cls, requester, recipe, distroseries, _now=None):
         from lp.buildmaster.model.buildfarmjob import BuildFarmJob
         if _now is None:
-            _now = datetime.now(utc)
+            _now = datetime.now(pytz.UTC)
         store = IMasterStore(SourcePackageRecipeBuild)
         old_threshold = _now - timedelta(days=1)
         return store.find(cls, cls.distroseries_id == distroseries.id,

=== modified file 'lib/lp/soyuz/model/binarypackagebuild.py'
--- lib/lp/soyuz/model/binarypackagebuild.py	2013-01-30 07:49:52 +0000
+++ lib/lp/soyuz/model/binarypackagebuild.py	2013-02-01 02:04:26 +0000
@@ -11,6 +11,7 @@
 import operator
 
 import apt_pkg
+import pytz
 from sqlobject import SQLObjectNotFound
 from storm.expr import (
     Desc,
@@ -19,8 +20,11 @@
     SQL,
     )
 from storm.locals import (
+    Bool,
+    DateTime,
     Int,
     Reference,
+    Unicode,
     )
 from storm.store import (
     EmptyResultSet,
@@ -38,6 +42,7 @@
     BuildFarmJobType,
     BuildStatus,
     )
+from lp.buildmaster.interfaces.buildfarmjob import IBuildFarmJobSource
 from lp.buildmaster.interfaces.packagebuild import IPackageBuildSource
 from lp.buildmaster.model.builder import Builder
 from lp.buildmaster.model.buildfarmjob import BuildFarmJob
@@ -46,9 +51,11 @@
     PackageBuild,
     PackageBuildMixin,
     )
+from lp.registry.interfaces.pocket import PackagePublishingPocket
 from lp.services.config import config
 from lp.services.database.bulk import load_related
 from lp.services.database.decoratedresultset import DecoratedResultSet
+from lp.services.database.enumcol import DBEnum
 from lp.services.database.interfaces import (
     DEFAULT_FLAVOR,
     IStoreSelector,
@@ -110,6 +117,57 @@
     source_package_release = Reference(
         source_package_release_id, 'SourcePackageRelease.id')
 
+    # Migrating from PackageBuild
+    _new_build_farm_job_id = Int(name='build_farm_job')
+    _new_build_farm_job = Reference(_new_build_farm_job_id, BuildFarmJob.id)
+
+    _new_archive_id = Int(name='archive')
+    _new_archive = Reference(_new_archive_id, 'Archive.id')
+
+    _new_pocket = DBEnum(name='pocket', enum=PackagePublishingPocket)
+
+    _new_upload_log_id = Int(name='upload_log')
+    _new_upload_log = Reference(_new_upload_log_id, 'LibraryFileAlias.id')
+
+    _new_dependencies = Unicode(name='dependencies')
+
+    # Migrating from BuildFarmJob.
+    _new_processor_id = Int(name='processor')
+    _new_processor = Reference(_new_processor_id, 'Processor.id')
+
+    _new_virtualized = Bool(name='virtualized')
+
+    _new_date_created = DateTime(name='date_created', tzinfo=pytz.UTC)
+
+    _new_date_started = DateTime(name='date_started', tzinfo=pytz.UTC)
+
+    _new_date_finished = DateTime(name='date_finished', tzinfo=pytz.UTC)
+
+    _new_date_first_dispatched = DateTime(
+        name='date_first_dispatched', tzinfo=pytz.UTC)
+
+    _new_builder_id = Int(name='builder')
+    _new_builder = Reference(_new_builder_id, 'Builder.id')
+
+    _new_status = DBEnum(name='status', enum=BuildStatus)
+
+    _new_log_id = Int(name='log')
+    _new_log = Reference(_new_log_id, 'LibraryFileAlias.id')
+
+    _new_failure_count = Int(name='failure_count')
+
+    _new_distribution_id = Int(name='distribution')
+    _new_distribution = Reference(_new_distribution_id, 'Distribution.id')
+
+    _new_distro_series_id = Int(name='distro_series')
+    _new_distro_series = Reference(_new_distro_series_id, 'DistroSeries.id')
+
+    _new_is_distro_archive = Bool(name='is_distro_archive')
+
+    _new_source_package_name_id = Int(name='source_package_name')
+    _new_source_package_name = Reference(
+        _new_source_package_name_id, 'SourcePackageName.id')
+
     @property
     def buildqueue_record(self):
         """See `IBuild`."""
@@ -357,13 +415,13 @@
     def retry(self):
         """See `IBuild`."""
         assert self.can_be_retried, "Build %s cannot be retried" % self.id
-        self.build_farm_job.status = BuildStatus.NEEDSBUILD
-        self.build_farm_job.date_finished = None
-        self.build_farm_job.date_started = None
-        self.build_farm_job.builder = None
-        self.build_farm_job.log = None
-        self.package_build.upload_log = None
-        self.package_build.dependencies = None
+        self.build_farm_job.status = self._new_status = BuildStatus.NEEDSBUILD
+        self.build_farm_job.date_finished = self._new_date_finished = None
+        self.build_farm_job.date_started = self._new_date_started = None
+        self.build_farm_job.builder = self._new_builder = None
+        self.build_farm_job.log = self._new_log = None
+        self.package_build.upload_log = self._new_upload_log = None
+        self.package_build.dependencies = self._new_upload_log = None
         self.queueBuild()
 
     def rescore(self, score):
@@ -513,7 +571,8 @@
             if not self._isDependencySatisfied(token)]
 
         # Update dependencies line
-        self.package_build.dependencies = u", ".join(remaining_deps)
+        self.package_build.dependencies = self._new_dependencies = (
+            u", ".join(remaining_deps))
 
     def __getitem__(self, name):
         return self.getBinaryPackageRelease(name)
@@ -814,15 +873,26 @@
         """See `IBinaryPackageBuildSet`."""
         # Create the PackageBuild to which the new BinaryPackageBuild
         # will delegate.
+        build_farm_job = getUtility(IBuildFarmJobSource).new(
+            BinaryPackageBuild.build_farm_job_type, status, processor,
+            archive.require_virtualized, date_created, builder, archive)
         package_build = getUtility(IPackageBuildSource).new(
-            BinaryPackageBuild.build_farm_job_type,
-            archive.require_virtualized, archive, pocket, processor,
-            status, date_created=date_created, builder=builder)
+            build_farm_job, archive, pocket)
 
         binary_package_build = BinaryPackageBuild(
+            _new_build_farm_job=build_farm_job,
             package_build=package_build,
             distro_arch_series=distro_arch_series,
-            source_package_release=source_package_release)
+            source_package_release=source_package_release,
+            _new_archive=archive, _new_pocket=pocket,
+            _new_status=status, _new_processor=processor,
+            _new_virtualized=archive.require_virtualized,
+            _new_builder=builder, _new_is_distro_archive=archive.is_main,
+            _new_distribution=distro_arch_series.distroseries.distribution,
+            _new_distro_series=distro_arch_series.distroseries,
+            _new_source_package_name=source_package_release.sourcepackagename)
+        if date_created is not None:
+            binary_package_build._new_date_created = date_created
         return binary_package_build
 
     def getBuildBySRAndArchtag(self, sourcepackagereleaseID, archtag):

=== modified file 'lib/lp/soyuz/tests/test_binarypackagebuild.py'
--- lib/lp/soyuz/tests/test_binarypackagebuild.py	2013-01-24 01:09:04 +0000
+++ lib/lp/soyuz/tests/test_binarypackagebuild.py	2013-02-01 02:04:26 +0000
@@ -10,6 +10,7 @@
 
 import pytz
 from storm.store import Store
+from testtools.matchers import MatchesStructure
 from zope.component import getUtility
 from zope.security.proxy import removeSecurityProxy
 
@@ -62,6 +63,25 @@
         self.assertProvides(self.build, IPackageBuild)
         self.assertProvides(self.build, IBinaryPackageBuild)
 
+    def test_denormed_attributes(self):
+        primary_build = self.factory.makeBinaryPackageBuild(
+            archive=self.factory.makeArchive(purpose=ArchivePurpose.PRIMARY))
+        partner_build = self.factory.makeBinaryPackageBuild(
+            archive=self.factory.makeArchive(purpose=ArchivePurpose.PARTNER))
+        ppa_build = self.factory.makeBinaryPackageBuild(
+            archive=self.factory.makeArchive(purpose=ArchivePurpose.PPA))
+        scenarios = [
+            (primary_build, True), (partner_build, True), (ppa_build, False)]
+        for build, is_distro_archive in scenarios:
+            self.assertThat(
+                removeSecurityProxy(build),
+                MatchesStructure.byEquality(
+                    _new_is_distro_archive=is_distro_archive,
+                    _new_distro_series=build.distro_arch_series.distroseries,
+                    _new_distribution=build.distro_series.distribution,
+                    _new_source_package_name=
+                        build.source_package_release.sourcepackagename))
+
     def test_queueBuild(self):
         # BinaryPackageBuild can create the queue entry for itself.
         bq = self.build.queueBuild()

=== modified file 'lib/lp/soyuz/tests/test_hasbuildrecords.py'
--- lib/lp/soyuz/tests/test_hasbuildrecords.py	2013-01-24 06:05:26 +0000
+++ lib/lp/soyuz/tests/test_hasbuildrecords.py	2013-02-01 02:04:26 +0000
@@ -10,7 +10,10 @@
     BuildFarmJobType,
     BuildStatus,
     )
-from lp.buildmaster.interfaces.buildfarmjob import IBuildFarmJob
+from lp.buildmaster.interfaces.buildfarmjob import (
+    IBuildFarmJob,
+    IBuildFarmJobSource,
+    )
 from lp.buildmaster.interfaces.packagebuild import IPackageBuildSource
 from lp.registry.interfaces.person import IPersonSet
 from lp.registry.interfaces.pocket import PackagePublishingPocket
@@ -178,9 +181,10 @@
         # Until we have different IBuildFarmJob types implemented, we
         # can only test this by creating a lone PackageBuild of a
         # different type.
+        bfj = getUtility(IBuildFarmJobSource).new(
+            BuildFarmJobType.RECIPEBRANCHBUILD, virtualized=True)
         getUtility(IPackageBuildSource).new(
-            job_type=BuildFarmJobType.RECIPEBRANCHBUILD, virtualized=True,
-            archive=self.context, pocket=PackagePublishingPocket.RELEASE)
+            bfj, archive=self.context, pocket=PackagePublishingPocket.RELEASE)
 
         builds = self.context.getBuildRecords(binary_only=True)
         self.failUnlessEqual(3, builds.count())

=== modified file 'lib/lp/translations/model/translationtemplatesbuild.py'
--- lib/lp/translations/model/translationtemplatesbuild.py	2013-01-30 07:49:52 +0000
+++ lib/lp/translations/model/translationtemplatesbuild.py	2013-02-01 02:04:26 +0000
@@ -8,7 +8,10 @@
     'TranslationTemplatesBuild',
     ]
 
+import pytz
 from storm.locals import (
+    Bool,
+    DateTime,
     Int,
     Reference,
     Storm,
@@ -20,7 +23,10 @@
     )
 
 from lp.app.interfaces.launchpad import ILaunchpadCelebrities
-from lp.buildmaster.enums import BuildFarmJobType
+from lp.buildmaster.enums import (
+    BuildFarmJobType,
+    BuildStatus,
+    )
 from lp.buildmaster.interfaces.buildfarmjob import IBuildFarmJobSource
 from lp.buildmaster.model.buildfarmjob import BuildFarmJobMixin
 from lp.code.model.branch import Branch
@@ -32,6 +38,7 @@
 from lp.registry.model.product import Product
 from lp.services.database.bulk import load_related
 from lp.services.database.decoratedresultset import DecoratedResultSet
+from lp.services.database.enumcol import DBEnum
 from lp.services.database.lpstorm import IStore
 from lp.translations.interfaces.translationtemplatesbuild import (
     ITranslationTemplatesBuild,
@@ -56,15 +63,42 @@
     branch_id = Int(name='branch', allow_none=False)
     branch = Reference(branch_id, 'Branch.id')
 
+    # Migrating from BuildFarmJob.
+    _new_processor_id = Int(name='processor')
+    _new_processor = Reference(_new_processor_id, 'Processor.id')
+
+    _new_virtualized = Bool(name='virtualized')
+
+    _new_date_created = DateTime(name='date_created', tzinfo=pytz.UTC)
+
+    _new_date_started = DateTime(name='date_started', tzinfo=pytz.UTC)
+
+    _new_date_finished = DateTime(name='date_finished', tzinfo=pytz.UTC)
+
+    _new_date_first_dispatched = DateTime(
+        name='date_first_dispatched', tzinfo=pytz.UTC)
+
+    _new_builder_id = Int(name='builder')
+    _new_builder = Reference(_new_builder_id, 'Builder.id')
+
+    _new_status = DBEnum(name='status', enum=BuildStatus)
+
+    _new_log_id = Int(name='log')
+    _new_log = Reference(_new_log_id, 'LibraryFileAlias.id')
+
+    _new_failure_count = Int(name='failure_count')
+
     @property
     def title(self):
         return u'Translation template build for %s' % (
             self.branch.displayname)
 
-    def __init__(self, build_farm_job, branch):
+    def __init__(self, build_farm_job, branch, processor):
         super(TranslationTemplatesBuild, self).__init__()
         self.build_farm_job = build_farm_job
         self.branch = branch
+        self._new_status = BuildStatus.NEEDSBUILD
+        self._new_processor = processor
 
     def makeJob(self):
         """See `IBuildFarmJobOld`."""
@@ -100,10 +134,10 @@
     @classmethod
     def create(cls, branch):
         """See `ITranslationTemplatesBuildSource`."""
+        processor = cls._getBuildArch()
         build_farm_job = getUtility(IBuildFarmJobSource).new(
-            BuildFarmJobType.TRANSLATIONTEMPLATESBUILD,
-            processor=cls._getBuildArch())
-        build = TranslationTemplatesBuild(build_farm_job, branch)
+            BuildFarmJobType.TRANSLATIONTEMPLATESBUILD, processor=processor)
+        build = TranslationTemplatesBuild(build_farm_job, branch, processor)
         store = cls._getStore()
         store.add(build)
         store.flush()