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 |