OLD | NEW |
---|---|
1 # Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 # Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 # Use of this source code is governed by a BSD-style license that can be | 2 # Use of this source code is governed by a BSD-style license that can be |
3 # found in the LICENSE file. | 3 # found in the LICENSE file. |
4 | 4 |
5 """Gclient-specific SCM-specific operations.""" | 5 """Gclient-specific SCM-specific operations.""" |
6 | 6 |
7 import logging | 7 import logging |
8 import os | 8 import os |
9 import posixpath | 9 import posixpath |
10 import re | 10 import re |
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
78 | 78 |
79 def CreateSCM(url, root_dir=None, relpath=None): | 79 def CreateSCM(url, root_dir=None, relpath=None): |
80 SCM_MAP = { | 80 SCM_MAP = { |
81 'svn' : SVNWrapper, | 81 'svn' : SVNWrapper, |
82 'git' : GitWrapper, | 82 'git' : GitWrapper, |
83 } | 83 } |
84 | 84 |
85 scm_name = GetScmName(url) | 85 scm_name = GetScmName(url) |
86 if not scm_name in SCM_MAP: | 86 if not scm_name in SCM_MAP: |
87 raise gclient_utils.Error('No SCM found for url %s' % url) | 87 raise gclient_utils.Error('No SCM found for url %s' % url) |
88 return SCM_MAP[scm_name](url, root_dir, relpath) | 88 found_scm = SCM_MAP[scm_name](url, root_dir, relpath) |
89 if not found_scm.BinaryExists(): | |
90 raise gclient_utils.Error('%s command not found' % scm_name) | |
91 return found_scm | |
89 | 92 |
90 | 93 |
91 # SCMWrapper base class | 94 # SCMWrapper base class |
92 | 95 |
93 class SCMWrapper(object): | 96 class SCMWrapper(object): |
94 """Add necessary glue between all the supported SCM. | 97 """Add necessary glue between all the supported SCM. |
95 | 98 |
96 This is the abstraction layer to bind to different SCM. | 99 This is the abstraction layer to bind to different SCM. |
97 """ | 100 """ |
98 def __init__(self, url=None, root_dir=None, relpath=None): | 101 def __init__(self, url=None, root_dir=None, relpath=None): |
99 self.url = url | 102 self.url = url |
100 self._root_dir = root_dir | 103 self._root_dir = root_dir |
101 if self._root_dir: | 104 if self._root_dir: |
102 self._root_dir = self._root_dir.replace('/', os.sep) | 105 self._root_dir = self._root_dir.replace('/', os.sep) |
103 self.relpath = relpath | 106 self.relpath = relpath |
104 if self.relpath: | 107 if self.relpath: |
105 self.relpath = self.relpath.replace('/', os.sep) | 108 self.relpath = self.relpath.replace('/', os.sep) |
106 if self.relpath and self._root_dir: | 109 if self.relpath and self._root_dir: |
107 self.checkout_path = os.path.join(self._root_dir, self.relpath) | 110 self.checkout_path = os.path.join(self._root_dir, self.relpath) |
111 self._checker_command = 'help' | |
112 self._binary_name = None | |
113 | |
114 def BinaryExists(self): | |
M-A Ruel
2012/04/17 12:15:55
This function may be called over 100 times for a g
Jun Mukai
2012/04/18 02:46:36
Oh, got it. Modified to use AssertVersion.
| |
115 """Returns true if the command exists.""" | |
116 # Do not call _Run() because this we don't want to leave any messages for | |
117 # this check. | |
118 try: | |
119 return gclient_utils.CheckCallAndFilter( | |
120 [self._binary_name, self._checker_command], print_stdout=False) == 0 | |
121 except OSError: | |
122 return False | |
108 | 123 |
109 def RunCommand(self, command, options, args, file_list=None): | 124 def RunCommand(self, command, options, args, file_list=None): |
110 # file_list will have all files that are modified appended to it. | 125 # file_list will have all files that are modified appended to it. |
111 if file_list is None: | 126 if file_list is None: |
112 file_list = [] | 127 file_list = [] |
113 | 128 |
114 commands = ['cleanup', 'update', 'updatesingle', 'revert', | 129 commands = ['cleanup', 'update', 'updatesingle', 'revert', |
115 'revinfo', 'status', 'diff', 'pack', 'runhooks'] | 130 'revinfo', 'status', 'diff', 'pack', 'runhooks'] |
116 | 131 |
117 if not command in commands: | 132 if not command in commands: |
118 raise gclient_utils.Error('Unknown command %s' % command) | 133 raise gclient_utils.Error('Unknown command %s' % command) |
119 | 134 |
120 if not command in dir(self): | 135 if not command in dir(self): |
121 raise gclient_utils.Error('Command %s not implemented in %s wrapper' % ( | 136 raise gclient_utils.Error('Command %s not implemented in %s wrapper' % ( |
122 command, self.__class__.__name__)) | 137 command, self.__class__.__name__)) |
123 | 138 |
124 return getattr(self, command)(options, args, file_list) | 139 return getattr(self, command)(options, args, file_list) |
125 | 140 |
126 | 141 |
127 class GitWrapper(SCMWrapper): | 142 class GitWrapper(SCMWrapper): |
128 """Wrapper for Git""" | 143 """Wrapper for Git""" |
129 | 144 |
130 def __init__(self, url=None, root_dir=None, relpath=None): | 145 def __init__(self, url=None, root_dir=None, relpath=None): |
131 """Removes 'git+' fake prefix from git URL.""" | 146 """Removes 'git+' fake prefix from git URL.""" |
132 if url.startswith('git+http://') or url.startswith('git+https://'): | 147 if url.startswith('git+http://') or url.startswith('git+https://'): |
133 url = url[4:] | 148 url = url[4:] |
134 SCMWrapper.__init__(self, url, root_dir, relpath) | 149 SCMWrapper.__init__(self, url, root_dir, relpath) |
150 self._binary_name = 'git' | |
135 | 151 |
136 def GetRevisionDate(self, revision): | 152 def GetRevisionDate(self, revision): |
137 """Returns the given revision's date in ISO-8601 format (which contains the | 153 """Returns the given revision's date in ISO-8601 format (which contains the |
138 time zone).""" | 154 time zone).""" |
139 # TODO(floitsch): get the time-stamp of the given revision and not just the | 155 # TODO(floitsch): get the time-stamp of the given revision and not just the |
140 # time-stamp of the currently checked out revision. | 156 # time-stamp of the currently checked out revision. |
141 return self._Capture(['log', '-n', '1', '--format=%ai']) | 157 return self._Capture(['log', '-n', '1', '--format=%ai']) |
142 | 158 |
143 @staticmethod | 159 @staticmethod |
144 def cleanup(options, args, file_list): | 160 def cleanup(options, args, file_list): |
(...skipping 607 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
752 | 768 |
753 def _GetCurrentBranch(self): | 769 def _GetCurrentBranch(self): |
754 # Returns name of current branch or None for detached HEAD | 770 # Returns name of current branch or None for detached HEAD |
755 branch = self._Capture(['rev-parse', '--abbrev-ref=strict', 'HEAD']) | 771 branch = self._Capture(['rev-parse', '--abbrev-ref=strict', 'HEAD']) |
756 if branch == 'HEAD': | 772 if branch == 'HEAD': |
757 return None | 773 return None |
758 return branch | 774 return branch |
759 | 775 |
760 def _Capture(self, args): | 776 def _Capture(self, args): |
761 return subprocess2.check_output( | 777 return subprocess2.check_output( |
762 ['git'] + args, | 778 [self._binary_name] + args, |
763 stderr=subprocess2.PIPE, | 779 stderr=subprocess2.PIPE, |
764 cwd=self.checkout_path).strip() | 780 cwd=self.checkout_path).strip() |
765 | 781 |
766 def _Run(self, args, options, **kwargs): | 782 def _Run(self, args, options, **kwargs): |
767 kwargs.setdefault('cwd', self.checkout_path) | 783 kwargs.setdefault('cwd', self.checkout_path) |
768 kwargs.setdefault('print_stdout', True) | 784 kwargs.setdefault('print_stdout', True) |
769 stdout = kwargs.get('stdout', sys.stdout) | 785 stdout = kwargs.get('stdout', sys.stdout) |
770 stdout.write('\n________ running \'git %s\' in \'%s\'\n' % ( | 786 stdout.write('\n________ running \'git %s\' in \'%s\'\n' % ( |
771 ' '.join(args), kwargs['cwd'])) | 787 ' '.join(args), kwargs['cwd'])) |
772 gclient_utils.CheckCallAndFilter(['git'] + args, **kwargs) | 788 gclient_utils.CheckCallAndFilter([self._binary_name] + args, **kwargs) |
773 | 789 |
774 | 790 |
775 class SVNWrapper(SCMWrapper): | 791 class SVNWrapper(SCMWrapper): |
776 """ Wrapper for SVN """ | 792 """ Wrapper for SVN """ |
777 | 793 |
794 def __init__(self, url=None, root_dir=None, relpath=None): | |
795 SCMWrapper.__init__(self, url, root_dir, relpath) | |
796 self._binary_name = 'svn' | |
797 | |
778 def GetRevisionDate(self, revision): | 798 def GetRevisionDate(self, revision): |
779 """Returns the given revision's date in ISO-8601 format (which contains the | 799 """Returns the given revision's date in ISO-8601 format (which contains the |
780 time zone).""" | 800 time zone).""" |
781 date = scm.SVN.Capture( | 801 date = scm.SVN.Capture( |
782 ['propget', '--revprop', 'svn:date', '-r', revision], | 802 ['propget', '--revprop', 'svn:date', '-r', revision], |
783 os.path.join(self.checkout_path, '.')) | 803 os.path.join(self.checkout_path, '.')) |
784 return date.strip() | 804 return date.strip() |
785 | 805 |
786 def cleanup(self, options, args, file_list): | 806 def cleanup(self, options, args, file_list): |
787 """Cleanup working copy.""" | 807 """Cleanup working copy.""" |
(...skipping 299 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1087 'correct.') % rev) | 1107 'correct.') % rev) |
1088 return rev | 1108 return rev |
1089 | 1109 |
1090 def FullUrlForRelativeUrl(self, url): | 1110 def FullUrlForRelativeUrl(self, url): |
1091 # Find the forth '/' and strip from there. A bit hackish. | 1111 # Find the forth '/' and strip from there. A bit hackish. |
1092 return '/'.join(self.url.split('/')[:4]) + url | 1112 return '/'.join(self.url.split('/')[:4]) + url |
1093 | 1113 |
1094 def _Run(self, args, options, **kwargs): | 1114 def _Run(self, args, options, **kwargs): |
1095 """Runs a commands that goes to stdout.""" | 1115 """Runs a commands that goes to stdout.""" |
1096 kwargs.setdefault('cwd', self.checkout_path) | 1116 kwargs.setdefault('cwd', self.checkout_path) |
1097 gclient_utils.CheckCallAndFilterAndHeader(['svn'] + args, | 1117 gclient_utils.CheckCallAndFilterAndHeader([self._binary_name] + args, |
1098 always=options.verbose, **kwargs) | 1118 always=options.verbose, **kwargs) |
1099 | 1119 |
1100 def _RunAndGetFileList(self, args, options, file_list, cwd=None): | 1120 def _RunAndGetFileList(self, args, options, file_list, cwd=None): |
1101 """Runs a commands that goes to stdout and grabs the file listed.""" | 1121 """Runs a commands that goes to stdout and grabs the file listed.""" |
1102 cwd = cwd or self.checkout_path | 1122 cwd = cwd or self.checkout_path |
1103 scm.SVN.RunAndGetFileList( | 1123 scm.SVN.RunAndGetFileList( |
1104 options.verbose, | 1124 options.verbose, |
1105 args + ['--ignore-externals'], | 1125 args + ['--ignore-externals'], |
1106 cwd=cwd, | 1126 cwd=cwd, |
1107 file_list=file_list) | 1127 file_list=file_list) |
(...skipping 21 matching lines...) Expand all Loading... | |
1129 new_command.append('--force') | 1149 new_command.append('--force') |
1130 if command[0] != 'checkout' and scm.SVN.AssertVersion('1.6')[0]: | 1150 if command[0] != 'checkout' and scm.SVN.AssertVersion('1.6')[0]: |
1131 new_command.extend(('--accept', 'theirs-conflict')) | 1151 new_command.extend(('--accept', 'theirs-conflict')) |
1132 elif options.manually_grab_svn_rev: | 1152 elif options.manually_grab_svn_rev: |
1133 new_command.append('--force') | 1153 new_command.append('--force') |
1134 if command[0] != 'checkout' and scm.SVN.AssertVersion('1.6')[0]: | 1154 if command[0] != 'checkout' and scm.SVN.AssertVersion('1.6')[0]: |
1135 new_command.extend(('--accept', 'postpone')) | 1155 new_command.extend(('--accept', 'postpone')) |
1136 elif command[0] != 'checkout' and scm.SVN.AssertVersion('1.6')[0]: | 1156 elif command[0] != 'checkout' and scm.SVN.AssertVersion('1.6')[0]: |
1137 new_command.extend(('--accept', 'postpone')) | 1157 new_command.extend(('--accept', 'postpone')) |
1138 return new_command | 1158 return new_command |
OLD | NEW |