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 |