Commit e0214743 authored by Paweł Hajdan, Jr's avatar Paweł Hajdan, Jr Committed by Commit Bot

gclient: add support for native boolean variables

Bug: 570091
Change-Id: I195f5f798d9869f385437db4e0bc5f4c5d4853ae
Reviewed-on: https://chromium-review.googlesource.com/687496
Commit-Queue: Paweł Hajdan Jr. <phajdan.jr@chromium.org>
Reviewed-by: 's avatarDirk Pranke <dpranke@chromium.org>
parent ecf53fec
...@@ -965,7 +965,9 @@ class Dependency(gclient_utils.WorkItem, DependencySettings): ...@@ -965,7 +965,9 @@ class Dependency(gclient_utils.WorkItem, DependencySettings):
lines = ['# Generated from %r' % self.deps_file] lines = ['# Generated from %r' % self.deps_file]
variables = self.get_vars() variables = self.get_vars()
for arg in self._gn_args: for arg in self._gn_args:
value = gclient_eval.EvaluateCondition(variables[arg], variables) value = variables[arg]
if isinstance(value, basestring):
value = gclient_eval.EvaluateCondition(value, variables)
lines.append('%s = %s' % (arg, ToGNString(value))) lines.append('%s = %s' % (arg, ToGNString(value)))
with open(os.path.join(self.root.root_dir, self._gn_args_file), 'w') as f: with open(os.path.join(self.root.root_dir, self._gn_args_file), 'w') as f:
f.write('\n'.join(lines)) f.write('\n'.join(lines))
......
...@@ -120,7 +120,9 @@ _GCLIENT_SCHEMA = schema.Schema({ ...@@ -120,7 +120,9 @@ _GCLIENT_SCHEMA = schema.Schema({
schema.Optional('use_relative_paths'): bool, schema.Optional('use_relative_paths'): bool,
# Variables that can be referenced using Var() - see 'deps'. # Variables that can be referenced using Var() - see 'deps'.
schema.Optional('vars'): {schema.Optional(basestring): basestring}, schema.Optional('vars'): {
schema.Optional(basestring): schema.Or(basestring, bool),
},
}) })
...@@ -237,27 +239,58 @@ def EvaluateCondition(condition, variables, referenced_variables=None): ...@@ -237,27 +239,58 @@ def EvaluateCondition(condition, variables, referenced_variables=None):
elif node.id in _allowed_names: elif node.id in _allowed_names:
return _allowed_names[node.id] return _allowed_names[node.id]
elif node.id in variables: elif node.id in variables:
value = variables[node.id]
# Allow using "native" types, without wrapping everything in strings.
# Note that schema constraints still apply to variables.
if not isinstance(value, basestring):
return value
# Recursively evaluate the variable reference.
return EvaluateCondition( return EvaluateCondition(
variables[node.id], variables[node.id],
variables, variables,
referenced_variables.union([node.id])) referenced_variables.union([node.id]))
else: else:
raise ValueError( # Implicitly convert unrecognized names to strings.
'invalid name %r (inside %r)' % (node.id, condition)) # If we want to change this, we'll need to explicitly distinguish
# between arguments for GN to be passed verbatim, and ones to
# be evaluated.
return node.id
elif isinstance(node, ast.BoolOp) and isinstance(node.op, ast.Or): elif isinstance(node, ast.BoolOp) and isinstance(node.op, ast.Or):
if len(node.values) != 2: if len(node.values) != 2:
raise ValueError( raise ValueError(
'invalid "or": exactly 2 operands required (inside %r)' % ( 'invalid "or": exactly 2 operands required (inside %r)' % (
condition)) condition))
return _convert(node.values[0]) or _convert(node.values[1]) left = _convert(node.values[0])
right = _convert(node.values[1])
if not isinstance(left, bool):
raise ValueError(
'invalid "or" operand %r (inside %r)' % (left, condition))
if not isinstance(right, bool):
raise ValueError(
'invalid "or" operand %r (inside %r)' % (right, condition))
return left or right
elif isinstance(node, ast.BoolOp) and isinstance(node.op, ast.And): elif isinstance(node, ast.BoolOp) and isinstance(node.op, ast.And):
if len(node.values) != 2: if len(node.values) != 2:
raise ValueError( raise ValueError(
'invalid "and": exactly 2 operands required (inside %r)' % ( 'invalid "and": exactly 2 operands required (inside %r)' % (
condition)) condition))
return _convert(node.values[0]) and _convert(node.values[1]) left = _convert(node.values[0])
right = _convert(node.values[1])
if not isinstance(left, bool):
raise ValueError(
'invalid "and" operand %r (inside %r)' % (left, condition))
if not isinstance(right, bool):
raise ValueError(
'invalid "and" operand %r (inside %r)' % (right, condition))
return left and right
elif isinstance(node, ast.UnaryOp) and isinstance(node.op, ast.Not): elif isinstance(node, ast.UnaryOp) and isinstance(node.op, ast.Not):
return not _convert(node.operand) value = _convert(node.operand)
if not isinstance(value, bool):
raise ValueError(
'invalid "not" operand %r (inside %r)' % (value, condition))
return not value
elif isinstance(node, ast.Compare): elif isinstance(node, ast.Compare):
if len(node.ops) != 1: if len(node.ops) != 1:
raise ValueError( raise ValueError(
......
...@@ -329,15 +329,21 @@ class FakeRepos(FakeReposBase): ...@@ -329,15 +329,21 @@ class FakeRepos(FakeReposBase):
'DEPS': """ 'DEPS': """
vars = { vars = {
'DummyVariable': 'repo', 'DummyVariable': 'repo',
'false_var': 'False', 'false_var': False,
'true_var': 'True', 'false_str_var': 'False',
'str_var': '"abc"', 'true_var': True,
'true_str_var': 'True',
'str_var': 'abc',
'cond_var': 'false_str_var and true_var',
} }
gclient_gn_args_file = 'src/gclient.args' gclient_gn_args_file = 'src/gclient.args'
gclient_gn_args = [ gclient_gn_args = [
'false_var', 'false_var',
'false_str_var',
'true_var', 'true_var',
'true_str_var',
'str_var', 'str_var',
'cond_var',
] ]
deps = { deps = {
'src/repo2': { 'src/repo2': {
...@@ -475,16 +481,22 @@ vars = { ...@@ -475,16 +481,22 @@ vars = {
'hook1_contents': 'git_hooked1', 'hook1_contents': 'git_hooked1',
'repo5_var': '/repo_5', 'repo5_var': '/repo_5',
'false_var': 'False', 'false_var': False,
'true_var': 'True', 'false_str_var': 'False',
'str_var': '"abc"', 'true_var': True,
'true_str_var': 'True',
'str_var': 'abc',
'cond_var': 'false_str_var and true_var',
} }
gclient_gn_args_file = 'src/gclient.args' gclient_gn_args_file = 'src/gclient.args'
gclient_gn_args = [ gclient_gn_args = [
'false_var', 'false_var',
'false_str_var',
'true_var', 'true_var',
'true_str_var',
'str_var', 'str_var',
'cond_var',
] ]
allowed_hosts = [ allowed_hosts = [
......
...@@ -145,6 +145,21 @@ class EvaluateConditionTest(unittest.TestCase): ...@@ -145,6 +145,21 @@ class EvaluateConditionTest(unittest.TestCase):
self.assertFalse(gclient_eval.EvaluateCondition( self.assertFalse(gclient_eval.EvaluateCondition(
'foo == "bar"', {'foo': '"baz"'})) 'foo == "bar"', {'foo': '"baz"'}))
def test_string_bool(self):
self.assertFalse(gclient_eval.EvaluateCondition(
'false_str_var and true_var',
{'false_str_var': 'False', 'true_var': True}))
def test_string_bool_typo(self):
with self.assertRaises(ValueError) as cm:
gclient_eval.EvaluateCondition(
'false_var_str and true_var',
{'false_str_var': 'False', 'true_var': True})
self.assertIn(
'invalid "and" operand \'false_var_str\' '
'(inside \'false_var_str and true_var\')',
str(cm.exception))
if __name__ == '__main__': if __name__ == '__main__':
level = logging.DEBUG if '-v' in sys.argv else logging.FATAL level = logging.DEBUG if '-v' in sys.argv else logging.FATAL
......
...@@ -327,8 +327,11 @@ class GClientSmokeGIT(GClientSmokeBase): ...@@ -327,8 +327,11 @@ class GClientSmokeGIT(GClientSmokeBase):
tree['src/gclient.args'] = '\n'.join([ tree['src/gclient.args'] = '\n'.join([
'# Generated from \'DEPS\'', '# Generated from \'DEPS\'',
'false_var = false', 'false_var = false',
'false_str_var = false',
'true_var = true', 'true_var = true',
'true_str_var = true',
'str_var = "abc"', 'str_var = "abc"',
'cond_var = false',
]) ])
self.assertTree(tree) self.assertTree(tree)
# Test incremental sync: delete-unversioned_trees isn't there. # Test incremental sync: delete-unversioned_trees isn't there.
...@@ -345,8 +348,11 @@ class GClientSmokeGIT(GClientSmokeBase): ...@@ -345,8 +348,11 @@ class GClientSmokeGIT(GClientSmokeBase):
tree['src/gclient.args'] = '\n'.join([ tree['src/gclient.args'] = '\n'.join([
'# Generated from \'DEPS\'', '# Generated from \'DEPS\'',
'false_var = false', 'false_var = false',
'false_str_var = false',
'true_var = true', 'true_var = true',
'true_str_var = true',
'str_var = "abc"', 'str_var = "abc"',
'cond_var = false',
]) ])
self.assertTree(tree) self.assertTree(tree)
...@@ -384,8 +390,11 @@ class GClientSmokeGIT(GClientSmokeBase): ...@@ -384,8 +390,11 @@ class GClientSmokeGIT(GClientSmokeBase):
tree['src/gclient.args'] = '\n'.join([ tree['src/gclient.args'] = '\n'.join([
'# Generated from \'DEPS\'', '# Generated from \'DEPS\'',
'false_var = false', 'false_var = false',
'false_str_var = false',
'true_var = true', 'true_var = true',
'true_str_var = true',
'str_var = "abc"', 'str_var = "abc"',
'cond_var = false',
]) ])
self.assertTree(tree) self.assertTree(tree)
...@@ -426,8 +435,11 @@ class GClientSmokeGIT(GClientSmokeBase): ...@@ -426,8 +435,11 @@ class GClientSmokeGIT(GClientSmokeBase):
tree['src/gclient.args'] = '\n'.join([ tree['src/gclient.args'] = '\n'.join([
'# Generated from \'DEPS\'', '# Generated from \'DEPS\'',
'false_var = false', 'false_var = false',
'false_str_var = false',
'true_var = true', 'true_var = true',
'true_str_var = true',
'str_var = "abc"', 'str_var = "abc"',
'cond_var = false',
]) ])
self.assertTree(tree) self.assertTree(tree)
# Test incremental sync: delete-unversioned_trees isn't there. # Test incremental sync: delete-unversioned_trees isn't there.
...@@ -445,8 +457,11 @@ class GClientSmokeGIT(GClientSmokeBase): ...@@ -445,8 +457,11 @@ class GClientSmokeGIT(GClientSmokeBase):
tree['src/gclient.args'] = '\n'.join([ tree['src/gclient.args'] = '\n'.join([
'# Generated from \'DEPS\'', '# Generated from \'DEPS\'',
'false_var = false', 'false_var = false',
'false_str_var = false',
'true_var = true', 'true_var = true',
'true_str_var = true',
'str_var = "abc"', 'str_var = "abc"',
'cond_var = false',
]) ])
self.assertTree(tree) self.assertTree(tree)
...@@ -626,7 +641,8 @@ class GClientSmokeGIT(GClientSmokeBase): ...@@ -626,7 +641,8 @@ class GClientSmokeGIT(GClientSmokeBase):
self.maxDiff = None self.maxDiff = None
self.assertEqual([ self.assertEqual([
'gclient_gn_args_file = "src/gclient.args"', 'gclient_gn_args_file = "src/gclient.args"',
'gclient_gn_args = [\'false_var\', \'true_var\', \'str_var\']', 'gclient_gn_args = [\'false_var\', \'false_str_var\', \'true_var\', '
'\'true_str_var\', \'str_var\', \'cond_var\']',
'allowed_hosts = [', 'allowed_hosts = [',
' "git://127.0.0.1:20000/git/",', ' "git://127.0.0.1:20000/git/",',
']', ']',
...@@ -749,7 +765,13 @@ class GClientSmokeGIT(GClientSmokeBase): ...@@ -749,7 +765,13 @@ class GClientSmokeGIT(GClientSmokeBase):
' "DummyVariable": \'repo\',', ' "DummyVariable": \'repo\',',
'', '',
' # src', ' # src',
' "false_var": \'False\',', ' "cond_var": \'false_str_var and true_var\',',
'',
' # src',
' "false_str_var": \'False\',',
'',
' # src',
' "false_var": False,',
'', '',
' # src', ' # src',
' "git_base": \'git://127.0.0.1:20000/git/\',', ' "git_base": \'git://127.0.0.1:20000/git/\',',
...@@ -761,10 +783,13 @@ class GClientSmokeGIT(GClientSmokeBase): ...@@ -761,10 +783,13 @@ class GClientSmokeGIT(GClientSmokeBase):
' "repo5_var": \'/repo_5\',', ' "repo5_var": \'/repo_5\',',
'', '',
' # src', ' # src',
' "str_var": \'"abc"\',', ' "str_var": \'abc\',',
'',
' # src',
' "true_str_var": \'True\',',
'', '',
' # src', ' # src',
' "true_var": \'True\',', ' "true_var": True,',
'', '',
'}', '}',
'', '',
...@@ -790,7 +815,8 @@ class GClientSmokeGIT(GClientSmokeBase): ...@@ -790,7 +815,8 @@ class GClientSmokeGIT(GClientSmokeBase):
self.assertEqual([ self.assertEqual([
'gclient_gn_args_file = "src/gclient.args"', 'gclient_gn_args_file = "src/gclient.args"',
'gclient_gn_args = [\'false_var\', \'true_var\', \'str_var\']', 'gclient_gn_args = [\'false_var\', \'false_str_var\', \'true_var\', '
'\'true_str_var\', \'str_var\', \'cond_var\']',
'allowed_hosts = [', 'allowed_hosts = [',
' "git://127.0.0.1:20000/git/",', ' "git://127.0.0.1:20000/git/",',
']', ']',
...@@ -914,7 +940,13 @@ class GClientSmokeGIT(GClientSmokeBase): ...@@ -914,7 +940,13 @@ class GClientSmokeGIT(GClientSmokeBase):
' "DummyVariable": \'repo\',', ' "DummyVariable": \'repo\',',
'', '',
' # src', ' # src',
' "false_var": \'False\',', ' "cond_var": \'false_str_var and true_var\',',
'',
' # src',
' "false_str_var": \'False\',',
'',
' # src',
' "false_var": False,',
'', '',
' # src', ' # src',
' "git_base": \'git://127.0.0.1:20000/git/\',', ' "git_base": \'git://127.0.0.1:20000/git/\',',
...@@ -926,10 +958,13 @@ class GClientSmokeGIT(GClientSmokeBase): ...@@ -926,10 +958,13 @@ class GClientSmokeGIT(GClientSmokeBase):
' "repo5_var": \'/repo_5\',', ' "repo5_var": \'/repo_5\',',
'', '',
' # src', ' # src',
' "str_var": \'"abc"\',', ' "str_var": \'abc\',',
'',
' # src',
' "true_str_var": \'True\',',
'', '',
' # src', ' # src',
' "true_var": \'True\',', ' "true_var": True,',
'', '',
'}', '}',
'', '',
......
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