OLD | NEW |
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 278 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
289 """ | 289 """ |
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 'step', 'step_result', 'open_step', 'nest_level')) |
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 25 matching lines...) Expand all Loading... |
336 | 336 |
337 This always returns the innermost nested step that is still open -- | 337 This always returns the innermost nested step that is still open -- |
338 presumably the one that just failed if we are in an exception handler.""" | 338 presumably the one that just failed if we are in an exception handler.""" |
339 if not self._step_stack: | 339 if not self._step_stack: |
340 raise ValueError( | 340 raise ValueError( |
341 "No steps have been run yet, and you are asking for a previous step" | 341 "No steps have been run yet, and you are asking for a previous step" |
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_to_level(self, level): | 346 def _close_through_level(self, level): |
347 """Close all open steps that are at least as deep as level.""" | 347 """Close all open steps whose nest level is >= the supplied level. |
348 while self._step_stack and level <= self._step_stack[-1].nest_level: | 348 |
| 349 Args: |
| 350 level (int): the nest level to close through. |
| 351 """ |
| 352 while self._step_stack and self._step_stack[-1].nest_level >= level: |
349 cur = self._step_stack.pop() | 353 cur = self._step_stack.pop() |
350 if cur.step_result: | 354 if cur.step_result: |
351 cur.step_result.presentation.finalize(cur.open_step.stream) | 355 cur.step_result.presentation.finalize(cur.open_step.stream) |
352 cur.open_step.finalize() | 356 cur.open_step.finalize() |
353 | 357 |
354 def run_step(self, step): | 358 def run_step(self, step): |
355 """ | 359 """ |
356 Runs a step. | 360 Runs a step. |
357 | 361 |
358 Args: | 362 Args: |
359 step: The step to run. | 363 step: The step to run. |
360 | 364 |
361 Returns: | 365 Returns: |
362 A StepData object containing the result of running the step. | 366 A StepData object containing the result of running the step. |
363 """ | 367 """ |
364 with util.raises((recipe_api.StepFailure, OSError), | 368 with util.raises((recipe_api.StepFailure, OSError), |
365 self._step_runner.stream_engine): | 369 self._step_runner.stream_engine): |
366 ok_ret = step.pop('ok_ret') | 370 ok_ret = step.pop('ok_ret') |
367 infra_step = step.pop('infra_step') | 371 infra_step = step.pop('infra_step') |
368 | 372 |
369 step_result = None | 373 step_result = None |
370 | 374 |
371 nest_level = step.pop('step_nest_level', 0) | 375 nest_level = step.get('nest_level', 0) |
372 self._close_to_level(nest_level) | 376 self._close_through_level(nest_level) |
373 | 377 |
374 open_step = self._step_runner.open_step(step) | 378 open_step = self._step_runner.open_step(step) |
375 self._step_stack.append(self.ActiveStep( | 379 self._step_stack.append(self.ActiveStep( |
376 step=step, | 380 step=step, |
377 step_result=None, | 381 step_result=None, |
378 open_step=open_step, | 382 open_step=open_step, |
379 nest_level=nest_level)) | 383 nest_level=nest_level)) |
380 if nest_level: | |
381 open_step.stream.set_nest_level(nest_level) | |
382 | 384 |
383 step_result = open_step.run() | 385 step_result = open_step.run() |
384 self._step_stack[-1] = ( | 386 self._step_stack[-1] = ( |
385 self._step_stack[-1]._replace(step_result=step_result)) | 387 self._step_stack[-1]._replace(step_result=step_result)) |
386 | 388 |
387 if step_result.retcode in ok_ret: | 389 if step_result.retcode in ok_ret: |
388 step_result.presentation.status = 'SUCCESS' | 390 step_result.presentation.status = 'SUCCESS' |
389 return step_result | 391 return step_result |
390 else: | 392 else: |
391 if not infra_step: | 393 if not infra_step: |
(...skipping 29 matching lines...) Expand all Loading... |
421 | 423 |
422 with self._step_runner.run_context(): | 424 with self._step_runner.run_context(): |
423 try: | 425 try: |
424 try: | 426 try: |
425 recipe_result = recipe_script.run(api, api._engine.properties) | 427 recipe_result = recipe_script.run(api, api._engine.properties) |
426 result = { | 428 result = { |
427 "recipe_result": recipe_result, | 429 "recipe_result": recipe_result, |
428 "status_code": 0 | 430 "status_code": 0 |
429 } | 431 } |
430 finally: | 432 finally: |
431 self._close_to_level(0) | 433 self._close_through_level(0) |
432 except recipe_api.StepFailure as f: | 434 except recipe_api.StepFailure as f: |
433 result = { | 435 result = { |
434 # Include "recipe_result" so it doesn't get marked as infra failure. | 436 # Include "recipe_result" so it doesn't get marked as infra failure. |
435 "recipe_result": None, | 437 "recipe_result": None, |
436 "reason": f.reason, | 438 "reason": f.reason, |
437 "status_code": f.retcode or 1 | 439 "status_code": f.retcode or 1 |
438 } | 440 } |
439 except types.StepDataAttributeError as ex: | 441 except types.StepDataAttributeError as ex: |
440 result = { | 442 result = { |
441 "reason": "Invalid Step Data Access: %r" % ex, | 443 "reason": "Invalid Step Data Access: %r" % ex, |
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
501 results.append( | 503 results.append( |
502 loader._invoke_with_properties( | 504 loader._invoke_with_properties( |
503 run_recipe, properties, recipe_script.PROPERTIES, | 505 run_recipe, properties, recipe_script.PROPERTIES, |
504 properties.keys())) | 506 properties.keys())) |
505 except TypeError as e: | 507 except TypeError as e: |
506 raise TypeError( | 508 raise TypeError( |
507 "Got %r while trying to call recipe %s with properties %r" % ( | 509 "Got %r while trying to call recipe %s with properties %r" % ( |
508 e, recipe, properties)) | 510 e, recipe, properties)) |
509 | 511 |
510 return results | 512 return results |
OLD | NEW |