| OLD | NEW |
| 1 # Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 # Copyright (c) 2010 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 273 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 284 raise gclient_utils.Error('Invalid Upstream: %s' % upstream_branch) | 284 raise gclient_utils.Error('Invalid Upstream: %s' % upstream_branch) |
| 285 | 285 |
| 286 # Update the remotes first so we have all the refs. | 286 # Update the remotes first so we have all the refs. |
| 287 backoff_time = 5 | 287 backoff_time = 5 |
| 288 for _ in range(10): | 288 for _ in range(10): |
| 289 try: | 289 try: |
| 290 remote_output = scm.GIT.Capture( | 290 remote_output = scm.GIT.Capture( |
| 291 ['remote'] + verbose + ['update'], | 291 ['remote'] + verbose + ['update'], |
| 292 cwd=self.checkout_path) | 292 cwd=self.checkout_path) |
| 293 break | 293 break |
| 294 except gclient_utils.CheckCallError, e: | 294 except subprocess2.CalledProcessError, e: |
| 295 # Hackish but at that point, git is known to work so just checking for | 295 # Hackish but at that point, git is known to work so just checking for |
| 296 # 502 in stderr should be fine. | 296 # 502 in stderr should be fine. |
| 297 if '502' in e.stderr: | 297 if '502' in e.stderr: |
| 298 print(str(e)) | 298 print(str(e)) |
| 299 print('Sleeping %.1f seconds and retrying...' % backoff_time) | 299 print('Sleeping %.1f seconds and retrying...' % backoff_time) |
| 300 time.sleep(backoff_time) | 300 time.sleep(backoff_time) |
| 301 backoff_time *= 1.3 | 301 backoff_time *= 1.3 |
| 302 continue | 302 continue |
| 303 raise | 303 raise |
| 304 | 304 |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 353 # case 3 - the default case | 353 # case 3 - the default case |
| 354 files = self._Capture(['diff', upstream_branch, '--name-only']).split() | 354 files = self._Capture(['diff', upstream_branch, '--name-only']).split() |
| 355 if verbose: | 355 if verbose: |
| 356 print('Trying fast-forward merge to branch : %s' % upstream_branch) | 356 print('Trying fast-forward merge to branch : %s' % upstream_branch) |
| 357 try: | 357 try: |
| 358 merge_args = ['merge'] | 358 merge_args = ['merge'] |
| 359 if not options.merge: | 359 if not options.merge: |
| 360 merge_args.append('--ff-only') | 360 merge_args.append('--ff-only') |
| 361 merge_args.append(upstream_branch) | 361 merge_args.append(upstream_branch) |
| 362 merge_output = scm.GIT.Capture(merge_args, cwd=self.checkout_path) | 362 merge_output = scm.GIT.Capture(merge_args, cwd=self.checkout_path) |
| 363 except gclient_utils.CheckCallError, e: | 363 except subprocess2.CalledProcessError, e: |
| 364 if re.match('fatal: Not possible to fast-forward, aborting.', e.stderr): | 364 if re.match('fatal: Not possible to fast-forward, aborting.', e.stderr): |
| 365 if not printed_path: | 365 if not printed_path: |
| 366 print('\n_____ %s%s' % (self.relpath, rev_str)) | 366 print('\n_____ %s%s' % (self.relpath, rev_str)) |
| 367 printed_path = True | 367 printed_path = True |
| 368 while True: | 368 while True: |
| 369 try: | 369 try: |
| 370 # TODO(maruel): That can't work with --jobs. | 370 # TODO(maruel): That can't work with --jobs. |
| 371 action = ask_for_data( | 371 action = ask_for_data( |
| 372 'Cannot fast-forward merge, attempt to rebase? ' | 372 'Cannot fast-forward merge, attempt to rebase? ' |
| 373 '(y)es / (q)uit / (s)kip : ') | 373 '(y)es / (q)uit / (s)kip : ') |
| (...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 501 parent_dir = os.path.dirname(self.checkout_path) | 501 parent_dir = os.path.dirname(self.checkout_path) |
| 502 if not os.path.exists(parent_dir): | 502 if not os.path.exists(parent_dir): |
| 503 os.makedirs(parent_dir) | 503 os.makedirs(parent_dir) |
| 504 | 504 |
| 505 for _ in range(3): | 505 for _ in range(3): |
| 506 try: | 506 try: |
| 507 self._Run(clone_cmd, options, cwd=self._root_dir) | 507 self._Run(clone_cmd, options, cwd=self._root_dir) |
| 508 break | 508 break |
| 509 except (gclient_utils.Error, subprocess2.CalledProcessError), e: | 509 except (gclient_utils.Error, subprocess2.CalledProcessError), e: |
| 510 # TODO(maruel): Hackish, should be fixed by moving _Run() to | 510 # TODO(maruel): Hackish, should be fixed by moving _Run() to |
| 511 # CheckCall(). | 511 # subprocess2.check_output(). |
| 512 # Too bad we don't have access to the actual output. | 512 # Too bad we don't have access to the actual output. |
| 513 # We should check for "transfer closed with NNN bytes remaining to | 513 # We should check for "transfer closed with NNN bytes remaining to |
| 514 # read". In the meantime, just make sure .git exists. | 514 # read". In the meantime, just make sure .git exists. |
| 515 if (e.args[0] == 'git command clone returned 128' and | 515 if (e.args[0] == 'git command clone returned 128' and |
| 516 os.path.exists(os.path.join(self.checkout_path, '.git'))): | 516 os.path.exists(os.path.join(self.checkout_path, '.git'))): |
| 517 print(str(e)) | 517 print(str(e)) |
| 518 print('Retrying...') | 518 print('Retrying...') |
| 519 continue | 519 continue |
| 520 raise e | 520 raise e |
| 521 | 521 |
| (...skipping 26 matching lines...) Expand all Loading... |
| 548 if options.verbose: | 548 if options.verbose: |
| 549 rebase_cmd.append('--verbose') | 549 rebase_cmd.append('--verbose') |
| 550 if newbase: | 550 if newbase: |
| 551 rebase_cmd.extend(['--onto', newbase]) | 551 rebase_cmd.extend(['--onto', newbase]) |
| 552 rebase_cmd.append(upstream) | 552 rebase_cmd.append(upstream) |
| 553 if branch: | 553 if branch: |
| 554 rebase_cmd.append(branch) | 554 rebase_cmd.append(branch) |
| 555 | 555 |
| 556 try: | 556 try: |
| 557 rebase_output = scm.GIT.Capture(rebase_cmd, cwd=self.checkout_path) | 557 rebase_output = scm.GIT.Capture(rebase_cmd, cwd=self.checkout_path) |
| 558 except gclient_utils.CheckCallError, e: | 558 except subprocess2.CalledProcessError, e: |
| 559 if (re.match(r'cannot rebase: you have unstaged changes', e.stderr) or | 559 if (re.match(r'cannot rebase: you have unstaged changes', e.stderr) or |
| 560 re.match(r'cannot rebase: your index contains uncommitted changes', | 560 re.match(r'cannot rebase: your index contains uncommitted changes', |
| 561 e.stderr)): | 561 e.stderr)): |
| 562 while True: | 562 while True: |
| 563 rebase_action = ask_for_data( | 563 rebase_action = ask_for_data( |
| 564 'Cannot rebase because of unstaged changes.\n' | 564 'Cannot rebase because of unstaged changes.\n' |
| 565 '\'git reset --hard HEAD\' ?\n' | 565 '\'git reset --hard HEAD\' ?\n' |
| 566 'WARNING: destroys any uncommitted work in your current branch!' | 566 'WARNING: destroys any uncommitted work in your current branch!' |
| 567 ' (y)es / (q)uit / (s)how : ') | 567 ' (y)es / (q)uit / (s)how : ') |
| 568 if re.match(r'yes|y', rebase_action, re.I): | 568 if re.match(r'yes|y', rebase_action, re.I): |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 612 g = os.path.join(self.checkout_path, '.git') | 612 g = os.path.join(self.checkout_path, '.git') |
| 613 return ( | 613 return ( |
| 614 os.path.isdir(os.path.join(g, "rebase-merge")) or | 614 os.path.isdir(os.path.join(g, "rebase-merge")) or |
| 615 os.path.isdir(os.path.join(g, "rebase-apply"))) | 615 os.path.isdir(os.path.join(g, "rebase-apply"))) |
| 616 | 616 |
| 617 def _CheckClean(self, rev_str): | 617 def _CheckClean(self, rev_str): |
| 618 # Make sure the tree is clean; see git-rebase.sh for reference | 618 # Make sure the tree is clean; see git-rebase.sh for reference |
| 619 try: | 619 try: |
| 620 scm.GIT.Capture(['update-index', '--ignore-submodules', '--refresh'], | 620 scm.GIT.Capture(['update-index', '--ignore-submodules', '--refresh'], |
| 621 cwd=self.checkout_path) | 621 cwd=self.checkout_path) |
| 622 except gclient_utils.CheckCallError: | 622 except subprocess2.CalledProcessError: |
| 623 raise gclient_utils.Error('\n____ %s%s\n' | 623 raise gclient_utils.Error('\n____ %s%s\n' |
| 624 '\tYou have unstaged changes.\n' | 624 '\tYou have unstaged changes.\n' |
| 625 '\tPlease commit, stash, or reset.\n' | 625 '\tPlease commit, stash, or reset.\n' |
| 626 % (self.relpath, rev_str)) | 626 % (self.relpath, rev_str)) |
| 627 try: | 627 try: |
| 628 scm.GIT.Capture(['diff-index', '--cached', '--name-status', '-r', | 628 scm.GIT.Capture(['diff-index', '--cached', '--name-status', '-r', |
| 629 '--ignore-submodules', 'HEAD', '--'], | 629 '--ignore-submodules', 'HEAD', '--'], |
| 630 cwd=self.checkout_path) | 630 cwd=self.checkout_path) |
| 631 except gclient_utils.CheckCallError: | 631 except subprocess2.CalledProcessError: |
| 632 raise gclient_utils.Error('\n____ %s%s\n' | 632 raise gclient_utils.Error('\n____ %s%s\n' |
| 633 '\tYour index contains uncommitted changes\n' | 633 '\tYour index contains uncommitted changes\n' |
| 634 '\tPlease commit, stash, or reset.\n' | 634 '\tPlease commit, stash, or reset.\n' |
| 635 % (self.relpath, rev_str)) | 635 % (self.relpath, rev_str)) |
| 636 | 636 |
| 637 def _CheckDetachedHead(self, rev_str, options): | 637 def _CheckDetachedHead(self, rev_str, options): |
| 638 # HEAD is detached. Make sure it is safe to move away from (i.e., it is | 638 # HEAD is detached. Make sure it is safe to move away from (i.e., it is |
| 639 # reference by a commit). If not, error out -- most likely a rebase is | 639 # reference by a commit). If not, error out -- most likely a rebase is |
| 640 # in progress, try to detect so we can give a better error. | 640 # in progress, try to detect so we can give a better error. |
| 641 try: | 641 try: |
| 642 scm.GIT.Capture(['name-rev', '--no-undefined', 'HEAD'], | 642 scm.GIT.Capture(['name-rev', '--no-undefined', 'HEAD'], |
| 643 cwd=self.checkout_path) | 643 cwd=self.checkout_path) |
| 644 except gclient_utils.CheckCallError: | 644 except subprocess2.CalledProcessError: |
| 645 # Commit is not contained by any rev. See if the user is rebasing: | 645 # Commit is not contained by any rev. See if the user is rebasing: |
| 646 if self._IsRebasing(): | 646 if self._IsRebasing(): |
| 647 # Punt to the user | 647 # Punt to the user |
| 648 raise gclient_utils.Error('\n____ %s%s\n' | 648 raise gclient_utils.Error('\n____ %s%s\n' |
| 649 '\tAlready in a conflict, i.e. (no branch).\n' | 649 '\tAlready in a conflict, i.e. (no branch).\n' |
| 650 '\tFix the conflict and run gclient again.\n' | 650 '\tFix the conflict and run gclient again.\n' |
| 651 '\tOr to abort run:\n\t\tgit-rebase --abort\n' | 651 '\tOr to abort run:\n\t\tgit-rebase --abort\n' |
| 652 '\tSee man git-rebase for details.\n' | 652 '\tSee man git-rebase for details.\n' |
| 653 % (self.relpath, rev_str)) | 653 % (self.relpath, rev_str)) |
| 654 # Let's just save off the commit so we can proceed. | 654 # Let's just save off the commit so we can proceed. |
| 655 name = ('saved-by-gclient-' + | 655 name = ('saved-by-gclient-' + |
| 656 self._Capture(['rev-parse', '--short', 'HEAD'])) | 656 self._Capture(['rev-parse', '--short', 'HEAD'])) |
| 657 self._Capture(['branch', name]) | 657 self._Capture(['branch', name]) |
| 658 print('\n_____ found an unreferenced commit and saved it as \'%s\'' % | 658 print('\n_____ found an unreferenced commit and saved it as \'%s\'' % |
| 659 name) | 659 name) |
| 660 | 660 |
| 661 def _GetCurrentBranch(self): | 661 def _GetCurrentBranch(self): |
| 662 # Returns name of current branch or None for detached HEAD | 662 # Returns name of current branch or None for detached HEAD |
| 663 branch = self._Capture(['rev-parse', '--abbrev-ref=strict', 'HEAD']) | 663 branch = self._Capture(['rev-parse', '--abbrev-ref=strict', 'HEAD']) |
| 664 if branch == 'HEAD': | 664 if branch == 'HEAD': |
| 665 return None | 665 return None |
| 666 return branch | 666 return branch |
| 667 | 667 |
| 668 def _Capture(self, args): | 668 def _Capture(self, args): |
| 669 return gclient_utils.CheckCall( | 669 return subprocess2.check_output( |
| 670 ['git'] + args, cwd=self.checkout_path, print_error=False)[0].strip() | 670 ['git'] + args, cwd=self.checkout_path).strip() |
| 671 | 671 |
| 672 def _Run(self, args, options, **kwargs): | 672 def _Run(self, args, options, **kwargs): |
| 673 kwargs.setdefault('cwd', self.checkout_path) | 673 kwargs.setdefault('cwd', self.checkout_path) |
| 674 gclient_utils.CheckCallAndFilterAndHeader(['git'] + args, | 674 gclient_utils.CheckCallAndFilterAndHeader(['git'] + args, |
| 675 always=options.verbose, **kwargs) | 675 always=options.verbose, **kwargs) |
| 676 | 676 |
| 677 | 677 |
| 678 class SVNWrapper(SCMWrapper): | 678 class SVNWrapper(SCMWrapper): |
| 679 """ Wrapper for SVN """ | 679 """ Wrapper for SVN """ |
| 680 | 680 |
| (...skipping 259 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 940 | 940 |
| 941 This method returns a new list to be used as a command.""" | 941 This method returns a new list to be used as a command.""" |
| 942 new_command = command[:] | 942 new_command = command[:] |
| 943 if revision: | 943 if revision: |
| 944 new_command.extend(['--revision', str(revision).strip()]) | 944 new_command.extend(['--revision', str(revision).strip()]) |
| 945 # --force was added to 'svn update' in svn 1.5. | 945 # --force was added to 'svn update' in svn 1.5. |
| 946 if ((options.force or options.manually_grab_svn_rev) and | 946 if ((options.force or options.manually_grab_svn_rev) and |
| 947 scm.SVN.AssertVersion("1.5")[0]): | 947 scm.SVN.AssertVersion("1.5")[0]): |
| 948 new_command.append('--force') | 948 new_command.append('--force') |
| 949 return new_command | 949 return new_command |
| OLD | NEW |