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 from __future__ import print_function | 7 from __future__ import print_function |
8 | 8 |
9 import logging | 9 import logging |
10 import os | 10 import os |
(...skipping 180 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
191 | 191 |
192 actual_remote_url = self.GetActualRemoteURL(options) | 192 actual_remote_url = self.GetActualRemoteURL(options) |
193 if actual_remote_url: | 193 if actual_remote_url: |
194 return (gclient_utils.SplitUrlRevision(actual_remote_url)[0].rstrip('/') | 194 return (gclient_utils.SplitUrlRevision(actual_remote_url)[0].rstrip('/') |
195 == gclient_utils.SplitUrlRevision(self.url)[0].rstrip('/')) | 195 == gclient_utils.SplitUrlRevision(self.url)[0].rstrip('/')) |
196 else: | 196 else: |
197 # This may occur if the self.checkout_path exists but does not contain a | 197 # This may occur if the self.checkout_path exists but does not contain a |
198 # valid git or svn checkout. | 198 # valid git or svn checkout. |
199 return False | 199 return False |
200 | 200 |
| 201 # TODO(borenet): Remove this once SCMWrapper._DeleteOrMove is enabled. |
| 202 # pylint: disable=R0201 |
| 203 def _DeleteOrMove(self, force): |
| 204 """Delete the checkout directory or move it out of the way. |
| 205 |
| 206 Args: |
| 207 force: bool; if True, delete the directory. Otherwise, just move it. |
| 208 """ |
| 209 gclient_utils.AddWarning('WARNING: Upcoming change in ' |
| 210 'https://codereview.chromium.org/225403015 would ' |
| 211 'cause %s to be deleted or moved to the side. ' |
| 212 'This is intended to ease changes to DEPS in the ' |
| 213 'future. If you are seeing this warning and ' |
| 214 'haven\'t changed the DEPS file, please contact ' |
| 215 'borenet@ immediately.' % self.checkout_path) |
| 216 |
201 | 217 |
202 class GitWrapper(SCMWrapper): | 218 class GitWrapper(SCMWrapper): |
203 """Wrapper for Git""" | 219 """Wrapper for Git""" |
204 name = 'git' | 220 name = 'git' |
205 remote = 'origin' | 221 remote = 'origin' |
206 | 222 |
207 cache_dir = None | 223 cache_dir = None |
208 | 224 |
209 def __init__(self, url=None, root_dir=None, relpath=None, out_fh=None, | 225 def __init__(self, url=None, root_dir=None, relpath=None, out_fh=None, |
210 out_cb=None): | 226 out_cb=None): |
(...skipping 142 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
353 # For compatibility with old naming, translate 'origin' to 'refs/heads' | 369 # For compatibility with old naming, translate 'origin' to 'refs/heads' |
354 revision = revision.replace(self.remote + '/', 'refs/heads/') | 370 revision = revision.replace(self.remote + '/', 'refs/heads/') |
355 rev_type = "branch" | 371 rev_type = "branch" |
356 else: | 372 else: |
357 # hash is also a tag, only make a distinction at checkout | 373 # hash is also a tag, only make a distinction at checkout |
358 rev_type = "hash" | 374 rev_type = "hash" |
359 | 375 |
360 if (not os.path.exists(self.checkout_path) or | 376 if (not os.path.exists(self.checkout_path) or |
361 (os.path.isdir(self.checkout_path) and | 377 (os.path.isdir(self.checkout_path) and |
362 not os.path.exists(os.path.join(self.checkout_path, '.git')))): | 378 not os.path.exists(os.path.join(self.checkout_path, '.git')))): |
| 379 if (os.path.isdir(self.checkout_path) and |
| 380 not os.path.exists(os.path.join(self.checkout_path, '.git'))): |
| 381 self._DeleteOrMove(options.force) |
363 self._Clone(revision, url, options) | 382 self._Clone(revision, url, options) |
364 self._UpdateBranchHeads(options, fetch=True) | 383 self._UpdateBranchHeads(options, fetch=True) |
365 self.UpdateSubmoduleConfig() | 384 self.UpdateSubmoduleConfig() |
366 if file_list is not None: | 385 if file_list is not None: |
367 files = self._Capture(['ls-files']).splitlines() | 386 files = self._Capture(['ls-files']).splitlines() |
368 file_list.extend([os.path.join(self.checkout_path, f) for f in files]) | 387 file_list.extend([os.path.join(self.checkout_path, f) for f in files]) |
369 if not verbose: | 388 if not verbose: |
370 # Make the output a little prettier. It's nice to have some whitespace | 389 # Make the output a little prettier. It's nice to have some whitespace |
371 # between projects when cloning. | 390 # between projects when cloning. |
372 self.Print('') | 391 self.Print('') |
373 return self._Capture(['rev-parse', '--verify', 'HEAD']) | 392 return self._Capture(['rev-parse', '--verify', 'HEAD']) |
374 | 393 |
375 if not managed: | 394 if not managed: |
376 self._UpdateBranchHeads(options, fetch=False) | 395 self._UpdateBranchHeads(options, fetch=False) |
377 self.UpdateSubmoduleConfig() | 396 self.UpdateSubmoduleConfig() |
378 self.Print('________ unmanaged solution; skipping %s' % self.relpath) | 397 self.Print('________ unmanaged solution; skipping %s' % self.relpath) |
379 return self._Capture(['rev-parse', '--verify', 'HEAD']) | 398 return self._Capture(['rev-parse', '--verify', 'HEAD']) |
380 | 399 |
381 if not os.path.exists(os.path.join(self.checkout_path, '.git')): | |
382 raise gclient_utils.Error('\n____ %s%s\n' | |
383 '\tPath is not a git repo. No .git dir.\n' | |
384 '\tTo resolve:\n' | |
385 '\t\trm -rf %s\n' | |
386 '\tAnd run gclient sync again\n' | |
387 % (self.relpath, rev_str, self.relpath)) | |
388 | |
389 # See if the url has changed (the unittests use git://foo for the url, let | 400 # See if the url has changed (the unittests use git://foo for the url, let |
390 # that through). | 401 # that through). |
391 current_url = self._Capture(['config', 'remote.%s.url' % self.remote]) | 402 current_url = self._Capture(['config', 'remote.%s.url' % self.remote]) |
392 return_early = False | 403 return_early = False |
393 # TODO(maruel): Delete url != 'git://foo' since it's just to make the | 404 # TODO(maruel): Delete url != 'git://foo' since it's just to make the |
394 # unit test pass. (and update the comment above) | 405 # unit test pass. (and update the comment above) |
395 # Skip url auto-correction if remote.origin.gclient-auto-fix-url is set. | 406 # Skip url auto-correction if remote.origin.gclient-auto-fix-url is set. |
396 # This allows devs to use experimental repos which have a different url | 407 # This allows devs to use experimental repos which have a different url |
397 # but whose branch(s) are the same as official repos. | 408 # but whose branch(s) are the same as official repos. |
398 if (current_url != url and | 409 if (current_url.rstrip('/') != url.rstrip('/') and |
399 url != 'git://foo' and | 410 url != 'git://foo' and |
400 subprocess2.capture( | 411 subprocess2.capture( |
401 ['git', 'config', 'remote.%s.gclient-auto-fix-url' % self.remote], | 412 ['git', 'config', 'remote.%s.gclient-auto-fix-url' % self.remote], |
402 cwd=self.checkout_path).strip() != 'False'): | 413 cwd=self.checkout_path).strip() != 'False'): |
403 self.Print('_____ switching %s to a new upstream' % self.relpath) | 414 self.Print('_____ switching %s to a new upstream' % self.relpath) |
404 # Make sure it's clean | 415 # Make sure it's clean |
405 self._CheckClean(rev_str) | 416 self._CheckClean(rev_str) |
406 # Switch over to the new upstream | 417 # Switch over to the new upstream |
407 self._Run(['remote', 'set-url', self.remote, url], options) | 418 self._Run(['remote', 'set-url', self.remote, url], options) |
408 self._FetchAndReset(revision, file_list, options) | 419 self._FetchAndReset(revision, file_list, options) |
(...skipping 647 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1056 filter_fn=SvnDiffFilterer(self.relpath).Filter, print_func=self.Print) | 1067 filter_fn=SvnDiffFilterer(self.relpath).Filter, print_func=self.Print) |
1057 | 1068 |
1058 def update(self, options, args, file_list): | 1069 def update(self, options, args, file_list): |
1059 """Runs svn to update or transparently checkout the working copy. | 1070 """Runs svn to update or transparently checkout the working copy. |
1060 | 1071 |
1061 All updated files will be appended to file_list. | 1072 All updated files will be appended to file_list. |
1062 | 1073 |
1063 Raises: | 1074 Raises: |
1064 Error: if can't get URL for relative path. | 1075 Error: if can't get URL for relative path. |
1065 """ | 1076 """ |
1066 # Only update if git or hg is not controlling the directory. | 1077 # Only update if hg is not controlling the directory. |
1067 git_path = os.path.join(self.checkout_path, '.git') | |
1068 if os.path.exists(git_path): | |
1069 self.Print('________ found .git directory; skipping %s' % self.relpath) | |
1070 return | |
1071 | |
1072 hg_path = os.path.join(self.checkout_path, '.hg') | 1078 hg_path = os.path.join(self.checkout_path, '.hg') |
1073 if os.path.exists(hg_path): | 1079 if os.path.exists(hg_path): |
1074 self.Print('________ found .hg directory; skipping %s' % self.relpath) | 1080 self.Print('________ found .hg directory; skipping %s' % self.relpath) |
1075 return | 1081 return |
1076 | 1082 |
1077 if args: | 1083 if args: |
1078 raise gclient_utils.Error("Unsupported argument(s): %s" % ",".join(args)) | 1084 raise gclient_utils.Error("Unsupported argument(s): %s" % ",".join(args)) |
1079 | 1085 |
1080 # revision is the revision to match. It is None if no revision is specified, | 1086 # revision is the revision to match. It is None if no revision is specified, |
1081 # i.e. the 'deps ain't pinned'. | 1087 # i.e. the 'deps ain't pinned'. |
(...skipping 10 matching lines...) Expand all Loading... |
1092 # Reconstruct the url. | 1098 # Reconstruct the url. |
1093 url = '%s@%s' % (url, revision) | 1099 url = '%s@%s' % (url, revision) |
1094 rev_str = ' at %s' % revision | 1100 rev_str = ' at %s' % revision |
1095 else: | 1101 else: |
1096 managed = False | 1102 managed = False |
1097 revision = None | 1103 revision = None |
1098 else: | 1104 else: |
1099 forced_revision = False | 1105 forced_revision = False |
1100 rev_str = '' | 1106 rev_str = '' |
1101 | 1107 |
| 1108 exists = os.path.exists(self.checkout_path) |
| 1109 if exists and managed: |
| 1110 # Git is only okay if it's a git-svn checkout of the right repo. |
| 1111 if scm.GIT.IsGitSvn(self.checkout_path): |
| 1112 remote_url = scm.GIT.Capture(['config', '--local', '--get', |
| 1113 'svn-remote.svn.url'], |
| 1114 cwd=self.checkout_path).rstrip() |
| 1115 if remote_url.rstrip('/') == base_url.rstrip('/'): |
| 1116 print('\n_____ %s looks like a git-svn checkout. Skipping.' |
| 1117 % self.relpath) |
| 1118 return # TODO(borenet): Get the svn revision number? |
| 1119 |
1102 # Get the existing scm url and the revision number of the current checkout. | 1120 # Get the existing scm url and the revision number of the current checkout. |
1103 exists = os.path.exists(self.checkout_path) | |
1104 if exists and managed: | 1121 if exists and managed: |
1105 try: | 1122 try: |
1106 from_info = scm.SVN.CaptureLocalInfo( | 1123 from_info = scm.SVN.CaptureLocalInfo( |
1107 [], os.path.join(self.checkout_path, '.')) | 1124 [], os.path.join(self.checkout_path, '.')) |
1108 except (gclient_utils.Error, subprocess2.CalledProcessError): | 1125 except (gclient_utils.Error, subprocess2.CalledProcessError): |
1109 if options.reset and options.delete_unversioned_trees: | 1126 self._DeleteOrMove(options.force) |
1110 self.Print('Removing troublesome path %s' % self.checkout_path) | 1127 exists = False |
1111 gclient_utils.rmtree(self.checkout_path) | |
1112 exists = False | |
1113 else: | |
1114 msg = ('Can\'t update/checkout %s if an unversioned directory is ' | |
1115 'present. Delete the directory and try again.') | |
1116 raise gclient_utils.Error(msg % self.checkout_path) | |
1117 | 1128 |
1118 BASE_URLS = { | 1129 BASE_URLS = { |
1119 '/chrome/trunk/src': 'gs://chromium-svn-checkout/chrome/', | 1130 '/chrome/trunk/src': 'gs://chromium-svn-checkout/chrome/', |
1120 '/blink/trunk': 'gs://chromium-svn-checkout/blink/', | 1131 '/blink/trunk': 'gs://chromium-svn-checkout/blink/', |
1121 } | 1132 } |
1122 WHITELISTED_ROOTS = [ | 1133 WHITELISTED_ROOTS = [ |
1123 'svn://svn.chromium.org', | 1134 'svn://svn.chromium.org', |
1124 'svn://svn-mirror.golo.chromium.org', | 1135 'svn://svn-mirror.golo.chromium.org', |
1125 ] | 1136 ] |
1126 if not exists: | 1137 if not exists: |
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1186 | 1197 |
1187 gclient_utils.safe_makedirs(os.path.dirname(self.checkout_path)) | 1198 gclient_utils.safe_makedirs(os.path.dirname(self.checkout_path)) |
1188 # We need to checkout. | 1199 # We need to checkout. |
1189 command = ['checkout', url, self.checkout_path] | 1200 command = ['checkout', url, self.checkout_path] |
1190 command = self._AddAdditionalUpdateFlags(command, options, revision) | 1201 command = self._AddAdditionalUpdateFlags(command, options, revision) |
1191 self._RunAndGetFileList(command, options, file_list, self._root_dir) | 1202 self._RunAndGetFileList(command, options, file_list, self._root_dir) |
1192 return self.Svnversion() | 1203 return self.Svnversion() |
1193 | 1204 |
1194 if not managed: | 1205 if not managed: |
1195 self.Print(('________ unmanaged solution; skipping %s' % self.relpath)) | 1206 self.Print(('________ unmanaged solution; skipping %s' % self.relpath)) |
1196 return self.Svnversion() | 1207 if os.path.exists(os.path.join(self.checkout_path, '.svn')): |
| 1208 return self.Svnversion() |
| 1209 return |
1197 | 1210 |
1198 if 'URL' not in from_info: | 1211 if 'URL' not in from_info: |
1199 raise gclient_utils.Error( | 1212 raise gclient_utils.Error( |
1200 ('gclient is confused. Couldn\'t get the url for %s.\n' | 1213 ('gclient is confused. Couldn\'t get the url for %s.\n' |
1201 'Try using @unmanaged.\n%s') % ( | 1214 'Try using @unmanaged.\n%s') % ( |
1202 self.checkout_path, from_info)) | 1215 self.checkout_path, from_info)) |
1203 | 1216 |
1204 # Look for locked directories. | 1217 # Look for locked directories. |
1205 dir_info = scm.SVN.CaptureStatus( | 1218 dir_info = scm.SVN.CaptureStatus( |
1206 None, os.path.join(self.checkout_path, '.')) | 1219 None, os.path.join(self.checkout_path, '.')) |
(...skipping 23 matching lines...) Expand all Loading... |
1230 if d[0][0] == '!': | 1243 if d[0][0] == '!': |
1231 self.Print('You can pass --force to enable automatic removal.') | 1244 self.Print('You can pass --force to enable automatic removal.') |
1232 raise e | 1245 raise e |
1233 | 1246 |
1234 # Retrieve the current HEAD version because svn is slow at null updates. | 1247 # Retrieve the current HEAD version because svn is slow at null updates. |
1235 if options.manually_grab_svn_rev and not revision: | 1248 if options.manually_grab_svn_rev and not revision: |
1236 from_info_live = scm.SVN.CaptureRemoteInfo(from_info['URL']) | 1249 from_info_live = scm.SVN.CaptureRemoteInfo(from_info['URL']) |
1237 revision = str(from_info_live['Revision']) | 1250 revision = str(from_info_live['Revision']) |
1238 rev_str = ' at %s' % revision | 1251 rev_str = ' at %s' % revision |
1239 | 1252 |
1240 if from_info['URL'] != base_url: | 1253 if from_info['URL'].rstrip('/') != base_url.rstrip('/'): |
1241 # The repository url changed, need to switch. | 1254 # The repository url changed, need to switch. |
1242 try: | 1255 try: |
1243 to_info = scm.SVN.CaptureRemoteInfo(url) | 1256 to_info = scm.SVN.CaptureRemoteInfo(url) |
1244 except (gclient_utils.Error, subprocess2.CalledProcessError): | 1257 except (gclient_utils.Error, subprocess2.CalledProcessError): |
1245 # The url is invalid or the server is not accessible, it's safer to bail | 1258 # The url is invalid or the server is not accessible, it's safer to bail |
1246 # out right now. | 1259 # out right now. |
1247 raise gclient_utils.Error('This url is unreachable: %s' % url) | 1260 raise gclient_utils.Error('This url is unreachable: %s' % url) |
1248 can_switch = ((from_info['Repository Root'] != to_info['Repository Root']) | 1261 can_switch = ((from_info['Repository Root'] != to_info['Repository Root']) |
1249 and (from_info['UUID'] == to_info['UUID'])) | 1262 and (from_info['UUID'] == to_info['UUID'])) |
1250 if can_switch: | 1263 if can_switch: |
(...skipping 215 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1466 new_command.append('--force') | 1479 new_command.append('--force') |
1467 if command[0] != 'checkout' and scm.SVN.AssertVersion('1.6')[0]: | 1480 if command[0] != 'checkout' and scm.SVN.AssertVersion('1.6')[0]: |
1468 new_command.extend(('--accept', 'theirs-conflict')) | 1481 new_command.extend(('--accept', 'theirs-conflict')) |
1469 elif options.manually_grab_svn_rev: | 1482 elif options.manually_grab_svn_rev: |
1470 new_command.append('--force') | 1483 new_command.append('--force') |
1471 if command[0] != 'checkout' and scm.SVN.AssertVersion('1.6')[0]: | 1484 if command[0] != 'checkout' and scm.SVN.AssertVersion('1.6')[0]: |
1472 new_command.extend(('--accept', 'postpone')) | 1485 new_command.extend(('--accept', 'postpone')) |
1473 elif command[0] != 'checkout' and scm.SVN.AssertVersion('1.6')[0]: | 1486 elif command[0] != 'checkout' and scm.SVN.AssertVersion('1.6')[0]: |
1474 new_command.extend(('--accept', 'postpone')) | 1487 new_command.extend(('--accept', 'postpone')) |
1475 return new_command | 1488 return new_command |
OLD | NEW |