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

Side by Side Diff: gclient.py

Issue 2404413002: Reland "Remove SVN and File support from gclient" (Closed)
Patch Set: Comment 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 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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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. '
2091 'Requires Git 1.9+') 1901 'Requires Git 1.9+')
2092 parser.add_option('--no_bootstrap', '--no-bootstrap', 1902 parser.add_option('--no_bootstrap', '--no-bootstrap',
2093 action='store_true', 1903 action='store_true',
2094 help='Don\'t bootstrap from Google Storage.') 1904 help='Don\'t bootstrap from Google Storage.')
2095 parser.add_option('--ignore_locks', action='store_true', 1905 parser.add_option('--ignore_locks', action='store_true',
2096 help='GIT ONLY - Ignore cache locks.') 1906 help='GIT ONLY - Ignore cache locks.')
2097 parser.add_option('--break_repo_locks', action='store_true', 1907 parser.add_option('--break_repo_locks', action='store_true',
2098 help='GIT ONLY - Forcibly remove repo locks (e.g. ' 1908 help='GIT ONLY - Forcibly remove repo locks (e.g. '
2099 'index.lock). This should only be used if you know for ' 1909 'index.lock). This should only be used if you know for '
2100 'certain that this invocation of gclient is the only ' 1910 'certain that this invocation of gclient is the only '
2101 'thing operating on the git repos (e.g. on a bot).') 1911 'thing operating on the git repos (e.g. on a bot).')
2102 parser.add_option('--lock_timeout', type='int', default=5000, 1912 parser.add_option('--lock_timeout', type='int', default=5000,
2103 help='GIT ONLY - Deadline (in seconds) to wait for git ' 1913 help='GIT ONLY - Deadline (in seconds) to wait for git '
2104 'cache lock to become available. Default is %default.') 1914 'cache lock to become available. Default is %default.')
1915 # TODO(agable): Remove these when the oldest CrOS release milestone is M56.
1916 parser.add_option('-t', '--transitive', action='store_true',
1917 help='DEPRECATED: This is a no-op.')
1918 parser.add_option('-m', '--manually_grap_svn_rev', action='store_true',
1919 help='DEPRECATED: This is a no-op.')
2105 (options, args) = parser.parse_args(args) 1920 (options, args) = parser.parse_args(args)
2106 client = GClient.LoadCurrentConfig(options) 1921 client = GClient.LoadCurrentConfig(options)
2107 1922
2108 if not client: 1923 if not client:
2109 raise gclient_utils.Error('client not configured; see \'gclient config\'') 1924 raise gclient_utils.Error('client not configured; see \'gclient config\'')
2110 1925
2111 if options.revisions and options.head: 1926 if options.revisions and options.head:
2112 # TODO(maruel): Make it a parser.error if it doesn't break any builder. 1927 # TODO(maruel): Make it a parser.error if it doesn't break any builder.
2113 print('Warning: you cannot use both --head and --revision') 1928 print('Warning: you cannot use both --head and --revision')
2114 1929
(...skipping 29 matching lines...) Expand all
2144 raise gclient_utils.Error('client not configured; see \'gclient config\'') 1959 raise gclient_utils.Error('client not configured; see \'gclient config\'')
2145 if options.verbose: 1960 if options.verbose:
2146 client.PrintLocationAndContents() 1961 client.PrintLocationAndContents()
2147 return client.RunOnDeps('diff', args) 1962 return client.RunOnDeps('diff', args)
2148 1963
2149 1964
2150 def CMDrevert(parser, args): 1965 def CMDrevert(parser, args):
2151 """Reverts all modifications in every dependencies. 1966 """Reverts all modifications in every dependencies.
2152 1967
2153 That's the nuclear option to get back to a 'clean' state. It removes anything 1968 That's the nuclear option to get back to a 'clean' state. It removes anything
2154 that shows up in svn status.""" 1969 that shows up in git status."""
2155 parser.add_option('--deps', dest='deps_os', metavar='OS_LIST', 1970 parser.add_option('--deps', dest='deps_os', metavar='OS_LIST',
2156 help='override deps for the specified (comma-separated) ' 1971 help='override deps for the specified (comma-separated) '
2157 'platform(s); \'all\' will process all deps_os ' 1972 'platform(s); \'all\' will process all deps_os '
2158 'references') 1973 'references')
2159 parser.add_option('-n', '--nohooks', action='store_true', 1974 parser.add_option('-n', '--nohooks', action='store_true',
2160 help='don\'t run hooks after the revert is complete') 1975 help='don\'t run hooks after the revert is complete')
2161 parser.add_option('-p', '--noprehooks', action='store_true', 1976 parser.add_option('-p', '--noprehooks', action='store_true',
2162 help='don\'t run pre-DEPS hooks', default=False) 1977 help='don\'t run pre-DEPS hooks', default=False)
2163 parser.add_option('--upstream', action='store_true', 1978 parser.add_option('--upstream', action='store_true',
2164 help='Make repo state match upstream branch.') 1979 help='Make repo state match upstream branch.')
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
2196 options.force = True 2011 options.force = True
2197 options.nohooks = False 2012 options.nohooks = False
2198 return client.RunOnDeps('runhooks', args) 2013 return client.RunOnDeps('runhooks', args)
2199 2014
2200 2015
2201 def CMDrevinfo(parser, args): 2016 def CMDrevinfo(parser, args):
2202 """Outputs revision info mapping for the client and its dependencies. 2017 """Outputs revision info mapping for the client and its dependencies.
2203 2018
2204 This allows the capture of an overall 'revision' for the source tree that 2019 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 2020 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 2021 '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 2022 A git branch name isn't 'pinned' since the actual commit can change.
2208 commit can change.
2209 """ 2023 """
2210 parser.add_option('--deps', dest='deps_os', metavar='OS_LIST', 2024 parser.add_option('--deps', dest='deps_os', metavar='OS_LIST',
2211 help='override deps for the specified (comma-separated) ' 2025 help='override deps for the specified (comma-separated) '
2212 'platform(s); \'all\' will process all deps_os ' 2026 'platform(s); \'all\' will process all deps_os '
2213 'references') 2027 'references')
2214 parser.add_option('-a', '--actual', action='store_true', 2028 parser.add_option('-a', '--actual', action='store_true',
2215 help='gets the actual checked out revisions instead of the ' 2029 help='gets the actual checked out revisions instead of the '
2216 'ones specified in the DEPS and .gclient files') 2030 'ones specified in the DEPS and .gclient files')
2217 parser.add_option('-s', '--snapshot', action='store_true', 2031 parser.add_option('-s', '--snapshot', action='store_true',
2218 help='creates a snapshot .gclient file of the current ' 2032 help='creates a snapshot .gclient file of the current '
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
2264 2078
2265 def __init__(self, **kwargs): 2079 def __init__(self, **kwargs):
2266 optparse.OptionParser.__init__( 2080 optparse.OptionParser.__init__(
2267 self, version='%prog ' + __version__, **kwargs) 2081 self, version='%prog ' + __version__, **kwargs)
2268 2082
2269 # Some arm boards have issues with parallel sync. 2083 # Some arm boards have issues with parallel sync.
2270 if platform.machine().startswith('arm'): 2084 if platform.machine().startswith('arm'):
2271 jobs = 1 2085 jobs = 1
2272 else: 2086 else:
2273 jobs = max(8, gclient_utils.NumLocalCpus()) 2087 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 2088
2281 self.add_option( 2089 self.add_option(
2282 '-j', '--jobs', default=jobs, type='int', 2090 '-j', '--jobs', default=jobs, type='int',
2283 help='Specify how many SCM commands can run in parallel; defaults to ' 2091 help='Specify how many SCM commands can run in parallel; defaults to '
2284 '%default on this machine') 2092 '%default on this machine')
2285 self.add_option( 2093 self.add_option(
2286 '-v', '--verbose', action='count', default=0, 2094 '-v', '--verbose', action='count', default=0,
2287 help='Produces additional output for diagnostics. Can be used up to ' 2095 help='Produces additional output for diagnostics. Can be used up to '
2288 'three times for more logging info.') 2096 'three times for more logging info.')
2289 self.add_option( 2097 self.add_option(
(...skipping 30 matching lines...) Expand all
2320 # GClient.RunOnDeps expects it even if not applicable. 2128 # GClient.RunOnDeps expects it even if not applicable.
2321 options.revisions = [] 2129 options.revisions = []
2322 if not hasattr(options, 'head'): 2130 if not hasattr(options, 'head'):
2323 options.head = None 2131 options.head = None
2324 if not hasattr(options, 'nohooks'): 2132 if not hasattr(options, 'nohooks'):
2325 options.nohooks = True 2133 options.nohooks = True
2326 if not hasattr(options, 'noprehooks'): 2134 if not hasattr(options, 'noprehooks'):
2327 options.noprehooks = True 2135 options.noprehooks = True
2328 if not hasattr(options, 'deps_os'): 2136 if not hasattr(options, 'deps_os'):
2329 options.deps_os = None 2137 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'): 2138 if not hasattr(options, 'force'):
2333 options.force = None 2139 options.force = None
2334 return (options, args) 2140 return (options, args)
2335 2141
2336 2142
2337 def disable_buffering(): 2143 def disable_buffering():
2338 # Make stdout auto-flush so buildbot doesn't kill us during lengthy 2144 # Make stdout auto-flush so buildbot doesn't kill us during lengthy
2339 # operations. Python as a strong tendency to buffer sys.stdout. 2145 # operations. Python as a strong tendency to buffer sys.stdout.
2340 sys.stdout = gclient_utils.MakeFileAutoFlush(sys.stdout) 2146 sys.stdout = gclient_utils.MakeFileAutoFlush(sys.stdout)
2341 # Make stdout annotated with the thread ids. 2147 # Make stdout annotated with the thread ids.
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
2374 2180
2375 2181
2376 if '__main__' == __name__: 2182 if '__main__' == __name__:
2377 try: 2183 try:
2378 sys.exit(main(sys.argv[1:])) 2184 sys.exit(main(sys.argv[1:]))
2379 except KeyboardInterrupt: 2185 except KeyboardInterrupt:
2380 sys.stderr.write('interrupted\n') 2186 sys.stderr.write('interrupted\n')
2381 sys.exit(1) 2187 sys.exit(1)
2382 2188
2383 # vim: ts=2:sw=2:tw=80:et: 2189 # 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