| 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 from __future__ import absolute_import | 5 from __future__ import absolute_import |
| 6 import bisect | 6 import bisect |
| 7 import collections | 7 import collections |
| 8 import contextlib | 8 import contextlib |
| 9 import copy | 9 import copy |
| 10 import json | 10 import json |
| 11 import keyword | 11 import keyword |
| 12 import os |
| 12 import re | 13 import re |
| 13 import types | 14 import types |
| 14 | 15 |
| 15 from functools import wraps | 16 from functools import wraps |
| 16 | 17 |
| 17 from .recipe_test_api import DisabledTestData, ModuleTestData | 18 from .recipe_test_api import DisabledTestData, ModuleTestData |
| 18 from .config import Single | 19 from .config import Single |
| 19 from .util import ModuleInjectionSite, Placeholder | 20 from .util import ModuleInjectionSite, Placeholder |
| 20 | 21 |
| 21 | 22 |
| (...skipping 144 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 166 return copy.deepcopy(self._engine.properties) | 167 return copy.deepcopy(self._engine.properties) |
| 167 | 168 |
| 168 | 169 |
| 169 class StepClient(object): | 170 class StepClient(object): |
| 170 """A recipe engine client representing step running and introspection.""" | 171 """A recipe engine client representing step running and introspection.""" |
| 171 | 172 |
| 172 IDENT = 'step' | 173 IDENT = 'step' |
| 173 | 174 |
| 174 | 175 |
| 175 class StepConfig(collections.namedtuple('_StepConfig', ( | 176 class StepConfig(collections.namedtuple('_StepConfig', ( |
| 176 'name', 'base_name', 'cmd', 'cwd', 'env', 'allow_subannotations', | 177 'name', 'base_name', 'cmd', 'cwd', 'env', 'env_prefixes', 'pathsep', |
| 177 'trigger_specs', 'timeout', 'infra_step', 'stdout', 'stderr', 'stdin', | 178 'allow_subannotations', 'trigger_specs', 'timeout', 'infra_step', |
| 178 'ok_ret', 'step_test_data', 'nest_level'))): | 179 'stdout', 'stderr', 'stdin', 'ok_ret', 'step_test_data', 'nest_level'))): |
| 179 | 180 |
| 180 """ | 181 """ |
| 181 StepConfig is the representation of a raw step as the recipe_engine sees it. | 182 StepConfig is the representation of a raw step as the recipe_engine sees it. |
| 182 You should use the standard 'step' recipe module, which will construct and | 183 You should use the standard 'step' recipe module, which will construct and |
| 183 pass this data to the engine for you, instead. The only reason why you would | 184 pass this data to the engine for you, instead. The only reason why you would |
| 184 need to worry about this object is if you're modifying the step module | 185 need to worry about this object is if you're modifying the step module |
| 185 itself. | 186 itself. |
| 186 | 187 |
| 187 Fields: | 188 Fields: |
| 188 name (str): name of the step, will appear in buildbots waterfall | 189 name (str): name of the step, will appear in buildbots waterfall |
| 189 base_name (str): the base name of the step. If the step has a derived | 190 base_name (str): the base name of the step. If the step has a derived |
| 190 name (e.g., nested may be concatenated with its parent), this is the | 191 name (e.g., nested may be concatenated with its parent), this is the |
| 191 name component of just this step. If None, this will be set to "name". | 192 name component of just this step. If None, this will be set to "name". |
| 192 cmd: command to run. Acceptable types: str, Path, Placeholder, or None. | 193 cmd: command to run. Acceptable types: str, Path, Placeholder, or None. |
| 193 cwd (str or None): absolute path to working directory for the command | 194 cwd (str or None): absolute path to working directory for the command |
| 194 env (dict): overrides for environment variables, described above. | 195 env (dict): overrides for environment variables, described above. |
| 196 env_prefixes (dict): environment prefix variables, described above. |
| 197 pathsep (str): system path enviornment variable separator. |
| 195 allow_subannotations (bool): if True, lets the step emit its own | 198 allow_subannotations (bool): if True, lets the step emit its own |
| 196 annotations. NOTE: Enabling this can cause some buggy behavior. Please | 199 annotations. NOTE: Enabling this can cause some buggy behavior. Please |
| 197 strongly consider using step_result.presentation instead. If you have | 200 strongly consider using step_result.presentation instead. If you have |
| 198 questions, please contact infra-dev@chromium.org. | 201 questions, please contact infra-dev@chromium.org. |
| 199 trigger_specs: a list of trigger specifications, see also _trigger_builds. | 202 trigger_specs: a list of trigger specifications, see also _trigger_builds. |
| 200 timeout: if not None, a datetime.timedelta for the step timeout. | 203 timeout: if not None, a datetime.timedelta for the step timeout. |
| 201 infra_step: if True, this is an infrastructure step. Failures will raise | 204 infra_step: if True, this is an infrastructure step. Failures will raise |
| 202 InfraFailure instead of StepFailure. | 205 InfraFailure instead of StepFailure. |
| 203 stdout: Placeholder to put step stdout into. If used, stdout won't appear | 206 stdout: Placeholder to put step stdout into. If used, stdout won't appear |
| 204 in annotator's stdout (and |allow_subannotations| is ignored). | 207 in annotator's stdout (and |allow_subannotations| is ignored). |
| (...skipping 11 matching lines...) Expand all Loading... |
| 216 | 219 |
| 217 The optional "env" parameter provides optional overrides for environment | 220 The optional "env" parameter provides optional overrides for environment |
| 218 variables. Each value is % formatted with the entire existing os.environ. A | 221 variables. Each value is % formatted with the entire existing os.environ. A |
| 219 value of `None` will remove that envvar from the environ. e.g. | 222 value of `None` will remove that envvar from the environ. e.g. |
| 220 | 223 |
| 221 { | 224 { |
| 222 "envvar": "%(envvar)s;%(envvar2)s;extra", | 225 "envvar": "%(envvar)s;%(envvar2)s;extra", |
| 223 "delete_this": None, | 226 "delete_this": None, |
| 224 "static_value": "something", | 227 "static_value": "something", |
| 225 } | 228 } |
| 229 |
| 230 The optional "env_prefixes" parameter contains values that, if specified, |
| 231 will transform an environment variable into a "pathsep"-delimited sequence |
| 232 of items: |
| 233 - If an environment variable is also specified for this key, it will be |
| 234 appended as the last element: <prefix0>:...:<prefixN>:ENV |
| 235 - If no enviornment variable is specified, the current environment's value |
| 236 will be appended, unless it's empty: <prefix0>:...:<prefixN>[:ENV]? |
| 237 - If an enviornment variable with a value of None (delete) is specified, |
| 238 nothing will be appeneded: <prefix0>:...:<prefixN> |
| 239 |
| 240 There is currently no way to remove prefix paths; once they're there, |
| 241 they're there for good. If you think you need to remove paths from the |
| 242 prefix lists, please talk to infra-dev@chromium.org. |
| 226 """ | 243 """ |
| 227 | 244 |
| 228 _RENDER_WHITELIST=frozenset(( | 245 _RENDER_WHITELIST=frozenset(( |
| 229 'cmd', | 246 'cmd', |
| 230 )) | 247 )) |
| 231 | 248 |
| 232 _RENDER_BLACKLIST=frozenset(( | 249 _RENDER_BLACKLIST=frozenset(( |
| 233 'base_name', | 250 'base_name', |
| 234 'nest_level', | 251 'nest_level', |
| 235 'ok_ret', | 252 'ok_ret', |
| 253 'pathsep', |
| 236 'step_test_data', | 254 'step_test_data', |
| 237 )) | 255 )) |
| 238 | 256 |
| 239 def __new__(cls, **kwargs): | 257 def __new__(cls, **kwargs): |
| 240 for field in cls._fields: | 258 for field in cls._fields: |
| 241 kwargs.setdefault(field, None) | 259 kwargs.setdefault(field, None) |
| 242 sc = super(StepClient.StepConfig, cls).__new__(cls, **kwargs) | 260 sc = super(StepClient.StepConfig, cls).__new__(cls, **kwargs) |
| 243 | 261 |
| 244 return sc._replace( | 262 return sc._replace( |
| 245 cmd=[(x if isinstance(x, Placeholder) else str(x)) | 263 cmd=[(x if isinstance(x, Placeholder) else str(x)) |
| 246 for x in (sc.cmd or ())], | 264 for x in (sc.cmd or ())], |
| 247 cwd=(str(sc.cwd) if sc.cwd else (None)), | 265 cwd=(str(sc.cwd) if sc.cwd else (None)), |
| 266 env=sc.env or {}, |
| 267 env_prefixes={k: tuple(str(x) for x in v) |
| 268 for k, v in (sc.env_prefixes or {}).iteritems()}, |
| 269 pathsep=sc.pathsep or os.pathsep, |
| 248 base_name=sc.base_name or sc.name, | 270 base_name=sc.base_name or sc.name, |
| 249 allow_subannotations=bool(sc.allow_subannotations), | 271 allow_subannotations=bool(sc.allow_subannotations), |
| 250 trigger_specs=sc.trigger_specs or (), | 272 trigger_specs=sc.trigger_specs or (), |
| 251 infra_step=bool(sc.infra_step), | 273 infra_step=bool(sc.infra_step), |
| 252 ok_ret=frozenset(sc.ok_ret or (0,)), | 274 ok_ret=frozenset(sc.ok_ret or (0,)), |
| 253 nest_level=int(sc.nest_level or 0), | 275 nest_level=int(sc.nest_level or 0), |
| 254 ) | 276 ) |
| 255 | 277 |
| 256 def render_to_dict(self): | 278 def render_to_dict(self): |
| 257 sc = self._replace( | 279 sc = self._replace( |
| 280 env_prefixes={k: list(v) for k, v in self.env_prefixes.iteritems()}, |
| 258 trigger_specs=[trig._render_to_dict() | 281 trigger_specs=[trig._render_to_dict() |
| 259 for trig in (self.trigger_specs or ())], | 282 for trig in (self.trigger_specs or ())], |
| 260 ) | 283 ) |
| 261 return dict((k, v) for k, v in sc._asdict().iteritems() | 284 return dict((k, v) for k, v in sc._asdict().iteritems() |
| 262 if (v or k in sc._RENDER_WHITELIST) | 285 if (v or k in sc._RENDER_WHITELIST) |
| 263 and k not in sc._RENDER_BLACKLIST) | 286 and k not in sc._RENDER_BLACKLIST) |
| 264 | 287 |
| 265 | 288 |
| 266 class TriggerSpec(collections.namedtuple('_TriggerSpec', ( | 289 class TriggerSpec(collections.namedtuple('_TriggerSpec', ( |
| 267 'bucket', 'builder_name', 'properties', 'buildbot_changes', 'tags', | 290 'bucket', 'builder_name', 'properties', 'buildbot_changes', 'tags', |
| (...skipping 787 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1055 def bind(self, name, property_type, full_decl_name): | 1078 def bind(self, name, property_type, full_decl_name): |
| 1056 """ | 1079 """ |
| 1057 Gets the BoundProperty version of this Property. Requires a name. | 1080 Gets the BoundProperty version of this Property. Requires a name. |
| 1058 """ | 1081 """ |
| 1059 return BoundProperty( | 1082 return BoundProperty( |
| 1060 self._default, self.help, self.kind, name, property_type, full_decl_name, | 1083 self._default, self.help, self.kind, name, property_type, full_decl_name, |
| 1061 self.param_name) | 1084 self.param_name) |
| 1062 | 1085 |
| 1063 class UndefinedPropertyException(TypeError): | 1086 class UndefinedPropertyException(TypeError): |
| 1064 pass | 1087 pass |
| OLD | NEW |