Commit 8f8a50d0 authored by Edward Lemur's avatar Edward Lemur Committed by Commit Bot

gclient: Make built-in vars available for expansion.

Make it possible to refer to built-in variables without having to declare
then in DEPS files.

Bug: None
Change-Id: I5403963052463befc074f29750de56cce13927ce
Reviewed-on: https://chromium-review.googlesource.com/c/1312234Reviewed-by: 's avatarDirk Pranke <dpranke@chromium.org>
Commit-Queue: Edward Lesmes <ehmaldonado@chromium.org>
parent 5ee6b6e6
......@@ -681,7 +681,7 @@ class Dependency(gclient_utils.WorkItem, DependencySettings):
try:
local_scope = gclient_eval.Parse(
deps_content, self._get_option('validate_syntax', False),
filepath, self.get_vars())
filepath, self.get_vars(), self.get_builtin_vars())
except SyntaxError as e:
gclient_utils.SyntaxErrorToError(filepath, e)
......@@ -1192,11 +1192,8 @@ class Dependency(gclient_utils.WorkItem, DependencySettings):
d = d.parent
return tuple(out)
def get_vars(self):
"""Returns a dictionary of effective variable values
(DEPS file contents with applied custom_vars overrides)."""
# Provide some built-in variables.
result = {
def get_builtin_vars(self):
return {
'checkout_android': 'android' in self.target_os,
'checkout_chromeos': 'chromeos' in self.target_os,
'checkout_fuchsia': 'fuchsia' in self.target_os,
......@@ -1216,15 +1213,22 @@ class Dependency(gclient_utils.WorkItem, DependencySettings):
'checkout_x64': 'x64' in self.target_cpu,
'host_cpu': detect_host_arch.HostArch(),
}
# Variable precedence:
# - built-in
def get_vars(self):
"""Returns a dictionary of effective variable values
(DEPS file contents with applied custom_vars overrides)."""
# Variable precedence (last has highest):
# - DEPS vars
# - parents, from first to last
# - built-in
# - custom_vars overrides
result = {}
result.update(self._vars)
if self.parent:
parent_vars = self.parent.get_vars()
result.update(parent_vars)
# Provide some built-in variables.
result.update(self.get_builtin_vars())
result.update(self.custom_vars or {})
return result
......
......@@ -277,7 +277,7 @@ def _gclient_eval(node_or_string, filename='<unknown>', vars_dict=None):
return _convert(node_or_string)
def Exec(content, filename='<unknown>', vars_override=None):
def Exec(content, filename='<unknown>', vars_override=None, builtin_vars=None):
"""Safely execs a set of assignments."""
def _validate_statement(node, local_scope):
if not isinstance(node, ast.Assign):
......@@ -334,11 +334,15 @@ def Exec(content, filename='<unknown>', vars_override=None):
# Update the parsed vars with the overrides, but only if they are already
# present (overrides do not introduce new variables).
vars_dict.update(value)
if vars_override:
vars_dict.update({
k: v
for k, v in vars_override.iteritems()
if k in vars_dict})
if builtin_vars:
vars_dict.update(builtin_vars)
if vars_override:
vars_dict.update({
k: v
for k, v in vars_override.iteritems()
if k in vars_dict})
for name, node in statements.iteritems():
value = _gclient_eval(node, filename, vars_dict)
......@@ -347,7 +351,8 @@ def Exec(content, filename='<unknown>', vars_override=None):
return _GCLIENT_SCHEMA.validate(local_scope)
def ExecLegacy(content, filename='<unknown>', vars_override=None):
def ExecLegacy(content, filename='<unknown>', vars_override=None,
builtin_vars=None):
"""Executes a DEPS file |content| using exec."""
local_scope = {}
global_scope = {'Var': lambda var_name: '{%s}' % var_name}
......@@ -358,11 +363,10 @@ def ExecLegacy(content, filename='<unknown>', vars_override=None):
# as "exec a in b, c" (See https://bugs.python.org/issue21591).
eval(compile(content, filename, 'exec'), global_scope, local_scope)
if 'vars' not in local_scope:
return local_scope
vars_dict = {}
vars_dict.update(local_scope['vars'])
vars_dict.update(local_scope.get('vars', {}))
if builtin_vars:
vars_dict.update(builtin_vars)
if vars_override:
vars_dict.update({
k: v
......@@ -370,6 +374,9 @@ def ExecLegacy(content, filename='<unknown>', vars_override=None):
if k in vars_dict
})
if not vars_dict:
return local_scope
def _DeepFormat(node):
if isinstance(node, basestring):
return node.format(**vars_dict)
......@@ -453,7 +460,8 @@ def UpdateCondition(info_dict, op, new_condition):
del info_dict['condition']
def Parse(content, validate_syntax, filename, vars_override=None):
def Parse(content, validate_syntax, filename, vars_override=None,
builtin_vars=None):
"""Parses DEPS strings.
Executes the Python-like string stored in content, resulting in a Python
......@@ -468,15 +476,17 @@ def Parse(content, validate_syntax, filename, vars_override=None):
of the content, e.g. '<string>', '<unknown>'.
vars_override: dict, optional. A dictionary with overrides for the variables
defined by the DEPS file.
builtin_vars: dict, optional. A dictionary with variables that are provided
by default.
Returns:
A Python dict with the parsed contents of the DEPS file, as specified by the
schema above.
"""
if validate_syntax:
result = Exec(content, filename, vars_override)
result = Exec(content, filename, vars_override, builtin_vars)
else:
result = ExecLegacy(content, filename, vars_override)
result = ExecLegacy(content, filename, vars_override, builtin_vars)
vars_dict = result.get('vars', {})
if 'deps' in result:
......
......@@ -701,6 +701,55 @@ class ParseTest(unittest.TestCase):
'condition': 'baz'}},
}, local_scope)
def test_has_builtin_vars(self):
builtin_vars = {'builtin_var': 'foo'}
deps_file = '\n'.join([
'deps = {',
' "a_dep": "a{builtin_var}b",',
'}',
])
for validate_syntax in False, True:
local_scope = gclient_eval.Parse(
deps_file, validate_syntax, '<unknown>', None, builtin_vars)
self.assertEqual({
'deps': {'a_dep': {'url': 'afoob',
'dep_type': 'git'}},
}, local_scope)
def test_declaring_builtin_var_has_no_effect(self):
builtin_vars = {'builtin_var': 'foo'}
deps_file = '\n'.join([
'vars = {',
' "builtin_var": "bar",',
'}',
'deps = {',
' "a_dep": "a{builtin_var}b",',
'}',
])
for validate_syntax in False, True:
local_scope = gclient_eval.Parse(
deps_file, validate_syntax, '<unknown>', None, builtin_vars)
self.assertEqual({
'vars': {'builtin_var': 'bar'},
'deps': {'a_dep': {'url': 'afoob',
'dep_type': 'git'}},
}, local_scope)
def test_override_builtin_var(self):
builtin_vars = {'builtin_var': 'foo'}
vars_override = {'builtin_var': 'override'}
deps_file = '\n'.join([
'deps = {',
' "a_dep": "a{builtin_var}b",',
'}',
])
for validate_syntax in False, True:
local_scope = gclient_eval.Parse(
deps_file, validate_syntax, '<unknown>', vars_override, builtin_vars)
self.assertEqual({
'deps': {'a_dep': {'url': 'aoverrideb',
'dep_type': 'git'}},
}, local_scope, str(local_scope))
def test_expands_vars(self):
for validate_syntax in True, False:
......
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