| 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 collections | 7 import collections |
| 8 import logging | 8 import logging |
| 9 import os | 9 import os |
| 10 import posixpath | 10 import posixpath |
| (...skipping 172 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 183 match = self.PERCENT_RE.match(line) | 183 match = self.PERCENT_RE.match(line) |
| 184 if not match: | 184 if not match: |
| 185 self.last_time = 0 | 185 self.last_time = 0 |
| 186 if (now - self.last_time) >= self.time_throttle: | 186 if (now - self.last_time) >= self.time_throttle: |
| 187 self.last_time = now | 187 self.last_time = now |
| 188 print line | 188 print line |
| 189 | 189 |
| 190 | 190 |
| 191 class GitWrapper(SCMWrapper): | 191 class GitWrapper(SCMWrapper): |
| 192 """Wrapper for Git""" | 192 """Wrapper for Git""" |
| 193 name = 'git' |
| 193 | 194 |
| 194 cache_dir = None | 195 cache_dir = None |
| 195 # If a given cache is used in a solution more than once, prevent multiple | 196 # If a given cache is used in a solution more than once, prevent multiple |
| 196 # threads from updating it simultaneously. | 197 # threads from updating it simultaneously. |
| 197 cache_locks = collections.defaultdict(threading.Lock) | 198 cache_locks = collections.defaultdict(threading.Lock) |
| 198 | 199 |
| 199 def __init__(self, url=None, root_dir=None, relpath=None): | 200 def __init__(self, url=None, root_dir=None, relpath=None): |
| 200 """Removes 'git+' fake prefix from git URL.""" | 201 """Removes 'git+' fake prefix from git URL.""" |
| 201 if url.startswith('git+http://') or url.startswith('git+https://'): | 202 if url.startswith('git+http://') or url.startswith('git+https://'): |
| 202 url = url[4:] | 203 url = url[4:] |
| (...skipping 153 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 356 not os.path.exists(os.path.join(self.checkout_path, '.git')))): | 357 not os.path.exists(os.path.join(self.checkout_path, '.git')))): |
| 357 self._Clone(revision, url, options) | 358 self._Clone(revision, url, options) |
| 358 self.UpdateSubmoduleConfig() | 359 self.UpdateSubmoduleConfig() |
| 359 if file_list is not None: | 360 if file_list is not None: |
| 360 files = self._Capture(['ls-files']).splitlines() | 361 files = self._Capture(['ls-files']).splitlines() |
| 361 file_list.extend([os.path.join(self.checkout_path, f) for f in files]) | 362 file_list.extend([os.path.join(self.checkout_path, f) for f in files]) |
| 362 if not verbose: | 363 if not verbose: |
| 363 # Make the output a little prettier. It's nice to have some whitespace | 364 # Make the output a little prettier. It's nice to have some whitespace |
| 364 # between projects when cloning. | 365 # between projects when cloning. |
| 365 print('') | 366 print('') |
| 366 return | 367 return self._Capture(['rev-parse', '--verify', 'HEAD']) |
| 367 | 368 |
| 368 if not managed: | 369 if not managed: |
| 369 self._UpdateBranchHeads(options, fetch=False) | 370 self._UpdateBranchHeads(options, fetch=False) |
| 370 self.UpdateSubmoduleConfig() | 371 self.UpdateSubmoduleConfig() |
| 371 print ('________ unmanaged solution; skipping %s' % self.relpath) | 372 print ('________ unmanaged solution; skipping %s' % self.relpath) |
| 372 return | 373 return self._Capture(['rev-parse', '--verify', 'HEAD']) |
| 373 | 374 |
| 374 if not os.path.exists(os.path.join(self.checkout_path, '.git')): | 375 if not os.path.exists(os.path.join(self.checkout_path, '.git')): |
| 375 raise gclient_utils.Error('\n____ %s%s\n' | 376 raise gclient_utils.Error('\n____ %s%s\n' |
| 376 '\tPath is not a git repo. No .git dir.\n' | 377 '\tPath is not a git repo. No .git dir.\n' |
| 377 '\tTo resolve:\n' | 378 '\tTo resolve:\n' |
| 378 '\t\trm -rf %s\n' | 379 '\t\trm -rf %s\n' |
| 379 '\tAnd run gclient sync again\n' | 380 '\tAnd run gclient sync again\n' |
| 380 % (self.relpath, rev_str, self.relpath)) | 381 % (self.relpath, rev_str, self.relpath)) |
| 381 | 382 |
| 382 # See if the url has changed (the unittests use git://foo for the url, let | 383 # See if the url has changed (the unittests use git://foo for the url, let |
| (...skipping 16 matching lines...) Expand all Loading... |
| 399 # Switch over to the new upstream | 400 # Switch over to the new upstream |
| 400 self._Run(['remote', 'set-url', 'origin', url], options) | 401 self._Run(['remote', 'set-url', 'origin', url], options) |
| 401 self._FetchAndReset(revision, file_list, options) | 402 self._FetchAndReset(revision, file_list, options) |
| 402 return_early = True | 403 return_early = True |
| 403 | 404 |
| 404 # Need to do this in the normal path as well as in the post-remote-switch | 405 # Need to do this in the normal path as well as in the post-remote-switch |
| 405 # path. | 406 # path. |
| 406 self._PossiblySwitchCache(url, options) | 407 self._PossiblySwitchCache(url, options) |
| 407 | 408 |
| 408 if return_early: | 409 if return_early: |
| 409 return | 410 return self._Capture(['rev-parse', '--verify', 'HEAD']) |
| 410 | 411 |
| 411 cur_branch = self._GetCurrentBranch() | 412 cur_branch = self._GetCurrentBranch() |
| 412 | 413 |
| 413 # Cases: | 414 # Cases: |
| 414 # 0) HEAD is detached. Probably from our initial clone. | 415 # 0) HEAD is detached. Probably from our initial clone. |
| 415 # - make sure HEAD is contained by a named ref, then update. | 416 # - make sure HEAD is contained by a named ref, then update. |
| 416 # Cases 1-4. HEAD is a branch. | 417 # Cases 1-4. HEAD is a branch. |
| 417 # 1) current branch is not tracking a remote branch (could be git-svn) | 418 # 1) current branch is not tracking a remote branch (could be git-svn) |
| 418 # - try to rebase onto the new hash or branch | 419 # - try to rebase onto the new hash or branch |
| 419 # 2) current branch is tracking a remote branch with local committed | 420 # 2) current branch is tracking a remote branch with local committed |
| (...skipping 168 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 588 # 'git ls-files --directory --others --exclude-standard' here directly. | 589 # 'git ls-files --directory --others --exclude-standard' here directly. |
| 589 paths = scm.GIT.Capture( | 590 paths = scm.GIT.Capture( |
| 590 ['ls-files', '--directory', '--others', '--exclude-standard'], | 591 ['ls-files', '--directory', '--others', '--exclude-standard'], |
| 591 self.checkout_path) | 592 self.checkout_path) |
| 592 for path in (p for p in paths.splitlines() if p.endswith('/')): | 593 for path in (p for p in paths.splitlines() if p.endswith('/')): |
| 593 full_path = os.path.join(self.checkout_path, path) | 594 full_path = os.path.join(self.checkout_path, path) |
| 594 if not os.path.islink(full_path): | 595 if not os.path.islink(full_path): |
| 595 print('\n_____ removing unversioned directory %s' % path) | 596 print('\n_____ removing unversioned directory %s' % path) |
| 596 gclient_utils.rmtree(full_path) | 597 gclient_utils.rmtree(full_path) |
| 597 | 598 |
| 599 return self._Capture(['rev-parse', '--verify', 'HEAD']) |
| 600 |
| 598 | 601 |
| 599 def revert(self, options, _args, file_list): | 602 def revert(self, options, _args, file_list): |
| 600 """Reverts local modifications. | 603 """Reverts local modifications. |
| 601 | 604 |
| 602 All reverted files will be appended to file_list. | 605 All reverted files will be appended to file_list. |
| 603 """ | 606 """ |
| 604 if not os.path.isdir(self.checkout_path): | 607 if not os.path.isdir(self.checkout_path): |
| 605 # revert won't work if the directory doesn't exist. It needs to | 608 # revert won't work if the directory doesn't exist. It needs to |
| 606 # checkout instead. | 609 # checkout instead. |
| 607 print('\n_____ %s is missing, synching instead' % self.relpath) | 610 print('\n_____ %s is missing, synching instead' % self.relpath) |
| (...skipping 473 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1081 else: | 1084 else: |
| 1082 kwargs.setdefault('print_stdout', True) | 1085 kwargs.setdefault('print_stdout', True) |
| 1083 stdout = kwargs.get('stdout', sys.stdout) | 1086 stdout = kwargs.get('stdout', sys.stdout) |
| 1084 stdout.write('\n________ running \'git %s\' in \'%s\'\n' % ( | 1087 stdout.write('\n________ running \'git %s\' in \'%s\'\n' % ( |
| 1085 ' '.join(args), kwargs['cwd'])) | 1088 ' '.join(args), kwargs['cwd'])) |
| 1086 gclient_utils.CheckCallAndFilter(['git'] + args, **kwargs) | 1089 gclient_utils.CheckCallAndFilter(['git'] + args, **kwargs) |
| 1087 | 1090 |
| 1088 | 1091 |
| 1089 class SVNWrapper(SCMWrapper): | 1092 class SVNWrapper(SCMWrapper): |
| 1090 """ Wrapper for SVN """ | 1093 """ Wrapper for SVN """ |
| 1094 name = 'svn' |
| 1091 | 1095 |
| 1092 @staticmethod | 1096 @staticmethod |
| 1093 def BinaryExists(): | 1097 def BinaryExists(): |
| 1094 """Returns true if the command exists.""" | 1098 """Returns true if the command exists.""" |
| 1095 try: | 1099 try: |
| 1096 result, version = scm.SVN.AssertVersion('1.4') | 1100 result, version = scm.SVN.AssertVersion('1.4') |
| 1097 if not result: | 1101 if not result: |
| 1098 raise gclient_utils.Error('SVN version is older than 1.4: %s' % version) | 1102 raise gclient_utils.Error('SVN version is older than 1.4: %s' % version) |
| 1099 return result | 1103 return result |
| 1100 except OSError: | 1104 except OSError: |
| (...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1195 msg = ('Can\'t update/checkout %s if an unversioned directory is ' | 1199 msg = ('Can\'t update/checkout %s if an unversioned directory is ' |
| 1196 'present. Delete the directory and try again.') | 1200 'present. Delete the directory and try again.') |
| 1197 raise gclient_utils.Error(msg % self.checkout_path) | 1201 raise gclient_utils.Error(msg % self.checkout_path) |
| 1198 | 1202 |
| 1199 if not exists: | 1203 if not exists: |
| 1200 gclient_utils.safe_makedirs(os.path.dirname(self.checkout_path)) | 1204 gclient_utils.safe_makedirs(os.path.dirname(self.checkout_path)) |
| 1201 # We need to checkout. | 1205 # We need to checkout. |
| 1202 command = ['checkout', url, self.checkout_path] | 1206 command = ['checkout', url, self.checkout_path] |
| 1203 command = self._AddAdditionalUpdateFlags(command, options, revision) | 1207 command = self._AddAdditionalUpdateFlags(command, options, revision) |
| 1204 self._RunAndGetFileList(command, options, file_list, self._root_dir) | 1208 self._RunAndGetFileList(command, options, file_list, self._root_dir) |
| 1205 return | 1209 return self.Svnversion() |
| 1206 | 1210 |
| 1207 if not managed: | 1211 if not managed: |
| 1208 print ('________ unmanaged solution; skipping %s' % self.relpath) | 1212 print ('________ unmanaged solution; skipping %s' % self.relpath) |
| 1209 return | 1213 return self.Svnversion() |
| 1210 | 1214 |
| 1211 if 'URL' not in from_info: | 1215 if 'URL' not in from_info: |
| 1212 raise gclient_utils.Error( | 1216 raise gclient_utils.Error( |
| 1213 ('gclient is confused. Couldn\'t get the url for %s.\n' | 1217 ('gclient is confused. Couldn\'t get the url for %s.\n' |
| 1214 'Try using @unmanaged.\n%s') % ( | 1218 'Try using @unmanaged.\n%s') % ( |
| 1215 self.checkout_path, from_info)) | 1219 self.checkout_path, from_info)) |
| 1216 | 1220 |
| 1217 # Look for locked directories. | 1221 # Look for locked directories. |
| 1218 dir_info = scm.SVN.CaptureStatus( | 1222 dir_info = scm.SVN.CaptureStatus( |
| 1219 None, os.path.join(self.checkout_path, '.')) | 1223 None, os.path.join(self.checkout_path, '.')) |
| (...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1287 ('Can\'t switch the checkout to %s; UUID don\'t match and ' | 1291 ('Can\'t switch the checkout to %s; UUID don\'t match and ' |
| 1288 'there is local changes in %s. Delete the directory and ' | 1292 'there is local changes in %s. Delete the directory and ' |
| 1289 'try again.') % (url, self.checkout_path)) | 1293 'try again.') % (url, self.checkout_path)) |
| 1290 # Ok delete it. | 1294 # Ok delete it. |
| 1291 print('\n_____ switching %s to a new checkout' % self.relpath) | 1295 print('\n_____ switching %s to a new checkout' % self.relpath) |
| 1292 gclient_utils.rmtree(self.checkout_path) | 1296 gclient_utils.rmtree(self.checkout_path) |
| 1293 # We need to checkout. | 1297 # We need to checkout. |
| 1294 command = ['checkout', url, self.checkout_path] | 1298 command = ['checkout', url, self.checkout_path] |
| 1295 command = self._AddAdditionalUpdateFlags(command, options, revision) | 1299 command = self._AddAdditionalUpdateFlags(command, options, revision) |
| 1296 self._RunAndGetFileList(command, options, file_list, self._root_dir) | 1300 self._RunAndGetFileList(command, options, file_list, self._root_dir) |
| 1297 return | 1301 return self.Svnversion() |
| 1298 | 1302 |
| 1299 # If the provided url has a revision number that matches the revision | 1303 # If the provided url has a revision number that matches the revision |
| 1300 # number of the existing directory, then we don't need to bother updating. | 1304 # number of the existing directory, then we don't need to bother updating. |
| 1301 if not options.force and str(from_info['Revision']) == revision: | 1305 if not options.force and str(from_info['Revision']) == revision: |
| 1302 if options.verbose or not forced_revision: | 1306 if options.verbose or not forced_revision: |
| 1303 print('\n_____ %s%s' % (self.relpath, rev_str)) | 1307 print('\n_____ %s%s' % (self.relpath, rev_str)) |
| 1304 else: | 1308 else: |
| 1305 command = ['update', self.checkout_path] | 1309 command = ['update', self.checkout_path] |
| 1306 command = self._AddAdditionalUpdateFlags(command, options, revision) | 1310 command = self._AddAdditionalUpdateFlags(command, options, revision) |
| 1307 self._RunAndGetFileList(command, options, file_list, self._root_dir) | 1311 self._RunAndGetFileList(command, options, file_list, self._root_dir) |
| 1308 | 1312 |
| 1309 # If --reset and --delete_unversioned_trees are specified, remove any | 1313 # If --reset and --delete_unversioned_trees are specified, remove any |
| 1310 # untracked files and directories. | 1314 # untracked files and directories. |
| 1311 if options.reset and options.delete_unversioned_trees: | 1315 if options.reset and options.delete_unversioned_trees: |
| 1312 for status in scm.SVN.CaptureStatus(None, self.checkout_path): | 1316 for status in scm.SVN.CaptureStatus(None, self.checkout_path): |
| 1313 full_path = os.path.join(self.checkout_path, status[1]) | 1317 full_path = os.path.join(self.checkout_path, status[1]) |
| 1314 if (status[0][0] == '?' | 1318 if (status[0][0] == '?' |
| 1315 and os.path.isdir(full_path) | 1319 and os.path.isdir(full_path) |
| 1316 and not os.path.islink(full_path)): | 1320 and not os.path.islink(full_path)): |
| 1317 print('\n_____ removing unversioned directory %s' % status[1]) | 1321 print('\n_____ removing unversioned directory %s' % status[1]) |
| 1318 gclient_utils.rmtree(full_path) | 1322 gclient_utils.rmtree(full_path) |
| 1323 return self.Svnversion() |
| 1319 | 1324 |
| 1320 def updatesingle(self, options, args, file_list): | 1325 def updatesingle(self, options, args, file_list): |
| 1321 filename = args.pop() | 1326 filename = args.pop() |
| 1322 if scm.SVN.AssertVersion("1.5")[0]: | 1327 if scm.SVN.AssertVersion("1.5")[0]: |
| 1323 if not os.path.exists(os.path.join(self.checkout_path, '.svn')): | 1328 if not os.path.exists(os.path.join(self.checkout_path, '.svn')): |
| 1324 # Create an empty checkout and then update the one file we want. Future | 1329 # Create an empty checkout and then update the one file we want. Future |
| 1325 # operations will only apply to the one file we checked out. | 1330 # operations will only apply to the one file we checked out. |
| 1326 command = ["checkout", "--depth", "empty", self.url, self.checkout_path] | 1331 command = ["checkout", "--depth", "empty", self.url, self.checkout_path] |
| 1327 self._Run(command, options, cwd=self._root_dir) | 1332 self._Run(command, options, cwd=self._root_dir) |
| 1328 if os.path.exists(os.path.join(self.checkout_path, filename)): | 1333 if os.path.exists(os.path.join(self.checkout_path, filename)): |
| (...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1435 return '/'.join(self.url.split('/')[:4]) + url | 1440 return '/'.join(self.url.split('/')[:4]) + url |
| 1436 | 1441 |
| 1437 def _Run(self, args, options, **kwargs): | 1442 def _Run(self, args, options, **kwargs): |
| 1438 """Runs a commands that goes to stdout.""" | 1443 """Runs a commands that goes to stdout.""" |
| 1439 kwargs.setdefault('cwd', self.checkout_path) | 1444 kwargs.setdefault('cwd', self.checkout_path) |
| 1440 kwargs.setdefault('nag_timer', self.nag_timer) | 1445 kwargs.setdefault('nag_timer', self.nag_timer) |
| 1441 kwargs.setdefault('nag_max', self.nag_max) | 1446 kwargs.setdefault('nag_max', self.nag_max) |
| 1442 gclient_utils.CheckCallAndFilterAndHeader(['svn'] + args, | 1447 gclient_utils.CheckCallAndFilterAndHeader(['svn'] + args, |
| 1443 always=options.verbose, **kwargs) | 1448 always=options.verbose, **kwargs) |
| 1444 | 1449 |
| 1450 def Svnversion(self): |
| 1451 """Runs the lowest checked out revision in the current project.""" |
| 1452 info = scm.SVN.CaptureLocalInfo([], os.path.join(self.checkout_path, '.')) |
| 1453 return info['Revision'] |
| 1454 |
| 1445 def _RunAndGetFileList(self, args, options, file_list, cwd=None): | 1455 def _RunAndGetFileList(self, args, options, file_list, cwd=None): |
| 1446 """Runs a commands that goes to stdout and grabs the file listed.""" | 1456 """Runs a commands that goes to stdout and grabs the file listed.""" |
| 1447 cwd = cwd or self.checkout_path | 1457 cwd = cwd or self.checkout_path |
| 1448 scm.SVN.RunAndGetFileList( | 1458 scm.SVN.RunAndGetFileList( |
| 1449 options.verbose, | 1459 options.verbose, |
| 1450 args + ['--ignore-externals'], | 1460 args + ['--ignore-externals'], |
| 1451 cwd=cwd, | 1461 cwd=cwd, |
| 1452 file_list=file_list) | 1462 file_list=file_list) |
| 1453 | 1463 |
| 1454 @staticmethod | 1464 @staticmethod |
| (...skipping 19 matching lines...) Expand all Loading... |
| 1474 new_command.append('--force') | 1484 new_command.append('--force') |
| 1475 if command[0] != 'checkout' and scm.SVN.AssertVersion('1.6')[0]: | 1485 if command[0] != 'checkout' and scm.SVN.AssertVersion('1.6')[0]: |
| 1476 new_command.extend(('--accept', 'theirs-conflict')) | 1486 new_command.extend(('--accept', 'theirs-conflict')) |
| 1477 elif options.manually_grab_svn_rev: | 1487 elif options.manually_grab_svn_rev: |
| 1478 new_command.append('--force') | 1488 new_command.append('--force') |
| 1479 if command[0] != 'checkout' and scm.SVN.AssertVersion('1.6')[0]: | 1489 if command[0] != 'checkout' and scm.SVN.AssertVersion('1.6')[0]: |
| 1480 new_command.extend(('--accept', 'postpone')) | 1490 new_command.extend(('--accept', 'postpone')) |
| 1481 elif command[0] != 'checkout' and scm.SVN.AssertVersion('1.6')[0]: | 1491 elif command[0] != 'checkout' and scm.SVN.AssertVersion('1.6')[0]: |
| 1482 new_command.extend(('--accept', 'postpone')) | 1492 new_command.extend(('--accept', 'postpone')) |
| 1483 return new_command | 1493 return new_command |
| OLD | NEW |