Index: recipe_modules/context/api.py |
diff --git a/recipe_modules/context/api.py b/recipe_modules/context/api.py |
index 1e53ce149f24043233733c80b301a333bd9d28ab..5a77154d1d015e81b3da90afde112784bc761ea0 100644 |
--- a/recipe_modules/context/api.py |
+++ b/recipe_modules/context/api.py |
@@ -28,17 +28,16 @@ with api.context(cwd=api.path['start_dir'].join('subdir')): |
``` |
""" |
- |
import collections |
-import os |
-import types |
+import copy |
from contextlib import contextmanager |
-from recipe_engine import recipe_api |
from recipe_engine.config_types import Path |
from recipe_engine.recipe_api import RecipeApi |
+from libs import luci_context as luci_ctx |
+ |
def check_type(name, var, expect): |
if not isinstance(var, expect): # pragma: no cover |
@@ -55,13 +54,17 @@ class ContextApi(RecipeApi): |
self._cwd = [None] |
self._env_prefixes = [{}] |
self._env = [{}] |
+ if self._test_data.enabled: |
+ self._luci_context = [self._test_data.get('luci_context', {})] |
+ else: # pragma: no cover |
+ self._luci_context = [luci_ctx.read_full()] |
self._infra_step = [False] |
self._name_prefix = [''] |
# this could be a number, but it makes the logic easier to use a stack. |
self._nest_level = [0] |
@contextmanager |
- def __call__(self, cwd=None, env_prefixes=None, env=None, |
+ def __call__(self, cwd=None, env_prefixes=None, env=None, luci_context=None, |
increment_nest_level=None, infra_steps=None, name_prefix=None): |
"""Allows adjustment of multiple context values in a single call. |
@@ -72,6 +75,7 @@ class ContextApi(RecipeApi): |
* env_prefixes (dict) - Environmental variable prefix augmentations. See |
below for more info. |
* env (dict) - Environmental variable overrides. See below for more info. |
+ * luci_context (dict) - LUCI_CONTEXT overrides. |
iannucci
2017/08/04 18:55:50
"see below for more info"
|
* increment_nest_level (True) - increment the nest level by 1 in this |
context. Typically you won't directly interact with this, but should |
use api.step.nest instead. |
@@ -117,6 +121,17 @@ class ContextApi(RecipeApi): |
defined in "env", it will be installed as the last path component if it is |
not empty. |
+ LUCI_CONTEXT overrides: |
+ |
+ This is advanced stuff. LUCI_CONTEXT is used to pass ambient information |
+ between layers of LUCI stack. 'luci_context' can be used to replace, add or |
+ pop items in the current LUCI_CONTEXT. Unlike 'env', LUCI_CONTEXT contains |
+ structured values, so values of 'luci_context' dict can be anything (not |
+ only strings), and we are not attempting to merge them in any way, e.g |
+ there's no equivalent of %(PATH)s trick. |
iannucci
2017/08/04 18:55:50
we're going to delete the %(PATH) trick anyway, so
|
+ |
+ See https://github.com/luci/client-py/blob/master/LUCI_CONTEXT.md. |
+ |
**TODO(iannucci): combine nest_level and name_prefix** |
Look at the examples in "examples/" for examples of context module usage. |
@@ -182,6 +197,20 @@ class ContextApi(RecipeApi): |
new[k] = v |
_push(self._env, new) |
+ if luci_context is not None and len(luci_context) > 0: |
+ check_type('luci_context', luci_context, dict) |
+ new = dict(self._luci_context[-1]) |
+ for k, v in luci_context.iteritems(): |
+ k = str(k) |
+ if v is None: |
+ new.pop(k, None) |
+ elif isinstance(v, dict): |
+ new[k] = copy.deepcopy(v) |
iannucci
2017/08/04 18:55:51
can we assert that v is serializable to json? Othe
|
+ else: |
+ raise TypeError( |
+ 'Bad type for LUCI_CONTEXT[%r]: %s', k, type(v).__name__) |
+ _push(self._luci_context, new) |
+ |
try: |
yield |
finally: |
@@ -228,6 +257,20 @@ class ContextApi(RecipeApi): |
return dict(self._env_prefixes[-1]) |
@property |
+ def luci_context(self): |
+ """Returns a dict with current state of LUCI_CONTEXT. |
+ |
+ This is advanced stuff. LUCI_CONTEXT is used to pass ambient information |
+ between layers of LUCI stack. Unlike 'env', it MAY be populated with |
+ information about LUCI execution environment when recipe engine starts. |
+ |
+ Do not dump the entirety of LUCI_CONTEXT into logs, it may contain secrets. |
iannucci
2017/08/04 18:55:50
s/may contain/contains
make them scared :)
|
+ |
+ See https://github.com/luci/client-py/blob/master/LUCI_CONTEXT.md. |
+ """ |
+ return dict(self._luci_context[-1]) |
+ |
+ @property |
def infra_step(self): |
"""Returns the current value of the infra_step setting. |