Commit 728244f7 authored by Benjamin Pastene's avatar Benjamin Pastene Committed by Commit Bot

Revert "gclient eval: Expand vars while parsing DEPS files"

This reverts commit 88f9c40e.

Reason for revert: suspected to be causing update scripts failures and prevent gce bots from connecting
https://build.chromium.org/deprecated/tryserver.chromium.win/builders/win7_chromium_rel_ng/builds/128479/steps/update_scripts/logs/stdio

Original change's description:
> gclient eval: Expand vars while parsing DEPS files
> 
> Introduce a Parse function that takes care of expanding vars while parsing
> the DEPS file.
> 
> It wraps Exec and exec calls, and supports deferring the expansion until
> later, so gclient flatten gets access to the unexpanded version.
> 
> Bug: 821199
> Change-Id: I943b021cc4474c9cda67b3816b841dd8ada3f5b2
> Reviewed-on: https://chromium-review.googlesource.com/973749
> Commit-Queue: Edward Lesmes <ehmaldonado@chromium.org>
> Reviewed-by: Aaron Gable <agable@chromium.org>
> Reviewed-by: Dirk Pranke <dpranke@chromium.org>

TBR=agable@chromium.org,dpranke@chromium.org,ehmaldonado@chromium.org

Change-Id: Ib9b84c13ef9b56735fd8f714b74a6601c61715e5
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Bug: 821199
Reviewed-on: https://chromium-review.googlesource.com/976721Reviewed-by: 's avatarBenjamin Pastene <bpastene@chromium.org>
Commit-Queue: Benjamin Pastene <bpastene@chromium.org>
parent 88f9c40e
...@@ -736,7 +736,7 @@ class Dependency(gclient_utils.WorkItem, DependencySettings): ...@@ -736,7 +736,7 @@ class Dependency(gclient_utils.WorkItem, DependencySettings):
deps_to_add.sort(key=lambda x: x.name) deps_to_add.sort(key=lambda x: x.name)
return deps_to_add return deps_to_add
def ParseDepsFile(self, expand_vars=True): def ParseDepsFile(self):
"""Parses the DEPS file for this dependency.""" """Parses the DEPS file for this dependency."""
assert not self.deps_parsed assert not self.deps_parsed
assert not self.dependencies assert not self.dependencies
...@@ -765,14 +765,15 @@ class Dependency(gclient_utils.WorkItem, DependencySettings): ...@@ -765,14 +765,15 @@ class Dependency(gclient_utils.WorkItem, DependencySettings):
local_scope = {} local_scope = {}
if deps_content: if deps_content:
# Eval the content.
try: try:
vars_override = self.get_vars() if self._get_option('validate_syntax', False):
if self.parent: local_scope = gclient_eval.Exec(deps_content, filepath)
vars_override.update(self.parent.get_vars()) else:
local_scope = gclient_eval.Parse( global_scope = {
deps_content, expand_vars, 'Var': lambda var_name: '{%s}' % var_name,
self._get_option('validate_syntax', False), }
filepath, vars_override) exec(deps_content, global_scope, local_scope)
except SyntaxError as e: except SyntaxError as e:
gclient_utils.SyntaxErrorToError(filepath, e) gclient_utils.SyntaxErrorToError(filepath, e)
...@@ -987,7 +988,7 @@ class Dependency(gclient_utils.WorkItem, DependencySettings): ...@@ -987,7 +988,7 @@ class Dependency(gclient_utils.WorkItem, DependencySettings):
file_list[i] = file_list[i][1:] file_list[i] = file_list[i][1:]
# Always parse the DEPS file. # Always parse the DEPS file.
self.ParseDepsFile(expand_vars=(command != 'flatten')) self.ParseDepsFile()
self._run_is_done(file_list or [], parsed_url) self._run_is_done(file_list or [], parsed_url)
if command in ('update', 'revert') and not options.noprehooks: if command in ('update', 'revert') and not options.noprehooks:
self.RunPreDepsHooks() self.RunPreDepsHooks()
...@@ -1863,7 +1864,7 @@ it or fix the checkout. ...@@ -1863,7 +1864,7 @@ it or fix the checkout.
print('%s: %s' % (x, entries[x])) print('%s: %s' % (x, entries[x]))
logging.info(str(self)) logging.info(str(self))
def ParseDepsFile(self, expand_vars=None): def ParseDepsFile(self):
"""No DEPS to parse for a .gclient file.""" """No DEPS to parse for a .gclient file."""
raise gclient_utils.Error('Internal error') raise gclient_utils.Error('Internal error')
...@@ -1972,7 +1973,7 @@ class CipdDependency(Dependency): ...@@ -1972,7 +1973,7 @@ class CipdDependency(Dependency):
self._cipd_package = self._cipd_root.add_package( self._cipd_package = self._cipd_root.add_package(
self._cipd_subdir, self._package_name, self._package_version) self._cipd_subdir, self._package_name, self._package_version)
def ParseDepsFile(self, expand_vars=None): def ParseDepsFile(self):
"""CIPD dependencies are not currently allowed to have nested deps.""" """CIPD dependencies are not currently allowed to have nested deps."""
self.add_dependencies_and_close([], []) self.add_dependencies_and_close([], [])
...@@ -2929,9 +2930,7 @@ def CMDsetdep(parser, args): ...@@ -2929,9 +2930,7 @@ def CMDsetdep(parser, args):
'DEPS file %s does not exist.' % options.deps_file) 'DEPS file %s does not exist.' % options.deps_file)
with open(options.deps_file) as f: with open(options.deps_file) as f:
contents = f.read() contents = f.read()
local_scope = gclient_eval.Parse( local_scope = gclient_eval.Exec(contents)
contents, expand_vars=True, validate_syntax=True,
filename=options.deps_file)
for var in options.vars: for var in options.vars:
name, _, value = var.partition('=') name, _, value = var.partition('=')
......
...@@ -37,7 +37,7 @@ class _NodeDict(collections.MutableMapping): ...@@ -37,7 +37,7 @@ class _NodeDict(collections.MutableMapping):
def GetNode(self, key): def GetNode(self, key):
return self.data[key][1] return self.data[key][1]
def SetNode(self, key, value, node): def _SetNode(self, key, value, node):
self.data[key] = (value, node) self.data[key] = (value, node)
...@@ -183,9 +183,8 @@ _GCLIENT_SCHEMA = schema.Schema(_NodeDictSchema({ ...@@ -183,9 +183,8 @@ _GCLIENT_SCHEMA = schema.Schema(_NodeDictSchema({
})) }))
def _gclient_eval(node_or_string, vars_dict, expand_vars, filename): def _gclient_eval(node_or_string, filename='<unknown>'):
"""Safely evaluates a single expression. Returns the result.""" """Safely evaluates a single expression. Returns the result."""
vars_dict = vars_dict or {}
_allowed_names = {'None': None, 'True': True, 'False': False} _allowed_names = {'None': None, 'True': True, 'False': False}
if isinstance(node_or_string, basestring): if isinstance(node_or_string, basestring):
node_or_string = ast.parse(node_or_string, filename=filename, mode='eval') node_or_string = ast.parse(node_or_string, filename=filename, mode='eval')
...@@ -193,15 +192,7 @@ def _gclient_eval(node_or_string, vars_dict, expand_vars, filename): ...@@ -193,15 +192,7 @@ def _gclient_eval(node_or_string, vars_dict, expand_vars, filename):
node_or_string = node_or_string.body node_or_string = node_or_string.body
def _convert(node): def _convert(node):
if isinstance(node, ast.Str): if isinstance(node, ast.Str):
if not expand_vars: return node.s
return node.s
try:
return node.s.format(**vars_dict)
except KeyError as e:
raise ValueError(
'%s was used as a variable, but was not declared in the vars dict '
'(file %r, line %s)' % (
e.message, filename, getattr(node, 'lineno', '<unknown>')))
elif isinstance(node, ast.Num): elif isinstance(node, ast.Num):
return node.n return node.n
elif isinstance(node, ast.Tuple): elif isinstance(node, ast.Tuple):
...@@ -231,18 +222,7 @@ def _gclient_eval(node_or_string, vars_dict, expand_vars, filename): ...@@ -231,18 +222,7 @@ def _gclient_eval(node_or_string, vars_dict, expand_vars, filename):
raise ValueError( raise ValueError(
'Var\'s argument must be a variable name (file %r, line %s)' % ( 'Var\'s argument must be a variable name (file %r, line %s)' % (
filename, getattr(node, 'lineno', '<unknown>'))) filename, getattr(node, 'lineno', '<unknown>')))
if not expand_vars: return '{%s}' % arg
return '{%s}' % arg
if vars_dict is None:
raise ValueError(
'vars must be declared before Var can be used (file %r, line %s)'
% (filename, getattr(node, 'lineno', '<unknown>')))
if arg not in vars_dict:
raise ValueError(
'%s was used as a variable, but was not declared in the vars dict '
'(file %r, line %s)' % (
arg, filename, getattr(node, 'lineno', '<unknown>')))
return vars_dict[arg]
elif isinstance(node, ast.BinOp) and isinstance(node.op, ast.Add): elif isinstance(node, ast.BinOp) and isinstance(node.op, ast.Add):
return _convert(node.left) + _convert(node.right) return _convert(node.left) + _convert(node.right)
elif isinstance(node, ast.BinOp) and isinstance(node.op, ast.Mod): elif isinstance(node, ast.BinOp) and isinstance(node.op, ast.Mod):
...@@ -255,18 +235,13 @@ def _gclient_eval(node_or_string, vars_dict, expand_vars, filename): ...@@ -255,18 +235,13 @@ def _gclient_eval(node_or_string, vars_dict, expand_vars, filename):
return _convert(node_or_string) return _convert(node_or_string)
def Exec(content, expand_vars=True, filename='<unknown>'): def Exec(content, filename='<unknown>'):
"""Safely execs a set of assignments.""" """Safely execs a set of assignments. Mutates |local_scope|."""
node_or_string = ast.parse(content, filename=filename, mode='exec') node_or_string = ast.parse(content, filename=filename, mode='exec')
if isinstance(node_or_string, ast.Expression): if isinstance(node_or_string, ast.Expression):
node_or_string = node_or_string.body node_or_string = node_or_string.body
tokens = { defined_variables = set()
token[2]: list(token)
for token in tokenize.generate_tokens(
cStringIO.StringIO(content).readline)
}
local_scope = _NodeDict({}, tokens)
def _visit_in_module(node): def _visit_in_module(node):
if isinstance(node, ast.Assign): if isinstance(node, ast.Assign):
if len(node.targets) != 1: if len(node.targets) != 1:
...@@ -278,15 +253,15 @@ def Exec(content, expand_vars=True, filename='<unknown>'): ...@@ -278,15 +253,15 @@ def Exec(content, expand_vars=True, filename='<unknown>'):
raise ValueError( raise ValueError(
'invalid assignment: target should be a name (file %r, line %s)' % ( 'invalid assignment: target should be a name (file %r, line %s)' % (
filename, getattr(node, 'lineno', '<unknown>'))) filename, getattr(node, 'lineno', '<unknown>')))
value = _gclient_eval(node.value, local_scope.get('vars', None), value = _gclient_eval(node.value, filename=filename)
expand_vars, filename)
if target.id in local_scope: if target.id in defined_variables:
raise ValueError( raise ValueError(
'invalid assignment: overrides var %r (file %r, line %s)' % ( 'invalid assignment: overrides var %r (file %r, line %s)' % (
target.id, filename, getattr(node, 'lineno', '<unknown>'))) target.id, filename, getattr(node, 'lineno', '<unknown>')))
local_scope.SetNode(target.id, value, node.value) defined_variables.add(target.id)
return target.id, (value, node.value)
else: else:
raise ValueError( raise ValueError(
'unexpected AST node: %s %s (file %r, line %s)' % ( 'unexpected AST node: %s %s (file %r, line %s)' % (
...@@ -294,8 +269,15 @@ def Exec(content, expand_vars=True, filename='<unknown>'): ...@@ -294,8 +269,15 @@ def Exec(content, expand_vars=True, filename='<unknown>'):
getattr(node, 'lineno', '<unknown>'))) getattr(node, 'lineno', '<unknown>')))
if isinstance(node_or_string, ast.Module): if isinstance(node_or_string, ast.Module):
data = []
for stmt in node_or_string.body: for stmt in node_or_string.body:
_visit_in_module(stmt) data.append(_visit_in_module(stmt))
tokens = {
token[2]: list(token)
for token in tokenize.generate_tokens(
cStringIO.StringIO(content).readline)
}
local_scope = _NodeDict(data, tokens)
else: else:
raise ValueError( raise ValueError(
'unexpected AST node: %s %s (file %r, line %s)' % ( 'unexpected AST node: %s %s (file %r, line %s)' % (
...@@ -307,69 +289,6 @@ def Exec(content, expand_vars=True, filename='<unknown>'): ...@@ -307,69 +289,6 @@ def Exec(content, expand_vars=True, filename='<unknown>'):
return _GCLIENT_SCHEMA.validate(local_scope) return _GCLIENT_SCHEMA.validate(local_scope)
def Parse(content, expand_vars, validate_syntax, filename, vars_override=None):
"""Parses DEPS strings.
Executes the Python-like string stored in content, resulting in a Python
dictionary specifyied by the schema above. Supports syntax validation and
variable expansion.
Args:
content: str. DEPS file stored as a string.
expand_vars: bool. Whether variables should be expanded to their values.
validate_syntax: bool. Whether syntax should be validated using the schema
defined above.
filename: str. The name of the DEPS file, or a string describing the source
of the content, e.g. '<string>', '<unknown>'.
vars_override: dict, optional. A dictionary with overrides for the variables
defined by the DEPS file.
Returns:
A Python dict with the parsed contents of the DEPS file, as specified by the
schema above.
"""
# TODO(ehmaldonado): Make validate_syntax = True the only case
if validate_syntax:
return Exec(content, expand_vars, filename)
vars_dict = {}
def _DeepFormat(node):
if isinstance(node, basestring):
return node.format(**vars_dict)
elif isinstance(node, dict):
return {
k.format(**vars_dict): _DeepFormat(v)
for k, v in node.iteritems()
}
elif isinstance(node, list):
return [
_DeepFormat(elem)
for elem in node
]
elif isinstance(node, tuple):
return tuple(
_DeepFormat(elem)
for elem in node
)
else:
return node
local_scope = {}
global_scope = {'Var': lambda var_name: '{%s}' % var_name}
exec(content, global_scope, local_scope)
if 'vars' not in local_scope or not expand_vars:
return local_scope
vars_dict.update(local_scope['vars'])
vars_override = vars_override or {}
for var, value in vars_override.iteritems():
if var in vars_dict:
vars_dict[var] = value
return _DeepFormat(local_scope)
def EvaluateCondition(condition, variables, referenced_variables=None): def EvaluateCondition(condition, variables, referenced_variables=None):
"""Safely evaluates a boolean condition. Returns the result.""" """Safely evaluates a boolean condition. Returns the result."""
if not referenced_variables: if not referenced_variables:
...@@ -497,7 +416,7 @@ def SetVar(gclient_dict, var_name, value): ...@@ -497,7 +416,7 @@ def SetVar(gclient_dict, var_name, value):
"The vars entry for %s has no formatting information." % var_name) "The vars entry for %s has no formatting information." % var_name)
_UpdateAstString(tokens, node, value) _UpdateAstString(tokens, node, value)
gclient_dict['vars'].SetNode(var_name, value, node) gclient_dict['vars']._SetNode(var_name, value, node)
def SetCIPD(gclient_dict, dep_name, package_name, new_version): def SetCIPD(gclient_dict, dep_name, package_name, new_version):
...@@ -531,7 +450,7 @@ def SetCIPD(gclient_dict, dep_name, package_name, new_version): ...@@ -531,7 +450,7 @@ def SetCIPD(gclient_dict, dep_name, package_name, new_version):
new_version = 'version:' + new_version new_version = 'version:' + new_version
_UpdateAstString(tokens, node, new_version) _UpdateAstString(tokens, node, new_version)
packages[0].SetNode('version', new_version, node) packages[0]._SetNode('version', new_version, node)
def SetRevision(gclient_dict, dep_name, new_revision): def SetRevision(gclient_dict, dep_name, new_revision):
...@@ -558,9 +477,8 @@ def SetRevision(gclient_dict, dep_name, new_revision): ...@@ -558,9 +477,8 @@ def SetRevision(gclient_dict, dep_name, new_revision):
SetVar(gclient_dict, node.args[0].s, new_revision) SetVar(gclient_dict, node.args[0].s, new_revision)
else: else:
_UpdateAstString(tokens, node, new_revision) _UpdateAstString(tokens, node, new_revision)
value = _gclient_eval(dep_node, gclient_dict.get('vars', None), value = _gclient_eval(dep_node)
expand_vars=True, filename='<unknown>') dep_dict._SetNode(dep_key, value, dep_node)
dep_dict.SetNode(dep_key, value, dep_node)
if isinstance(gclient_dict['deps'][dep_name], _NodeDict): if isinstance(gclient_dict['deps'][dep_name], _NodeDict):
_UpdateRevision(gclient_dict['deps'][dep_name], 'url') _UpdateRevision(gclient_dict['deps'][dep_name], 'url')
......
...@@ -20,17 +20,6 @@ import gclient_eval ...@@ -20,17 +20,6 @@ import gclient_eval
_SAMPLE_DEPS_FILE = textwrap.dedent("""\ _SAMPLE_DEPS_FILE = textwrap.dedent("""\
vars = {
'git_repo': 'https://example.com/repo.git',
# Some comment with bad indentation
'dep_2_rev': '1ced',
# Some more comments
# 1
# 2
# 3
'dep_3_rev': '5p1e5',
}
deps = { deps = {
'src/dep': Var('git_repo') + '/dep' + '@' + 'deadbeef', 'src/dep': Var('git_repo') + '/dep' + '@' + 'deadbeef',
# Some comment # Some comment
...@@ -56,82 +45,59 @@ deps = { ...@@ -56,82 +45,59 @@ deps = {
'dep_type': 'cipd', 'dep_type': 'cipd',
}, },
} }
""")
vars = {
'git_repo': 'https://example.com/repo.git',
# Some comment with bad indentation
'dep_2_rev': '1ced',
# Some more comments
# 1
# 2
# 3
'dep_3_rev': '5p1e5',
}""")
class GClientEvalTest(unittest.TestCase): class GClientEvalTest(unittest.TestCase):
def test_str(self): def test_str(self):
self.assertEqual( self.assertEqual('foo', gclient_eval._gclient_eval('"foo"'))
'foo',
gclient_eval._gclient_eval('"foo"', vars_dict=None, expand_vars=False,
filename='<unknown>'))
def test_tuple(self): def test_tuple(self):
self.assertEqual( self.assertEqual(('a', 'b'), gclient_eval._gclient_eval('("a", "b")'))
('a', 'b'),
gclient_eval._gclient_eval('("a", "b")', vars_dict=None,
expand_vars=False, filename='<unknown>'))
def test_list(self): def test_list(self):
self.assertEqual( self.assertEqual(['a', 'b'], gclient_eval._gclient_eval('["a", "b"]'))
['a', 'b'],
gclient_eval._gclient_eval('["a", "b"]', vars_dict=None,
expand_vars=False, filename='<unknown>'))
def test_dict(self): def test_dict(self):
self.assertEqual( self.assertEqual({'a': 'b'}, gclient_eval._gclient_eval('{"a": "b"}'))
{'a': 'b'},
gclient_eval._gclient_eval('{"a": "b"}', vars_dict=None,
expand_vars=False, filename='<unknown>'))
def test_name_safe(self): def test_name_safe(self):
self.assertEqual( self.assertEqual(True, gclient_eval._gclient_eval('True'))
True,
gclient_eval._gclient_eval('True', vars_dict=None,
expand_vars=False, filename='<unknown>'))
def test_name_unsafe(self): def test_name_unsafe(self):
with self.assertRaises(ValueError) as cm: with self.assertRaises(ValueError) as cm:
gclient_eval._gclient_eval('UnsafeName', vars_dict=None, gclient_eval._gclient_eval('UnsafeName')
expand_vars=False, filename='<unknown>')
self.assertIn('invalid name \'UnsafeName\'', str(cm.exception)) self.assertIn('invalid name \'UnsafeName\'', str(cm.exception))
def test_invalid_call(self):
with self.assertRaises(ValueError) as cm:
gclient_eval._gclient_eval('Foo("bar")', vars_dict=None,
expand_vars=False, filename='<unknown>')
self.assertIn('Var is the only allowed function', str(cm.exception))
def test_call(self): def test_call(self):
self.assertEqual( self.assertEqual(
'{bar}', '{bar}',
gclient_eval._gclient_eval('Var("bar")', vars_dict=None, gclient_eval._gclient_eval('Var("bar")'))
expand_vars=False, filename='<unknown>'))
def test_plus(self): def test_plus(self):
self.assertEqual( self.assertEqual('foo', gclient_eval._gclient_eval('"f" + "o" + "o"'))
'foo',
gclient_eval._gclient_eval('"f" + "o" + "o"', vars_dict=None,
expand_vars=False, filename='<unknown>'))
def test_format(self): def test_format(self):
self.assertEqual( self.assertEqual('foo', gclient_eval._gclient_eval('"%s" % "foo"'))
'foo',
gclient_eval._gclient_eval('"%s" % "foo"', vars_dict=None,
expand_vars=False, filename='<unknown>'))
def test_not_expression(self): def test_not_expression(self):
with self.assertRaises(SyntaxError) as cm: with self.assertRaises(SyntaxError) as cm:
gclient_eval._gclient_eval( gclient_eval._gclient_eval('def foo():\n pass')
'def foo():\n pass', vars_dict=None, expand_vars=False,
filename='<unknown>')
self.assertIn('invalid syntax', str(cm.exception)) self.assertIn('invalid syntax', str(cm.exception))
def test_not_whitelisted(self): def test_not_whitelisted(self):
with self.assertRaises(ValueError) as cm: with self.assertRaises(ValueError) as cm:
gclient_eval._gclient_eval( gclient_eval._gclient_eval('[x for x in [1, 2, 3]]')
'[x for x in [1, 2, 3]]', vars_dict=None, expand_vars=False,
filename='<unknown>')
self.assertIn( self.assertIn(
'unexpected AST node: <_ast.ListComp object', str(cm.exception)) 'unexpected AST node: <_ast.ListComp object', str(cm.exception))
...@@ -139,9 +105,7 @@ class GClientEvalTest(unittest.TestCase): ...@@ -139,9 +105,7 @@ class GClientEvalTest(unittest.TestCase):
for test_case in itertools.permutations(range(4)): for test_case in itertools.permutations(range(4)):
input_data = ['{'] + ['"%s": "%s",' % (n, n) for n in test_case] + ['}'] input_data = ['{'] + ['"%s": "%s",' % (n, n) for n in test_case] + ['}']
expected = [(str(n), str(n)) for n in test_case] expected = [(str(n), str(n)) for n in test_case]
result = gclient_eval._gclient_eval( result = gclient_eval._gclient_eval(''.join(input_data))
''.join(input_data), vars_dict=None, expand_vars=False,
filename='<unknown>')
self.assertEqual(expected, result.items()) self.assertEqual(expected, result.items())
...@@ -160,11 +124,12 @@ class ExecTest(unittest.TestCase): ...@@ -160,11 +124,12 @@ class ExecTest(unittest.TestCase):
def test_schema_wrong_type(self): def test_schema_wrong_type(self):
with self.assertRaises(schema.SchemaError): with self.assertRaises(schema.SchemaError):
gclient_eval.Exec('include_rules = {}') gclient_eval.Exec('include_rules = {}', '<string>')
def test_recursedeps_list(self): def test_recursedeps_list(self):
local_scope = gclient_eval.Exec( local_scope = gclient_eval.Exec(
'recursedeps = [["src/third_party/angle", "DEPS.chromium"]]') 'recursedeps = [["src/third_party/angle", "DEPS.chromium"]]',
'<string>')
self.assertEqual( self.assertEqual(
{'recursedeps': [['src/third_party/angle', 'DEPS.chromium']]}, {'recursedeps': [['src/third_party/angle', 'DEPS.chromium']]},
local_scope) local_scope)
...@@ -177,35 +142,7 @@ class ExecTest(unittest.TestCase): ...@@ -177,35 +142,7 @@ class ExecTest(unittest.TestCase):
'deps = {', 'deps = {',
' "a_dep": "a" + Var("foo") + "b",', ' "a_dep": "a" + Var("foo") + "b",',
'}', '}',
])) ]), '<string>')
self.assertEqual({
'vars': collections.OrderedDict([('foo', 'bar')]),
'deps': collections.OrderedDict([('a_dep', 'abarb')]),
}, local_scope)
def test_braces_var(self):
local_scope = gclient_eval.Exec('\n'.join([
'vars = {',
' "foo": "bar",',
'}',
'deps = {',
' "a_dep": "a{foo}b",',
'}',
]))
self.assertEqual({
'vars': collections.OrderedDict([('foo', 'bar')]),
'deps': collections.OrderedDict([('a_dep', 'abarb')]),
}, local_scope)
def test_var_unexpanded(self):
local_scope = gclient_eval.Exec('\n'.join([
'vars = {',
' "foo": "bar",',
'}',
'deps = {',
' "a_dep": "a" + Var("foo") + "b",',
'}',
]), expand_vars=False)
self.assertEqual({ self.assertEqual({
'vars': collections.OrderedDict([('foo', 'bar')]), 'vars': collections.OrderedDict([('foo', 'bar')]),
'deps': collections.OrderedDict([('a_dep', 'a{foo}b')]), 'deps': collections.OrderedDict([('a_dep', 'a{foo}b')]),
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment