Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 # Copyright 2017 The LUCI Authors. All rights reserved. | 1 # Copyright 2017 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 """The context module provides APIs for manipulating a few pieces of 'ambient' | 5 """The context module provides APIs for manipulating a few pieces of 'ambient' |
| 6 data that affect how steps are run: | 6 data that affect how steps are run: |
| 7 cwd - The current working directory. | 7 cwd - The current working directory. |
| 8 env - The environment variables. | 8 env - The environment variables. |
| 9 infra_step - Whether or not failures should be treated as infrastructure | 9 infra_step - Whether or not failures should be treated as infrastructure |
| 10 failures vs. normal failures. | 10 failures vs. normal failures. |
| 11 name_prefix - A prefix for all step names. | 11 name_prefix - A prefix for all step names. |
| 12 nest_level - An indicator for the UI of how deeply to nest steps. | 12 nest_level - An indicator for the UI of how deeply to nest steps. |
| 13 | 13 |
| 14 The values here are all scoped using Python's `with` statement; there's no | 14 The values here are all scoped using Python's `with` statement; there's no |
| 15 mechanism to make an open-ended adjustment to these values (i.e. there's no way | 15 mechanism to make an open-ended adjustment to these values (i.e. there's no way |
| 16 to change the cwd permanently for a recipe, except by surrounding the entire | 16 to change the cwd permanently for a recipe, except by surrounding the entire |
| 17 recipe with a with statement). This is done to avoid the surprises that | 17 recipe with a with statement). This is done to avoid the surprises that |
| 18 typically arise with things like os.environ or os.chdir in a normal python | 18 typically arise with things like os.environ or os.chdir in a normal python |
| 19 program. | 19 program. |
| 20 | 20 |
| 21 Example: | 21 Example: |
| 22 with api.context(cwd=api.path['start_dir'].join('subdir')): | 22 with api.context(cwd=api.path['start_dir'].join('subdir')): |
| 23 # this step is run inside of the subdir directory. | 23 # this step is run inside of the subdir directory. |
| 24 api.step("cat subdir/foo", ['cat', './foo']) | 24 api.step("cat subdir/foo", ['cat', './foo']) |
| 25 """ | 25 """ |
| 26 | 26 |
| 27 | 27 |
| 28 import collections | |
| 28 import copy | 29 import copy |
| 29 | 30 |
| 30 from contextlib import contextmanager | 31 from contextlib import contextmanager |
| 31 | 32 |
| 32 from recipe_engine import recipe_api | 33 from recipe_engine import recipe_api |
| 33 from recipe_engine.config_types import Path | 34 from recipe_engine.config_types import Path |
| 34 from recipe_engine.recipe_api import context, RecipeApi | 35 from recipe_engine.recipe_api import context, RecipeApi |
| 35 | 36 |
| 36 | 37 |
| 37 def check_type(name, var, expect): | 38 def check_type(name, var, expect): |
| (...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 130 kwargs['nest_level'] = 1 | 131 kwargs['nest_level'] = 1 |
| 131 | 132 |
| 132 if name_prefix is not None: | 133 if name_prefix is not None: |
| 133 check_type('name_prefix', name_prefix, str) | 134 check_type('name_prefix', name_prefix, str) |
| 134 kwargs['name'] = name_prefix | 135 kwargs['name'] = name_prefix |
| 135 | 136 |
| 136 if env is not None and env != {}: | 137 if env is not None and env != {}: |
| 137 check_type('env', env, dict) | 138 check_type('env', env, dict) |
| 138 # strify everything except None in the env to allow for ints, Paths, etc. | 139 # strify everything except None in the env to allow for ints, Paths, etc. |
| 139 # None has special meaning (i.e. "delete this env key") | 140 # None has special meaning (i.e. "delete this env key") |
| 140 kwargs['env'] = {str(k): (str(v) if v is not None else None) | 141 new_env = {} |
| 141 for k, v in env.iteritems()} | 142 for k, v in env.iteritems(): |
| 143 k = str(k) | |
| 144 if v is not None: | |
| 145 v = str(v) | |
| 146 try: | |
| 147 # This odd little piece of code does the following: | |
| 148 # * add a bogus dictionary format %(foo)s to v. This forces % into | |
| 149 # 'dictionary lookup' mode | |
| 150 # * format the result with a defaultdict. This allows all | |
| 151 # `%(key)s` format lookups to succeed, but any sequential `%s` | |
| 152 # lookups to fail. | |
| 153 # If the string contains any accidental sequential lookups, this | |
| 154 # will raise an exception. If not, then this is a pluasible format | |
| 155 # string. | |
| 156 ("%(foo)s"+v) % collections.defaultdict(str) | |
|
nodir
2017/05/31 21:58:41
use ' ?
iannucci
2017/05/31 22:07:55
Done.
| |
| 157 except Exception: | |
| 158 raise ValueError(('Invalid %%-formatting parameter in envvar, ' | |
| 159 'only %%(ENVVAR)s allowed: %r') % (v,)) | |
| 160 new_env[k] = v | |
| 161 kwargs['env'] = new_env | |
| 142 | 162 |
| 143 if not kwargs: | 163 if not kwargs: |
| 144 yield | 164 yield |
| 145 else: | 165 else: |
| 146 with context(kwargs): | 166 with context(kwargs): |
| 147 yield | 167 yield |
| 148 | 168 |
| 149 @property | 169 @property |
| 150 def cwd(self): | 170 def cwd(self): |
| 151 """Returns the current working directory that steps will run in. | 171 """Returns the current working directory that steps will run in. |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 191 def nest_level(self): | 211 def nest_level(self): |
| 192 """Returns the current 'nesting' level. | 212 """Returns the current 'nesting' level. |
| 193 | 213 |
| 194 Note: This api is low-level, and you should always prefer to use | 214 Note: This api is low-level, and you should always prefer to use |
| 195 `api.step.nest`. This api is included for completeness and documentation | 215 `api.step.nest`. This api is included for completeness and documentation |
| 196 purposes. | 216 purposes. |
| 197 | 217 |
| 198 Returns (int) - The current nesting level. | 218 Returns (int) - The current nesting level. |
| 199 """ | 219 """ |
| 200 return recipe_api._STEP_CONTEXT.get('nest_level', 0) | 220 return recipe_api._STEP_CONTEXT.get('nest_level', 0) |
| OLD | NEW |