| OLD | NEW |
| (Empty) |
| 1 # Copyright 2013 The Chromium Authors. All rights reserved. | |
| 2 # Use of this source code is governed by a BSD-style license that can be | |
| 3 # found in the LICENSE file. | |
| 4 | |
| 5 import contextlib | |
| 6 | |
| 7 from recipe_engine import recipe_api | |
| 8 | |
| 9 | |
| 10 # Inherit from RecipeApiPlain because the only thing which is a step is | |
| 11 # run_from_dict() | |
| 12 class StepApi(recipe_api.RecipeApiPlain): | |
| 13 def __init__(self, **kwargs): | |
| 14 super(StepApi, self).__init__(**kwargs) | |
| 15 self._step_names = {} | |
| 16 | |
| 17 EXCEPTION = 'EXCEPTION' | |
| 18 FAILURE = 'FAILURE' | |
| 19 SUCCESS = 'SUCCESS' | |
| 20 WARNING = 'WARNING' | |
| 21 | |
| 22 @property | |
| 23 def StepFailure(self): | |
| 24 """ See recipe_api.py for docs. """ | |
| 25 return recipe_api.StepFailure | |
| 26 | |
| 27 @property | |
| 28 def StepWarning(self): | |
| 29 """ See recipe_api.py for docs. """ | |
| 30 return recipe_api.StepWarning | |
| 31 | |
| 32 @property | |
| 33 def InfraFailure(self): | |
| 34 """ See recipe_api.py for docs. """ | |
| 35 return recipe_api.InfraFailure | |
| 36 | |
| 37 @property | |
| 38 def active_result(self): | |
| 39 """The currently active (open) result from the last step that was run. | |
| 40 | |
| 41 Allows you to do things like: | |
| 42 try: | |
| 43 api.step('run test', [..., api.json.output()]) | |
| 44 finally: | |
| 45 result = api.step.active_result | |
| 46 if result.json.output: | |
| 47 new_step_text = result.json.output['step_text'] | |
| 48 api.step.active_result.presentation.step_text = new_step_text | |
| 49 | |
| 50 This will update the step_text of the test, even if the test fails. Without | |
| 51 this api, the above code would look like: | |
| 52 | |
| 53 try: | |
| 54 result = api.step('run test', [..., api.json.output()]) | |
| 55 except api.StepFailure as f: | |
| 56 result = f.result | |
| 57 raise | |
| 58 finally: | |
| 59 if result.json.output: | |
| 60 new_step_text = result.json.output['step_text'] | |
| 61 api.step.active_result.presentation.step_text = new_step_text | |
| 62 """ | |
| 63 return self._engine.previous_step_result | |
| 64 | |
| 65 @property | |
| 66 def context(self): | |
| 67 """ See recipe_api.py for docs. """ | |
| 68 return recipe_api.context | |
| 69 | |
| 70 @contextlib.contextmanager | |
| 71 def nest(self, name): | |
| 72 """Nest is the high-level interface to annotated hierarchical steps. | |
| 73 | |
| 74 Calling | |
| 75 | |
| 76 with api.step.nest(<name>): | |
| 77 ... | |
| 78 | |
| 79 will generate a dummy step and implicitly create a new context (as | |
| 80 above); the dummy step will govern annotation emission, while the implicit | |
| 81 context will propagate the dummy step's name to subordinate steps. | |
| 82 """ | |
| 83 self(name, []) | |
| 84 context_dict = {'name': name, 'nest_level': 1} | |
| 85 with self.context(context_dict): | |
| 86 yield | |
| 87 | |
| 88 @property | |
| 89 def defer_results(self): | |
| 90 """ See recipe_api.py for docs. """ | |
| 91 return recipe_api.defer_results | |
| 92 | |
| 93 def __call__(self, name, cmd, ok_ret=None, infra_step=False, wrapper=(), | |
| 94 **kwargs): | |
| 95 """Returns a step dictionary which is compatible with annotator.py. | |
| 96 | |
| 97 Args: | |
| 98 name (string): The name of this step. | |
| 99 cmd (list of strings): in the style of subprocess.Popen. | |
| 100 ok_ret (tuple or set of ints, str): allowed return codes. Any unexpected | |
| 101 return codes will cause an exception to be thrown. If you pass in the | |
| 102 value 'any' or 'all', the engine will allow any return code to be | |
| 103 returned. Defaults to {0} | |
| 104 infra_step: Whether or not this is an infrastructure step. Infrastructure | |
| 105 steps will place the step in an EXCEPTION state and raise InfraFailure. | |
| 106 wrapper: If supplied, a command to prepend to the executed step as a | |
| 107 command wrapper. | |
| 108 **kwargs: Additional entries to add to the annotator.py step dictionary. | |
| 109 | |
| 110 Returns: | |
| 111 Opaque step object produced and understood by recipe engine. | |
| 112 """ | |
| 113 assert 'shell' not in kwargs | |
| 114 assert isinstance(cmd, list) | |
| 115 if not ok_ret: | |
| 116 ok_ret = {0} | |
| 117 if ok_ret in ('any', 'all'): | |
| 118 ok_ret = set(range(-256, 256)) | |
| 119 | |
| 120 command = list(wrapper) | |
| 121 command += cmd | |
| 122 compositor = recipe_api._STEP_CONTEXT | |
| 123 kwargs['cmd'] = command | |
| 124 step_count = self._step_names.setdefault(name, 0) + 1 | |
| 125 self._step_names[name] = step_count | |
| 126 if step_count > 1: | |
| 127 name = "%s (%d)" % (name, step_count) | |
| 128 | |
| 129 kwargs['ok_ret'] = ok_ret | |
| 130 kwargs['infra_step'] = bool(infra_step) | |
| 131 | |
| 132 # Obtain information from composite step parent. | |
| 133 kwargs['name'] = compositor.get_with_context('name', name) | |
| 134 kwargs['env'] = compositor.get_with_context('env', kwargs.get('env', {})) | |
| 135 kwargs['step_nest_level'] = compositor.get_with_context('nest_level', 0) | |
| 136 kwargs.setdefault('cwd', self.m.path['slave_build']) | |
| 137 | |
| 138 schema = self.make_config() | |
| 139 schema.set_val(kwargs) | |
| 140 return self.run_from_dict(self._engine.create_step(schema)) | |
| 141 | |
| 142 # TODO(martiniss) delete, and make generator_script use **kwargs on step() | |
| 143 @recipe_api.composite_step | |
| 144 def run_from_dict(self, dct): | |
| 145 return self._engine.run_step(dct) | |
| OLD | NEW |