Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(161)

Side by Side Diff: recipe_engine/recipe_api.py

Issue 2933473002: [context] Split "env" values and prefixes. (Closed)
Patch Set: fix typo Created 3 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « bootstrap/bootstrap_vpython.py ('k') | recipe_engine/step_runner.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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',
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, mapping environment
197 variable names to EnvPrefix values.
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
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 environment variable is specified, the current environment's value
236 will be appended, unless it's empty: <prefix0>:...:<prefixN>[:ENV]?
237 - If an environment 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
245 class EnvPrefix(collections.namedtuple('_EnvPrefix', (
246 'prefixes', 'pathsep'))):
247 """Expresses a series of environment prefixes.
248
249 This is used as StepConfig's "env_prefix" value.
250 """
251
252 @classmethod
253 def empty(cls):
254 return cls(prefixes={}, pathsep=None)
255
256
228 _RENDER_WHITELIST=frozenset(( 257 _RENDER_WHITELIST=frozenset((
229 'cmd', 258 'cmd',
230 )) 259 ))
231 260
232 _RENDER_BLACKLIST=frozenset(( 261 _RENDER_BLACKLIST=frozenset((
233 'base_name', 262 'base_name',
234 'nest_level', 263 'nest_level',
235 'ok_ret', 264 'ok_ret',
236 'step_test_data', 265 'step_test_data',
237 )) 266 ))
238 267
239 def __new__(cls, **kwargs): 268 def __new__(cls, **kwargs):
240 for field in cls._fields: 269 for field in cls._fields:
241 kwargs.setdefault(field, None) 270 kwargs.setdefault(field, None)
242 sc = super(StepClient.StepConfig, cls).__new__(cls, **kwargs) 271 sc = super(StepClient.StepConfig, cls).__new__(cls, **kwargs)
243 272
244 return sc._replace( 273 return sc._replace(
245 cmd=[(x if isinstance(x, Placeholder) else str(x)) 274 cmd=[(x if isinstance(x, Placeholder) else str(x))
246 for x in (sc.cmd or ())], 275 for x in (sc.cmd or ())],
247 cwd=(str(sc.cwd) if sc.cwd else (None)), 276 cwd=(str(sc.cwd) if sc.cwd else (None)),
277 env=sc.env or {},
278 env_prefixes=sc.env_prefixes or cls.EnvPrefix.empty(),
248 base_name=sc.base_name or sc.name, 279 base_name=sc.base_name or sc.name,
249 allow_subannotations=bool(sc.allow_subannotations), 280 allow_subannotations=bool(sc.allow_subannotations),
250 trigger_specs=sc.trigger_specs or (), 281 trigger_specs=sc.trigger_specs or (),
251 infra_step=bool(sc.infra_step), 282 infra_step=bool(sc.infra_step),
252 ok_ret=frozenset(sc.ok_ret or (0,)), 283 ok_ret=frozenset(sc.ok_ret or (0,)),
253 nest_level=int(sc.nest_level or 0), 284 nest_level=int(sc.nest_level or 0),
254 ) 285 )
255 286
256 def render_to_dict(self): 287 def render_to_dict(self):
257 sc = self._replace( 288 sc = self._replace(
289 env_prefixes={k: list(str(e) for e in v)
290 for k, v in self.env_prefixes.prefixes.iteritems()},
258 trigger_specs=[trig._render_to_dict() 291 trigger_specs=[trig._render_to_dict()
259 for trig in (self.trigger_specs or ())], 292 for trig in (self.trigger_specs or ())],
260 ) 293 )
261 return dict((k, v) for k, v in sc._asdict().iteritems() 294 return dict((k, v) for k, v in sc._asdict().iteritems()
262 if (v or k in sc._RENDER_WHITELIST) 295 if (v or k in sc._RENDER_WHITELIST)
263 and k not in sc._RENDER_BLACKLIST) 296 and k not in sc._RENDER_BLACKLIST)
264 297
265 298
266 class TriggerSpec(collections.namedtuple('_TriggerSpec', ( 299 class TriggerSpec(collections.namedtuple('_TriggerSpec', (
267 'bucket', 'builder_name', 'properties', 'buildbot_changes', 'tags', 300 'bucket', 'builder_name', 'properties', 'buildbot_changes', 'tags',
(...skipping 787 matching lines...) Expand 10 before | Expand all | Expand 10 after
1055 def bind(self, name, property_type, full_decl_name): 1088 def bind(self, name, property_type, full_decl_name):
1056 """ 1089 """
1057 Gets the BoundProperty version of this Property. Requires a name. 1090 Gets the BoundProperty version of this Property. Requires a name.
1058 """ 1091 """
1059 return BoundProperty( 1092 return BoundProperty(
1060 self._default, self.help, self.kind, name, property_type, full_decl_name, 1093 self._default, self.help, self.kind, name, property_type, full_decl_name,
1061 self.param_name) 1094 self.param_name)
1062 1095
1063 class UndefinedPropertyException(TypeError): 1096 class UndefinedPropertyException(TypeError):
1064 pass 1097 pass
OLDNEW
« no previous file with comments | « bootstrap/bootstrap_vpython.py ('k') | recipe_engine/step_runner.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698