launchpad-reviewers team mailing list archive
-
launchpad-reviewers team
-
Mailing list archive
-
Message #19851
[Merge] lp:~cjwatson/launchpad/sprd-utilities into lp:launchpad
Colin Watson has proposed merging lp:~cjwatson/launchpad/sprd-utilities into lp:launchpad.
Commit message:
Access recipe parsing via interfaces.
Requested reviews:
Launchpad code reviewers (launchpad-reviewers)
Related bugs:
Bug #1453022 in Launchpad itself: "Please support daily builds via git"
https://bugs.launchpad.net/launchpad/+bug/1453022
For more details, see:
https://code.launchpad.net/~cjwatson/launchpad/sprd-utilities/+merge/282218
Access recipe parsing via interfaces.
This is a bit of refactoring before starting on Git recipe support; for that, we're going to want to push recipe text through a small amount of munging before passing it to RecipeParser, so it makes sense for it all to go through common code, and that ought to use an interface so that it can be used correctly from browser code.
--
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~cjwatson/launchpad/sprd-utilities into lp:launchpad.
=== modified file 'lib/lp/code/browser/sourcepackagerecipe.py'
--- lib/lp/code/browser/sourcepackagerecipe.py 2015-07-08 16:05:11 +0000
+++ lib/lp/code/browser/sourcepackagerecipe.py 2016-01-11 19:38:23 +0000
@@ -1,4 +1,4 @@
-# Copyright 2010-2013 Canonical Ltd. This software is licensed under the
+# Copyright 2010-2016 Canonical Ltd. This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).
"""SourcePackageRecipe views."""
@@ -20,7 +20,6 @@
from bzrlib.plugins.builder.recipe import (
ForbiddenInstructionError,
RecipeParseError,
- RecipeParser,
)
from lazr.lifecycle.event import ObjectModifiedEvent
from lazr.lifecycle.snapshot import Snapshot
@@ -92,6 +91,7 @@
)
from lp.code.interfaces.branchtarget import IBranchTarget
from lp.code.interfaces.sourcepackagerecipe import (
+ IRecipeBranchSource,
ISourcePackageRecipe,
ISourcePackageRecipeSource,
MINIMAL_RECIPE_TEXT,
@@ -611,10 +611,11 @@
'distroseries',
'You must specify at least one series for daily builds.')
try:
- parser = RecipeParser(data['recipe_text'])
- parser.parse()
- except RecipeParseError as error:
- self.setFieldError('recipe_text', str(error))
+ self.error_handler(
+ getUtility(IRecipeBranchSource).getParsedRecipe,
+ data['recipe_text'])
+ except ErrorHandled:
+ pass
def error_handler(self, callable, *args, **kwargs):
try:
@@ -631,7 +632,7 @@
except NoSuchBranch as e:
self.setFieldError(
'recipe_text', '%s is not a branch on Launchpad.' % e.name)
- except PrivateBranchRecipe as e:
+ except (RecipeParseError, PrivateBranchRecipe) as e:
self.setFieldError('recipe_text', str(e))
raise ErrorHandled()
@@ -872,14 +873,14 @@
self.context, providing=providedBy(self.context))
recipe_text = data.pop('recipe_text')
- parser = RecipeParser(recipe_text)
- recipe = parser.parse()
- if self.context.builder_recipe != recipe:
- try:
+ try:
+ recipe = self.error_handler(
+ getUtility(IRecipeBranchSource).getParsedRecipe, recipe_text)
+ if self.context.builder_recipe != recipe:
self.error_handler(self.context.setRecipeText, recipe_text)
changed = True
- except ErrorHandled:
- return
+ except ErrorHandled:
+ return
distros = data.pop('distroseries')
if distros != self.context.distroseries:
@@ -927,7 +928,7 @@
label = title
class schema(Interface):
- """Schema for deleting a branch."""
+ """Schema for deleting a recipe."""
@property
def cancel_url(self):
=== modified file 'lib/lp/code/configure.zcml'
--- lib/lp/code/configure.zcml 2015-10-09 16:56:45 +0000
+++ lib/lp/code/configure.zcml 2016-01-11 19:38:23 +0000
@@ -1,4 +1,4 @@
-<!-- Copyright 2009-2015 Canonical Ltd. This software is licensed under the
+<!-- Copyright 2009-2016 Canonical Ltd. This software is licensed under the
GNU Affero General Public License version 3 (see the file LICENSE).
-->
@@ -1053,6 +1053,15 @@
<require permission="launchpad.View"
interface="lp.code.interfaces.sourcepackagerecipe.ISourcePackageRecipeData"/>
</class>
+ <utility
+ component="lp.code.model.sourcepackagerecipedata.SourcePackageRecipeData"
+ provides="lp.code.interfaces.sourcepackagerecipe.IRecipeBranchSource">
+ </utility>
+ <securedutility
+ component="lp.code.model.sourcepackagerecipedata.SourcePackageRecipeData"
+ provides="lp.code.interfaces.sourcepackagerecipe.ISourcePackageRecipeDataSource">
+ <allow interface="lp.code.interfaces.sourcepackagerecipe.ISourcePackageRecipeDataSource"/>
+ </securedutility>
<!-- SourcePackageRecipe -->
<class
class="lp.code.model.sourcepackagerecipe.SourcePackageRecipe">
=== modified file 'lib/lp/code/interfaces/sourcepackagerecipe.py'
--- lib/lp/code/interfaces/sourcepackagerecipe.py 2015-04-30 01:45:30 +0000
+++ lib/lp/code/interfaces/sourcepackagerecipe.py 2016-01-11 19:38:23 +0000
@@ -1,4 +1,4 @@
-# Copyright 2009-2012 Canonical Ltd. This software is licensed under the
+# Copyright 2009-2016 Canonical Ltd. This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).
"""Interface of the `SourcePackageRecipe` content type."""
@@ -8,8 +8,10 @@
__all__ = [
+ 'IRecipeBranchSource',
'ISourcePackageRecipe',
'ISourcePackageRecipeData',
+ 'ISourcePackageRecipeDataSource',
'ISourcePackageRecipeSource',
'MINIMAL_RECIPE_TEXT',
]
@@ -88,6 +90,28 @@
"""An iterator of the branches referenced by this recipe."""
+class IRecipeBranchSource(Interface):
+
+ def getParsedRecipe(recipe_text):
+ """Parse recipe text into recipe data.
+
+ :param recipe_text: Recipe text as a string.
+ :return: a `RecipeBranch` representing the recipe.
+ """
+
+
+class ISourcePackageRecipeDataSource(Interface):
+
+ def createManifestFromText(text, sourcepackage_recipe_build):
+ """Create a manifest for the specified build.
+
+ :param text: The text of the recipe to create a manifest for.
+ :param sourcepackage_recipe_build: The build to associate the manifest
+ with.
+ :return: an instance of `SourcePackageRecipeData`.
+ """
+
+
class ISourcePackageRecipeView(Interface):
"""IBranch attributes that require launchpad.View permission."""
=== modified file 'lib/lp/code/model/sourcepackagerecipe.py'
--- lib/lp/code/model/sourcepackagerecipe.py 2015-09-28 17:38:45 +0000
+++ lib/lp/code/model/sourcepackagerecipe.py 2016-01-11 19:38:23 +0000
@@ -1,4 +1,4 @@
-# Copyright 2009-2015 Canonical Ltd. This software is licensed under the
+# Copyright 2009-2016 Canonical Ltd. This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).
"""Implementation of the `SourcePackageRecipe` content type."""
@@ -42,6 +42,7 @@
BuildNotAllowedForDistro,
)
from lp.code.interfaces.sourcepackagerecipe import (
+ IRecipeBranchSource,
ISourcePackageRecipe,
ISourcePackageRecipeData,
ISourcePackageRecipeSource,
@@ -167,7 +168,7 @@
owner_ids, need_validity=True))
def setRecipeText(self, recipe_text):
- parsed = SourcePackageRecipeData.getParsedRecipe(recipe_text)
+ parsed = getUtility(IRecipeBranchSource).getParsedRecipe(recipe_text)
self._recipe_data.setRecipe(parsed)
@property
@@ -187,7 +188,8 @@
"""See `ISourcePackageRecipeSource.new`."""
store = IMasterStore(SourcePackageRecipe)
sprecipe = SourcePackageRecipe()
- builder_recipe = SourcePackageRecipeData.getParsedRecipe(recipe)
+ builder_recipe = getUtility(IRecipeBranchSource).getParsedRecipe(
+ recipe)
SourcePackageRecipeData(builder_recipe, sprecipe)
sprecipe.registrant = registrant
sprecipe.owner = owner
=== modified file 'lib/lp/code/model/sourcepackagerecipebuild.py'
--- lib/lp/code/model/sourcepackagerecipebuild.py 2015-09-11 15:11:34 +0000
+++ lib/lp/code/model/sourcepackagerecipebuild.py 2016-01-11 19:38:23 +0000
@@ -1,4 +1,4 @@
-# Copyright 2010-2013 Canonical Ltd. This software is licensed under the
+# Copyright 2010-2016 Canonical Ltd. This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).
"""Implementation code for source package builds."""
@@ -46,6 +46,10 @@
BuildAlreadyPending,
BuildNotAllowedForDistro,
)
+from lp.code.interfaces.sourcepackagerecipe import (
+ IRecipeBranchSource,
+ ISourcePackageRecipeDataSource,
+ )
from lp.code.interfaces.sourcepackagerecipebuild import (
ISourcePackageRecipeBuild,
ISourcePackageRecipeBuildSource,
@@ -53,7 +57,6 @@
from lp.code.mail.sourcepackagerecipebuild import (
SourcePackageRecipeBuildMailer,
)
-from lp.code.model.sourcepackagerecipedata import SourcePackageRecipeData
from lp.registry.interfaces.pocket import PackagePublishingPocket
from lp.registry.model.person import Person
from lp.services.database.bulk import load_related
@@ -158,10 +161,11 @@
if self.manifest is not None:
IStore(self.manifest).remove(self.manifest)
elif self.manifest is None:
- SourcePackageRecipeData.createManifestFromText(text, self)
+ getUtility(ISourcePackageRecipeDataSource).createManifestFromText(
+ text, self)
else:
- from bzrlib.plugins.builder.recipe import RecipeParser
- self.manifest.setRecipe(RecipeParser(text).parse())
+ self.manifest.setRecipe(
+ getUtility(IRecipeBranchSource).getParsedRecipe(text))
def getManifestText(self):
if self.manifest is None:
=== modified file 'lib/lp/code/model/sourcepackagerecipedata.py'
--- lib/lp/code/model/sourcepackagerecipedata.py 2015-02-25 11:21:43 +0000
+++ lib/lp/code/model/sourcepackagerecipedata.py 2016-01-11 19:38:23 +0000
@@ -1,4 +1,4 @@
-# Copyright 2009-2015 Canonical Ltd. This software is licensed under the
+# Copyright 2009-2016 Canonical Ltd. This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).
"""Implementation of the recipe storage.
@@ -38,6 +38,10 @@
Unicode,
)
from zope.component import getUtility
+from zope.interface import (
+ implementer,
+ provider,
+ )
from lp.code.errors import (
NoSuchBranch,
@@ -45,6 +49,11 @@
TooNewRecipeFormat,
)
from lp.code.interfaces.branchlookup import IBranchLookup
+from lp.code.interfaces.sourcepackagerecipe import (
+ IRecipeBranchSource,
+ ISourcePackageRecipeData,
+ ISourcePackageRecipeDataSource,
+ )
from lp.code.model.branch import Branch
from lp.services.database.bulk import (
load_referencing,
@@ -142,6 +151,8 @@
MAX_RECIPE_FORMAT = 0.4
+@implementer(ISourcePackageRecipeData)
+@provider(IRecipeBranchSource, ISourcePackageRecipeDataSource)
class SourcePackageRecipeData(Storm):
"""The database representation of a BaseRecipeBranch from bzr-builder.
@@ -177,6 +188,7 @@
@staticmethod
def getParsedRecipe(recipe_text):
+ """See `IRecipeBranchSource`."""
parser = RecipeParser(recipe_text)
return parser.parse(permitted_instructions=SAFE_INSTRUCTIONS)
@@ -202,13 +214,7 @@
@classmethod
def createManifestFromText(cls, text, sourcepackage_recipe_build):
- """Create a manifest for the specified build.
-
- :param text: The text of the recipe to create a manifest for.
- :param sourcepackage_recipe_build: The build to associate the manifest
- with.
- :return: an instance of SourcePackageRecipeData.
- """
+ """See `ISourcePackageRecipeDataSource`."""
parsed = cls.getParsedRecipe(text)
return cls(
parsed, sourcepackage_recipe_build=sourcepackage_recipe_build)
Follow ups