| OLD | NEW |
| 1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
| 2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. | 2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 3 # Use of this source code is governed by a BSD-style license that can be | 3 # Use of this source code is governed by a BSD-style license that can be |
| 4 # found in the LICENSE file. | 4 # found in the LICENSE file. |
| 5 | 5 |
| 6 """Meta checkout manager supporting both Subversion and GIT.""" | 6 """Meta checkout dependency manager for Git.""" |
| 7 # Files | 7 # Files |
| 8 # .gclient : Current client configuration, written by 'config' command. | 8 # .gclient : Current client configuration, written by 'config' command. |
| 9 # Format is a Python script defining 'solutions', a list whose | 9 # Format is a Python script defining 'solutions', a list whose |
| 10 # entries each are maps binding the strings "name" and "url" | 10 # entries each are maps binding the strings "name" and "url" |
| 11 # to strings specifying the name and location of the client | 11 # to strings specifying the name and location of the client |
| 12 # module, as well as "custom_deps" to a map similar to the | 12 # module, as well as "custom_deps" to a map similar to the |
| 13 # deps section of the DEPS file below, as well as | 13 # deps section of the DEPS file below, as well as |
| 14 # "custom_hooks" to a list similar to the hooks sections of | 14 # "custom_hooks" to a list similar to the hooks sections of |
| 15 # the DEPS file below. | 15 # the DEPS file below. |
| 16 # .gclient_entries : A cache constructed by 'update' command. Format is a | 16 # .gclient_entries : A cache constructed by 'update' command. Format is a |
| (...skipping 149 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 166 | 166 |
| 167 sub_target_name is an optional parameter if the module name in the other | 167 sub_target_name is an optional parameter if the module name in the other |
| 168 DEPS file is different. E.g., you might want to map src/net to net.""" | 168 DEPS file is different. E.g., you might want to map src/net to net.""" |
| 169 self.module_name = module_name | 169 self.module_name = module_name |
| 170 self.sub_target_name = sub_target_name | 170 self.sub_target_name = sub_target_name |
| 171 | 171 |
| 172 def __str__(self): | 172 def __str__(self): |
| 173 return 'From(%s, %s)' % (repr(self.module_name), | 173 return 'From(%s, %s)' % (repr(self.module_name), |
| 174 repr(self.sub_target_name)) | 174 repr(self.sub_target_name)) |
| 175 | 175 |
| 176 class FileImpl(object): | |
| 177 """Used to implement the File('') syntax which lets you sync a single file | |
| 178 from a SVN repo.""" | |
| 179 | |
| 180 def __init__(self, file_location): | |
| 181 self.file_location = file_location | |
| 182 | |
| 183 def __str__(self): | |
| 184 return 'File("%s")' % self.file_location | |
| 185 | |
| 186 def GetPath(self): | |
| 187 return os.path.split(self.file_location)[0] | |
| 188 | |
| 189 def GetFilename(self): | |
| 190 rev_tokens = self.file_location.split('@') | |
| 191 return os.path.split(rev_tokens[0])[1] | |
| 192 | |
| 193 def GetRevision(self): | |
| 194 rev_tokens = self.file_location.split('@') | |
| 195 if len(rev_tokens) > 1: | |
| 196 return rev_tokens[1] | |
| 197 return None | |
| 198 | |
| 199 class VarImpl(object): | 176 class VarImpl(object): |
| 200 def __init__(self, custom_vars, local_scope): | 177 def __init__(self, custom_vars, local_scope): |
| 201 self._custom_vars = custom_vars | 178 self._custom_vars = custom_vars |
| 202 self._local_scope = local_scope | 179 self._local_scope = local_scope |
| 203 | 180 |
| 204 def Lookup(self, var_name): | 181 def Lookup(self, var_name): |
| 205 """Implements the Var syntax.""" | 182 """Implements the Var syntax.""" |
| 206 if var_name in self._custom_vars: | 183 if var_name in self._custom_vars: |
| 207 return self._custom_vars[var_name] | 184 return self._custom_vars[var_name] |
| 208 elif var_name in self._local_scope.get("vars", {}): | 185 elif var_name in self._local_scope.get("vars", {}): |
| (...skipping 28 matching lines...) Expand all Loading... |
| 237 self._relative = relative | 214 self._relative = relative |
| 238 # This is a mutable value which has the list of 'target_os' OSes listed in | 215 # This is a mutable value which has the list of 'target_os' OSes listed in |
| 239 # the current deps file. | 216 # the current deps file. |
| 240 self.local_target_os = None | 217 self.local_target_os = None |
| 241 | 218 |
| 242 # These are only set in .gclient and not in DEPS files. | 219 # These are only set in .gclient and not in DEPS files. |
| 243 self._custom_vars = custom_vars or {} | 220 self._custom_vars = custom_vars or {} |
| 244 self._custom_deps = custom_deps or {} | 221 self._custom_deps = custom_deps or {} |
| 245 self._custom_hooks = custom_hooks or [] | 222 self._custom_hooks = custom_hooks or [] |
| 246 | 223 |
| 247 # TODO(iannucci): Remove this when all masters are correctly substituting | |
| 248 # the new blink url. | |
| 249 if (self._custom_vars.get('webkit_trunk', '') == | |
| 250 'svn://svn-mirror.golo.chromium.org/webkit-readonly/trunk'): | |
| 251 new_url = 'svn://svn-mirror.golo.chromium.org/blink/trunk' | |
| 252 print('Overwriting Var("webkit_trunk") with %s' % new_url) | |
| 253 self._custom_vars['webkit_trunk'] = new_url | |
| 254 | |
| 255 # Post process the url to remove trailing slashes. | 224 # Post process the url to remove trailing slashes. |
| 256 if isinstance(self._url, basestring): | 225 if isinstance(self._url, basestring): |
| 257 # urls are sometime incorrectly written as proto://host/path/@rev. Replace | 226 # urls are sometime incorrectly written as proto://host/path/@rev. Replace |
| 258 # it to proto://host/path@rev. | 227 # it to proto://host/path@rev. |
| 259 self._url = self._url.replace('/@', '@') | 228 self._url = self._url.replace('/@', '@') |
| 260 elif not isinstance(self._url, | 229 elif not isinstance(self._url, (self.FromImpl, None.__class__)): |
| 261 (self.FromImpl, self.FileImpl, None.__class__)): | |
| 262 raise gclient_utils.Error( | 230 raise gclient_utils.Error( |
| 263 ('dependency url must be either a string, None, ' | 231 ('dependency url must be either a string, None, ' |
| 264 'File() or From() instead of %s') % self._url.__class__.__name__) | 232 'or From() instead of %s') % self._url.__class__.__name__) |
| 265 # Make any deps_file path platform-appropriate. | 233 # Make any deps_file path platform-appropriate. |
| 266 for sep in ['/', '\\']: | 234 for sep in ['/', '\\']: |
| 267 self._deps_file = self._deps_file.replace(sep, os.sep) | 235 self._deps_file = self._deps_file.replace(sep, os.sep) |
| 268 | 236 |
| 269 @property | 237 @property |
| 270 def deps_file(self): | 238 def deps_file(self): |
| 271 return self._deps_file | 239 return self._deps_file |
| 272 | 240 |
| 273 @property | 241 @property |
| 274 def managed(self): | 242 def managed(self): |
| (...skipping 252 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 527 parsed_url = urlparse.urlparse(url) | 495 parsed_url = urlparse.urlparse(url) |
| 528 if (not parsed_url[0] and | 496 if (not parsed_url[0] and |
| 529 not re.match(r'^\w+\@[\w\.-]+\:[\w\/]+', parsed_url[2])): | 497 not re.match(r'^\w+\@[\w\.-]+\:[\w\/]+', parsed_url[2])): |
| 530 # A relative url. Fetch the real base. | 498 # A relative url. Fetch the real base. |
| 531 path = parsed_url[2] | 499 path = parsed_url[2] |
| 532 if not path.startswith('/'): | 500 if not path.startswith('/'): |
| 533 raise gclient_utils.Error( | 501 raise gclient_utils.Error( |
| 534 'relative DEPS entry \'%s\' must begin with a slash' % url) | 502 'relative DEPS entry \'%s\' must begin with a slash' % url) |
| 535 # Create a scm just to query the full url. | 503 # Create a scm just to query the full url. |
| 536 parent_url = self.parent.parsed_url | 504 parent_url = self.parent.parsed_url |
| 537 if isinstance(parent_url, self.FileImpl): | |
| 538 parent_url = parent_url.file_location | |
| 539 scm = gclient_scm.CreateSCM( | 505 scm = gclient_scm.CreateSCM( |
| 540 parent_url, self.root.root_dir, None, self.outbuf) | 506 parent_url, self.root.root_dir, None, self.outbuf) |
| 541 parsed_url = scm.FullUrlForRelativeUrl(url) | 507 parsed_url = scm.FullUrlForRelativeUrl(url) |
| 542 else: | 508 else: |
| 543 parsed_url = url | 509 parsed_url = url |
| 544 logging.info( | 510 logging.info( |
| 545 'Dependency(%s).LateOverride(%s) -> %s' % | 511 'Dependency(%s).LateOverride(%s) -> %s' % |
| 546 (self.name, url, parsed_url)) | 512 (self.name, url, parsed_url)) |
| 547 return parsed_url | 513 return parsed_url |
| 548 | 514 |
| 549 if isinstance(url, self.FileImpl): | |
| 550 logging.info( | |
| 551 'Dependency(%s).LateOverride(%s) -> %s (File)' % | |
| 552 (self.name, url, url)) | |
| 553 return url | |
| 554 | |
| 555 if url is None: | 515 if url is None: |
| 556 logging.info( | 516 logging.info( |
| 557 'Dependency(%s).LateOverride(%s) -> %s' % (self.name, url, url)) | 517 'Dependency(%s).LateOverride(%s) -> %s' % (self.name, url, url)) |
| 558 return url | 518 return url |
| 559 | 519 |
| 560 raise gclient_utils.Error('Unknown url type') | 520 raise gclient_utils.Error('Unknown url type') |
| 561 | 521 |
| 562 @staticmethod | 522 @staticmethod |
| 563 def MergeWithOsDeps(deps, deps_os, target_os_list): | 523 def MergeWithOsDeps(deps, deps_os, target_os_list): |
| 564 """Returns a new "deps" structure that is the deps sent in updated | 524 """Returns a new "deps" structure that is the deps sent in updated |
| (...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 635 if use_strict: | 595 if use_strict: |
| 636 logging.info( | 596 logging.info( |
| 637 'ParseDepsFile(%s): Strict Mode Enabled', self.name) | 597 'ParseDepsFile(%s): Strict Mode Enabled', self.name) |
| 638 global_scope = { | 598 global_scope = { |
| 639 '__builtins__': {'None': None}, | 599 '__builtins__': {'None': None}, |
| 640 'Var': var.Lookup, | 600 'Var': var.Lookup, |
| 641 'deps_os': {}, | 601 'deps_os': {}, |
| 642 } | 602 } |
| 643 else: | 603 else: |
| 644 global_scope = { | 604 global_scope = { |
| 645 'File': self.FileImpl, | |
| 646 'From': self.FromImpl, | 605 'From': self.FromImpl, |
| 647 'Var': var.Lookup, | 606 'Var': var.Lookup, |
| 648 'deps_os': {}, | 607 'deps_os': {}, |
| 649 } | 608 } |
| 650 # Eval the content. | 609 # Eval the content. |
| 651 try: | 610 try: |
| 652 exec(deps_content, global_scope, local_scope) | 611 exec(deps_content, global_scope, local_scope) |
| 653 except SyntaxError as e: | 612 except SyntaxError as e: |
| 654 gclient_utils.SyntaxErrorToError(filepath, e) | 613 gclient_utils.SyntaxErrorToError(filepath, e) |
| 655 if use_strict: | 614 if use_strict: |
| (...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 766 self.add_dependencies_and_close(deps_to_add, hooks_to_run) | 725 self.add_dependencies_and_close(deps_to_add, hooks_to_run) |
| 767 logging.info('ParseDepsFile(%s) done' % self.name) | 726 logging.info('ParseDepsFile(%s) done' % self.name) |
| 768 | 727 |
| 769 def add_dependencies_and_close(self, deps_to_add, hooks): | 728 def add_dependencies_and_close(self, deps_to_add, hooks): |
| 770 """Adds the dependencies, hooks and mark the parsing as done.""" | 729 """Adds the dependencies, hooks and mark the parsing as done.""" |
| 771 for dep in deps_to_add: | 730 for dep in deps_to_add: |
| 772 if dep.verify_validity(): | 731 if dep.verify_validity(): |
| 773 self.add_dependency(dep) | 732 self.add_dependency(dep) |
| 774 self._mark_as_parsed(hooks) | 733 self._mark_as_parsed(hooks) |
| 775 | 734 |
| 776 def maybeGetParentRevision(self, command, options, parsed_url, parent): | |
| 777 """Uses revision/timestamp of parent if no explicit revision was specified. | |
| 778 | |
| 779 If we are performing an update and --transitive is set, use | |
| 780 - the parent's revision if 'self.url' is in the same repository | |
| 781 - the parent's timestamp otherwise | |
| 782 to update 'self.url'. The used revision/timestamp will be set in | |
| 783 'options.revision'. | |
| 784 If we have an explicit revision do nothing. | |
| 785 """ | |
| 786 if command == 'update' and options.transitive and not options.revision: | |
| 787 _, revision = gclient_utils.SplitUrlRevision(parsed_url) | |
| 788 if not revision: | |
| 789 options.revision = getattr(parent, '_used_revision', None) | |
| 790 if (options.revision and | |
| 791 not gclient_utils.IsDateRevision(options.revision)): | |
| 792 assert self.parent and self.parent.used_scm | |
| 793 # If this dependency is in the same repository as parent it's url will | |
| 794 # start with a slash. If so we take the parent revision instead of | |
| 795 # it's timestamp. | |
| 796 # (The timestamps of commits in google code are broken -- which can | |
| 797 # result in dependencies to be checked out at the wrong revision) | |
| 798 if self.url.startswith('/'): | |
| 799 if options.verbose: | |
| 800 print('Using parent\'s revision %s since we are in the same ' | |
| 801 'repository.' % options.revision) | |
| 802 else: | |
| 803 parent_revision_date = self.parent.used_scm.GetRevisionDate( | |
| 804 options.revision) | |
| 805 options.revision = gclient_utils.MakeDateRevision( | |
| 806 parent_revision_date) | |
| 807 if options.verbose: | |
| 808 print('Using parent\'s revision date %s since we are in a ' | |
| 809 'different repository.' % options.revision) | |
| 810 | |
| 811 def findDepsFromNotAllowedHosts(self): | 735 def findDepsFromNotAllowedHosts(self): |
| 812 """Returns a list of depenecies from not allowed hosts. | 736 """Returns a list of depenecies from not allowed hosts. |
| 813 | 737 |
| 814 If allowed_hosts is not set, allows all hosts and returns empty list. | 738 If allowed_hosts is not set, allows all hosts and returns empty list. |
| 815 """ | 739 """ |
| 816 if not self._allowed_hosts: | 740 if not self._allowed_hosts: |
| 817 return [] | 741 return [] |
| 818 bad_deps = [] | 742 bad_deps = [] |
| 819 for dep in self._dependencies: | 743 for dep in self._dependencies: |
| 820 # Don't enforce this for custom_deps. | 744 # Don't enforce this for custom_deps. |
| (...skipping 14 matching lines...) Expand all Loading... |
| 835 if not self.should_process: | 759 if not self.should_process: |
| 836 return | 760 return |
| 837 # When running runhooks, there's no need to consult the SCM. | 761 # When running runhooks, there's no need to consult the SCM. |
| 838 # All known hooks are expected to run unconditionally regardless of working | 762 # All known hooks are expected to run unconditionally regardless of working |
| 839 # copy state, so skip the SCM status check. | 763 # copy state, so skip the SCM status check. |
| 840 run_scm = command not in ('runhooks', 'recurse', None) | 764 run_scm = command not in ('runhooks', 'recurse', None) |
| 841 parsed_url = self.LateOverride(self.url) | 765 parsed_url = self.LateOverride(self.url) |
| 842 file_list = [] if not options.nohooks else None | 766 file_list = [] if not options.nohooks else None |
| 843 revision_override = revision_overrides.pop(self.name, None) | 767 revision_override = revision_overrides.pop(self.name, None) |
| 844 if run_scm and parsed_url: | 768 if run_scm and parsed_url: |
| 845 if isinstance(parsed_url, self.FileImpl): | 769 # Create a shallow copy to mutate revision. |
| 846 # Special support for single-file checkout. | 770 options = copy.copy(options) |
| 847 if not command in (None, 'cleanup', 'diff', 'pack', 'status'): | 771 options.revision = revision_override |
| 848 # Sadly, pylint doesn't realize that parsed_url is of FileImpl. | 772 self._used_revision = options.revision |
| 849 # pylint: disable=E1103 | 773 self._used_scm = gclient_scm.CreateSCM( |
| 850 options.revision = parsed_url.GetRevision() | 774 parsed_url, self.root.root_dir, self.name, self.outbuf, |
| 851 self._used_scm = gclient_scm.SVNWrapper( | 775 out_cb=work_queue.out_cb) |
| 852 parsed_url.GetPath(), self.root.root_dir, self.name, | 776 self._got_revision = self._used_scm.RunCommand(command, options, args, |
| 853 out_cb=work_queue.out_cb) | 777 file_list) |
| 854 self._used_scm.RunCommand('updatesingle', | 778 if file_list: |
| 855 options, args + [parsed_url.GetFilename()], file_list) | 779 file_list = [os.path.join(self.name, f.strip()) for f in file_list] |
| 856 else: | |
| 857 # Create a shallow copy to mutate revision. | |
| 858 options = copy.copy(options) | |
| 859 options.revision = revision_override | |
| 860 self.maybeGetParentRevision( | |
| 861 command, options, parsed_url, self.parent) | |
| 862 self._used_revision = options.revision | |
| 863 self._used_scm = gclient_scm.CreateSCM( | |
| 864 parsed_url, self.root.root_dir, self.name, self.outbuf, | |
| 865 out_cb=work_queue.out_cb) | |
| 866 self._got_revision = self._used_scm.RunCommand(command, options, args, | |
| 867 file_list) | |
| 868 if file_list: | |
| 869 file_list = [os.path.join(self.name, f.strip()) for f in file_list] | |
| 870 | 780 |
| 871 # TODO(phajdan.jr): We should know exactly when the paths are absolute. | 781 # TODO(phajdan.jr): We should know exactly when the paths are absolute. |
| 872 # Convert all absolute paths to relative. | 782 # Convert all absolute paths to relative. |
| 873 for i in range(len(file_list or [])): | 783 for i in range(len(file_list or [])): |
| 874 # It depends on the command being executed (like runhooks vs sync). | 784 # It depends on the command being executed (like runhooks vs sync). |
| 875 if not os.path.isabs(file_list[i]): | 785 if not os.path.isabs(file_list[i]): |
| 876 continue | 786 continue |
| 877 prefix = os.path.commonprefix( | 787 prefix = os.path.commonprefix( |
| 878 [self.root.root_dir.lower(), file_list[i].lower()]) | 788 [self.root.root_dir.lower(), file_list[i].lower()]) |
| 879 file_list[i] = file_list[i][len(prefix):] | 789 file_list[i] = file_list[i][len(prefix):] |
| 880 # Strip any leading path separators. | 790 # Strip any leading path separators. |
| 881 while file_list[i].startswith(('\\', '/')): | 791 while file_list[i].startswith(('\\', '/')): |
| 882 file_list[i] = file_list[i][1:] | 792 file_list[i] = file_list[i][1:] |
| 883 | 793 |
| 884 # Always parse the DEPS file. | 794 # Always parse the DEPS file. |
| 885 self.ParseDepsFile() | 795 self.ParseDepsFile() |
| 886 self._run_is_done(file_list or [], parsed_url) | 796 self._run_is_done(file_list or [], parsed_url) |
| 887 if command in ('update', 'revert') and not options.noprehooks: | 797 if command in ('update', 'revert') and not options.noprehooks: |
| 888 self.RunPreDepsHooks() | 798 self.RunPreDepsHooks() |
| 889 | 799 |
| 890 if self.recursion_limit: | 800 if self.recursion_limit: |
| 891 # Parse the dependencies of this dependency. | 801 # Parse the dependencies of this dependency. |
| 892 for s in self.dependencies: | 802 for s in self.dependencies: |
| 893 work_queue.enqueue(s) | 803 work_queue.enqueue(s) |
| 894 | 804 |
| 895 if command == 'recurse': | 805 if command == 'recurse': |
| 896 if not isinstance(parsed_url, self.FileImpl): | 806 # Skip file only checkout. |
| 897 # Skip file only checkout. | 807 scm = gclient_scm.GetScmName(parsed_url) |
| 898 scm = gclient_scm.GetScmName(parsed_url) | 808 if not options.scm or scm in options.scm: |
| 899 if not options.scm or scm in options.scm: | 809 cwd = os.path.normpath(os.path.join(self.root.root_dir, self.name)) |
| 900 cwd = os.path.normpath(os.path.join(self.root.root_dir, self.name)) | 810 # Pass in the SCM type as an env variable. Make sure we don't put |
| 901 # Pass in the SCM type as an env variable. Make sure we don't put | 811 # unicode strings in the environment. |
| 902 # unicode strings in the environment. | 812 env = os.environ.copy() |
| 903 env = os.environ.copy() | 813 if scm: |
| 904 if scm: | 814 env['GCLIENT_SCM'] = str(scm) |
| 905 env['GCLIENT_SCM'] = str(scm) | 815 if parsed_url: |
| 906 if parsed_url: | 816 env['GCLIENT_URL'] = str(parsed_url) |
| 907 env['GCLIENT_URL'] = str(parsed_url) | 817 env['GCLIENT_DEP_PATH'] = str(self.name) |
| 908 env['GCLIENT_DEP_PATH'] = str(self.name) | 818 if options.prepend_dir and scm == 'git': |
| 909 if options.prepend_dir and scm == 'git': | 819 print_stdout = False |
| 910 print_stdout = False | 820 def filter_fn(line): |
| 911 def filter_fn(line): | 821 """Git-specific path marshaling. It is optimized for git-grep.""" |
| 912 """Git-specific path marshaling. It is optimized for git-grep.""" | |
| 913 | 822 |
| 914 def mod_path(git_pathspec): | 823 def mod_path(git_pathspec): |
| 915 match = re.match('^(\\S+?:)?([^\0]+)$', git_pathspec) | 824 match = re.match('^(\\S+?:)?([^\0]+)$', git_pathspec) |
| 916 modified_path = os.path.join(self.name, match.group(2)) | 825 modified_path = os.path.join(self.name, match.group(2)) |
| 917 branch = match.group(1) or '' | 826 branch = match.group(1) or '' |
| 918 return '%s%s' % (branch, modified_path) | 827 return '%s%s' % (branch, modified_path) |
| 919 | 828 |
| 920 match = re.match('^Binary file ([^\0]+) matches$', line) | 829 match = re.match('^Binary file ([^\0]+) matches$', line) |
| 921 if match: | 830 if match: |
| 922 print('Binary file %s matches\n' % mod_path(match.group(1))) | 831 print('Binary file %s matches\n' % mod_path(match.group(1))) |
| 923 return | 832 return |
| 924 | 833 |
| 925 items = line.split('\0') | 834 items = line.split('\0') |
| 926 if len(items) == 2 and items[1]: | 835 if len(items) == 2 and items[1]: |
| 927 print('%s : %s' % (mod_path(items[0]), items[1])) | 836 print('%s : %s' % (mod_path(items[0]), items[1])) |
| 928 elif len(items) >= 2: | 837 elif len(items) >= 2: |
| 929 # Multiple null bytes or a single trailing null byte indicate | 838 # Multiple null bytes or a single trailing null byte indicate |
| 930 # git is likely displaying filenames only (such as with -l) | 839 # git is likely displaying filenames only (such as with -l) |
| 931 print('\n'.join(mod_path(path) for path in items if path)) | 840 print('\n'.join(mod_path(path) for path in items if path)) |
| 932 else: | 841 else: |
| 933 print(line) | 842 print(line) |
| 934 else: | 843 else: |
| 935 print_stdout = True | 844 print_stdout = True |
| 936 filter_fn = None | 845 filter_fn = None |
| 937 | 846 |
| 938 if parsed_url is None: | 847 if parsed_url is None: |
| 939 print('Skipped omitted dependency %s' % cwd, file=sys.stderr) | 848 print('Skipped omitted dependency %s' % cwd, file=sys.stderr) |
| 940 elif os.path.isdir(cwd): | 849 elif os.path.isdir(cwd): |
| 941 try: | 850 try: |
| 942 gclient_utils.CheckCallAndFilter( | 851 gclient_utils.CheckCallAndFilter( |
| 943 args, cwd=cwd, env=env, print_stdout=print_stdout, | 852 args, cwd=cwd, env=env, print_stdout=print_stdout, |
| 944 filter_fn=filter_fn, | 853 filter_fn=filter_fn, |
| 945 ) | 854 ) |
| 946 except subprocess2.CalledProcessError: | 855 except subprocess2.CalledProcessError: |
| 947 if not options.ignore: | 856 if not options.ignore: |
| 948 raise | 857 raise |
| 949 else: | 858 else: |
| 950 print('Skipped missing %s' % cwd, file=sys.stderr) | 859 print('Skipped missing %s' % cwd, file=sys.stderr) |
| 951 | 860 |
| 952 | 861 |
| 953 @gclient_utils.lockedmethod | 862 @gclient_utils.lockedmethod |
| 954 def _run_is_done(self, file_list, parsed_url): | 863 def _run_is_done(self, file_list, parsed_url): |
| 955 # Both these are kept for hooks that are run as a separate tree traversal. | 864 # Both these are kept for hooks that are run as a separate tree traversal. |
| 956 self._file_list = file_list | 865 self._file_list = file_list |
| 957 self._parsed_url = parsed_url | 866 self._parsed_url = parsed_url |
| 958 self._processed = True | 867 self._processed = True |
| 959 | 868 |
| 960 @staticmethod | 869 @staticmethod |
| (...skipping 17 matching lines...) Expand all Loading... |
| 978 | 887 |
| 979 RunOnDeps() must have been called before to load the DEPS. | 888 RunOnDeps() must have been called before to load the DEPS. |
| 980 """ | 889 """ |
| 981 result = [] | 890 result = [] |
| 982 if not self.should_process or not self.recursion_limit: | 891 if not self.should_process or not self.recursion_limit: |
| 983 # Don't run the hook when it is above recursion_limit. | 892 # Don't run the hook when it is above recursion_limit. |
| 984 return result | 893 return result |
| 985 # If "--force" was specified, run all hooks regardless of what files have | 894 # If "--force" was specified, run all hooks regardless of what files have |
| 986 # changed. | 895 # changed. |
| 987 if self.deps_hooks: | 896 if self.deps_hooks: |
| 988 # TODO(maruel): If the user is using git or git-svn, then we don't know | 897 # TODO(maruel): If the user is using git, then we don't know |
| 989 # what files have changed so we always run all hooks. It'd be nice to fix | 898 # what files have changed so we always run all hooks. It'd be nice to fix |
| 990 # that. | 899 # that. |
| 991 if (options.force or | 900 if (options.force or |
| 992 isinstance(self.parsed_url, self.FileImpl) or | |
| 993 gclient_scm.GetScmName(self.parsed_url) in ('git', None) or | 901 gclient_scm.GetScmName(self.parsed_url) in ('git', None) or |
| 994 os.path.isdir(os.path.join(self.root.root_dir, self.name, '.git'))): | 902 os.path.isdir(os.path.join(self.root.root_dir, self.name, '.git'))): |
| 995 for hook_dict in self.deps_hooks: | 903 for hook_dict in self.deps_hooks: |
| 996 result.append(self.GetHookAction(hook_dict, [])) | 904 result.append(self.GetHookAction(hook_dict, [])) |
| 997 else: | 905 else: |
| 998 # Run hooks on the basis of whether the files from the gclient operation | 906 # Run hooks on the basis of whether the files from the gclient operation |
| 999 # match each hook's pattern. | 907 # match each hook's pattern. |
| 1000 for hook_dict in self.deps_hooks: | 908 for hook_dict in self.deps_hooks: |
| 1001 pattern = re.compile(hook_dict['pattern']) | 909 pattern = re.compile(hook_dict['pattern']) |
| 1002 matching_file_list = [ | 910 matching_file_list = [ |
| (...skipping 263 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1266 is actually checked out in %(checkout_path)s. | 1174 is actually checked out in %(checkout_path)s. |
| 1267 | 1175 |
| 1268 The .gclient file contains: | 1176 The .gclient file contains: |
| 1269 URL: %(expected_url)s (%(expected_scm)s) | 1177 URL: %(expected_url)s (%(expected_scm)s) |
| 1270 Cache mirror: %(mirror_string)s | 1178 Cache mirror: %(mirror_string)s |
| 1271 | 1179 |
| 1272 The local checkout in %(checkout_path)s reports: | 1180 The local checkout in %(checkout_path)s reports: |
| 1273 %(actual_url)s (%(actual_scm)s) | 1181 %(actual_url)s (%(actual_scm)s) |
| 1274 | 1182 |
| 1275 You should ensure that the URL listed in .gclient is correct and either change | 1183 You should ensure that the URL listed in .gclient is correct and either change |
| 1276 it or fix the checkout. If you're managing your own git checkout in | 1184 it or fix the checkout. |
| 1277 %(checkout_path)s but the URL in .gclient is for an svn repository, you probably | |
| 1278 want to set 'managed': False in .gclient. | |
| 1279 ''' % {'checkout_path': os.path.join(self.root_dir, dep.name), | 1185 ''' % {'checkout_path': os.path.join(self.root_dir, dep.name), |
| 1280 'expected_url': dep.url, | 1186 'expected_url': dep.url, |
| 1281 'expected_scm': gclient_scm.GetScmName(dep.url), | 1187 'expected_scm': gclient_scm.GetScmName(dep.url), |
| 1282 'mirror_string' : mirror_string, | 1188 'mirror_string' : mirror_string, |
| 1283 'actual_url': actual_url, | 1189 'actual_url': actual_url, |
| 1284 'actual_scm': gclient_scm.GetScmName(actual_url)}) | 1190 'actual_scm': gclient_scm.GetScmName(actual_url)}) |
| 1285 | 1191 |
| 1286 def SetConfig(self, content): | 1192 def SetConfig(self, content): |
| 1287 assert not self.dependencies | 1193 assert not self.dependencies |
| 1288 config_dict = {} | 1194 config_dict = {} |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1331 raise gclient_utils.Error('Invalid .gclient file. Solution is ' | 1237 raise gclient_utils.Error('Invalid .gclient file. Solution is ' |
| 1332 'incomplete: %s' % s) | 1238 'incomplete: %s' % s) |
| 1333 self.add_dependencies_and_close(deps_to_add, config_dict.get('hooks', [])) | 1239 self.add_dependencies_and_close(deps_to_add, config_dict.get('hooks', [])) |
| 1334 logging.info('SetConfig() done') | 1240 logging.info('SetConfig() done') |
| 1335 | 1241 |
| 1336 def SaveConfig(self): | 1242 def SaveConfig(self): |
| 1337 gclient_utils.FileWrite(os.path.join(self.root_dir, | 1243 gclient_utils.FileWrite(os.path.join(self.root_dir, |
| 1338 self._options.config_filename), | 1244 self._options.config_filename), |
| 1339 self.config_content) | 1245 self.config_content) |
| 1340 | 1246 |
| 1341 def MigrateConfigToGit(self, path, options): | |
| 1342 svn_url_re = re.compile('^(https?://src\.chromium\.org/svn|' | |
| 1343 'svn://svn\.chromium\.org/chrome)/' | |
| 1344 '(trunk|branches/[^/]+)/src') | |
| 1345 old_git_re = re.compile('^(https?://git\.chromium\.org|' | |
| 1346 'ssh://([a-zA-Z_][a-zA-Z0-9_-]*@)?' | |
| 1347 'gerrit\.chromium\.org(:2941[89])?)/' | |
| 1348 'chromium/src\.git') | |
| 1349 # Scan existing .gclient file for obsolete settings. It would be simpler | |
| 1350 # to traverse self.dependencies, but working with the AST allows the code to | |
| 1351 # dump an updated .gclient file that preserves the ordering of the original. | |
| 1352 a = ast.parse(self.config_content, options.config_filename, 'exec') | |
| 1353 modified = False | |
| 1354 solutions = [elem for elem in a.body if 'solutions' in | |
| 1355 [target.id for target in elem.targets]] | |
| 1356 if not solutions: | |
| 1357 return self | |
| 1358 solutions = solutions[-1] | |
| 1359 for solution in solutions.value.elts: | |
| 1360 # Check for obsolete URL's | |
| 1361 url_idx = ast_dict_index(solution, 'url') | |
| 1362 if url_idx == -1: | |
| 1363 continue | |
| 1364 url_val = solution.values[url_idx] | |
| 1365 if type(url_val) is not ast.Str: | |
| 1366 continue | |
| 1367 if (svn_url_re.match(url_val.s.strip())): | |
| 1368 raise gclient_utils.Error( | |
| 1369 """ | |
| 1370 The chromium code repository has migrated completely to git. | |
| 1371 Your SVN-based checkout is now obsolete; you need to create a brand-new | |
| 1372 git checkout by following these instructions: | |
| 1373 | |
| 1374 http://www.chromium.org/developers/how-tos/get-the-code | |
| 1375 """) | |
| 1376 if (old_git_re.match(url_val.s.strip())): | |
| 1377 url_val.s = CHROMIUM_SRC_URL | |
| 1378 modified = True | |
| 1379 | |
| 1380 # Ensure deps_file is set to .DEPS.git. We enforce this here to smooth | |
| 1381 # over switching between pre-git-migration and post-git-migration | |
| 1382 # revisions. | |
| 1383 # - For pre-migration revisions, .DEPS.git must be explicitly set. | |
| 1384 # - For post-migration revisions, .DEPS.git is not present, so gclient | |
| 1385 # will correctly fall back to DEPS. | |
| 1386 if url_val.s == CHROMIUM_SRC_URL: | |
| 1387 deps_file_idx = ast_dict_index(solution, 'deps_file') | |
| 1388 if deps_file_idx != -1: | |
| 1389 continue | |
| 1390 solution.keys.append(ast.Str('deps_file')) | |
| 1391 solution.values.append(ast.Str('.DEPS.git')) | |
| 1392 modified = True | |
| 1393 | |
| 1394 if not modified: | |
| 1395 return self | |
| 1396 | |
| 1397 print( | |
| 1398 """ | |
| 1399 WARNING: gclient detected an obsolete setting in your %s file. The file has | |
| 1400 been automagically updated. The previous version is available at %s.old. | |
| 1401 """ % (options.config_filename, options.config_filename)) | |
| 1402 | |
| 1403 # Replace existing .gclient with the updated version. | |
| 1404 # Return a new GClient instance based on the new content. | |
| 1405 new_content = ast2str(a) | |
| 1406 dot_gclient_fn = os.path.join(path, options.config_filename) | |
| 1407 try: | |
| 1408 os.rename(dot_gclient_fn, dot_gclient_fn + '.old') | |
| 1409 except OSError: | |
| 1410 pass | |
| 1411 with open(dot_gclient_fn, 'w') as fh: | |
| 1412 fh.write(new_content) | |
| 1413 client = GClient(path, options) | |
| 1414 client.SetConfig(new_content) | |
| 1415 return client | |
| 1416 | |
| 1417 @staticmethod | 1247 @staticmethod |
| 1418 def LoadCurrentConfig(options): | 1248 def LoadCurrentConfig(options): |
| 1419 """Searches for and loads a .gclient file relative to the current working | 1249 """Searches for and loads a .gclient file relative to the current working |
| 1420 dir. Returns a GClient object.""" | 1250 dir. Returns a GClient object.""" |
| 1421 if options.spec: | 1251 if options.spec: |
| 1422 client = GClient('.', options) | 1252 client = GClient('.', options) |
| 1423 client.SetConfig(options.spec) | 1253 client.SetConfig(options.spec) |
| 1424 else: | 1254 else: |
| 1425 if options.verbose: | 1255 if options.verbose: |
| 1426 print('Looking for %s starting from %s\n' % ( | 1256 print('Looking for %s starting from %s\n' % ( |
| 1427 options.config_filename, os.getcwd())) | 1257 options.config_filename, os.getcwd())) |
| 1428 path = gclient_utils.FindGclientRoot(os.getcwd(), options.config_filename) | 1258 path = gclient_utils.FindGclientRoot(os.getcwd(), options.config_filename) |
| 1429 if not path: | 1259 if not path: |
| 1430 return None | 1260 return None |
| 1431 client = GClient(path, options) | 1261 client = GClient(path, options) |
| 1432 client.SetConfig(gclient_utils.FileRead( | 1262 client.SetConfig(gclient_utils.FileRead( |
| 1433 os.path.join(path, options.config_filename))) | 1263 os.path.join(path, options.config_filename))) |
| 1434 client = client.MigrateConfigToGit(path, options) | |
| 1435 | 1264 |
| 1436 if (options.revisions and | 1265 if (options.revisions and |
| 1437 len(client.dependencies) > 1 and | 1266 len(client.dependencies) > 1 and |
| 1438 any('@' not in r for r in options.revisions)): | 1267 any('@' not in r for r in options.revisions)): |
| 1439 print( | 1268 print( |
| 1440 ('You must specify the full solution name like --revision %s@%s\n' | 1269 ('You must specify the full solution name like --revision %s@%s\n' |
| 1441 'when you have multiple solutions setup in your .gclient file.\n' | 1270 'when you have multiple solutions setup in your .gclient file.\n' |
| 1442 'Other solutions present are: %s.') % ( | 1271 'Other solutions present are: %s.') % ( |
| 1443 client.dependencies[0].name, | 1272 client.dependencies[0].name, |
| 1444 options.revisions[0], | 1273 options.revisions[0], |
| (...skipping 14 matching lines...) Expand all Loading... |
| 1459 | 1288 |
| 1460 def _SaveEntries(self): | 1289 def _SaveEntries(self): |
| 1461 """Creates a .gclient_entries file to record the list of unique checkouts. | 1290 """Creates a .gclient_entries file to record the list of unique checkouts. |
| 1462 | 1291 |
| 1463 The .gclient_entries file lives in the same directory as .gclient. | 1292 The .gclient_entries file lives in the same directory as .gclient. |
| 1464 """ | 1293 """ |
| 1465 # Sometimes pprint.pformat will use {', sometimes it'll use { ' ... It | 1294 # Sometimes pprint.pformat will use {', sometimes it'll use { ' ... It |
| 1466 # makes testing a bit too fun. | 1295 # makes testing a bit too fun. |
| 1467 result = 'entries = {\n' | 1296 result = 'entries = {\n' |
| 1468 for entry in self.root.subtree(False): | 1297 for entry in self.root.subtree(False): |
| 1469 # Skip over File() dependencies as we can't version them. | 1298 result += ' %s: %s,\n' % (pprint.pformat(entry.name), |
| 1470 if not isinstance(entry.parsed_url, self.FileImpl): | 1299 pprint.pformat(entry.parsed_url)) |
| 1471 result += ' %s: %s,\n' % (pprint.pformat(entry.name), | |
| 1472 pprint.pformat(entry.parsed_url)) | |
| 1473 result += '}\n' | 1300 result += '}\n' |
| 1474 file_path = os.path.join(self.root_dir, self._options.entries_filename) | 1301 file_path = os.path.join(self.root_dir, self._options.entries_filename) |
| 1475 logging.debug(result) | 1302 logging.debug(result) |
| 1476 gclient_utils.FileWrite(file_path, result) | 1303 gclient_utils.FileWrite(file_path, result) |
| 1477 | 1304 |
| 1478 def _ReadEntries(self): | 1305 def _ReadEntries(self): |
| 1479 """Read the .gclient_entries file for the given client. | 1306 """Read the .gclient_entries file for the given client. |
| 1480 | 1307 |
| 1481 Returns: | 1308 Returns: |
| 1482 A sequence of solution names, which will be empty if there is the | 1309 A sequence of solution names, which will be empty if there is the |
| (...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1592 e_dir = os.path.join(self.root_dir, entry_fixed) | 1419 e_dir = os.path.join(self.root_dir, entry_fixed) |
| 1593 # Use entry and not entry_fixed there. | 1420 # Use entry and not entry_fixed there. |
| 1594 if (entry not in entries and | 1421 if (entry not in entries and |
| 1595 (not any(path.startswith(entry + '/') for path in entries)) and | 1422 (not any(path.startswith(entry + '/') for path in entries)) and |
| 1596 os.path.exists(e_dir)): | 1423 os.path.exists(e_dir)): |
| 1597 # The entry has been removed from DEPS. | 1424 # The entry has been removed from DEPS. |
| 1598 scm = gclient_scm.CreateSCM( | 1425 scm = gclient_scm.CreateSCM( |
| 1599 prev_url, self.root_dir, entry_fixed, self.outbuf) | 1426 prev_url, self.root_dir, entry_fixed, self.outbuf) |
| 1600 | 1427 |
| 1601 # Check to see if this directory is now part of a higher-up checkout. | 1428 # Check to see if this directory is now part of a higher-up checkout. |
| 1602 # The directory might be part of a git OR svn checkout. | |
| 1603 scm_root = None | 1429 scm_root = None |
| 1604 scm_class = None | 1430 try: |
| 1605 for scm_class in (gclient_scm.scm.GIT, gclient_scm.scm.SVN): | 1431 scm_root = gclient_scm.scm.GIT.GetCheckoutRoot(scm.checkout_path) |
| 1606 try: | 1432 except subprocess2.CalledProcessError: |
| 1607 scm_root = scm_class.GetCheckoutRoot(scm.checkout_path) | 1433 pass |
| 1608 except subprocess2.CalledProcessError: | 1434 if not scm_root: |
| 1609 pass | |
| 1610 if scm_root: | |
| 1611 break | |
| 1612 else: | |
| 1613 logging.warning('Could not find checkout root for %s. Unable to ' | 1435 logging.warning('Could not find checkout root for %s. Unable to ' |
| 1614 'determine whether it is part of a higher-level ' | 1436 'determine whether it is part of a higher-level ' |
| 1615 'checkout, so not removing.' % entry) | 1437 'checkout, so not removing.' % entry) |
| 1616 continue | 1438 continue |
| 1617 | 1439 |
| 1618 # This is to handle the case of third_party/WebKit migrating from | 1440 # This is to handle the case of third_party/WebKit migrating from |
| 1619 # being a DEPS entry to being part of the main project. | 1441 # being a DEPS entry to being part of the main project. |
| 1620 # If the subproject is a Git project, we need to remove its .git | 1442 # If the subproject is a Git project, we need to remove its .git |
| 1621 # folder. Otherwise git operations on that folder will have different | 1443 # folder. Otherwise git operations on that folder will have different |
| 1622 # effects depending on the current working directory. | 1444 # effects depending on the current working directory. |
| 1623 if scm_class == gclient_scm.scm.GIT and ( | 1445 if os.path.abspath(scm_root) == os.path.abspath(e_dir): |
| 1624 os.path.abspath(scm_root) == os.path.abspath(e_dir)): | |
| 1625 e_par_dir = os.path.join(e_dir, os.pardir) | 1446 e_par_dir = os.path.join(e_dir, os.pardir) |
| 1626 if scm_class.IsInsideWorkTree(e_par_dir): | 1447 if gclient_scm.scm.GIT.IsInsideWorkTree(e_par_dir): |
| 1627 par_scm_root = scm_class.GetCheckoutRoot(e_par_dir) | 1448 par_scm_root = gclient_scm.scm.GIT.GetCheckoutRoot(e_par_dir) |
| 1628 # rel_e_dir : relative path of entry w.r.t. its parent repo. | 1449 # rel_e_dir : relative path of entry w.r.t. its parent repo. |
| 1629 rel_e_dir = os.path.relpath(e_dir, par_scm_root) | 1450 rel_e_dir = os.path.relpath(e_dir, par_scm_root) |
| 1630 if scm_class.IsDirectoryVersioned(par_scm_root, rel_e_dir): | 1451 if gclient_scm.scm.GIT.IsDirectoryVersioned( |
| 1452 par_scm_root, rel_e_dir): |
| 1631 save_dir = scm.GetGitBackupDirPath() | 1453 save_dir = scm.GetGitBackupDirPath() |
| 1632 # Remove any eventual stale backup dir for the same project. | 1454 # Remove any eventual stale backup dir for the same project. |
| 1633 if os.path.exists(save_dir): | 1455 if os.path.exists(save_dir): |
| 1634 gclient_utils.rmtree(save_dir) | 1456 gclient_utils.rmtree(save_dir) |
| 1635 os.rename(os.path.join(e_dir, '.git'), save_dir) | 1457 os.rename(os.path.join(e_dir, '.git'), save_dir) |
| 1636 # When switching between the two states (entry/ is a subproject | 1458 # When switching between the two states (entry/ is a subproject |
| 1637 # -> entry/ is part of the outer project), it is very likely | 1459 # -> entry/ is part of the outer project), it is very likely |
| 1638 # that some files are changed in the checkout, unless we are | 1460 # that some files are changed in the checkout, unless we are |
| 1639 # jumping *exactly* across the commit which changed just DEPS. | 1461 # jumping *exactly* across the commit which changed just DEPS. |
| 1640 # In such case we want to cleanup any eventual stale files | 1462 # In such case we want to cleanup any eventual stale files |
| 1641 # (coming from the old subproject) in order to end up with a | 1463 # (coming from the old subproject) in order to end up with a |
| 1642 # clean checkout. | 1464 # clean checkout. |
| 1643 scm_class.CleanupDir(par_scm_root, rel_e_dir) | 1465 gclient_scm.scm.GIT.CleanupDir(par_scm_root, rel_e_dir) |
| 1644 assert not os.path.exists(os.path.join(e_dir, '.git')) | 1466 assert not os.path.exists(os.path.join(e_dir, '.git')) |
| 1645 print(('\nWARNING: \'%s\' has been moved from DEPS to a higher ' | 1467 print(('\nWARNING: \'%s\' has been moved from DEPS to a higher ' |
| 1646 'level checkout. The git folder containing all the local' | 1468 'level checkout. The git folder containing all the local' |
| 1647 ' branches has been saved to %s.\n' | 1469 ' branches has been saved to %s.\n' |
| 1648 'If you don\'t care about its state you can safely ' | 1470 'If you don\'t care about its state you can safely ' |
| 1649 'remove that folder to free up space.') % | 1471 'remove that folder to free up space.') % |
| 1650 (entry, save_dir)) | 1472 (entry, save_dir)) |
| 1651 continue | 1473 continue |
| 1652 | 1474 |
| 1653 if scm_root in full_entries: | 1475 if scm_root in full_entries: |
| (...skipping 27 matching lines...) Expand all Loading... |
| 1681 work_queue = gclient_utils.ExecutionQueue( | 1503 work_queue = gclient_utils.ExecutionQueue( |
| 1682 self._options.jobs, None, False, verbose=self._options.verbose) | 1504 self._options.jobs, None, False, verbose=self._options.verbose) |
| 1683 for s in self.dependencies: | 1505 for s in self.dependencies: |
| 1684 work_queue.enqueue(s) | 1506 work_queue.enqueue(s) |
| 1685 work_queue.flush({}, None, [], options=self._options) | 1507 work_queue.flush({}, None, [], options=self._options) |
| 1686 | 1508 |
| 1687 def GetURLAndRev(dep): | 1509 def GetURLAndRev(dep): |
| 1688 """Returns the revision-qualified SCM url for a Dependency.""" | 1510 """Returns the revision-qualified SCM url for a Dependency.""" |
| 1689 if dep.parsed_url is None: | 1511 if dep.parsed_url is None: |
| 1690 return None | 1512 return None |
| 1691 if isinstance(dep.parsed_url, self.FileImpl): | 1513 url, _ = gclient_utils.SplitUrlRevision(dep.parsed_url) |
| 1692 original_url = dep.parsed_url.file_location | |
| 1693 else: | |
| 1694 original_url = dep.parsed_url | |
| 1695 url, _ = gclient_utils.SplitUrlRevision(original_url) | |
| 1696 scm = gclient_scm.CreateSCM( | 1514 scm = gclient_scm.CreateSCM( |
| 1697 original_url, self.root_dir, dep.name, self.outbuf) | 1515 dep.parsed_url, self.root_dir, dep.name, self.outbuf) |
| 1698 if not os.path.isdir(scm.checkout_path): | 1516 if not os.path.isdir(scm.checkout_path): |
| 1699 return None | 1517 return None |
| 1700 return '%s@%s' % (url, scm.revinfo(self._options, [], None)) | 1518 return '%s@%s' % (url, scm.revinfo(self._options, [], None)) |
| 1701 | 1519 |
| 1702 if self._options.snapshot: | 1520 if self._options.snapshot: |
| 1703 new_gclient = '' | 1521 new_gclient = '' |
| 1704 # First level at .gclient | 1522 # First level at .gclient |
| 1705 for d in self.dependencies: | 1523 for d in self.dependencies: |
| 1706 entries = {} | 1524 entries = {} |
| 1707 def GrabDeps(dep): | 1525 def GrabDeps(dep): |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1771 | 1589 |
| 1772 @property | 1590 @property |
| 1773 def target_os(self): | 1591 def target_os(self): |
| 1774 return self._enforced_os | 1592 return self._enforced_os |
| 1775 | 1593 |
| 1776 | 1594 |
| 1777 #### gclient commands. | 1595 #### gclient commands. |
| 1778 | 1596 |
| 1779 | 1597 |
| 1780 def CMDcleanup(parser, args): | 1598 def CMDcleanup(parser, args): |
| 1781 """Cleans up all working copies. | 1599 """DEPRECATED: SVN-only. Cleaned up all working copies. |
| 1782 | 1600 |
| 1783 Mostly svn-specific. Simply runs 'svn cleanup' for each module. | 1601 This is a no-op in Git. |
| 1784 """ | 1602 """ |
| 1785 parser.add_option('--deps', dest='deps_os', metavar='OS_LIST', | 1603 parser.add_option('--deps', dest='deps_os', metavar='OS_LIST', |
| 1786 help='override deps for the specified (comma-separated) ' | 1604 help='override deps for the specified (comma-separated) ' |
| 1787 'platform(s); \'all\' will process all deps_os ' | 1605 'platform(s); \'all\' will process all deps_os ' |
| 1788 'references') | 1606 'references') |
| 1789 (options, args) = parser.parse_args(args) | 1607 (options, args) = parser.parse_args(args) |
| 1790 client = GClient.LoadCurrentConfig(options) | 1608 client = GClient.LoadCurrentConfig(options) |
| 1791 if not client: | 1609 if not client: |
| 1792 raise gclient_utils.Error('client not configured; see \'gclient config\'') | 1610 raise gclient_utils.Error('client not configured; see \'gclient config\'') |
| 1793 if options.verbose: | 1611 if options.verbose: |
| (...skipping 162 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1956 return 0 | 1774 return 0 |
| 1957 | 1775 |
| 1958 | 1776 |
| 1959 @subcommand.epilog("""Example: | 1777 @subcommand.epilog("""Example: |
| 1960 gclient pack > patch.txt | 1778 gclient pack > patch.txt |
| 1961 generate simple patch for configured client and dependences | 1779 generate simple patch for configured client and dependences |
| 1962 """) | 1780 """) |
| 1963 def CMDpack(parser, args): | 1781 def CMDpack(parser, args): |
| 1964 """Generates a patch which can be applied at the root of the tree. | 1782 """Generates a patch which can be applied at the root of the tree. |
| 1965 | 1783 |
| 1966 Internally, runs 'svn diff'/'git diff' on each checked out module and | 1784 Internally, runs 'git diff' on each checked out module and |
| 1967 dependencies, and performs minimal postprocessing of the output. The | 1785 dependencies, and performs minimal postprocessing of the output. The |
| 1968 resulting patch is printed to stdout and can be applied to a freshly | 1786 resulting patch is printed to stdout and can be applied to a freshly |
| 1969 checked out tree via 'patch -p0 < patchfile'. | 1787 checked out tree via 'patch -p0 < patchfile'. |
| 1970 """ | 1788 """ |
| 1971 parser.add_option('--deps', dest='deps_os', metavar='OS_LIST', | 1789 parser.add_option('--deps', dest='deps_os', metavar='OS_LIST', |
| 1972 help='override deps for the specified (comma-separated) ' | 1790 help='override deps for the specified (comma-separated) ' |
| 1973 'platform(s); \'all\' will process all deps_os ' | 1791 'platform(s); \'all\' will process all deps_os ' |
| 1974 'references') | 1792 'references') |
| 1975 parser.remove_option('--jobs') | 1793 parser.remove_option('--jobs') |
| 1976 (options, args) = parser.parse_args(args) | 1794 (options, args) = parser.parse_args(args) |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2011 | 1829 |
| 2012 JSON output format: | 1830 JSON output format: |
| 2013 If the --output-json option is specified, the following document structure will | 1831 If the --output-json option is specified, the following document structure will |
| 2014 be emitted to the provided file. 'null' entries may occur for subprojects which | 1832 be emitted to the provided file. 'null' entries may occur for subprojects which |
| 2015 are present in the gclient solution, but were not processed (due to custom_deps, | 1833 are present in the gclient solution, but were not processed (due to custom_deps, |
| 2016 os_deps, etc.) | 1834 os_deps, etc.) |
| 2017 | 1835 |
| 2018 { | 1836 { |
| 2019 "solutions" : { | 1837 "solutions" : { |
| 2020 "<name>": { # <name> is the posix-normalized path to the solution. | 1838 "<name>": { # <name> is the posix-normalized path to the solution. |
| 2021 "revision": [<svn rev int>|<git id hex string>|null], | 1839 "revision": [<git id hex string>|null], |
| 2022 "scm": ["svn"|"git"|null], | 1840 "scm": ["git"|null], |
| 2023 } | 1841 } |
| 2024 } | 1842 } |
| 2025 } | 1843 } |
| 2026 """) | 1844 """) |
| 2027 def CMDsync(parser, args): | 1845 def CMDsync(parser, args): |
| 2028 """Checkout/update all modules.""" | 1846 """Checkout/update all modules.""" |
| 2029 parser.add_option('-f', '--force', action='store_true', | 1847 parser.add_option('-f', '--force', action='store_true', |
| 2030 help='force update even for unchanged modules') | 1848 help='force update even for unchanged modules') |
| 2031 parser.add_option('-n', '--nohooks', action='store_true', | 1849 parser.add_option('-n', '--nohooks', action='store_true', |
| 2032 help='don\'t run hooks after the update is complete') | 1850 help='don\'t run hooks after the update is complete') |
| 2033 parser.add_option('-p', '--noprehooks', action='store_true', | 1851 parser.add_option('-p', '--noprehooks', action='store_true', |
| 2034 help='don\'t run pre-DEPS hooks', default=False) | 1852 help='don\'t run pre-DEPS hooks', default=False) |
| 2035 parser.add_option('-r', '--revision', action='append', | 1853 parser.add_option('-r', '--revision', action='append', |
| 2036 dest='revisions', metavar='REV', default=[], | 1854 dest='revisions', metavar='REV', default=[], |
| 2037 help='Enforces revision/hash for the solutions with the ' | 1855 help='Enforces revision/hash for the solutions with the ' |
| 2038 'format src@rev. The src@ part is optional and can be ' | 1856 'format src@rev. The src@ part is optional and can be ' |
| 2039 'skipped. -r can be used multiple times when .gclient ' | 1857 'skipped. -r can be used multiple times when .gclient ' |
| 2040 'has multiple solutions configured and will work even ' | 1858 'has multiple solutions configured and will work even ' |
| 2041 'if the src@ part is skipped. Note that specifying ' | 1859 'if the src@ part is skipped. Note that specifying ' |
| 2042 '--revision means your safesync_url gets ignored.') | 1860 '--revision means your safesync_url gets ignored.') |
| 2043 parser.add_option('--with_branch_heads', action='store_true', | 1861 parser.add_option('--with_branch_heads', action='store_true', |
| 2044 help='Clone git "branch_heads" refspecs in addition to ' | 1862 help='Clone git "branch_heads" refspecs in addition to ' |
| 2045 'the default refspecs. This adds about 1/2GB to a ' | 1863 'the default refspecs. This adds about 1/2GB to a ' |
| 2046 'full checkout. (git only)') | 1864 'full checkout. (git only)') |
| 2047 parser.add_option('--with_tags', action='store_true', | 1865 parser.add_option('--with_tags', action='store_true', |
| 2048 help='Clone git tags in addition to the default refspecs.') | 1866 help='Clone git tags in addition to the default refspecs.') |
| 2049 parser.add_option('-t', '--transitive', action='store_true', | |
| 2050 help='When a revision is specified (in the DEPS file or ' | |
| 2051 'with the command-line flag), transitively update ' | |
| 2052 'the dependencies to the date of the given revision. ' | |
| 2053 'Only supported for SVN repositories.') | |
| 2054 parser.add_option('-H', '--head', action='store_true', | 1867 parser.add_option('-H', '--head', action='store_true', |
| 2055 help='skips any safesync_urls specified in ' | 1868 help='skips any safesync_urls specified in ' |
| 2056 'configured solutions and sync to head instead') | 1869 'configured solutions and sync to head instead') |
| 2057 parser.add_option('-D', '--delete_unversioned_trees', action='store_true', | 1870 parser.add_option('-D', '--delete_unversioned_trees', action='store_true', |
| 2058 help='Deletes from the working copy any dependencies that ' | 1871 help='Deletes from the working copy any dependencies that ' |
| 2059 'have been removed since the last sync, as long as ' | 1872 'have been removed since the last sync, as long as ' |
| 2060 'there are no local modifications. When used with ' | 1873 'there are no local modifications. When used with ' |
| 2061 '--force, such dependencies are removed even if they ' | 1874 '--force, such dependencies are removed even if they ' |
| 2062 'have local modifications. When used with --reset, ' | 1875 'have local modifications. When used with --reset, ' |
| 2063 'all untracked directories are removed from the ' | 1876 'all untracked directories are removed from the ' |
| 2064 'working copy, excluding those which are explicitly ' | 1877 'working copy, excluding those which are explicitly ' |
| 2065 'ignored in the repository.') | 1878 'ignored in the repository.') |
| 2066 parser.add_option('-R', '--reset', action='store_true', | 1879 parser.add_option('-R', '--reset', action='store_true', |
| 2067 help='resets any local changes before updating (git only)') | 1880 help='resets any local changes before updating (git only)') |
| 2068 parser.add_option('-M', '--merge', action='store_true', | 1881 parser.add_option('-M', '--merge', action='store_true', |
| 2069 help='merge upstream changes instead of trying to ' | 1882 help='merge upstream changes instead of trying to ' |
| 2070 'fast-forward or rebase') | 1883 'fast-forward or rebase') |
| 2071 parser.add_option('-A', '--auto_rebase', action='store_true', | 1884 parser.add_option('-A', '--auto_rebase', action='store_true', |
| 2072 help='Automatically rebase repositories against local ' | 1885 help='Automatically rebase repositories against local ' |
| 2073 'checkout during update (git only).') | 1886 'checkout during update (git only).') |
| 2074 parser.add_option('--deps', dest='deps_os', metavar='OS_LIST', | 1887 parser.add_option('--deps', dest='deps_os', metavar='OS_LIST', |
| 2075 help='override deps for the specified (comma-separated) ' | 1888 help='override deps for the specified (comma-separated) ' |
| 2076 'platform(s); \'all\' will process all deps_os ' | 1889 'platform(s); \'all\' will process all deps_os ' |
| 2077 'references') | 1890 'references') |
| 2078 parser.add_option('-m', '--manually_grab_svn_rev', action='store_true', | |
| 2079 help='Skip svn up whenever possible by requesting ' | |
| 2080 'actual HEAD revision from the repository') | |
| 2081 parser.add_option('--upstream', action='store_true', | 1891 parser.add_option('--upstream', action='store_true', |
| 2082 help='Make repo state match upstream branch.') | 1892 help='Make repo state match upstream branch.') |
| 2083 parser.add_option('--output-json', | 1893 parser.add_option('--output-json', |
| 2084 help='Output a json document to this path containing ' | 1894 help='Output a json document to this path containing ' |
| 2085 'summary information about the sync.') | 1895 'summary information about the sync.') |
| 2086 parser.add_option('--no-history', action='store_true', | 1896 parser.add_option('--no-history', action='store_true', |
| 2087 help='GIT ONLY - Reduces the size/time of the checkout at ' | 1897 help='GIT ONLY - Reduces the size/time of the checkout at ' |
| 2088 'the cost of no history. Requires Git 1.9+') | 1898 'the cost of no history. Requires Git 1.9+') |
| 2089 parser.add_option('--shallow', action='store_true', | 1899 parser.add_option('--shallow', action='store_true', |
| 2090 help='GIT ONLY - Do a shallow clone into the cache dir. ' | 1900 help='GIT ONLY - Do a shallow clone into the cache dir. ' |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2144 raise gclient_utils.Error('client not configured; see \'gclient config\'') | 1954 raise gclient_utils.Error('client not configured; see \'gclient config\'') |
| 2145 if options.verbose: | 1955 if options.verbose: |
| 2146 client.PrintLocationAndContents() | 1956 client.PrintLocationAndContents() |
| 2147 return client.RunOnDeps('diff', args) | 1957 return client.RunOnDeps('diff', args) |
| 2148 | 1958 |
| 2149 | 1959 |
| 2150 def CMDrevert(parser, args): | 1960 def CMDrevert(parser, args): |
| 2151 """Reverts all modifications in every dependencies. | 1961 """Reverts all modifications in every dependencies. |
| 2152 | 1962 |
| 2153 That's the nuclear option to get back to a 'clean' state. It removes anything | 1963 That's the nuclear option to get back to a 'clean' state. It removes anything |
| 2154 that shows up in svn status.""" | 1964 that shows up in git status.""" |
| 2155 parser.add_option('--deps', dest='deps_os', metavar='OS_LIST', | 1965 parser.add_option('--deps', dest='deps_os', metavar='OS_LIST', |
| 2156 help='override deps for the specified (comma-separated) ' | 1966 help='override deps for the specified (comma-separated) ' |
| 2157 'platform(s); \'all\' will process all deps_os ' | 1967 'platform(s); \'all\' will process all deps_os ' |
| 2158 'references') | 1968 'references') |
| 2159 parser.add_option('-n', '--nohooks', action='store_true', | 1969 parser.add_option('-n', '--nohooks', action='store_true', |
| 2160 help='don\'t run hooks after the revert is complete') | 1970 help='don\'t run hooks after the revert is complete') |
| 2161 parser.add_option('-p', '--noprehooks', action='store_true', | 1971 parser.add_option('-p', '--noprehooks', action='store_true', |
| 2162 help='don\'t run pre-DEPS hooks', default=False) | 1972 help='don\'t run pre-DEPS hooks', default=False) |
| 2163 parser.add_option('--upstream', action='store_true', | 1973 parser.add_option('--upstream', action='store_true', |
| 2164 help='Make repo state match upstream branch.') | 1974 help='Make repo state match upstream branch.') |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2196 options.force = True | 2006 options.force = True |
| 2197 options.nohooks = False | 2007 options.nohooks = False |
| 2198 return client.RunOnDeps('runhooks', args) | 2008 return client.RunOnDeps('runhooks', args) |
| 2199 | 2009 |
| 2200 | 2010 |
| 2201 def CMDrevinfo(parser, args): | 2011 def CMDrevinfo(parser, args): |
| 2202 """Outputs revision info mapping for the client and its dependencies. | 2012 """Outputs revision info mapping for the client and its dependencies. |
| 2203 | 2013 |
| 2204 This allows the capture of an overall 'revision' for the source tree that | 2014 This allows the capture of an overall 'revision' for the source tree that |
| 2205 can be used to reproduce the same tree in the future. It is only useful for | 2015 can be used to reproduce the same tree in the future. It is only useful for |
| 2206 'unpinned dependencies', i.e. DEPS/deps references without a svn revision | 2016 'unpinned dependencies', i.e. DEPS/deps references without a git hash. |
| 2207 number or a git hash. A git branch name isn't 'pinned' since the actual | 2017 A git branch name isn't 'pinned' since the actual commit can change. |
| 2208 commit can change. | |
| 2209 """ | 2018 """ |
| 2210 parser.add_option('--deps', dest='deps_os', metavar='OS_LIST', | 2019 parser.add_option('--deps', dest='deps_os', metavar='OS_LIST', |
| 2211 help='override deps for the specified (comma-separated) ' | 2020 help='override deps for the specified (comma-separated) ' |
| 2212 'platform(s); \'all\' will process all deps_os ' | 2021 'platform(s); \'all\' will process all deps_os ' |
| 2213 'references') | 2022 'references') |
| 2214 parser.add_option('-a', '--actual', action='store_true', | 2023 parser.add_option('-a', '--actual', action='store_true', |
| 2215 help='gets the actual checked out revisions instead of the ' | 2024 help='gets the actual checked out revisions instead of the ' |
| 2216 'ones specified in the DEPS and .gclient files') | 2025 'ones specified in the DEPS and .gclient files') |
| 2217 parser.add_option('-s', '--snapshot', action='store_true', | 2026 parser.add_option('-s', '--snapshot', action='store_true', |
| 2218 help='creates a snapshot .gclient file of the current ' | 2027 help='creates a snapshot .gclient file of the current ' |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2264 | 2073 |
| 2265 def __init__(self, **kwargs): | 2074 def __init__(self, **kwargs): |
| 2266 optparse.OptionParser.__init__( | 2075 optparse.OptionParser.__init__( |
| 2267 self, version='%prog ' + __version__, **kwargs) | 2076 self, version='%prog ' + __version__, **kwargs) |
| 2268 | 2077 |
| 2269 # Some arm boards have issues with parallel sync. | 2078 # Some arm boards have issues with parallel sync. |
| 2270 if platform.machine().startswith('arm'): | 2079 if platform.machine().startswith('arm'): |
| 2271 jobs = 1 | 2080 jobs = 1 |
| 2272 else: | 2081 else: |
| 2273 jobs = max(8, gclient_utils.NumLocalCpus()) | 2082 jobs = max(8, gclient_utils.NumLocalCpus()) |
| 2274 # cmp: 2013/06/19 | |
| 2275 # Temporary workaround to lower bot-load on SVN server. | |
| 2276 # Bypassed if a bot_update flag is detected. | |
| 2277 if (os.environ.get('CHROME_HEADLESS') == '1' and | |
| 2278 not os.path.exists('update.flag')): | |
| 2279 jobs = 1 | |
| 2280 | 2083 |
| 2281 self.add_option( | 2084 self.add_option( |
| 2282 '-j', '--jobs', default=jobs, type='int', | 2085 '-j', '--jobs', default=jobs, type='int', |
| 2283 help='Specify how many SCM commands can run in parallel; defaults to ' | 2086 help='Specify how many SCM commands can run in parallel; defaults to ' |
| 2284 '%default on this machine') | 2087 '%default on this machine') |
| 2285 self.add_option( | 2088 self.add_option( |
| 2286 '-v', '--verbose', action='count', default=0, | 2089 '-v', '--verbose', action='count', default=0, |
| 2287 help='Produces additional output for diagnostics. Can be used up to ' | 2090 help='Produces additional output for diagnostics. Can be used up to ' |
| 2288 'three times for more logging info.') | 2091 'three times for more logging info.') |
| 2289 self.add_option( | 2092 self.add_option( |
| (...skipping 30 matching lines...) Expand all Loading... |
| 2320 # GClient.RunOnDeps expects it even if not applicable. | 2123 # GClient.RunOnDeps expects it even if not applicable. |
| 2321 options.revisions = [] | 2124 options.revisions = [] |
| 2322 if not hasattr(options, 'head'): | 2125 if not hasattr(options, 'head'): |
| 2323 options.head = None | 2126 options.head = None |
| 2324 if not hasattr(options, 'nohooks'): | 2127 if not hasattr(options, 'nohooks'): |
| 2325 options.nohooks = True | 2128 options.nohooks = True |
| 2326 if not hasattr(options, 'noprehooks'): | 2129 if not hasattr(options, 'noprehooks'): |
| 2327 options.noprehooks = True | 2130 options.noprehooks = True |
| 2328 if not hasattr(options, 'deps_os'): | 2131 if not hasattr(options, 'deps_os'): |
| 2329 options.deps_os = None | 2132 options.deps_os = None |
| 2330 if not hasattr(options, 'manually_grab_svn_rev'): | |
| 2331 options.manually_grab_svn_rev = None | |
| 2332 if not hasattr(options, 'force'): | 2133 if not hasattr(options, 'force'): |
| 2333 options.force = None | 2134 options.force = None |
| 2334 return (options, args) | 2135 return (options, args) |
| 2335 | 2136 |
| 2336 | 2137 |
| 2337 def disable_buffering(): | 2138 def disable_buffering(): |
| 2338 # Make stdout auto-flush so buildbot doesn't kill us during lengthy | 2139 # Make stdout auto-flush so buildbot doesn't kill us during lengthy |
| 2339 # operations. Python as a strong tendency to buffer sys.stdout. | 2140 # operations. Python as a strong tendency to buffer sys.stdout. |
| 2340 sys.stdout = gclient_utils.MakeFileAutoFlush(sys.stdout) | 2141 sys.stdout = gclient_utils.MakeFileAutoFlush(sys.stdout) |
| 2341 # Make stdout annotated with the thread ids. | 2142 # Make stdout annotated with the thread ids. |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2374 | 2175 |
| 2375 | 2176 |
| 2376 if '__main__' == __name__: | 2177 if '__main__' == __name__: |
| 2377 try: | 2178 try: |
| 2378 sys.exit(main(sys.argv[1:])) | 2179 sys.exit(main(sys.argv[1:])) |
| 2379 except KeyboardInterrupt: | 2180 except KeyboardInterrupt: |
| 2380 sys.stderr.write('interrupted\n') | 2181 sys.stderr.write('interrupted\n') |
| 2381 sys.exit(1) | 2182 sys.exit(1) |
| 2382 | 2183 |
| 2383 # vim: ts=2:sw=2:tw=80:et: | 2184 # vim: ts=2:sw=2:tw=80:et: |
| OLD | NEW |