Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(315)

Side by Side Diff: recipe_engine/run.py

Issue 2253943003: Formally define step config, pass to stream. (Closed) Base URL: https://github.com/luci/recipes-py@nest-single-event
Patch Set: Rebase Created 4 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 # Copyright 2016 The LUCI Authors. All rights reserved. 1 # Copyright 2016 The LUCI Authors. All rights reserved.
2 # Use of this source code is governed under the Apache License, Version 2.0 2 # Use of this source code is governed under the Apache License, Version 2.0
3 # that can be found in the LICENSE file. 3 # that can be found in the LICENSE file.
4 4
5 """Entry point for fully-annotated builds. 5 """Entry point for fully-annotated builds.
6 6
7 This script is part of the effort to move all builds to annotator-based 7 This script is part of the effort to move all builds to annotator-based
8 systems. Any builder configured to use the AnnotatorFactory.BaseFactory() 8 systems. Any builder configured to use the AnnotatorFactory.BaseFactory()
9 found in scripts/master/factory/annotator_factory.py executes a single 9 found in scripts/master/factory/annotator_factory.py executes a single
10 AddAnnotatedScript step. That step (found in annotator_commands.py) calls 10 AddAnnotatedScript step. That step (found in annotator_commands.py) calls
(...skipping 192 matching lines...) Expand 10 before | Expand all | Expand 10 after
203 properties.pop('root', None) 203 properties.pop('root', None)
204 204
205 # TODO(iannucci): A much better way to do this would be to dynamically 205 # TODO(iannucci): A much better way to do this would be to dynamically
206 # detect if the mirrors are actually available during the execution of the 206 # detect if the mirrors are actually available during the execution of the
207 # recipe. 207 # recipe.
208 if ('use_mirror' not in properties and ( 208 if ('use_mirror' not in properties and (
209 'TESTING_MASTERNAME' in os.environ or 209 'TESTING_MASTERNAME' in os.environ or
210 'TESTING_SLAVENAME' in os.environ)): 210 'TESTING_SLAVENAME' in os.environ)):
211 properties['use_mirror'] = False 211 properties['use_mirror'] = False
212 212
213 with stream_engine.new_step_stream('setup_build') as s: 213 with stream_engine.make_step_stream('setup_build') as s:
214 engine = RecipeEngine(step_runner, properties, universe_view) 214 engine = RecipeEngine(step_runner, properties, universe_view)
215 215
216 # Create all API modules and top level RunSteps function. It doesn't launch 216 # Create all API modules and top level RunSteps function. It doesn't launch
217 # any recipe code yet; RunSteps needs to be called. 217 # any recipe code yet; RunSteps needs to be called.
218 api = None 218 api = None
219 219
220 assert 'recipe' in properties 220 assert 'recipe' in properties
221 recipe = properties['recipe'] 221 recipe = properties['recipe']
222 222
223 properties_to_print = properties.copy() 223 properties_to_print = properties.copy()
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after
290 Knows how to execute steps emitted by a recipe, holds global state such as 290 Knows how to execute steps emitted by a recipe, holds global state such as
291 step history and build properties. Each recipe module API has a reference to 291 step history and build properties. Each recipe module API has a reference to
292 this object. 292 this object.
293 293
294 Recipe modules that are aware of the engine: 294 Recipe modules that are aware of the engine:
295 * properties - uses engine.properties. 295 * properties - uses engine.properties.
296 * step - uses engine.create_step(...), and previous_step_result. 296 * step - uses engine.create_step(...), and previous_step_result.
297 """ 297 """
298 298
299 ActiveStep = collections.namedtuple('ActiveStep', ( 299 ActiveStep = collections.namedtuple('ActiveStep', (
300 'step', 'step_result', 'open_step', 'nest_level')) 300 'config', 'step_result', 'open_step'))
301 301
302 def __init__(self, step_runner, properties, universe_view): 302 def __init__(self, step_runner, properties, universe_view):
303 """See run_steps() for parameter meanings.""" 303 """See run_steps() for parameter meanings."""
304 self._step_runner = step_runner 304 self._step_runner = step_runner
305 self._properties = properties 305 self._properties = properties
306 self._universe_view = universe_view 306 self._universe_view = universe_view
307 307
308 # A stack of ActiveStep objects, holding the most recently executed step at 308 # A stack of ActiveStep objects, holding the most recently executed step at
309 # each nest level (objects deeper in the stack have lower nest levels). 309 # each nest level (objects deeper in the stack have lower nest levels).
310 # When we pop from this stack, we close the corresponding step stream. 310 # When we pop from this stack, we close the corresponding step stream.
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
342 " result. Check to make sure your code isn't doing incorrect logic" 342 " result. Check to make sure your code isn't doing incorrect logic"
343 " with try-finally blocks.") 343 " with try-finally blocks.")
344 return self._step_stack[-1].step_result 344 return self._step_stack[-1].step_result
345 345
346 def _close_through_level(self, level): 346 def _close_through_level(self, level):
347 """Close all open steps whose nest level is >= the supplied level. 347 """Close all open steps whose nest level is >= the supplied level.
348 348
349 Args: 349 Args:
350 level (int): the nest level to close through. 350 level (int): the nest level to close through.
351 """ 351 """
352 while self._step_stack and self._step_stack[-1].nest_level >= level: 352 while self._step_stack and self._step_stack[-1].config.nest_level >= level:
353 cur = self._step_stack.pop() 353 cur = self._step_stack.pop()
354 if cur.step_result: 354 if cur.step_result:
355 cur.step_result.presentation.finalize(cur.open_step.stream) 355 cur.step_result.presentation.finalize(cur.open_step.stream)
356 cur.open_step.finalize() 356 cur.open_step.finalize()
357 357
358 def run_step(self, step): 358 def run_step(self, step_dict):
359 """ 359 """
360 Runs a step. 360 Runs a step.
361 361
362 Args: 362 Args:
363 step: The step to run. 363 step_dict (dict): A step dictionary to run.
364 364
365 Returns: 365 Returns:
366 A StepData object containing the result of running the step. 366 A StepData object containing the result of running the step.
367 """ 367 """
368 step_config = recipe_api._make_step_config(**step_dict)
368 with util.raises((recipe_api.StepFailure, OSError), 369 with util.raises((recipe_api.StepFailure, OSError),
369 self._step_runner.stream_engine): 370 self._step_runner.stream_engine):
370 ok_ret = step.pop('ok_ret')
371 infra_step = step.pop('infra_step')
372
373 step_result = None 371 step_result = None
374 372
375 nest_level = step.get('nest_level', 0) 373 self._close_through_level(step_config.nest_level)
376 self._close_through_level(nest_level)
377 374
378 open_step = self._step_runner.open_step(step) 375 open_step = self._step_runner.open_step(step_config)
379 self._step_stack.append(self.ActiveStep( 376 self._step_stack.append(self.ActiveStep(
380 step=step, 377 config=step_config,
381 step_result=None, 378 step_result=None,
382 open_step=open_step, 379 open_step=open_step))
383 nest_level=nest_level))
384 380
385 step_result = open_step.run() 381 step_result = open_step.run()
386 self._step_stack[-1] = ( 382 self._step_stack[-1] = (
387 self._step_stack[-1]._replace(step_result=step_result)) 383 self._step_stack[-1]._replace(step_result=step_result))
388 384
389 if step_result.retcode in ok_ret: 385 if step_result.retcode in step_config.ok_ret:
390 step_result.presentation.status = 'SUCCESS' 386 step_result.presentation.status = 'SUCCESS'
391 return step_result 387 return step_result
392 else: 388 else:
393 if not infra_step: 389 if not step_config.infra_step:
394 state = 'FAILURE' 390 state = 'FAILURE'
395 exc = recipe_api.StepFailure 391 exc = recipe_api.StepFailure
396 else: 392 else:
397 state = 'EXCEPTION' 393 state = 'EXCEPTION'
398 exc = recipe_api.InfraFailure 394 exc = recipe_api.InfraFailure
399 395
400 step_result.presentation.status = state 396 step_result.presentation.status = state
401 397
402 self._step_stack[-1].open_step.stream.write_line( 398 self._step_stack[-1].open_step.stream.write_line(
403 'step returned non-zero exit code: %d' % step_result.retcode) 399 'step returned non-zero exit code: %d' % step_result.retcode)
404 400
405 raise exc(step['name'], step_result) 401 raise exc(step_config.name, step_result)
406 402
407 def run(self, recipe_script, api): 403 def run(self, recipe_script, api):
408 """Run a recipe represented by a recipe_script object. 404 """Run a recipe represented by a recipe_script object.
409 405
410 This function blocks until recipe finishes. 406 This function blocks until recipe finishes.
411 It mainly executes the recipe, and has some exception handling logic, and 407 It mainly executes the recipe, and has some exception handling logic, and
412 adds the step history to the result. 408 adds the step history to the result.
413 409
414 Args: 410 Args:
415 recipe_script: The recipe to run, as represented by a RecipeScript object. 411 recipe_script: The recipe to run, as represented by a RecipeScript object.
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
457 "reason": "Uncaught Exception: %r" % ex, 453 "reason": "Uncaught Exception: %r" % ex,
458 "traceback": traceback.format_exc().splitlines(), 454 "traceback": traceback.format_exc().splitlines(),
459 "status_code": -1 455 "status_code": -1
460 } 456 }
461 457
462 raise 458 raise
463 459
464 result['name'] = '$result' 460 result['name'] = '$result'
465 return RecipeResult(result) 461 return RecipeResult(result)
466 462
467 def create_step(self, step): # pylint: disable=R0201
468 """Called by step module to instantiate a new step.
469
470 Args:
471 step: ConfigGroup object with information about the step, see
472 recipe_modules/step/config.py.
473
474 Returns:
475 Opaque engine specific object that is understood by 'run_steps' method.
476 """
477 return step.as_jsonish()
478
479 def depend_on(self, recipe, properties, distributor=None): 463 def depend_on(self, recipe, properties, distributor=None):
480 return self.depend_on_multi( 464 return self.depend_on_multi(
481 ((recipe, properties),), distributor=distributor)[0] 465 ((recipe, properties),), distributor=distributor)[0]
482 466
483 def depend_on_multi(self, dependencies, distributor=None): 467 def depend_on_multi(self, dependencies, distributor=None):
484 results = [] 468 results = []
485 for recipe, properties in dependencies: 469 for recipe, properties in dependencies:
486 recipe_script = self._universe_view.load_recipe(recipe) 470 recipe_script = self._universe_view.load_recipe(recipe)
487 471
488 return_schema = getattr(recipe_script, 'RETURN_SCHEMA', None) 472 return_schema = getattr(recipe_script, 'RETURN_SCHEMA', None)
(...skipping 14 matching lines...) Expand all
503 results.append( 487 results.append(
504 loader._invoke_with_properties( 488 loader._invoke_with_properties(
505 run_recipe, properties, recipe_script.PROPERTIES, 489 run_recipe, properties, recipe_script.PROPERTIES,
506 properties.keys())) 490 properties.keys()))
507 except TypeError as e: 491 except TypeError as e:
508 raise TypeError( 492 raise TypeError(
509 "Got %r while trying to call recipe %s with properties %r" % ( 493 "Got %r while trying to call recipe %s with properties %r" % (
510 e, recipe, properties)) 494 e, recipe, properties))
511 495
512 return results 496 return results
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698