| Index: pipa/py/deps_utils.py
|
| diff --git a/pipa/py/deps_utils.py b/pipa/py/deps_utils.py
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..e33a872e5fa1fe81d58901bb9e64ed0e1f763d6e
|
| --- /dev/null
|
| +++ b/pipa/py/deps_utils.py
|
| @@ -0,0 +1,95 @@
|
| +# Copyright 2014 Google Inc. All Rights Reserved.
|
| +#
|
| +# Licensed under the Apache License, Version 2.0 (the "License");
|
| +# you may not use this file except in compliance with the License.
|
| +# You may obtain a copy of the License at
|
| +#
|
| +# http://www.apache.org/licenses/LICENSE-2.0
|
| +#
|
| +# Unless required by applicable law or agreed to in writing, software
|
| +# distributed under the License is distributed on an "AS IS" BASIS,
|
| +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| +# See the License for the specific language governing permissions and
|
| +# limitations under the License.
|
| +
|
| +"""Utility library for parsing DEPS-like files."""
|
| +
|
| +import ast
|
| +
|
| +def _FindGlobalVariableInAstTree(tree, name, functions=None):
|
| + """Finds and evaluates to global assignment of the variables |name| in the
|
| + AST |tree|. Will allow the evaluations of some functions as defined in
|
| + |functions|.
|
| + """
|
| + if functions is None:
|
| + functions = {}
|
| +
|
| + class FunctionEvaluator(ast.NodeTransformer):
|
| + """A tree transformer that evaluates permitted functions."""
|
| +
|
| + def visit_BinOp(self, binop_node):
|
| + """Is called for BinOp nodes. We only support string additions."""
|
| + if type(binop_node.op) != ast.Add:
|
| + return binop_node
|
| + left = ast.literal_eval(self.visit(binop_node.left))
|
| + right = ast.literal_eval(self.visit(binop_node.right))
|
| + value = left + right
|
| + new_node = ast.Str(s=value)
|
| + new_node = ast.copy_location(new_node, binop_node)
|
| + return new_node
|
| +
|
| + def visit_Call(self, call_node):
|
| + """Evaluates function calls that return a single string as output."""
|
| + func_name = call_node.func.id
|
| + if func_name not in functions:
|
| + return call_node
|
| + func = functions[func_name]
|
| +
|
| + # Evaluate the arguments. We don't care about starargs, keywords or
|
| + # kwargs.
|
| + args = [ast.literal_eval(self.visit(arg)) for arg in
|
| + call_node.args]
|
| +
|
| + # Now evaluate the function.
|
| + value = func(*args)
|
| + new_node = ast.Str(s=value)
|
| + new_node = ast.copy_location(new_node, call_node)
|
| + return new_node
|
| +
|
| + # Look for assignment nodes.
|
| + for node in tree.body:
|
| + if type(node) != ast.Assign:
|
| + continue
|
| + # Look for assignment in the 'store' context, to a variable with
|
| + # the given name.
|
| + for target in node.targets:
|
| + if type(target) != ast.Name:
|
| + continue
|
| + if type(target.ctx) != ast.Store:
|
| + continue
|
| + if target.id == name:
|
| + value = FunctionEvaluator().visit(node.value)
|
| + value = ast.fix_missing_locations(value)
|
| + value = ast.literal_eval(value)
|
| + return value
|
| +
|
| +
|
| +def ParseDepsFile(path):
|
| + """Parsed a DEPS-like file at the given |path|."""
|
| + with open(path, 'rb') as f:
|
| + contents = f.read()
|
| + return ParseDeps(contents, path)
|
| +
|
| +
|
| +def ParseDeps(contents, path):
|
| + """Parses contents of a DEPS-like file."""
|
| + # Utility function for performing variable expansions.
|
| + vars_dict = {}
|
| + def _Var(s):
|
| + return vars_dict[s]
|
| +
|
| + tree = ast.parse(contents, path)
|
| + vars_dict = _FindGlobalVariableInAstTree(tree, 'vars')
|
| + deps_dict = _FindGlobalVariableInAstTree(
|
| + tree, 'deps', functions={'Var': _Var})
|
| + return deps_dict
|
|
|