Merge lp:~abentley/launchpad/permit-commands into lp:launchpad

Proposed by Aaron Bentley
Status: Merged
Merged at revision: 11517
Proposed branch: lp:~abentley/launchpad/permit-commands
Merge into: lp:launchpad
Prerequisite: lp:~abentley/launchpad/recipe-interfaces
Diff against target: 494 lines (+68/-102)
9 files modified
lib/lp/code/browser/sourcepackagerecipe.py (+6/-8)
lib/lp/code/errors.py (+0/-9)
lib/lp/code/interfaces/sourcepackagerecipe.py (+2/-2)
lib/lp/code/model/sourcepackagerecipe.py (+7/-10)
lib/lp/code/model/sourcepackagerecipedata.py (+10/-8)
lib/lp/code/model/tests/test_sourcepackagerecipe.py (+36/-59)
lib/lp/registry/model/person.py (+1/-3)
lib/lp/testing/factory.py (+5/-2)
utilities/sourcedeps.conf (+1/-1)
To merge this branch: bzr merge lp:~abentley/launchpad/permit-commands
Reviewer Review Type Date Requested Status
Paul Hummer (community) Approve
Review via email: mp+34476@code.launchpad.net

Commit message

Update forbidden command handling to use bzr-builder facilities.

Description of the change

= Summary =
Update launchpad to use bzr-builder's facilities for using only safe
instructions.

== Proposed fix ==
Provide permitted_instructions to RecipeParser.parse

== Pre-implementation notes ==
None

== Implementation details ==
Several things are needed for this change. Crucially, there should be a single
codepath that is used to parse recipe text, so that no one can forget to supply
permitted_instructions. SourcePackageRecipeData.getParsedRecipe provides this.

From this, it made sense to change the constructor of SourcePackageRecipe to
take unparsed recipe text as instead of a parsed "builder recipe" as an
argument.

This required changing many tests.

Additionally, the check for forbidden instructions now happens at parse time,
instead of at as a later stage.

Additionally, tests were changed to use
LaunchpadObjectFactory.makeSourcePackageRecipe where possible. And for many
tests, it was simpler to use LaunchpadObjectFactory.makeRecipeText instead of
makeRecipe.

== Tests ==
bin/tests test_sourcepackagerecipe

== Demo and Q/A ==
None

= Launchpad lint =

Checking for conflicts and issues in changed files.

Linting changed files:
  lib/lp/code/configure.zcml
  lib/lp/code/model/sourcepackagerecipedata.py
  lib/lp/code/errors.py
  lib/lp/code/model/tests/test_sourcepackagerecipe.py
  lib/lp/testing/factory.py
  lib/lp/code/browser/sourcepackagerecipe.py
  utilities/sourcedeps.conf
  lib/lp/code/model/sourcepackagerecipe.py
  lib/lp/code/interfaces/sourcepackagerecipe.py
  lib/lp/registry/model/person.py

./lib/lp/code/model/sourcepackagerecipedata.py
     174: E202 whitespace before ')'
./lib/lp/code/errors.py
     142: E231 missing whitespace after ','
     172: E231 missing whitespace after ','
     180: E231 missing whitespace after ','
./lib/lp/code/model/tests/test_sourcepackagerecipe.py
     243: E501 line too long (80 characters)
     256: E231 missing whitespace after ','
     280: E231 missing whitespace after ','
     288: E231 missing whitespace after ','
     295: E231 missing whitespace after ','
     303: E231 missing whitespace after ','
     341: E231 missing whitespace after ','
     401: E231 missing whitespace after ','
     243: Line exceeds 78 characters.
./lib/lp/code/browser/sourcepackagerecipe.py
     163: E231 missing whitespace after ','
     271: E202 whitespace before ']'
     381: E231 missing whitespace after ','
./lib/lp/code/interfaces/sourcepackagerecipe.py
      77: E231 missing whitespace after ','
     121: E202 whitespace before ')'
     121: E231 missing whitespace after ','
     150: E302 expected 2 blank lines, found 1
./lib/lp/registry/model/person.py
    1617: E301 expected 1 blank line, found 0
    1624: E301 expected 1 blank line, found 0

To post a comment you must log in.
Revision history for this message
Paul Hummer (rockstar) wrote :

Thanks for simplifying the parsed recipe stuff.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'lib/lp/code/browser/sourcepackagerecipe.py'
--- lib/lp/code/browser/sourcepackagerecipe.py 2010-08-23 02:07:45 +0000
+++ lib/lp/code/browser/sourcepackagerecipe.py 2010-09-09 13:41:57 +0000
@@ -16,6 +16,7 @@
1616
1717
18from bzrlib.plugins.builder.recipe import (18from bzrlib.plugins.builder.recipe import (
19 ForbiddenInstructionError,
19 RecipeParseError,20 RecipeParseError,
20 RecipeParser,21 RecipeParser,
21 )22 )
@@ -57,7 +58,6 @@
57from canonical.widgets.itemswidgets import LabeledMultiCheckBoxWidget58from canonical.widgets.itemswidgets import LabeledMultiCheckBoxWidget
58from lp.code.errors import (59from lp.code.errors import (
59 BuildAlreadyPending,60 BuildAlreadyPending,
60 ForbiddenInstruction,
61 NoSuchBranch,61 NoSuchBranch,
62 PrivateBranchRecipe,62 PrivateBranchRecipe,
63 )63 )
@@ -326,16 +326,14 @@
326326
327 @action('Create Recipe', name='create')327 @action('Create Recipe', name='create')
328 def request_action(self, action, data):328 def request_action(self, action, data):
329 parser = RecipeParser(data['recipe_text'])
330 recipe = parser.parse()
331 try:329 try:
332 source_package_recipe = getUtility(330 source_package_recipe = getUtility(
333 ISourcePackageRecipeSource).new(331 ISourcePackageRecipeSource).new(
334 self.user, data['owner'], data['name'], recipe,332 self.user, data['owner'], data['name'],
335 data['description'], data['distros'],333 data['recipe_text'], data['description'], data['distros'],
336 data['daily_build_archive'], data['build_daily'])334 data['daily_build_archive'], data['build_daily'])
337 Store.of(source_package_recipe).flush()335 Store.of(source_package_recipe).flush()
338 except ForbiddenInstruction:336 except ForbiddenInstructionError:
339 # XXX: bug=592513 We shouldn't be hardcoding "run" here.337 # XXX: bug=592513 We shouldn't be hardcoding "run" here.
340 self.setFieldError(338 self.setFieldError(
341 'recipe_text',339 'recipe_text',
@@ -397,9 +395,9 @@
397 recipe = parser.parse()395 recipe = parser.parse()
398 if self.context.builder_recipe != recipe:396 if self.context.builder_recipe != recipe:
399 try:397 try:
400 self.context.builder_recipe = recipe398 self.context.setRecipeText(recipe_text)
401 changed = True399 changed = True
402 except ForbiddenInstruction:400 except ForbiddenInstructionError:
403 # XXX: bug=592513 We shouldn't be hardcoding "run" here.401 # XXX: bug=592513 We shouldn't be hardcoding "run" here.
404 self.setFieldError(402 self.setFieldError(
405 'recipe_text',403 'recipe_text',
406404
=== modified file 'lib/lp/code/errors.py'
--- lib/lp/code/errors.py 2010-08-03 03:43:33 +0000
+++ lib/lp/code/errors.py 2010-09-09 13:41:57 +0000
@@ -25,7 +25,6 @@
25 'CodeImportAlreadyRunning',25 'CodeImportAlreadyRunning',
26 'CodeImportNotInReviewedState',26 'CodeImportNotInReviewedState',
27 'ClaimReviewFailed',27 'ClaimReviewFailed',
28 'ForbiddenInstruction',
29 'InvalidBranchMergeProposal',28 'InvalidBranchMergeProposal',
30 'InvalidNamespace',29 'InvalidNamespace',
31 'NoLinkedBranch',30 'NoLinkedBranch',
@@ -242,14 +241,6 @@
242 webservice_error(400)241 webservice_error(400)
243242
244243
245class ForbiddenInstruction(Exception):
246 """A forbidden instruction was found in the recipe."""
247
248 def __init__(self, instruction_name):
249 super(ForbiddenInstruction, self).__init__()
250 self.instruction_name = instruction_name
251
252
253class TooNewRecipeFormat(Exception):244class TooNewRecipeFormat(Exception):
254 """The format of the recipe supplied was too new."""245 """The format of the recipe supplied was too new."""
255246
256247
=== modified file 'lib/lp/code/interfaces/sourcepackagerecipe.py'
--- lib/lp/code/interfaces/sourcepackagerecipe.py 2010-09-09 13:41:38 +0000
+++ lib/lp/code/interfaces/sourcepackagerecipe.py 2010-09-09 13:41:57 +0000
@@ -93,8 +93,6 @@
93 required=True, readonly=True,93 required=True, readonly=True,
94 vocabulary='ValidPersonOrTeam'))94 vocabulary='ValidPersonOrTeam'))
9595
96 is_stale = Bool(title=_('Recipe is stale.'))
97
98 recipe_text = exported(Text())96 recipe_text = exported(Text())
9997
100 def isOverQuota(requester, distroseries):98 def isOverQuota(requester, distroseries):
@@ -183,6 +181,8 @@
183181
184 date_last_modified = Datetime(required=True, readonly=True)182 date_last_modified = Datetime(required=True, readonly=True)
185183
184 is_stale = Bool(title=_('Recipe is stale.'))
185
186186
187class ISourcePackageRecipe(ISourcePackageRecipeData,187class ISourcePackageRecipe(ISourcePackageRecipeData,
188 ISourcePackageRecipeEdit, ISourcePackageRecipeEditableAttributes,188 ISourcePackageRecipeEdit, ISourcePackageRecipeEditableAttributes,
189189
=== modified file 'lib/lp/code/model/sourcepackagerecipe.py'
--- lib/lp/code/model/sourcepackagerecipe.py 2010-09-01 03:25:36 +0000
+++ lib/lp/code/model/sourcepackagerecipe.py 2010-09-09 13:41:57 +0000
@@ -11,7 +11,6 @@
11 'SourcePackageRecipe',11 'SourcePackageRecipe',
12 ]12 ]
1313
14from bzrlib.plugins.builder.recipe import RecipeParser
15from lazr.delegates import delegates14from lazr.delegates import delegates
16from storm.locals import (15from storm.locals import (
17 Bool,16 Bool,
@@ -139,33 +138,30 @@
139 SourcePackageRecipeData,138 SourcePackageRecipeData,
140 SourcePackageRecipeData.sourcepackage_recipe == self).one()139 SourcePackageRecipeData.sourcepackage_recipe == self).one()
141140
142 def _get_builder_recipe(self):141 @property
142 def builder_recipe(self):
143 """Accesses of the recipe go to the SourcePackageRecipeData."""143 """Accesses of the recipe go to the SourcePackageRecipeData."""
144 return self._recipe_data.getRecipe()144 return self._recipe_data.getRecipe()
145145
146 def _set_builder_recipe(self, value):
147 """Setting of the recipe goes to the SourcePackageRecipeData."""
148 self._recipe_data.setRecipe(value)
149
150 builder_recipe = property(_get_builder_recipe, _set_builder_recipe)
151
152 @property146 @property
153 def base_branch(self):147 def base_branch(self):
154 return self._recipe_data.base_branch148 return self._recipe_data.base_branch
155149
156 def setRecipeText(self, recipe_text):150 def setRecipeText(self, recipe_text):
157 self.builder_recipe = RecipeParser(recipe_text).parse()151 parsed = SourcePackageRecipeData.getParsedRecipe(recipe_text)
152 self._recipe_data.setRecipe(parsed)
158153
159 @property154 @property
160 def recipe_text(self):155 def recipe_text(self):
161 return str(self.builder_recipe)156 return str(self.builder_recipe)
162157
163 @staticmethod158 @staticmethod
164 def new(registrant, owner, name, builder_recipe, description,159 def new(registrant, owner, name, recipe, description,
165 distroseries=None, daily_build_archive=None, build_daily=False):160 distroseries=None, daily_build_archive=None, build_daily=False):
166 """See `ISourcePackageRecipeSource.new`."""161 """See `ISourcePackageRecipeSource.new`."""
167 store = IMasterStore(SourcePackageRecipe)162 store = IMasterStore(SourcePackageRecipe)
168 sprecipe = SourcePackageRecipe()163 sprecipe = SourcePackageRecipe()
164 builder_recipe = SourcePackageRecipeData.getParsedRecipe(recipe)
169 SourcePackageRecipeData(builder_recipe, sprecipe)165 SourcePackageRecipeData(builder_recipe, sprecipe)
170 sprecipe.registrant = registrant166 sprecipe.registrant = registrant
171 sprecipe.owner = owner167 sprecipe.owner = owner
@@ -201,6 +197,7 @@
201 store = Store.of(self)197 store = Store.of(self)
202 self.distroseries.clear()198 self.distroseries.clear()
203 self._recipe_data.instructions.find().remove()199 self._recipe_data.instructions.find().remove()
200
204 def destroyBuilds(pending):201 def destroyBuilds(pending):
205 builds = self.getBuilds(pending=pending)202 builds = self.getBuilds(pending=pending)
206 for build in builds:203 for build in builds:
207204
=== modified file 'lib/lp/code/model/sourcepackagerecipedata.py'
--- lib/lp/code/model/sourcepackagerecipedata.py 2010-08-20 20:31:18 +0000
+++ lib/lp/code/model/sourcepackagerecipedata.py 2010-09-09 13:41:57 +0000
@@ -18,6 +18,8 @@
18 MergeInstruction,18 MergeInstruction,
19 NestInstruction,19 NestInstruction,
20 RecipeBranch,20 RecipeBranch,
21 RecipeParser,
22 SAFE_INSTRUCTIONS,
21 )23 )
22from lazr.enum import (24from lazr.enum import (
23 DBEnumeratedType,25 DBEnumeratedType,
@@ -39,7 +41,6 @@
39from canonical.database.enumcol import EnumCol41from canonical.database.enumcol import EnumCol
40from canonical.launchpad.interfaces.lpstorm import IStore42from canonical.launchpad.interfaces.lpstorm import IStore
41from lp.code.errors import (43from lp.code.errors import (
42 ForbiddenInstruction,
43 NoSuchBranch,44 NoSuchBranch,
44 PrivateBranchRecipe,45 PrivateBranchRecipe,
45 TooNewRecipeFormat,46 TooNewRecipeFormat,
@@ -151,6 +152,11 @@
151 sourcepackage_recipe_build_id, 'SourcePackageRecipeBuild.id')152 sourcepackage_recipe_build_id, 'SourcePackageRecipeBuild.id')
152153
153 @staticmethod154 @staticmethod
155 def getParsedRecipe(recipe_text):
156 parser = RecipeParser(recipe_text)
157 return parser.parse(permitted_instructions=SAFE_INSTRUCTIONS)
158
159 @staticmethod
154 def findRecipes(branch):160 def findRecipes(branch):
155 from lp.code.model.sourcepackagerecipe import SourcePackageRecipe161 from lp.code.model.sourcepackagerecipe import SourcePackageRecipe
156 store = Store.of(branch)162 store = Store.of(branch)
@@ -179,10 +185,9 @@
179 with.185 with.
180 :return: an instance of SourcePackageRecipeData.186 :return: an instance of SourcePackageRecipeData.
181 """187 """
182 from bzrlib.plugins.builder.recipe import RecipeParser188 parsed = cls.getParsedRecipe(text)
183 parser = RecipeParser(text)189 return cls(
184 return cls(parser.parse(),190 parsed, sourcepackage_recipe_build=sourcepackage_recipe_build)
185 sourcepackage_recipe_build=sourcepackage_recipe_build)
186191
187 def getRecipe(self):192 def getRecipe(self):
188 """The BaseRecipeBranch version of the recipe."""193 """The BaseRecipeBranch version of the recipe."""
@@ -213,9 +218,6 @@
213 """218 """
214 r = {}219 r = {}
215 for instruction in recipe_branch.child_branches:220 for instruction in recipe_branch.child_branches:
216 if not (isinstance(instruction, MergeInstruction) or
217 isinstance(instruction, NestInstruction)):
218 raise ForbiddenInstruction(str(instruction))
219 db_branch = getUtility(IBranchLookup).getByUrl(221 db_branch = getUtility(IBranchLookup).getByUrl(
220 instruction.recipe_branch.url)222 instruction.recipe_branch.url)
221 if db_branch is None:223 if db_branch is None:
222224
=== modified file 'lib/lp/code/model/tests/test_sourcepackagerecipe.py'
--- lib/lp/code/model/tests/test_sourcepackagerecipe.py 2010-09-09 13:41:38 +0000
+++ lib/lp/code/model/tests/test_sourcepackagerecipe.py 2010-09-09 13:41:57 +0000
@@ -14,7 +14,9 @@
14import textwrap14import textwrap
15import unittest15import unittest
1616
17from bzrlib.plugins.builder.recipe import RecipeParser17from bzrlib.plugins.builder.recipe import (
18 ForbiddenInstructionError,
19)
18from pytz import UTC20from pytz import UTC
19from storm.locals import Store21from storm.locals import Store
20import transaction22import transaction
@@ -33,7 +35,6 @@
33from lp.buildmaster.model.buildqueue import BuildQueue35from lp.buildmaster.model.buildqueue import BuildQueue
34from lp.code.errors import (36from lp.code.errors import (
35 BuildAlreadyPending,37 BuildAlreadyPending,
36 ForbiddenInstruction,
37 PrivateBranchRecipe,38 PrivateBranchRecipe,
38 TooManyBuilds,39 TooManyBuilds,
39 TooNewRecipeFormat,40 TooNewRecipeFormat,
@@ -84,18 +85,6 @@
84 recipe = self.factory.makeSourcePackageRecipe()85 recipe = self.factory.makeSourcePackageRecipe()
85 verifyObject(ISourcePackageRecipe, recipe)86 verifyObject(ISourcePackageRecipe, recipe)
8687
87 def makeSourcePackageRecipeFromBuilderRecipe(self, builder_recipe):
88 """Make a SourcePackageRecipe from a recipe with arbitrary other data.
89 """
90 registrant = self.factory.makePerson()
91 owner = self.factory.makeTeam(owner=registrant)
92 distroseries = self.factory.makeDistroSeries()
93 name = self.factory.getUniqueString(u'recipe-name')
94 description = self.factory.getUniqueString(u'recipe-description')
95 return getUtility(ISourcePackageRecipeSource).new(
96 registrant=registrant, owner=owner, distroseries=[distroseries],
97 name=name, description=description, builder_recipe=builder_recipe)
98
99 def makeRecipeComponents(self, branches=()):88 def makeRecipeComponents(self, branches=()):
100 """Return a dict of values that can be used to make a recipe.89 """Return a dict of values that can be used to make a recipe.
10190
@@ -110,7 +99,7 @@
110 distroseries = [self.factory.makeDistroSeries()],99 distroseries = [self.factory.makeDistroSeries()],
111 name = self.factory.getUniqueString(u'recipe-name'),100 name = self.factory.getUniqueString(u'recipe-name'),
112 description = self.factory.getUniqueString(u'recipe-description'),101 description = self.factory.getUniqueString(u'recipe-description'),
113 builder_recipe = self.factory.makeRecipe(*branches))102 recipe = self.factory.makeRecipeText(*branches))
114103
115 def test_creation(self):104 def test_creation(self):
116 # The metadata supplied when a SourcePackageRecipe is created is105 # The metadata supplied when a SourcePackageRecipe is created is
@@ -174,8 +163,7 @@
174163
175 def test_recipe_implements_interface(self):164 def test_recipe_implements_interface(self):
176 # SourcePackageRecipe objects implement ISourcePackageRecipe.165 # SourcePackageRecipe objects implement ISourcePackageRecipe.
177 recipe = self.makeSourcePackageRecipeFromBuilderRecipe(166 recipe = self.factory.makeSourcePackageRecipe()
178 self.factory.makeRecipe())
179 transaction.commit()167 transaction.commit()
180 with person_logged_in(recipe.owner):168 with person_logged_in(recipe.owner):
181 self.assertProvides(recipe, ISourcePackageRecipe)169 self.assertProvides(recipe, ISourcePackageRecipe)
@@ -183,9 +171,7 @@
183 def test_base_branch(self):171 def test_base_branch(self):
184 # When a recipe is created, we can access its base branch.172 # When a recipe is created, we can access its base branch.
185 branch = self.factory.makeAnyBranch()173 branch = self.factory.makeAnyBranch()
186 builder_recipe = self.factory.makeRecipe(branch)174 sp_recipe = self.factory.makeSourcePackageRecipe(branches=[branch])
187 sp_recipe = self.makeSourcePackageRecipeFromBuilderRecipe(
188 builder_recipe)
189 transaction.commit()175 transaction.commit()
190 self.assertEquals(branch, sp_recipe.base_branch)176 self.assertEquals(branch, sp_recipe.base_branch)
191177
@@ -193,9 +179,8 @@
193 # When a recipe is created, we can query it for links to the branch179 # When a recipe is created, we can query it for links to the branch
194 # it references.180 # it references.
195 branch = self.factory.makeAnyBranch()181 branch = self.factory.makeAnyBranch()
196 builder_recipe = self.factory.makeRecipe(branch)182 sp_recipe = self.factory.makeSourcePackageRecipe(
197 sp_recipe = self.makeSourcePackageRecipeFromBuilderRecipe(183 branches=[branch])
198 builder_recipe)
199 transaction.commit()184 transaction.commit()
200 self.assertEquals([branch], list(sp_recipe.getReferencedBranches()))185 self.assertEquals([branch], list(sp_recipe.getReferencedBranches()))
201186
@@ -204,9 +189,8 @@
204 # returns all of them.189 # returns all of them.
205 branch1 = self.factory.makeAnyBranch()190 branch1 = self.factory.makeAnyBranch()
206 branch2 = self.factory.makeAnyBranch()191 branch2 = self.factory.makeAnyBranch()
207 builder_recipe = self.factory.makeRecipe(branch1, branch2)192 sp_recipe = self.factory.makeSourcePackageRecipe(
208 sp_recipe = self.makeSourcePackageRecipeFromBuilderRecipe(193 branches=[branch1, branch2])
209 builder_recipe)
210 transaction.commit()194 transaction.commit()
211 self.assertEquals(195 self.assertEquals(
212 sorted([branch1, branch2]),196 sorted([branch1, branch2]),
@@ -215,27 +199,23 @@
215 def test_random_user_cant_edit(self):199 def test_random_user_cant_edit(self):
216 # An arbitrary user can't set attributes.200 # An arbitrary user can't set attributes.
217 branch1 = self.factory.makeAnyBranch()201 branch1 = self.factory.makeAnyBranch()
218 builder_recipe1 = self.factory.makeRecipe(branch1)202 recipe_1 = self.factory.makeRecipeText(branch1)
219 sp_recipe = self.makeSourcePackageRecipeFromBuilderRecipe(203 sp_recipe = self.factory.makeSourcePackageRecipe(
220 builder_recipe1)204 recipe=recipe_1)
221 branch2 = self.factory.makeAnyBranch()
222 builder_recipe2 = self.factory.makeRecipe(branch2)
223 login_person(self.factory.makePerson())205 login_person(self.factory.makePerson())
224 self.assertRaises(206 self.assertRaises(
225 Unauthorized, setattr, sp_recipe, 'builder_recipe',207 Unauthorized, getattr, sp_recipe, 'setRecipeText')
226 builder_recipe2)
227208
228 def test_set_recipe_text_resets_branch_references(self):209 def test_set_recipe_text_resets_branch_references(self):
229 # When the recipe_text is replaced, getReferencedBranches returns210 # When the recipe_text is replaced, getReferencedBranches returns
230 # (only) the branches referenced by the new recipe.211 # (only) the branches referenced by the new recipe.
231 branch1 = self.factory.makeAnyBranch()212 branch1 = self.factory.makeAnyBranch()
232 builder_recipe1 = self.factory.makeRecipe(branch1)213 sp_recipe = self.factory.makeSourcePackageRecipe(
233 sp_recipe = self.makeSourcePackageRecipeFromBuilderRecipe(214 branches=[branch1])
234 builder_recipe1)
235 branch2 = self.factory.makeAnyBranch()215 branch2 = self.factory.makeAnyBranch()
236 builder_recipe2 = self.factory.makeRecipe(branch2)216 new_recipe = self.factory.makeRecipeText(branch2)
237 login_person(sp_recipe.owner.teamowner)217 with person_logged_in(sp_recipe.owner):
238 sp_recipe.builder_recipe = builder_recipe2218 sp_recipe.setRecipeText(new_recipe)
239 self.assertEquals([branch2], list(sp_recipe.getReferencedBranches()))219 self.assertEquals([branch2], list(sp_recipe.getReferencedBranches()))
240220
241 def test_rejects_run_command(self):221 def test_rejects_run_command(self):
@@ -244,36 +224,32 @@
244 %(base)s224 %(base)s
245 run touch test225 run touch test
246 ''' % dict(base=self.factory.makeAnyBranch().bzr_identity)226 ''' % dict(base=self.factory.makeAnyBranch().bzr_identity)
247 parser = RecipeParser(textwrap.dedent(recipe_text))227 recipe_text = textwrap.dedent(recipe_text)
248 builder_recipe = parser.parse()
249 self.assertRaises(228 self.assertRaises(
250 ForbiddenInstruction,229 ForbiddenInstructionError, self.factory.makeSourcePackageRecipe,
251 self.makeSourcePackageRecipeFromBuilderRecipe, builder_recipe)230 recipe=recipe_text)
252231
253 def test_run_rejected_without_mangling_recipe(self):232 def test_run_rejected_without_mangling_recipe(self):
254 branch1 = self.factory.makeAnyBranch()233 sp_recipe = self.factory.makeSourcePackageRecipe()
255 builder_recipe1 = self.factory.makeRecipe(branch1)234 old_branches = list(sp_recipe.getReferencedBranches())
256 sp_recipe = self.makeSourcePackageRecipeFromBuilderRecipe(
257 builder_recipe1)
258 recipe_text = '''\235 recipe_text = '''\
259 # bzr-builder format 0.2 deb-version 0.1-{revno}236 # bzr-builder format 0.2 deb-version 0.1-{revno}
260 %(base)s237 %(base)s
261 run touch test238 run touch test
262 ''' % dict(base=self.factory.makeAnyBranch().bzr_identity)239 ''' % dict(base=self.factory.makeAnyBranch().bzr_identity)
263 parser = RecipeParser(textwrap.dedent(recipe_text))240 recipe_text = textwrap.dedent(recipe_text)
264 builder_recipe2 = parser.parse()241 with person_logged_in(sp_recipe.owner):
265 login_person(sp_recipe.owner.teamowner)242 self.assertRaises(
266 self.assertRaises(243 ForbiddenInstructionError, sp_recipe.setRecipeText, recipe_text)
267 ForbiddenInstruction, setattr, sp_recipe, 'builder_recipe',244 self.assertEquals(
268 builder_recipe2)245 old_branches, list(sp_recipe.getReferencedBranches()))
269 self.assertEquals([branch1], list(sp_recipe.getReferencedBranches()))
270246
271 def test_reject_newer_formats(self):247 def test_reject_newer_formats(self):
272 builder_recipe = self.factory.makeRecipe()248 builder_recipe = self.factory.makeRecipe()
273 builder_recipe.format = 0.3249 builder_recipe.format = 0.3
274 self.assertRaises(250 self.assertRaises(
275 TooNewRecipeFormat,251 TooNewRecipeFormat,
276 self.makeSourcePackageRecipeFromBuilderRecipe, builder_recipe)252 self.factory.makeSourcePackageRecipe, recipe=str(builder_recipe))
277253
278 def test_requestBuild(self):254 def test_requestBuild(self):
279 recipe = self.factory.makeSourcePackageRecipe()255 recipe = self.factory.makeSourcePackageRecipe()
@@ -503,6 +479,7 @@
503 SourcePackageRecipe.findStaleDailyBuilds())479 SourcePackageRecipe.findStaleDailyBuilds())
504480
505 def test_getMedianBuildDuration(self):481 def test_getMedianBuildDuration(self):
482
506 def set_duration(build, minutes):483 def set_duration(build, minutes):
507 duration = timedelta(minutes=minutes)484 duration = timedelta(minutes=minutes)
508 build = removeSecurityProxy(build)485 build = removeSecurityProxy(build)
@@ -542,7 +519,7 @@
542 }519 }
543520
544 def get_recipe(self, recipe_text):521 def get_recipe(self, recipe_text):
545 builder_recipe = RecipeParser(textwrap.dedent(recipe_text)).parse()522 recipe_text = textwrap.dedent(recipe_text)
546 registrant = self.factory.makePerson()523 registrant = self.factory.makePerson()
547 owner = self.factory.makeTeam(owner=registrant)524 owner = self.factory.makeTeam(owner=registrant)
548 distroseries = self.factory.makeDistroSeries()525 distroseries = self.factory.makeDistroSeries()
@@ -550,7 +527,7 @@
550 description = self.factory.getUniqueString(u'recipe-description')527 description = self.factory.getUniqueString(u'recipe-description')
551 recipe = getUtility(ISourcePackageRecipeSource).new(528 recipe = getUtility(ISourcePackageRecipeSource).new(
552 registrant=registrant, owner=owner, distroseries=[distroseries],529 registrant=registrant, owner=owner, distroseries=[distroseries],
553 name=name, description=description, builder_recipe=builder_recipe)530 name=name, description=description, recipe=recipe_text)
554 transaction.commit()531 transaction.commit()
555 return recipe.builder_recipe532 return recipe.builder_recipe
556533
@@ -724,8 +701,8 @@
724 return MINIMAL_RECIPE_TEXT % branch.bzr_identity701 return MINIMAL_RECIPE_TEXT % branch.bzr_identity
725702
726 def makeRecipe(self, user=None, owner=None, recipe_text=None):703 def makeRecipe(self, user=None, owner=None, recipe_text=None):
727 # rockstar 21 Jul 2010 - This function does more commits than I'd like,704 # rockstar 21 Jul 2010 - This function does more commits than I'd
728 # but it's the result of the fact that the webservice runs in a705 # like, but it's the result of the fact that the webservice runs in a
729 # separate thread so doesn't get the database updates without those706 # separate thread so doesn't get the database updates without those
730 # commits.707 # commits.
731 if user is None:708 if user is None:
732709
=== modified file 'lib/lp/registry/model/person.py'
--- lib/lp/registry/model/person.py 2010-09-03 16:43:11 +0000
+++ lib/lp/registry/model/person.py 2010-09-09 13:41:57 +0000
@@ -36,7 +36,6 @@
36import subprocess36import subprocess
37import weakref37import weakref
3838
39from bzrlib.plugins.builder.recipe import RecipeParser
40import pytz39import pytz
41from sqlobject import (40from sqlobject import (
42 BoolCol,41 BoolCol,
@@ -2634,9 +2633,8 @@
2634 registrant, daily_build_archive=None, build_daily=False):2633 registrant, daily_build_archive=None, build_daily=False):
2635 """See `IPerson`."""2634 """See `IPerson`."""
2636 from lp.code.model.sourcepackagerecipe import SourcePackageRecipe2635 from lp.code.model.sourcepackagerecipe import SourcePackageRecipe
2637 builder_recipe = RecipeParser(recipe_text).parse()
2638 recipe = SourcePackageRecipe.new(2636 recipe = SourcePackageRecipe.new(
2639 registrant, self, name, builder_recipe, description, distroseries,2637 registrant, self, name, recipe_text, description, distroseries,
2640 daily_build_archive, build_daily)2638 daily_build_archive, build_daily)
2641 Store.of(recipe).flush()2639 Store.of(recipe).flush()
2642 return recipe2640 return recipe
26432641
=== modified file 'lib/lp/testing/factory.py'
--- lib/lp/testing/factory.py 2010-09-03 16:43:11 +0000
+++ lib/lp/testing/factory.py 2010-09-09 13:41:57 +0000
@@ -2035,7 +2035,7 @@
2035 distroseries=None, name=None,2035 distroseries=None, name=None,
2036 description=None, branches=(),2036 description=None, branches=(),
2037 build_daily=False, daily_build_archive=None,2037 build_daily=False, daily_build_archive=None,
2038 is_stale=None):2038 is_stale=None, recipe=None):
2039 """Make a `SourcePackageRecipe`."""2039 """Make a `SourcePackageRecipe`."""
2040 if registrant is None:2040 if registrant is None:
2041 registrant = self.makePerson()2041 registrant = self.makePerson()
@@ -2051,7 +2051,10 @@
2051 if daily_build_archive is None:2051 if daily_build_archive is None:
2052 daily_build_archive = self.makeArchive(2052 daily_build_archive = self.makeArchive(
2053 distribution=distroseries.distribution, owner=owner)2053 distribution=distroseries.distribution, owner=owner)
2054 recipe = self.makeRecipe(*branches)2054 if recipe is None:
2055 recipe = self.makeRecipeText(*branches)
2056 else:
2057 assert branches == ()
2055 source_package_recipe = getUtility(ISourcePackageRecipeSource).new(2058 source_package_recipe = getUtility(ISourcePackageRecipeSource).new(
2056 registrant, owner, name, recipe, description, [distroseries],2059 registrant, owner, name, recipe, description, [distroseries],
2057 daily_build_archive, build_daily)2060 daily_build_archive, build_daily)
20582061
=== modified file 'utilities/sourcedeps.conf'
--- utilities/sourcedeps.conf 2010-09-03 03:12:39 +0000
+++ utilities/sourcedeps.conf 2010-09-09 13:41:57 +0000
@@ -1,4 +1,4 @@
1bzr-builder lp:~launchpad-pqm/bzr-builder/trunk;revno=651bzr-builder lp:~launchpad-pqm/bzr-builder/trunk;revno=66
2bzr-git lp:~launchpad-pqm/bzr-git/devel;revno=2582bzr-git lp:~launchpad-pqm/bzr-git/devel;revno=258
3bzr-hg lp:~launchpad-pqm/bzr-hg/devel;revno=2833bzr-hg lp:~launchpad-pqm/bzr-hg/devel;revno=283
4bzr-loom lp:~launchpad-pqm/bzr-loom/trunk;revno=484bzr-loom lp:~launchpad-pqm/bzr-loom/trunk;revno=48