Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(80)

Side by Side Diff: gclient.py

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

Powered by Google App Engine
This is Rietveld 408576698