← Back to team overview

launchpad-reviewers team mailing list archive

[Merge] lp:~wgrant/launchpad/specificbuildfarmjobsource into lp:launchpad

 

William Grant has proposed merging lp:~wgrant/launchpad/specificbuildfarmjobsource into lp:launchpad.

Requested reviews:
  Launchpad code reviewers (launchpad-reviewers)

For more details, see:
https://code.launchpad.net/~wgrant/launchpad/specificbuildfarmjobsource/+merge/59881

With the impending demise of BuildFarmJob as a concrete table and class, we need some way to get specific jobs other than taking a BuildFarmJob ID and using BuildFarmJob.getSpecificJob().

This branch introduces ISpecificBuildFarmJobSource, a marker interface for such utilities, similar in design to the existing ISpecificBuildFarmJob adapter: each BuildFarmJobType has a ISBFJS registered with its name, which gets the concrete object given an ID or a BuildFarmJob. The existing ISBFJ adapters have been removed, and callsites fixed to use the ISBFJS utilities instead.

Further branches will remove getByBuildFarmJob as BuildFarmJob fades into abstraction, but getByID remains a key part of the new strategy for identifying BuildFarmJobs. Callsites such as BuildUploadHandler._getBuild will use (BuildFarmJobType, $BUILDCLASS.id) as an identifier instead of a BuildFarmJob.id.
-- 
https://code.launchpad.net/~wgrant/launchpad/specificbuildfarmjobsource/+merge/59881
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~wgrant/launchpad/specificbuildfarmjobsource into lp:launchpad.
=== modified file 'lib/lp/buildmaster/interfaces/buildfarmjob.py'
--- lib/lp/buildmaster/interfaces/buildfarmjob.py	2011-03-22 16:04:10 +0000
+++ lib/lp/buildmaster/interfaces/buildfarmjob.py	2011-05-04 07:10:58 +0000
@@ -13,7 +13,7 @@
     'IBuildFarmJobSet',
     'IBuildFarmJobSource',
     'InconsistentBuildFarmJobError',
-    'ISpecificBuildFarmJob',
+    'ISpecificBuildFarmJobSource',
     ]
 
 from lazr.enum import (
@@ -276,13 +276,25 @@
         as_of="beta")
 
 
-class ISpecificBuildFarmJob(IBuildFarmJob):
-    """A marker interface with which to define adapters for IBuildFarmJob.
+class ISpecificBuildFarmJobSource(Interface):
+    """A utility for retrieving objects of a specific IBuildFarmJob type.
 
-    This enables the registered adapters for ISpecificBuildFarmJob to be
-    iterated when calculating IBuildFarmJob.specific_job.
+    Implementations are registered with their BuildFarmJobType's name.
     """
 
+    def getByID(id):
+        """Look up a concrete `IBuildFarmJob` by ID.
+
+        :param id: An ID of the concrete job class to look up.
+        """
+
+    def getByBuildFarmJob(build_farm_job):
+        """"Look up the concrete `IBuildFarmJob` for a BuildFarmJob.
+
+        :param build_farm_job: A BuildFarmJob for which to get the concrete
+            job.
+        """
+
 
 class IBuildFarmJobSource(Interface):
     """A utility of BuildFarmJob used to create _things_."""

=== modified file 'lib/lp/buildmaster/model/buildfarmjob.py'
--- lib/lp/buildmaster/model/buildfarmjob.py	2011-02-10 17:24:25 +0000
+++ lib/lp/buildmaster/model/buildfarmjob.py	2011-05-04 07:10:58 +0000
@@ -63,7 +63,7 @@
     IBuildFarmJobSet,
     IBuildFarmJobSource,
     InconsistentBuildFarmJobError,
-    ISpecificBuildFarmJob,
+    ISpecificBuildFarmJobSource,
     )
 from lp.buildmaster.interfaces.buildqueue import IBuildQueueSet
 from lp.registry.model.teammembership import TeamParticipation
@@ -351,29 +351,26 @@
         """See `IBuild`"""
         # Adapt ourselves based on our job type.
         try:
-            build = getAdapter(
-                self, ISpecificBuildFarmJob, self.job_type.name)
+            source = getUtility(
+                ISpecificBuildFarmJobSource, self.job_type.name)
         except ComponentLookupError:
             raise InconsistentBuildFarmJobError(
-                "No adapter was found for the build farm job type %s." % (
+                "No source was found for the build farm job type %s." % (
                     self.job_type.name))
 
-        # Since the adapters of to ISpecificBuildFarmJob proxy their
-        # results manually, we don't want the second proxy added by
-        # getAdapter above.
-        build_without_outer_proxy = removeSecurityProxy(build)
+        build = source.getByBuildFarmJob(self)
 
-        if build_without_outer_proxy is None:
+        if build is None:
             raise InconsistentBuildFarmJobError(
                 "There is no related specific job for the build farm "
                 "job with id %d." % self.id)
 
         # Just to be on the safe side, make sure the build is still
         # proxied before returning it.
-        assert isProxy(build_without_outer_proxy), (
-            "Unproxied result returned from ISpecificBuildFarmJob adapter.")
+        assert isProxy(build), (
+            "Unproxied result returned from ISpecificBuildFarmJobSource.")
 
-        return build_without_outer_proxy
+        return build
 
     def gotFailure(self):
         """See `IBuildFarmJob`."""

=== modified file 'lib/lp/code/browser/branch.py'
--- lib/lp/code/browser/branch.py	2011-04-27 01:42:46 +0000
+++ lib/lp/code/browser/branch.py	2011-05-04 07:10:58 +0000
@@ -114,6 +114,7 @@
 from lp.bugs.interfaces.bug import IBugSet
 from lp.bugs.interfaces.bugbranch import IBugBranch
 from lp.bugs.interfaces.bugtask import UNRESOLVED_BUGTASK_STATUSES
+from lp.buildmaster.interfaces.buildfarmjob import IBuildFarmJobSet
 from lp.code.browser.branchmergeproposal import (
     latest_proposals_for_each_branch,
     )
@@ -255,7 +256,9 @@
         except ValueError:
             raise NotFoundError(id_string)
         source = getUtility(ITranslationTemplatesBuildSource)
-        return source.getByBuildFarmJob(buildfarmjob_id)
+        buildfarmjob = getUtility(IBuildFarmJobSet).getByID(
+            buildfarmjob_id)
+        return source.getByBuildFarmJob(buildfarmjob)
 
 
 class BranchEditMenu(NavigationMenu):

=== modified file 'lib/lp/code/configure.zcml'
--- lib/lp/code/configure.zcml	2011-03-23 16:28:51 +0000
+++ lib/lp/code/configure.zcml	2011-05-04 07:10:58 +0000
@@ -933,6 +933,13 @@
     <allow interface="lp.code.interfaces.sourcepackagerecipebuild.ISourcePackageRecipeBuildSource"/>
   </securedutility>
 
+  <securedutility
+     component="lp.code.model.sourcepackagerecipebuild.SourcePackageRecipeBuild"
+     provides="lp.buildmaster.interfaces.buildfarmjob.ISpecificBuildFarmJobSource"
+     name="RECIPEBRANCHBUILD">
+    <allow interface="lp.buildmaster.interfaces.buildfarmjob.ISpecificBuildFarmJobSource"/>
+  </securedutility>
+
   <class
      class="lp.code.model.sourcepackagerecipebuild.SourcePackageRecipeBuildJob">
     <require permission="launchpad.View" interface="lp.code.interfaces.sourcepackagerecipebuild.ISourcePackageRecipeBuildJob"/>
@@ -994,12 +1001,6 @@
         provides="lp.buildmaster.interfaces.buildfarmjob.IBuildFarmJob"/>
 
   <webservice:register module="lp.code.interfaces.webservice" />
-    <adapter
-        provides="lp.buildmaster.interfaces.buildfarmjob.ISpecificBuildFarmJob"
-        for="lp.buildmaster.interfaces.buildfarmjob.IBuildFarmJob"
-        factory="lp.code.model.sourcepackagerecipebuild.get_recipe_build_for_build_farm_job"
-        name="RECIPEBRANCHBUILD"
-        permission="zope.Public"/>
 
   <adapter
     factory="lp.code.browser.sourcepackagerecipe.distroseries_renderer"

=== modified file 'lib/lp/code/interfaces/sourcepackagerecipebuild.py'
--- lib/lp/code/interfaces/sourcepackagerecipebuild.py	2011-02-16 13:28:59 +0000
+++ lib/lp/code/interfaces/sourcepackagerecipebuild.py	2011-05-04 07:10:58 +0000
@@ -26,6 +26,7 @@
     )
 
 from canonical.launchpad import _
+from lp.buildmaster.interfaces.buildfarmjob import ISpecificBuildFarmJobSource
 from lp.buildmaster.interfaces.packagebuild import IPackageBuild
 from lp.code.interfaces.sourcepackagerecipe import (
     ISourcePackageRecipe,
@@ -83,7 +84,7 @@
         """Delete the build itself."""
 
 
-class ISourcePackageRecipeBuildSource(Interface):
+class ISourcePackageRecipeBuildSource(ISpecificBuildFarmJobSource):
     """A utility of this interface be used to create source package builds."""
 
     def new(distroseries, recipe, requester, archive, date_created=None):
@@ -104,13 +105,6 @@
         :param logger: An optional logger to write debug info to.
         """
 
-    def getById(build_id):
-        """Return the `ISourcePackageRecipeBuild` for the given build id.
-
-        :param build_id: The id of the build to return.
-        :return: `ISourcePackageRecipeBuild`
-        """
-
 
 class ISourcePackageRecipeBuildJob(IBuildFarmBuildJob):
     """A read-only interface for recipe build jobs."""

=== modified file 'lib/lp/code/model/sourcepackagerecipebuild.py'
--- lib/lp/code/model/sourcepackagerecipebuild.py	2011-04-13 02:08:31 +0000
+++ lib/lp/code/model/sourcepackagerecipebuild.py	2011-05-04 07:10:58 +0000
@@ -32,7 +32,6 @@
     classProvides,
     implements,
     )
-from zope.security.proxy import ProxyFactory
 
 from canonical.database.constants import UTC_NOW
 from canonical.launchpad.browser.librarian import ProxiedLibraryFileAlias
@@ -260,12 +259,19 @@
         package_build.destroySelf()
 
     @classmethod
-    def getById(cls, build_id):
+    def getByID(cls, build_id):
         """See `ISourcePackageRecipeBuildSource`."""
         store = IMasterStore(SourcePackageRecipeBuild)
         return store.find(cls, cls.id == build_id).one()
 
     @classmethod
+    def getByBuildFarmJob(cls, build_farm_job):
+        """See `ISpecificBuildFarmJobSource`."""
+        return Store.of(build_farm_job).find(cls,
+            cls.package_build_id == PackageBuild.id,
+            PackageBuild.build_farm_job_id == build_farm_job.id).one()
+
+    @classmethod
     def getRecentBuilds(cls, requester, recipe, distroseries, _now=None):
         from lp.buildmaster.model.buildfarmjob import BuildFarmJob
         if _now is None:
@@ -404,12 +410,3 @@
 
     def score(self):
         return 2505 + self.build.archive.relative_build_score
-
-
-def get_recipe_build_for_build_farm_job(build_farm_job):
-    """Return the SourcePackageRecipeBuild associated with a BuildFarmJob."""
-    store = Store.of(build_farm_job)
-    result = store.find(SourcePackageRecipeBuild,
-        SourcePackageRecipeBuild.package_build_id == PackageBuild.id,
-        PackageBuild.build_farm_job_id == build_farm_job.id)
-    return ProxyFactory(result.one())

=== modified file 'lib/lp/code/model/tests/test_recipebuilder.py'
--- lib/lp/code/model/tests/test_recipebuilder.py	2011-03-16 16:53:48 +0000
+++ lib/lp/code/model/tests/test_recipebuilder.py	2011-05-04 07:10:58 +0000
@@ -253,11 +253,11 @@
             job.build, distroarchseries, None)
         self.assertEqual(args["archives"], expected_archives)
 
-    def test_getById(self):
+    def test_getByID(self):
         job = self.makeJob()
         transaction.commit()
         self.assertEquals(
-            job.build, SourcePackageRecipeBuild.getById(job.build.id))
+            job.build, SourcePackageRecipeBuild.getByID(job.build.id))
 
     @run_test_with(AsynchronousDeferredRunTest)
     def test_dispatchBuildToSlave(self):

=== modified file 'lib/lp/soyuz/browser/build.py'
--- lib/lp/soyuz/browser/build.py	2011-05-03 03:08:21 +0000
+++ lib/lp/soyuz/browser/build.py	2011-05-04 07:10:58 +0000
@@ -109,7 +109,7 @@
         except ValueError:
             return None
         try:
-            return getUtility(IBinaryPackageBuildSet).getByBuildID(build_id)
+            return getUtility(IBinaryPackageBuildSet).getByID(build_id)
         except NotFoundError:
             return None
 
@@ -120,7 +120,7 @@
         except ValueError:
             return None
         try:
-            return getUtility(ISourcePackageRecipeBuildSource).getById(
+            return getUtility(ISourcePackageRecipeBuildSource).getByID(
                 build_id)
         except NotFoundError:
             return None

=== modified file 'lib/lp/soyuz/configure.zcml'
--- lib/lp/soyuz/configure.zcml	2011-04-20 12:49:31 +0000
+++ lib/lp/soyuz/configure.zcml	2011-05-04 07:10:58 +0000
@@ -518,12 +518,6 @@
         for="lp.soyuz.interfaces.binarypackagebuild.IBinaryPackageBuild"
         factory="lp.soyuz.browser.build.BuildBreadcrumb"
         permission="zope.Public"/>
-    <adapter
-        provides="lp.buildmaster.interfaces.buildfarmjob.ISpecificBuildFarmJob"
-        for="lp.buildmaster.interfaces.buildfarmjob.IBuildFarmJob"
-        factory="lp.soyuz.model.binarypackagebuild.get_binary_build_for_build_farm_job"
-        name="PACKAGEBUILD"
-        permission="zope.Public"/>
 
     <!-- BinaryPackageBuildSet -->
 
@@ -533,6 +527,12 @@
         <allow
             interface="lp.soyuz.interfaces.binarypackagebuild.IBinaryPackageBuildSet"/>
     </securedutility>
+    <securedutility
+        class="lp.soyuz.model.binarypackagebuild.BinaryPackageBuildSet"
+        provides="lp.buildmaster.interfaces.buildfarmjob.ISpecificBuildFarmJobSource"
+        name="PACKAGEBUILD">
+        <allow interface="lp.buildmaster.interfaces.buildfarmjob.ISpecificBuildFarmJobSource"/>
+    </securedutility>
 
     <!-- DistroArchSeriesBinaryPackage -->
 

=== modified file 'lib/lp/soyuz/doc/build-failedtoupload-workflow.txt'
--- lib/lp/soyuz/doc/build-failedtoupload-workflow.txt	2011-05-03 02:39:30 +0000
+++ lib/lp/soyuz/doc/build-failedtoupload-workflow.txt	2011-05-04 07:10:58 +0000
@@ -23,7 +23,7 @@
 
 Let's use a sampledata build record in FAILEDTOUPLOAD:
 
-  >>> failedtoupload_candidate = buildset.getByBuildID(22)
+  >>> failedtoupload_candidate = buildset.getByID(22)
 
   >>> print failedtoupload_candidate.title
   i386 build of cdrkit 1.0 in ubuntu breezy-autotest RELEASE

=== modified file 'lib/lp/soyuz/doc/buildd-mass-retry.txt'
--- lib/lp/soyuz/doc/buildd-mass-retry.txt	2010-08-24 15:29:01 +0000
+++ lib/lp/soyuz/doc/buildd-mass-retry.txt	2011-05-04 07:10:58 +0000
@@ -54,7 +54,7 @@
   >>> from lp.soyuz.interfaces.binarypackagebuild import (
   ...     IBinaryPackageBuildSet)
   >>> from lp.soyuz.enums import PackagePublishingStatus
-  >>> build = getUtility(IBinaryPackageBuildSet).getByBuildID(12)
+  >>> build = getUtility(IBinaryPackageBuildSet).getByID(12)
   >>> pub = removeSecurityProxy(build.current_source_publication)
 
 Let's mark the build from the previous run superseded.

=== modified file 'lib/lp/soyuz/interfaces/binarypackagebuild.py'
--- lib/lp/soyuz/interfaces/binarypackagebuild.py	2011-03-14 02:21:28 +0000
+++ lib/lp/soyuz/interfaces/binarypackagebuild.py	2011-05-04 07:10:58 +0000
@@ -41,6 +41,7 @@
 
 from canonical.launchpad import _
 from lp.buildmaster.enums import BuildStatus
+from lp.buildmaster.interfaces.buildfarmjob import ISpecificBuildFarmJobSource
 from lp.buildmaster.interfaces.packagebuild import IPackageBuild
 from lp.soyuz.interfaces.processor import IProcessor
 from lp.soyuz.interfaces.publishing import ISourcePackagePublishingHistory
@@ -268,7 +269,7 @@
                     description="There are some builds currently building.")
 
 
-class IBinaryPackageBuildSet(Interface):
+class IBinaryPackageBuildSet(ISpecificBuildFarmJobSource):
     """Interface for BinaryPackageBuildSet"""
 
     def new(distro_arch_series, source_package_release, processor,
@@ -289,13 +290,6 @@
     def getBuildBySRAndArchtag(sourcepackagereleaseID, archtag):
         """Return a build for a SourcePackageRelease and an ArchTag"""
 
-    def getByBuildID(id):
-        """Return the exact build specified.
-
-        id is the numeric ID of the build record in the database.
-        I.E. getUtility(IBuildSet).getByBuildID(foo).id == foo
-        """
-
     def getPendingBuildsForArchSet(archseries):
         """Return all pending build records within a group of ArchSeries
 

=== modified file 'lib/lp/soyuz/model/binarypackagebuild.py'
--- lib/lp/soyuz/model/binarypackagebuild.py	2011-03-14 02:21:28 +0000
+++ lib/lp/soyuz/model/binarypackagebuild.py	2011-05-04 07:10:58 +0000
@@ -31,10 +31,7 @@
     )
 from zope.component import getUtility
 from zope.interface import implements
-from zope.security.proxy import (
-    ProxyFactory,
-    removeSecurityProxy,
-    )
+from zope.security.proxy import removeSecurityProxy
 
 from canonical.config import config
 from canonical.database.sqlbase import (
@@ -106,24 +103,6 @@
     )
 
 
-def get_binary_build_for_build_farm_job(build_farm_job):
-    """Factory method to returning a binary for a build farm job."""
-    store = getUtility(IStoreSelector).get(MAIN_STORE, DEFAULT_FLAVOR)
-    find_spec = (BinaryPackageBuild, PackageBuild, BuildFarmJob)
-    resulting_tuple = store.find(
-        find_spec,
-        BinaryPackageBuild.package_build == PackageBuild.id,
-        PackageBuild.build_farm_job == BuildFarmJob.id,
-        BuildFarmJob.id == build_farm_job.id).one()
-
-    if resulting_tuple is None:
-        return None
-
-    # We specifically return a proxied BinaryPackageBuild so that we can
-    # be sure it has the correct proxy.
-    return ProxyFactory(resulting_tuple[0])
-
-
 class BinaryPackageBuild(PackageBuildDerived, SQLBase):
     implements(IBinaryPackageBuild)
     _table = 'BinaryPackageBuild'
@@ -838,13 +817,25 @@
 
         return BinaryPackageBuild.select(query, clauseTables=clauseTables)
 
-    def getByBuildID(self, id):
+    def getByID(self, id):
         """See `IBinaryPackageBuildSet`."""
         try:
             return BinaryPackageBuild.get(id)
         except SQLObjectNotFound, e:
             raise NotFoundError(str(e))
 
+    def getByBuildFarmJob(self, build_farm_job):
+        """See `ISpecificBuildFarmJobSource`."""
+        find_spec = (BinaryPackageBuild, PackageBuild, BuildFarmJob)
+        resulting_tuple = Store.of(build_farm_job).find(
+            find_spec,
+            BinaryPackageBuild.package_build == PackageBuild.id,
+            PackageBuild.build_farm_job == BuildFarmJob.id,
+            BuildFarmJob.id == build_farm_job.id).one()
+        if resulting_tuple is None:
+            return None
+        return resulting_tuple[0]
+
     def getPendingBuildsForArchSet(self, archseries):
         """See `IBinaryPackageBuildSet`."""
         if not archseries:

=== modified file 'lib/lp/soyuz/stories/soyuz/xx-binarypackagerelease-index.txt'
--- lib/lp/soyuz/stories/soyuz/xx-binarypackagerelease-index.txt	2011-05-03 02:39:30 +0000
+++ lib/lp/soyuz/stories/soyuz/xx-binarypackagerelease-index.txt	2011-05-04 07:10:58 +0000
@@ -28,7 +28,7 @@
   >>> from zope.component import getUtility
 
   >>> login('foo.bar@xxxxxxxxxxxxx')
-  >>> build = getUtility(IBinaryPackageBuildSet).getByBuildID(2)
+  >>> build = getUtility(IBinaryPackageBuildSet).getByID(2)
   >>> package_upload = build.distro_series.createQueueEntry(
   ...     PackagePublishingPocket.UPDATES, 'changes.txt', 'my changes',
   ...     build.archive)

=== modified file 'lib/lp/soyuz/stories/webservice/xx-builds.txt'
--- lib/lp/soyuz/stories/webservice/xx-builds.txt	2011-05-03 02:39:30 +0000
+++ lib/lp/soyuz/stories/webservice/xx-builds.txt	2011-05-04 07:10:58 +0000
@@ -97,7 +97,7 @@
     >>> from lp.soyuz.interfaces.binarypackagebuild import (
     ...     IBinaryPackageBuildSet)
 
-    >>> build = getUtility(IBinaryPackageBuildSet).getByBuildID(26)
+    >>> build = getUtility(IBinaryPackageBuildSet).getByID(26)
     >>> build.upload_log = build.log
     >>> ws_uncache(build)
 

=== modified file 'lib/lp/soyuz/tests/test_binarypackagebuild.py'
--- lib/lp/soyuz/tests/test_binarypackagebuild.py	2011-05-03 02:39:30 +0000
+++ lib/lp/soyuz/tests/test_binarypackagebuild.py	2011-05-04 07:10:58 +0000
@@ -137,7 +137,7 @@
         # they would normally be queries.
         store = Store.of(build_farm_job)
         store.flush()
-        store.reset()
+        store.invalidate()
 
         binary_package_build = build_farm_job.getSpecificJob()
 
@@ -348,6 +348,25 @@
         self.sources.append(gtg_src_hist)
 
 
+class TestBuildSet(TestCaseWithFactory):
+
+    layer = LaunchpadZopelessLayer
+
+    def test_getByBuildFarmJob_works(self):
+        bpb = self.factory.makeBinaryPackageBuild()
+        self.assertEqual(
+            bpb,
+            getUtility(IBinaryPackageBuildSet).getByBuildFarmJob(
+                bpb.build_farm_job))
+
+    def test_getByBuildFarmJob_returns_none_when_missing(self):
+        sprb = self.factory.makeSourcePackageRecipeBuild()
+        self.assertIs(
+            None,
+            getUtility(IBinaryPackageBuildSet).getByBuildFarmJob(
+                sprb.build_farm_job))
+
+
 class TestBuildSetGetBuildsForArchive(BaseTestCaseWithThreeBuilds):
 
     def setUp(self):

=== modified file 'lib/lp/translations/configure.zcml'
--- lib/lp/translations/configure.zcml	2011-02-25 20:14:31 +0000
+++ lib/lp/translations/configure.zcml	2011-05-04 07:10:58 +0000
@@ -647,12 +647,6 @@
         component="lp.translations.model.translationtemplatesbuildjob.TranslationTemplatesBuildJob"
         provides="lp.buildmaster.interfaces.buildfarmjob.IBuildFarmJob"
         name="TRANSLATIONTEMPLATESBUILD"/>
-    <adapter
-        provides="lp.buildmaster.interfaces.buildfarmjob.ISpecificBuildFarmJob"
-        for="lp.buildmaster.interfaces.buildfarmjob.IBuildFarmJob"
-        factory="lp.translations.model.translationtemplatesbuild.get_translation_templates_build_for_build_farm_job"
-        name="TRANSLATIONTEMPLATESBUILD"
-        permission="zope.Public"/>
 
     <!-- TranslationTemplatesBuild -->
     <class
@@ -664,6 +658,12 @@
         provides="lp.translations.interfaces.translationtemplatesbuild.ITranslationTemplatesBuildSource">
         <allow interface="lp.translations.interfaces.translationtemplatesbuild.ITranslationTemplatesBuildSource"/>
     </securedutility>
+    <securedutility
+        component="lp.translations.model.translationtemplatesbuild.TranslationTemplatesBuild"
+        provides="lp.buildmaster.interfaces.buildfarmjob.ISpecificBuildFarmJobSource"
+        name="TRANSLATIONTEMPLATESBUILD">
+        <allow interface="lp.buildmaster.interfaces.buildfarmjob.ISpecificBuildFarmJobSource"/>
+    </securedutility>
 
     <!-- TranslationTemplateBuildBehavior -->
     <class

=== modified file 'lib/lp/translations/interfaces/translationtemplatesbuild.py'
--- lib/lp/translations/interfaces/translationtemplatesbuild.py	2010-09-10 11:27:48 +0000
+++ lib/lp/translations/interfaces/translationtemplatesbuild.py	2011-05-04 07:10:58 +0000
@@ -13,7 +13,10 @@
 from zope.interface import Interface
 
 from canonical.launchpad import _
-from lp.buildmaster.interfaces.buildfarmjob import IBuildFarmJob
+from lp.buildmaster.interfaces.buildfarmjob import (
+    IBuildFarmJob,
+    ISpecificBuildFarmJobSource,
+    )
 from lp.code.interfaces.branch import IBranch
 
 
@@ -29,7 +32,7 @@
         required=True, readonly=True, schema=IBranch)
 
 
-class ITranslationTemplatesBuildSource(Interface):
+class ITranslationTemplatesBuildSource(ISpecificBuildFarmJobSource):
     """Utility for `ITranslationTemplatesBuild`."""
 
     def create(build_farm_job, branch):
@@ -37,13 +40,3 @@
 
     def findByBranch(branch, store=None):
         """Find `ITranslationTemplatesBuild`s for `branch`."""
-
-    def get(build_id, store=None):
-        """Find `ITranslationTemplatesBuild`s by id.
-
-        :param build_id: Numerical id to look for.
-        :param store: Optional database store to look in.
-        """
-
-    def getByBuildFarmJob(buildfarmjob_id, store=None):
-        """Find `ITranslationTemplatesBuild`s by `BuildFarmJob` id."""

=== modified file 'lib/lp/translations/model/translationtemplatesbuild.py'
--- lib/lp/translations/model/translationtemplatesbuild.py	2010-12-17 12:13:54 +0000
+++ lib/lp/translations/model/translationtemplatesbuild.py	2011-05-04 07:10:58 +0000
@@ -86,7 +86,7 @@
         return build
 
     @classmethod
-    def get(cls, build_id, store=None):
+    def getByID(cls, build_id, store=None):
         """See `ITranslationTemplatesBuildSource`."""
         store = cls._getStore(store)
         match = store.find(
@@ -95,12 +95,12 @@
         return match.one()
 
     @classmethod
-    def getByBuildFarmJob(cls, buildfarmjob_id, store=None):
+    def getByBuildFarmJob(cls, buildfarmjob, store=None):
         """See `ITranslationTemplatesBuildSource`."""
         store = cls._getStore(store)
         match = store.find(
             TranslationTemplatesBuild,
-            TranslationTemplatesBuild.build_farm_job == buildfarmjob_id)
+            TranslationTemplatesBuild.build_farm_job_id == buildfarmjob.id)
         return match.one()
 
     @classmethod
@@ -110,11 +110,3 @@
         return store.find(
             TranslationTemplatesBuild,
             TranslationTemplatesBuild.branch == branch)
-
-
-def get_translation_templates_build_for_build_farm_job(build_farm_job):
-    """Return a `TranslationTemplatesBuild` from its `BuildFarmJob`."""
-    build = Store.of(build_farm_job).find(
-        TranslationTemplatesBuild,
-        TranslationTemplatesBuild.build_farm_job == build_farm_job).one()
-    return ProxyFactory(build)

=== modified file 'lib/lp/translations/model/translationtemplatesbuildjob.py'
--- lib/lp/translations/model/translationtemplatesbuildjob.py	2010-12-17 12:13:54 +0000
+++ lib/lp/translations/model/translationtemplatesbuildjob.py	2011-05-04 07:10:58 +0000
@@ -112,7 +112,7 @@
         if build_id is None:
             return None
         else:
-            return getUtility(ITranslationTemplatesBuildSource).get(
+            return getUtility(ITranslationTemplatesBuildSource).getByID(
                 int(build_id))
 
     @classmethod

=== modified file 'lib/lp/translations/tests/test_translationtemplatesbuild.py'
--- lib/lp/translations/tests/test_translationtemplatesbuild.py	2010-09-24 10:33:18 +0000
+++ lib/lp/translations/tests/test_translationtemplatesbuild.py	2011-05-04 07:10:58 +0000
@@ -105,7 +105,7 @@
         branch = self.factory.makeBranch()
         build = source.create(build_farm_job, branch)
 
-        self.assertEqual(build, source.get(build.id))
+        self.assertEqual(build, source.getByID(build.id))
 
     def test_get_returns_none_if_not_found(self):
         source = getUtility(ITranslationTemplatesBuildSource)
@@ -113,7 +113,7 @@
         branch = self.factory.makeBranch()
         build = source.create(build_farm_job, branch)
 
-        self.assertIs(None, source.get(build.id + 999))
+        self.assertIs(None, source.getByID(build.id + 999))
 
     def test_getByBuildFarmJob(self):
         source = getUtility(ITranslationTemplatesBuildSource)
@@ -121,14 +121,15 @@
         branch = self.factory.makeBranch()
         build = source.create(build_farm_job, branch)
 
-        self.assertEqual(build, source.getByBuildFarmJob(build_farm_job.id))
+        self.assertEqual(build, source.getByBuildFarmJob(build_farm_job))
 
     def test_getByBuildFarmJob_returns_none_if_not_found(self):
         source = getUtility(ITranslationTemplatesBuildSource)
         build_farm_job = self._makeBuildFarmJob()
         branch = self.factory.makeBranch()
-        build = source.create(build_farm_job, branch)
+        source.create(build_farm_job, branch)
 
+        another_job = self._makeBuildFarmJob()
         self.assertIs(
             None,
-            source.getByBuildFarmJob(build_farm_job.id + 999))
+            source.getByBuildFarmJob(another_job))