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 or None to create | |
100 a no-op fake step. | |
101 ok_ret (tuple or set of ints, str): allowed return codes. Any unexpected | |
102 return codes will cause an exception to be thrown. If you pass in the | |
103 value 'any' or 'all', the engine will allow any return code to be | |
104 returned. Defaults to {0} | |
105 infra_step: Whether or not this is an infrastructure step. Infrastructure | |
106 steps will place the step in an EXCEPTION state and raise InfraFailure. | |
107 wrapper: If supplied, a command to prepend to the executed step as a | |
108 command wrapper. | |
109 **kwargs: Additional entries to add to the annotator.py step dictionary. | |
110 | |
111 Returns: | |
112 Opaque step object produced and understood by recipe engine. | |
113 """ | |
114 assert 'shell' not in kwargs | |
115 assert cmd is None or isinstance(cmd, list) | |
116 if not ok_ret: | |
117 ok_ret = {0} | |
118 if ok_ret in ('any', 'all'): | |
119 ok_ret = set(range(-256, 256)) | |
120 | |
121 if cmd is not None: | |
122 command = list(wrapper) | |
123 command += cmd | |
124 kwargs['cmd'] = command | |
125 | |
126 kwargs['ok_ret'] = ok_ret | |
127 kwargs['infra_step'] = bool(infra_step) | |
128 | |
129 # Obtain information from composite step parent. | |
130 compositor = recipe_api._STEP_CONTEXT | |
131 name = compositor.get_with_context('name', name) | |
132 kwargs['env'] = compositor.get_with_context('env', kwargs.get('env', {})) | |
133 kwargs['step_nest_level'] = compositor.get_with_context('nest_level', 0) | |
134 kwargs.setdefault('cwd', self.m.path['slave_build']) | |
135 | |
136 # Disambiguate repeated names | |
137 step_count = self._step_names.setdefault(name, 0) + 1 | |
138 self._step_names[name] = step_count | |
139 if step_count > 1: | |
140 name = "%s (%d)" % (name, step_count) | |
141 kwargs['name'] = name | |
142 | |
143 schema = self.make_config() | |
144 schema.set_val(kwargs) | |
145 return self.run_from_dict(self._engine.create_step(schema)) | |
146 | |
147 # TODO(martiniss) delete, and make generator_script use **kwargs on step() | |
148 @recipe_api.composite_step | |
149 def run_from_dict(self, dct): | |
150 return self._engine.run_step(dct) | |
OLD | NEW |