| OLD | NEW |
| 1 # Copyright 2014 Google Inc. All Rights Reserved. | 1 # Copyright 2014 Google Inc. All Rights Reserved. |
| 2 # | 2 # |
| 3 # Licensed under the Apache License, Version 2.0 (the "License"); | 3 # Licensed under the Apache License, Version 2.0 (the "License"); |
| 4 # you may not use this file except in compliance with 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 | 5 # You may obtain a copy of the License at |
| 6 # | 6 # |
| 7 # http://www.apache.org/licenses/LICENSE-2.0 | 7 # http://www.apache.org/licenses/LICENSE-2.0 |
| 8 # | 8 # |
| 9 # Unless required by applicable law or agreed to in writing, software | 9 # Unless required by applicable law or agreed to in writing, software |
| 10 # distributed under the License is distributed on an "AS IS" BASIS, | 10 # distributed under the License is distributed on an "AS IS" BASIS, |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 47 import glob | 47 import glob |
| 48 import hashlib | 48 import hashlib |
| 49 import logging | 49 import logging |
| 50 import optparse | 50 import optparse |
| 51 import os | 51 import os |
| 52 import random | 52 import random |
| 53 import re | 53 import re |
| 54 import subprocess | 54 import subprocess |
| 55 import threading | 55 import threading |
| 56 | 56 |
| 57 import deps_utils |
| 57 | 58 |
| 58 _LOGGER = logging.getLogger(os.path.basename(__file__)) | 59 _LOGGER = logging.getLogger(os.path.basename(__file__)) |
| 59 | 60 |
| 60 | 61 |
| 61 # Matches a SHA1 hash used as a git revision. | 62 # Matches a SHA1 hash used as a git revision. |
| 62 _GIT_SHA1_RE = re.compile('^[A-Fa-f0-9]{40}$') | 63 _GIT_SHA1_RE = re.compile('^[A-Fa-f0-9]{40}$') |
| 63 | 64 |
| 64 | 65 |
| 65 def _ParseCommandLine(): | 66 def _ParseCommandLine(): |
| 66 """Parses the command-line and returns an options structure.""" | 67 """Parses the command-line and returns an options structure.""" |
| (...skipping 556 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 623 'safesync_url': '', | 624 'safesync_url': '', |
| 624 } | 625 } |
| 625 ] | 626 ] |
| 626 solutions = 'solutions=%s' % solutions.__repr__() | 627 solutions = 'solutions=%s' % solutions.__repr__() |
| 627 _WriteIfChanged(gclient_file, solutions, options.dry_run) | 628 _WriteIfChanged(gclient_file, solutions, options.dry_run) |
| 628 | 629 |
| 629 # Invoke 'gclient' on the sub-repository. | 630 # Invoke 'gclient' on the sub-repository. |
| 630 _Shell('gclient', 'sync', cwd=repo.checkout_dir, dry_run=options.dry_run) | 631 _Shell('gclient', 'sync', cwd=repo.checkout_dir, dry_run=options.dry_run) |
| 631 | 632 |
| 632 | 633 |
| 633 def _FindGlobalVariableInAstTree(tree, name, functions=None): | |
| 634 """Finds and evaluates to global assignment of the variables |name| in the | |
| 635 AST |tree|. Will allow the evaluations of some functions as defined in | |
| 636 |functions|. | |
| 637 """ | |
| 638 if functions is None: | |
| 639 functions = {} | |
| 640 | |
| 641 class FunctionEvaluator(ast.NodeTransformer): | |
| 642 """A tree transformer that evaluates permitted functions.""" | |
| 643 | |
| 644 def visit_BinOp(self, binop_node): | |
| 645 """Is called for BinOp nodes. We only support string additions.""" | |
| 646 if type(binop_node.op) != ast.Add: | |
| 647 return binop_node | |
| 648 left = ast.literal_eval(self.visit(binop_node.left)) | |
| 649 right = ast.literal_eval(self.visit(binop_node.right)) | |
| 650 value = left + right | |
| 651 new_node = ast.Str(s=value) | |
| 652 new_node = ast.copy_location(new_node, binop_node) | |
| 653 return new_node | |
| 654 | |
| 655 def visit_Call(self, call_node): | |
| 656 """Evaluates function calls that return a single string as output.""" | |
| 657 func_name = call_node.func.id | |
| 658 if func_name not in functions: | |
| 659 return call_node | |
| 660 func = functions[func_name] | |
| 661 | |
| 662 # Evaluate the arguments. We don't care about starargs, keywords or | |
| 663 # kwargs. | |
| 664 args = [ast.literal_eval(self.visit(arg)) for arg in | |
| 665 call_node.args] | |
| 666 | |
| 667 # Now evaluate the function. | |
| 668 value = func(*args) | |
| 669 new_node = ast.Str(s=value) | |
| 670 new_node = ast.copy_location(new_node, call_node) | |
| 671 return new_node | |
| 672 | |
| 673 # Look for assignment nodes. | |
| 674 for node in tree.body: | |
| 675 if type(node) != ast.Assign: | |
| 676 continue | |
| 677 # Look for assignment in the 'store' context, to a variable with | |
| 678 # the given name. | |
| 679 for target in node.targets: | |
| 680 if type(target) != ast.Name: | |
| 681 continue | |
| 682 if type(target.ctx) != ast.Store: | |
| 683 continue | |
| 684 if target.id == name: | |
| 685 value = FunctionEvaluator().visit(node.value) | |
| 686 value = ast.fix_missing_locations(value) | |
| 687 value = ast.literal_eval(value) | |
| 688 return value | |
| 689 | |
| 690 | |
| 691 def _ParseDepsFile(path): | |
| 692 """Parsed a DEPS-like file at the given |path|.""" | |
| 693 # Utility function for performing variable expansions. | |
| 694 vars_dict = {} | |
| 695 def _Var(s): | |
| 696 return vars_dict[s] | |
| 697 | |
| 698 contents = open(path, 'rb').read() | |
| 699 tree = ast.parse(contents, path) | |
| 700 vars_dict = _FindGlobalVariableInAstTree(tree, 'vars') | |
| 701 deps_dict = _FindGlobalVariableInAstTree( | |
| 702 tree, 'deps', functions={'Var': _Var}) | |
| 703 return deps_dict | |
| 704 | 634 |
| 705 | 635 |
| 706 def _RemoveFile(options, path): | 636 def _RemoveFile(options, path): |
| 707 """Removes the provided file. If it doesn't exist, raises an Exception.""" | 637 """Removes the provided file. If it doesn't exist, raises an Exception.""" |
| 708 _LOGGER.debug('Removing file: %s', path) | 638 _LOGGER.debug('Removing file: %s', path) |
| 709 if not os.path.isfile(path): | 639 if not os.path.isfile(path): |
| 710 raise Exception('Path does not exist: %s' % path) | 640 raise Exception('Path does not exist: %s' % path) |
| 711 | 641 |
| 712 if not options.dry_run: | 642 if not options.dry_run: |
| 713 os.remove(path) | 643 os.remove(path) |
| (...skipping 153 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 867 | 797 |
| 868 # Read junctions that have been written in previous runs. | 798 # Read junctions that have been written in previous runs. |
| 869 state_path = _GetJunctionStatePath(options) | 799 state_path = _GetJunctionStatePath(options) |
| 870 old_junctions = _ReadJunctions(options) | 800 old_junctions = _ReadJunctions(options) |
| 871 | 801 |
| 872 # Parse each deps file in order, and extract the dependencies, looking for | 802 # Parse each deps file in order, and extract the dependencies, looking for |
| 873 # conflicts in the output directories. | 803 # conflicts in the output directories. |
| 874 output_dirs = {} | 804 output_dirs = {} |
| 875 all_deps = [] | 805 all_deps = [] |
| 876 for deps_file in args: | 806 for deps_file in args: |
| 877 deps = _ParseDepsFile(deps_file) | 807 deps = deps_utils.ParseDepsFile(deps_file) |
| 878 for key, value in deps.iteritems(): | 808 for key, value in deps.iteritems(): |
| 879 repo_options = _ParseRepoOptions( | 809 repo_options = _ParseRepoOptions( |
| 880 options.cache_dir, options.output_dir, deps_file, key, value) | 810 options.cache_dir, options.output_dir, deps_file, key, value) |
| 881 if repo_options.output_dir in output_dirs: | 811 if repo_options.output_dir in output_dirs: |
| 882 other_repo_options = output_dirs[repo_options.output_dir] | 812 other_repo_options = output_dirs[repo_options.output_dir] |
| 883 _LOGGER.error('Conflicting output directory: %s', | 813 _LOGGER.error('Conflicting output directory: %s', |
| 884 repo_options.output_dir) | 814 repo_options.output_dir) |
| 885 _LOGGER.error('First specified in file: %s', | 815 _LOGGER.error('First specified in file: %s', |
| 886 other_repo_options.deps_file) | 816 other_repo_options.deps_file) |
| 887 _LOGGER.error('And then specified in file: %s', repo_options.deps_file) | 817 _LOGGER.error('And then specified in file: %s', repo_options.deps_file) |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 944 continue | 874 continue |
| 945 if not checkout_dirs[repo.checkout_dir] and not options.force: | 875 if not checkout_dirs[repo.checkout_dir] and not options.force: |
| 946 continue | 876 continue |
| 947 _RecurseRepository(options, repo) | 877 _RecurseRepository(options, repo) |
| 948 | 878 |
| 949 return | 879 return |
| 950 | 880 |
| 951 | 881 |
| 952 if __name__ == '__main__': | 882 if __name__ == '__main__': |
| 953 main() | 883 main() |
| OLD | NEW |