Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(182)

Side by Side Diff: checkout.py

Issue 200923005: Revert changes to checkout.GitCheckout. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/tools/depot_tools
Patch Set: Created 6 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 # coding=utf8 1 # coding=utf8
2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 # Copyright (c) 2012 The Chromium Authors. All rights reserved.
3 # Use of this source code is governed by a BSD-style license that can be 3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file. 4 # found in the LICENSE file.
5 """Manages a project checkout. 5 """Manages a project checkout.
6 6
7 Includes support for svn, git-svn and git. 7 Includes support for svn, git-svn and git.
8 """ 8 """
9 9
10 import ConfigParser 10 import ConfigParser
(...skipping 548 matching lines...) Expand 10 before | Expand all | Expand 10 after
559 commit_user, post_processors=None, base_ref=None): 559 commit_user, post_processors=None, base_ref=None):
560 super(GitCheckout, self).__init__(root_dir, project_name, post_processors) 560 super(GitCheckout, self).__init__(root_dir, project_name, post_processors)
561 self.base_ref = base_ref 561 self.base_ref = base_ref
562 self.git_url = git_url 562 self.git_url = git_url
563 self.commit_user = commit_user 563 self.commit_user = commit_user
564 self.remote_branch = remote_branch 564 self.remote_branch = remote_branch
565 # The working branch where patches will be applied. It will track the 565 # The working branch where patches will be applied. It will track the
566 # remote branch. 566 # remote branch.
567 self.working_branch = 'working_branch' 567 self.working_branch = 'working_branch'
568 # There is no reason to not hardcode origin. 568 # There is no reason to not hardcode origin.
569 self.pull_remote = 'origin' 569 self.remote = 'origin'
570 self.push_remote = 'upstream' 570 # There is no reason to not hardcode master.
571 self.master_branch = 'master'
571 572
572 def prepare(self, revision): 573 def prepare(self, revision):
573 """Resets the git repository in a clean state. 574 """Resets the git repository in a clean state.
574 575
575 Checks it out if not present and deletes the working branch. 576 Checks it out if not present and deletes the working branch.
576 """ 577 """
578 assert self.remote_branch
577 assert self.git_url 579 assert self.git_url
578 assert self.remote_branch
579
580 self._check_call_git(
581 ['cache', 'populate', self.git_url], timeout=FETCH_TIMEOUT, cwd=None)
582 cache_path = self._check_output_git(
583 ['cache', 'exists', self.git_url], cwd=None).strip()
584 580
585 if not os.path.isdir(self.project_path): 581 if not os.path.isdir(self.project_path):
586 # Clone the repo if the directory is not present. 582 # Clone the repo if the directory is not present.
583 logging.info(
584 'Checking out %s in %s', self.project_name, self.project_path)
587 self._check_call_git( 585 self._check_call_git(
588 ['clone', '--shared', cache_path, self.project_path], 586 ['clone', self.git_url, '-b', self.remote_branch, self.project_path],
589 cwd=None, timeout=FETCH_TIMEOUT) 587 cwd=None, timeout=FETCH_TIMEOUT)
590 self._call_git( 588 else:
591 ['config', 'remote.%s.url' % self.push_remote, self.git_url], 589 # Throw away all uncommitted changes in the existing checkout.
592 cwd=self.project_path) 590 self._check_call_git(['checkout', self.remote_branch])
591 self._check_call_git(
592 ['reset', '--hard', '--quiet',
593 '%s/%s' % (self.remote, self.remote_branch)])
593 594
594 if not revision: 595 if revision:
595 revision = self.remote_branch 596 try:
597 # Look if the commit hash already exist. If so, we can skip a
598 # 'git fetch' call.
599 revision = self._check_output_git(['rev-parse', revision])
600 except subprocess.CalledProcessError:
601 self._check_call_git(
602 ['fetch', self.remote, self.remote_branch, '--quiet'])
603 revision = self._check_output_git(['rev-parse', revision])
604 self._check_call_git(['checkout', '--force', '--quiet', revision])
605 else:
606 branches, active = self._branches()
607 if active != self.master_branch:
608 self._check_call_git(
609 ['checkout', '--force', '--quiet', self.master_branch])
610 self._sync_remote_branch()
596 611
597 if not re.match(r'[0-9a-f]{40}$', revision, flags=re.IGNORECASE): 612 if self.working_branch in branches:
598 self._check_call_git(['fetch', self.pull_remote, revision]) 613 self._call_git(['branch', '-D', self.working_branch])
599 revision = self.pull_remote + '/' + revision 614 return self._get_head_commit_hash()
600 615
601 self._check_call_git(['checkout', '--force', '--quiet', revision]) 616 def _sync_remote_branch(self):
602 self._call_git(['clean', '-fdx']) 617 """Syncs the remote branch."""
603 618 # We do a 'git pull origin master:refs/remotes/origin/master' instead of
604 branches, _ = self._branches() 619 # 'git pull origin master' because from the manpage for git-pull:
605 if self.working_branch in branches: 620 # A parameter <ref> without a colon is equivalent to <ref>: when
606 self._call_git(['branch', '-D', self.working_branch]) 621 # pulling/fetching, so it merges <ref> into the current branch without
607 622 # storing the remote branch anywhere locally.
608 return self._get_head_commit_hash() 623 remote_tracked_path = 'refs/remotes/%s/%s' % (
624 self.remote, self.remote_branch)
625 self._check_call_git(
626 ['pull', self.remote,
627 '%s:%s' % (self.remote_branch, remote_tracked_path),
628 '--quiet'])
609 629
610 def _get_head_commit_hash(self): 630 def _get_head_commit_hash(self):
611 """Gets the current revision (in unicode) from the local branch.""" 631 """Gets the current revision (in unicode) from the local branch."""
612 return unicode(self._check_output_git(['rev-parse', 'HEAD']).strip()) 632 return unicode(self._check_output_git(['rev-parse', 'HEAD']).strip())
613 633
614 def apply_patch(self, patches, post_processors=None, verbose=False, 634 def apply_patch(self, patches, post_processors=None, verbose=False,
615 name=None, email=None): 635 name=None, email=None):
616 """Applies a patch on 'working_branch' and switches to it. 636 """Applies a patch on 'working_branch' and switches to it.
617 637
618 Also commits the changes on the local branch. 638 Also commits the changes on the local branch.
619 639
620 Ignores svn properties and raise an exception on unexpected ones. 640 Ignores svn properties and raise an exception on unexpected ones.
621 """ 641 """
622 post_processors = post_processors or self.post_processors or [] 642 post_processors = post_processors or self.post_processors or []
623 # It this throws, the checkout is corrupted. Maybe worth deleting it and 643 # It this throws, the checkout is corrupted. Maybe worth deleting it and
624 # trying again? 644 # trying again?
625 if self.remote_branch: 645 if self.remote_branch:
626 self._check_call_git( 646 self._check_call_git(
627 ['checkout', '-b', self.working_branch, 647 ['checkout', '-b', self.working_branch, '-t', self.remote_branch,
628 '-t', '%s/%s' % (self.pull_remote, self.remote_branch),
629 '--quiet']) 648 '--quiet'])
630 649
631 for index, p in enumerate(patches): 650 for index, p in enumerate(patches):
632 stdout = [] 651 stdout = []
633 try: 652 try:
634 filepath = os.path.join(self.project_path, p.filename) 653 filepath = os.path.join(self.project_path, p.filename)
635 if p.is_delete: 654 if p.is_delete:
636 if (not os.path.exists(filepath) and 655 if (not os.path.exists(filepath) and
637 any(p1.source_filename == p.filename for p1 in patches[0:index])): 656 any(p1.source_filename == p.filename for p1 in patches[0:index])):
638 # The file was already deleted if a prior patch with file rename 657 # The file was already deleted if a prior patch with file rename
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after
694 # index. 713 # index.
695 cmd = ['commit', '-m', 'Committed patch'] 714 cmd = ['commit', '-m', 'Committed patch']
696 if name and email: 715 if name and email:
697 cmd = ['-c', 'user.email=%s' % email, '-c', 'user.name=%s' % name] + cmd 716 cmd = ['-c', 'user.email=%s' % email, '-c', 'user.name=%s' % name] + cmd
698 if verbose: 717 if verbose:
699 cmd.append('--verbose') 718 cmd.append('--verbose')
700 self._check_call_git(cmd) 719 self._check_call_git(cmd)
701 if self.base_ref: 720 if self.base_ref:
702 base_ref = self.base_ref 721 base_ref = self.base_ref
703 else: 722 else:
704 base_ref = '%s/%s' % (self.pull_remote, self.remote_branch) 723 base_ref = '%s/%s' % (self.remote,
724 self.remote_branch or self.master_branch)
705 found_files = self._check_output_git( 725 found_files = self._check_output_git(
706 ['diff', base_ref, 726 ['diff', base_ref,
707 '--name-only']).splitlines(False) 727 '--name-only']).splitlines(False)
708 assert sorted(patches.filenames) == sorted(found_files), ( 728 assert sorted(patches.filenames) == sorted(found_files), (
709 sorted(patches.filenames), sorted(found_files)) 729 sorted(patches.filenames), sorted(found_files))
710 730
711 def commit(self, commit_message, user): 731 def commit(self, commit_message, user):
712 """Commits, updates the commit message and pushes.""" 732 """Commits, updates the commit message and pushes."""
713 assert self.commit_user 733 assert self.commit_user
714 assert isinstance(commit_message, unicode) 734 assert isinstance(commit_message, unicode)
715 current_branch = self._check_output_git( 735 current_branch = self._check_output_git(
716 ['rev-parse', '--abbrev-ref', 'HEAD']).strip() 736 ['rev-parse', '--abbrev-ref', 'HEAD']).strip()
717 assert current_branch == self.working_branch 737 assert current_branch == self.working_branch
718 738
719 commit_cmd = ['commit', '--amend', '-m', commit_message] 739 commit_cmd = ['commit', '--amend', '-m', commit_message]
720 if user and user != self.commit_user: 740 if user and user != self.commit_user:
721 # We do not have the first or last name of the user, grab the username 741 # We do not have the first or last name of the user, grab the username
722 # from the email and call it the original author's name. 742 # from the email and call it the original author's name.
723 # TODO(rmistry): Do not need the below if user is already in 743 # TODO(rmistry): Do not need the below if user is already in
724 # "Name <email>" format. 744 # "Name <email>" format.
725 name = user.split('@')[0] 745 name = user.split('@')[0]
726 commit_cmd.extend(['--author', '%s <%s>' % (name, user)]) 746 commit_cmd.extend(['--author', '%s <%s>' % (name, user)])
727 self._check_call_git(commit_cmd) 747 self._check_call_git(commit_cmd)
728 748
729 # Push to the remote repository. 749 # Push to the remote repository.
730 self._check_call_git( 750 self._check_call_git(
731 ['push', self.push_remote, 751 ['push', 'origin', '%s:%s' % (self.working_branch, self.remote_branch),
732 '%s:%s' % (self.working_branch, self.remote_branch),
733 '--force', '--quiet']) 752 '--force', '--quiet'])
734 # Get the revision after the push. 753 # Get the revision after the push.
735 revision = self._get_head_commit_hash() 754 revision = self._get_head_commit_hash()
736 # Switch back to the remote_branch. 755 # Switch back to the remote_branch and sync it.
737 self._check_call_git(['cache', 'populate', self.git_url]) 756 self._check_call_git(['checkout', self.remote_branch])
738 self._check_call_git(['fetch', self.pull_remote]) 757 self._sync_remote_branch()
739 self._check_call_git(['checkout', '--force', '--quiet',
740 '%s/%s' % (self.pull_remote, self.remote_branch)])
741 # Delete the working branch since we are done with it. 758 # Delete the working branch since we are done with it.
742 self._check_call_git(['branch', '-D', self.working_branch]) 759 self._check_call_git(['branch', '-D', self.working_branch])
743 760
744 return revision 761 return revision
745 762
746 def _check_call_git(self, args, **kwargs): 763 def _check_call_git(self, args, **kwargs):
747 kwargs.setdefault('cwd', self.project_path) 764 kwargs.setdefault('cwd', self.project_path)
748 kwargs.setdefault('stdout', self.VOID) 765 kwargs.setdefault('stdout', self.VOID)
749 kwargs.setdefault('timeout', GLOBAL_TIMEOUT) 766 kwargs.setdefault('timeout', GLOBAL_TIMEOUT)
750 return subprocess2.check_call_out(['git'] + args, **kwargs) 767 return subprocess2.check_call_out(['git'] + args, **kwargs)
(...skipping 19 matching lines...) Expand all
770 for l in out: 787 for l in out:
771 if l.startswith('*'): 788 if l.startswith('*'):
772 active = l[2:] 789 active = l[2:]
773 break 790 break
774 return branches, active 791 return branches, active
775 792
776 def revisions(self, rev1, rev2): 793 def revisions(self, rev1, rev2):
777 """Returns the number of actual commits between both hash.""" 794 """Returns the number of actual commits between both hash."""
778 self._fetch_remote() 795 self._fetch_remote()
779 796
780 rev2 = rev2 or '%s/%s' % (self.pull_remote, self.remote_branch) 797 rev2 = rev2 or '%s/%s' % (self.remote, self.remote_branch)
781 # Revision range is ]rev1, rev2] and ordering matters. 798 # Revision range is ]rev1, rev2] and ordering matters.
782 try: 799 try:
783 out = self._check_output_git( 800 out = self._check_output_git(
784 ['log', '--format="%H"' , '%s..%s' % (rev1, rev2)]) 801 ['log', '--format="%H"' , '%s..%s' % (rev1, rev2)])
785 except subprocess.CalledProcessError: 802 except subprocess.CalledProcessError:
786 return None 803 return None
787 return len(out.splitlines()) 804 return len(out.splitlines())
788 805
789 def _fetch_remote(self): 806 def _fetch_remote(self):
790 """Fetches the remote without rebasing.""" 807 """Fetches the remote without rebasing."""
791 # git fetch is always verbose even with -q, so redirect its output. 808 # git fetch is always verbose even with -q, so redirect its output.
792 self._check_output_git(['fetch', self.pull_remote, self.remote_branch], 809 self._check_output_git(['fetch', self.remote, self.remote_branch],
793 timeout=FETCH_TIMEOUT) 810 timeout=FETCH_TIMEOUT)
794 811
795 812
796 class ReadOnlyCheckout(object): 813 class ReadOnlyCheckout(object):
797 """Converts a checkout into a read-only one.""" 814 """Converts a checkout into a read-only one."""
798 def __init__(self, checkout, post_processors=None): 815 def __init__(self, checkout, post_processors=None):
799 super(ReadOnlyCheckout, self).__init__() 816 super(ReadOnlyCheckout, self).__init__()
800 self.checkout = checkout 817 self.checkout = checkout
801 self.post_processors = (post_processors or []) + ( 818 self.post_processors = (post_processors or []) + (
802 self.checkout.post_processors or []) 819 self.checkout.post_processors or [])
(...skipping 17 matching lines...) Expand all
820 def revisions(self, rev1, rev2): 837 def revisions(self, rev1, rev2):
821 return self.checkout.revisions(rev1, rev2) 838 return self.checkout.revisions(rev1, rev2)
822 839
823 @property 840 @property
824 def project_name(self): 841 def project_name(self):
825 return self.checkout.project_name 842 return self.checkout.project_name
826 843
827 @property 844 @property
828 def project_path(self): 845 def project_path(self):
829 return self.checkout.project_path 846 return self.checkout.project_path
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698