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

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

Powered by Google App Engine
This is Rietveld 408576698