mirror of
https://chromium.googlesource.com/chromium/tools/depot_tools.git
synced 2026-01-11 10:41:31 +00:00
Reland "Add a Str() function to gclient for use in DEPS files."
This relandsc7eed83with a fix to the way variables are propagated from parent dependencies into child dependencies. The original CL description fromc7eed83was: > gclient's existing functionality for handling variables is > ambiguous: the value of a variable can either be a string literal > or an expression fragment. The implementation is required to > parse a value as an expression, and, if it is legal, treat it > as an expression instead of a literal. This means that > > gclient_gn_args_file = 'src/build/args.gni' > gclient_gn_args = ['xcode_version'] > vars = { > 'xcode_version': 'xcode-12' > } > > would cause a problem because gclient would try to parse the > variable as an expression, and 'xcode' would not be defined. > > This patch adds a workaround for this, where you can instead > use the Str() function to explicitly tell gclient to treat the > value as a string and not a potential expression. > > The above example would be changed to: > > gclient_gn_args_file = 'src/build/args.gni' > gclient_gn_args = ['xcode_version'] > vars = { > 'xcode_version': Str('xcode-12') > } > > The variable may still be used in every context where it was legal > to be used before. > This reverts commit 84431987dd384c79c84515004d19db67345a1c00. Bug: 1099242 TBR=ehmaldonado@chromium.org Change-Id: I047b871df47c367c1f34a3985e5813504e3c5c6f Reviewed-on: https://chromium-review.googlesource.com/c/chromium/tools/depot_tools/+/2274152 Commit-Queue: Dirk Pranke <dpranke@google.com> Reviewed-by: Ben Pastene <bpastene@chromium.org>
This commit is contained in:
@@ -24,6 +24,27 @@ else:
|
||||
basestring = str
|
||||
|
||||
|
||||
class ConstantString(object):
|
||||
def __init__(self, value):
|
||||
self.value = value
|
||||
|
||||
def __format__(self, format_spec):
|
||||
del format_spec
|
||||
return self.value
|
||||
|
||||
def __repr__(self):
|
||||
return "Str('" + self.value + "')"
|
||||
|
||||
def __eq__(self, other):
|
||||
if isinstance(other, ConstantString):
|
||||
return self.value == other.value
|
||||
else:
|
||||
return self.value == other
|
||||
|
||||
def __hash__(self):
|
||||
return self.value.__hash__()
|
||||
|
||||
|
||||
class _NodeDict(collections_abc.MutableMapping):
|
||||
"""Dict-like type that also stores information on AST nodes and tokens."""
|
||||
def __init__(self, data=None, tokens=None):
|
||||
@@ -114,7 +135,7 @@ _GCLIENT_DEPS_SCHEMA = _NodeDictSchema({
|
||||
_GCLIENT_HOOKS_SCHEMA = [
|
||||
_NodeDictSchema({
|
||||
# Hook action: list of command-line arguments to invoke.
|
||||
'action': [basestring],
|
||||
'action': [schema.Or(basestring)],
|
||||
|
||||
# Name of the hook. Doesn't affect operation.
|
||||
schema.Optional('name'): basestring,
|
||||
@@ -220,7 +241,9 @@ _GCLIENT_SCHEMA = schema.Schema(
|
||||
|
||||
# Variables that can be referenced using Var() - see 'deps'.
|
||||
schema.Optional('vars'): _NodeDictSchema({
|
||||
schema.Optional(basestring): schema.Or(basestring, bool),
|
||||
schema.Optional(basestring): schema.Or(ConstantString,
|
||||
basestring,
|
||||
bool),
|
||||
}),
|
||||
}))
|
||||
|
||||
@@ -228,6 +251,8 @@ _GCLIENT_SCHEMA = schema.Schema(
|
||||
def _gclient_eval(node_or_string, filename='<unknown>', vars_dict=None):
|
||||
"""Safely evaluates a single expression. Returns the result."""
|
||||
_allowed_names = {'None': None, 'True': True, 'False': False}
|
||||
if isinstance(node_or_string, ConstantString):
|
||||
return node_or_string.value
|
||||
if isinstance(node_or_string, basestring):
|
||||
node_or_string = ast.parse(node_or_string, filename=filename, mode='eval')
|
||||
if isinstance(node_or_string, ast.Expression):
|
||||
@@ -269,16 +294,23 @@ def _gclient_eval(node_or_string, filename='<unknown>', vars_dict=None):
|
||||
node, ast.NameConstant): # Since Python 3.4
|
||||
return node.value
|
||||
elif isinstance(node, ast.Call):
|
||||
if not isinstance(node.func, ast.Name) or node.func.id != 'Var':
|
||||
if (not isinstance(node.func, ast.Name) or
|
||||
(node.func.id not in ('Str', 'Var'))):
|
||||
raise ValueError(
|
||||
'Var is the only allowed function (file %r, line %s)' % (
|
||||
'Str and Var are the only allowed functions (file %r, line %s)' % (
|
||||
filename, getattr(node, 'lineno', '<unknown>')))
|
||||
if node.keywords or getattr(node, 'starargs', None) or getattr(
|
||||
node, 'kwargs', None) or len(node.args) != 1:
|
||||
raise ValueError(
|
||||
'Var takes exactly one argument (file %r, line %s)' % (
|
||||
filename, getattr(node, 'lineno', '<unknown>')))
|
||||
arg = _convert(node.args[0])
|
||||
'%s takes exactly one argument (file %r, line %s)' % (
|
||||
node.func.id, filename, getattr(node, 'lineno', '<unknown>')))
|
||||
if node.func.id == 'Str':
|
||||
if isinstance(node.args[0], ast.Str):
|
||||
return ConstantString(node.args[0].s)
|
||||
raise ValueError('Passed a non-string to Str() (file %r, line%s)' % (
|
||||
filename, getattr(node, 'lineno', '<unknown>')))
|
||||
else:
|
||||
arg = _convert(node.args[0])
|
||||
if not isinstance(arg, basestring):
|
||||
raise ValueError(
|
||||
'Var\'s argument must be a variable name (file %r, line %s)' % (
|
||||
@@ -290,7 +322,10 @@ def _gclient_eval(node_or_string, filename='<unknown>', vars_dict=None):
|
||||
'%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]
|
||||
val = vars_dict[arg]
|
||||
if isinstance(val, ConstantString):
|
||||
val = val.value
|
||||
return val
|
||||
elif isinstance(node, ast.BinOp) and isinstance(node.op, ast.Add):
|
||||
return _convert(node.left) + _convert(node.right)
|
||||
elif isinstance(node, ast.BinOp) and isinstance(node.op, ast.Mod):
|
||||
@@ -601,6 +636,8 @@ def RenderDEPSFile(gclient_dict):
|
||||
|
||||
|
||||
def _UpdateAstString(tokens, node, value):
|
||||
if isinstance(node, ast.Call):
|
||||
node = node.args[0]
|
||||
position = node.lineno, node.col_offset
|
||||
quote_char = ''
|
||||
if isinstance(node, ast.Str):
|
||||
@@ -810,7 +847,10 @@ def GetVar(gclient_dict, var_name):
|
||||
raise KeyError(
|
||||
"Could not find any variable called %s." % var_name)
|
||||
|
||||
return gclient_dict['vars'][var_name]
|
||||
val = gclient_dict['vars'][var_name]
|
||||
if isinstance(val, ConstantString):
|
||||
return val.value
|
||||
return val
|
||||
|
||||
|
||||
def GetCIPD(gclient_dict, dep_name, package_name):
|
||||
|
||||
Reference in New Issue
Block a user