OLD | NEW |
(Empty) | |
| 1 # Copyright 2014 Google Inc. All Rights Reserved. |
| 2 # |
| 3 # Licensed under the Apache License, Version 2.0 (the "License"); |
| 4 # you may not use this file except in compliance with the License. |
| 5 # You may obtain a copy of the License at |
| 6 # |
| 7 # http://www.apache.org/licenses/LICENSE-2.0 |
| 8 # |
| 9 # Unless required by applicable law or agreed to in writing, software |
| 10 # distributed under the License is distributed on an "AS IS" BASIS, |
| 11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 12 # See the License for the specific language governing permissions and |
| 13 # limitations under the License. |
| 14 |
| 15 """Utility library for parsing DEPS-like files.""" |
| 16 |
| 17 import ast |
| 18 |
| 19 def _FindGlobalVariableInAstTree(tree, name, functions=None): |
| 20 """Finds and evaluates to global assignment of the variables |name| in the |
| 21 AST |tree|. Will allow the evaluations of some functions as defined in |
| 22 |functions|. |
| 23 """ |
| 24 if functions is None: |
| 25 functions = {} |
| 26 |
| 27 class FunctionEvaluator(ast.NodeTransformer): |
| 28 """A tree transformer that evaluates permitted functions.""" |
| 29 |
| 30 def visit_BinOp(self, binop_node): |
| 31 """Is called for BinOp nodes. We only support string additions.""" |
| 32 if type(binop_node.op) != ast.Add: |
| 33 return binop_node |
| 34 left = ast.literal_eval(self.visit(binop_node.left)) |
| 35 right = ast.literal_eval(self.visit(binop_node.right)) |
| 36 value = left + right |
| 37 new_node = ast.Str(s=value) |
| 38 new_node = ast.copy_location(new_node, binop_node) |
| 39 return new_node |
| 40 |
| 41 def visit_Call(self, call_node): |
| 42 """Evaluates function calls that return a single string as output.""" |
| 43 func_name = call_node.func.id |
| 44 if func_name not in functions: |
| 45 return call_node |
| 46 func = functions[func_name] |
| 47 |
| 48 # Evaluate the arguments. We don't care about starargs, keywords or |
| 49 # kwargs. |
| 50 args = [ast.literal_eval(self.visit(arg)) for arg in |
| 51 call_node.args] |
| 52 |
| 53 # Now evaluate the function. |
| 54 value = func(*args) |
| 55 new_node = ast.Str(s=value) |
| 56 new_node = ast.copy_location(new_node, call_node) |
| 57 return new_node |
| 58 |
| 59 # Look for assignment nodes. |
| 60 for node in tree.body: |
| 61 if type(node) != ast.Assign: |
| 62 continue |
| 63 # Look for assignment in the 'store' context, to a variable with |
| 64 # the given name. |
| 65 for target in node.targets: |
| 66 if type(target) != ast.Name: |
| 67 continue |
| 68 if type(target.ctx) != ast.Store: |
| 69 continue |
| 70 if target.id == name: |
| 71 value = FunctionEvaluator().visit(node.value) |
| 72 value = ast.fix_missing_locations(value) |
| 73 value = ast.literal_eval(value) |
| 74 return value |
| 75 |
| 76 |
| 77 def ParseDepsFile(path): |
| 78 """Parsed a DEPS-like file at the given |path|.""" |
| 79 with open(path, 'rb') as f: |
| 80 contents = f.read() |
| 81 return ParseDeps(contents, path) |
| 82 |
| 83 |
| 84 def ParseDeps(contents, path): |
| 85 """Parses contents of a DEPS-like file.""" |
| 86 # Utility function for performing variable expansions. |
| 87 vars_dict = {} |
| 88 def _Var(s): |
| 89 return vars_dict[s] |
| 90 |
| 91 tree = ast.parse(contents, path) |
| 92 vars_dict = _FindGlobalVariableInAstTree(tree, 'vars') |
| 93 deps_dict = _FindGlobalVariableInAstTree( |
| 94 tree, 'deps', functions={'Var': _Var}) |
| 95 return deps_dict |
OLD | NEW |