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 |