Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 # Copyright 2013 The LUCI Authors. All rights reserved. | 1 # Copyright 2013 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 import contextlib | 5 import contextlib |
| 6 import copy | 6 import copy |
| 7 import types | |
| 7 | 8 |
| 8 from recipe_engine import recipe_api | 9 from recipe_engine import recipe_api |
| 10 from recipe_engine.config_types import Path | |
| 11 from recipe_engine.util import Placeholder | |
| 9 | 12 |
| 10 | 13 |
| 11 # Inherit from RecipeApiPlain because the only thing which is a step is | 14 # Inherit from RecipeApiPlain because the only thing which is a step is |
| 12 # run_from_dict() | 15 # run_from_dict() |
| 13 class StepApi(recipe_api.RecipeApiPlain): | 16 class StepApi(recipe_api.RecipeApiPlain): |
| 14 | 17 |
| 15 step_client = recipe_api.RequireClient('step') | 18 step_client = recipe_api.RequireClient('step') |
| 16 | 19 |
| 17 def __init__(self, step_properties, **kwargs): | 20 def __init__(self, step_properties, **kwargs): |
| 18 super(StepApi, self).__init__(**kwargs) | 21 super(StepApi, self).__init__(**kwargs) |
| (...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 116 infra_step: Whether or not this is an infrastructure step. Infrastructure | 119 infra_step: Whether or not this is an infrastructure step. Infrastructure |
| 117 steps will place the step in an EXCEPTION state and raise InfraFailure. | 120 steps will place the step in an EXCEPTION state and raise InfraFailure. |
| 118 wrapper: If supplied, a command to prepend to the executed step as a | 121 wrapper: If supplied, a command to prepend to the executed step as a |
| 119 command wrapper. | 122 command wrapper. |
| 120 timeout: If supplied, the recipe engine will kill the step after the | 123 timeout: If supplied, the recipe engine will kill the step after the |
| 121 specified number of seconds. | 124 specified number of seconds. |
| 122 allow_subannotations (bool): if True, lets the step emit its own | 125 allow_subannotations (bool): if True, lets the step emit its own |
| 123 annotations. NOTE: Enabling this can cause some buggy behavior. Please | 126 annotations. NOTE: Enabling this can cause some buggy behavior. Please |
| 124 strongly consider using step_result.presentation instead. If you have | 127 strongly consider using step_result.presentation instead. If you have |
| 125 questions, please contact infra-dev@chromium.org. | 128 questions, please contact infra-dev@chromium.org. |
| 126 trigger_specs: a list of trigger specifications | 129 trigger_specs: a list of trigger specifications |
|
iannucci
2017/06/12 19:37:57
do you know enough about this to add a bit more do
dnj
2017/06/13 18:28:38
no :(
| |
| 127 stdout: Placeholder to put step stdout into. If used, stdout won't appear | 130 stdout: Placeholder to put step stdout into. If used, stdout won't appear |
| 128 in annotator's stdout (and |allow_subannotations| is ignored). | 131 in annotator's stdout (and |allow_subannotations| is ignored). |
| 129 stderr: Placeholder to put step stderr into. If used, stderr won't appear | 132 stderr: Placeholder to put step stderr into. If used, stderr won't appear |
| 130 in annotator's stderr. | 133 in annotator's stderr. |
| 131 stdin: Placeholder to read step stdin from. | 134 stdin: Placeholder to read step stdin from. |
| 132 step_test_data (func -> recipe_test_api.StepTestData): A factory which | 135 step_test_data (func -> recipe_test_api.StepTestData): A factory which |
| 133 returns a StepTestData object that will be used as the default test | 136 returns a StepTestData object that will be used as the default test |
| 134 data for this step. The recipe author can override/augment this object | 137 data for this step. The recipe author can override/augment this object |
| 135 in the GenTests function. | 138 in the GenTests function. |
| 136 | 139 |
| 137 Returns: | 140 Returns: |
| 138 Opaque step object produced and understood by recipe engine. | 141 Opaque step object produced and understood by recipe engine. |
| 139 """ | 142 """ |
| 140 kwargs = {} | |
| 141 if allow_subannotations is not None: | |
| 142 kwargs['allow_subannotations'] = allow_subannotations | |
| 143 if trigger_specs: | |
| 144 kwargs['trigger_specs'] = trigger_specs | |
| 145 if stdout: | |
| 146 kwargs['stdout'] = stdout | |
| 147 if stderr: | |
| 148 kwargs['stderr'] = stderr | |
| 149 if stdin: | |
| 150 kwargs['stdin'] = stdin | |
| 151 if step_test_data: | |
| 152 kwargs['step_test_data'] = step_test_data | |
| 153 assert cmd is None or isinstance(cmd, list) | |
| 154 if not ok_ret: | |
| 155 ok_ret = {0} | |
| 156 if ok_ret in ('any', 'all'): | |
| 157 ok_ret = set(range(-256, 256)) | |
| 158 | |
| 159 if cmd is not None: | |
| 160 command = list(wrapper) | |
| 161 command += cmd | |
| 162 kwargs['cmd'] = command | |
| 163 | |
| 164 kwargs['timeout'] = timeout | |
| 165 kwargs['ok_ret'] = ok_ret | |
| 166 | |
| 167 # Calculate our full step name. If a step already has that name, add an | 143 # Calculate our full step name. If a step already has that name, add an |
| 168 # index to the end of it. | 144 # index to the end of it. |
| 169 # | 145 # |
| 170 # Note that another step could exist with that index already added to it | 146 # Note that another step could exist with that index already added to it |
| 171 # by the user. If this happens, we'll continue appending indexes until we | 147 # by the user. If this happens, we'll continue appending indexes until we |
| 172 # have a unique step name. | 148 # have a unique step name. |
| 173 with self.m.context(name_prefix=name): | 149 with self.m.context(name_prefix=name): |
| 174 base_name = self.m.context.name_prefix | 150 base_name = self.m.context.name_prefix |
| 175 name_suffix = '' | 151 name_suffix = '' |
| 176 | 152 |
| 177 while True: | 153 while True: |
| 178 full_name = base_name + name_suffix | 154 full_name = base_name + name_suffix |
| 179 if full_name not in self._seen_steps: | 155 if full_name not in self._seen_steps: |
| 180 break | 156 break |
| 181 | 157 |
| 182 step_count = self._step_names.setdefault(full_name, 1) + 1 | 158 step_count = self._step_names.setdefault(full_name, 1) + 1 |
| 183 self._step_names[full_name] = step_count | 159 self._step_names[full_name] = step_count |
| 184 name_suffix = ' (%d)' % step_count | 160 name_suffix = ' (%d)' % step_count |
| 185 self._seen_steps.add(full_name) | 161 self._seen_steps.add(full_name) |
| 186 | 162 |
| 163 assert isinstance(cmd, (types.NoneType, list)) | |
| 164 if cmd is not None: | |
| 165 cmd = list(wrapper) + cmd | |
| 166 assert all(isinstance(x, (int, long, basestring, Path, Placeholder)) | |
| 167 for x in cmd) | |
| 168 | |
| 187 cwd = self.m.context.cwd | 169 cwd = self.m.context.cwd |
| 188 if cwd is not None and cwd != self.m.path['start_dir']: | 170 if cwd and cwd == self.m.path['start_dir']: |
| 189 kwargs['cwd'] = cwd | 171 cwd = None |
| 190 kwargs['env'] = self.m.context.env | 172 |
| 173 env = self.m.context.env | |
| 191 if self._prefix_path: | 174 if self._prefix_path: |
| 192 ps = self.m.path.pathsep | 175 ps = self.m.path.pathsep |
| 193 prefix = ps.join(self._prefix_path) | 176 prefix = ps.join(self._prefix_path) |
| 194 suffix = kwargs['env'].get('PATH', '%(PATH)s') | 177 suffix = env.get('PATH', '%(PATH)s') |
| 195 kwargs['env']['PATH'] = '%s%s%s' % (prefix, ps, suffix) | 178 env['PATH'] = '%s%s%s' % (prefix, ps, suffix) |
| 196 kwargs['infra_step'] = self.m.context.infra_step or bool(infra_step) | |
| 197 kwargs['step_nest_level'] = self.m.context.nest_level | |
| 198 kwargs['name'] = full_name | |
| 199 kwargs['base_name'] = name | |
| 200 | 179 |
| 201 schema = self.make_config() | 180 if ok_ret in ('any', 'all'): |
| 202 schema.set_val(kwargs) | 181 ok_ret = range(-256, 256) |
| 203 return self.run_from_dict(schema.as_jsonish()) | |
| 204 | 182 |
| 205 # TODO(martiniss) delete, and make generator_script use **kwargs on step() | 183 return self.run_step( |
| 184 name=full_name, | |
| 185 base_name=full_name or name, | |
| 186 cmd=cmd, | |
| 187 cwd=cwd, | |
| 188 env=env, | |
| 189 allow_subannotations=bool(allow_subannotations), | |
| 190 trigger_specs=[self._make_trigger_spec(trig) | |
| 191 for trig in (trigger_specs or ())], | |
| 192 timeout=timeout, | |
| 193 infra_step=self.m.context.infra_step or bool(infra_step), | |
| 194 stdout=stdout, | |
| 195 stderr=stderr, | |
| 196 stdin=stdin, | |
| 197 ok_ret=ok_ret, | |
| 198 step_test_data=step_test_data, | |
| 199 nest_level=self.m.context.nest_level, | |
| 200 ) | |
| 201 | |
| 206 @recipe_api.composite_step | 202 @recipe_api.composite_step |
| 207 def run_from_dict(self, dct): | 203 def run_step(self, **kwargs): |
| 208 return self.step_client.run_step(dct) | 204 # TODO(dnj,iannucci): Remove this once "generator_script" is deleted. Make |
| 205 # sure we preserve "composite_step". | |
| 206 return self.step_client.run_step(self.step_client.StepConfig(**kwargs)) | |
|
iannucci
2017/06/12 19:37:57
delete this function
dnj
2017/06/13 18:28:38
Done.
| |
| 207 | |
| 208 def _make_trigger_spec(self, trig): | |
| 209 buildbot_changes = trig.get('buildbot_changes') | |
| 210 assert isinstance(buildbot_changes, (types.NoneType, list)) | |
| 211 | |
| 212 critical = trig.get('critical') | |
| 213 return self.step_client.TriggerSpec( | |
| 214 bucket=trig.get('bucket'), | |
| 215 builder_name=trig['builder_name'], | |
| 216 properties=trig.get('properties'), | |
| 217 buildbot_changes=buildbot_changes, | |
| 218 tags=trig.get('tags'), | |
| 219 critical=bool(critical) if critical is not None else (True), | |
| 220 ) | |
| OLD | NEW |