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

Side by Side Diff: checkout.py

Issue 280063003: Re-land of have apply_patch.py/checkout.py stage git patches instead of committing them (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/tools/depot_tools
Patch Set: Re-add deprecated flags Created 6 years, 7 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 | « apply_issue.py ('k') | tests/checkout_test.py » ('j') | 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 113 matching lines...) Expand 10 before | Expand all | Expand 10 after
124 """Checks out a clean copy of the tree and removes any local modification. 124 """Checks out a clean copy of the tree and removes any local modification.
125 125
126 This function shouldn't throw unless the remote repository is inaccessible, 126 This function shouldn't throw unless the remote repository is inaccessible,
127 there is no free disk space or hard issues like that. 127 there is no free disk space or hard issues like that.
128 128
129 Args: 129 Args:
130 revision: The revision it should sync to, SCM specific. 130 revision: The revision it should sync to, SCM specific.
131 """ 131 """
132 raise NotImplementedError() 132 raise NotImplementedError()
133 133
134 def apply_patch(self, patches, post_processors=None, verbose=False, 134 def apply_patch(self, patches, post_processors=None, verbose=False):
135 name=None, email=None):
136 """Applies a patch and returns the list of modified files. 135 """Applies a patch and returns the list of modified files.
137 136
138 This function should throw patch.UnsupportedPatchFormat or 137 This function should throw patch.UnsupportedPatchFormat or
139 PatchApplicationFailed when relevant. 138 PatchApplicationFailed when relevant.
140 139
141 Args: 140 Args:
142 patches: patch.PatchSet object. 141 patches: patch.PatchSet object.
143 """ 142 """
144 raise NotImplementedError() 143 raise NotImplementedError()
145 144
(...skipping 13 matching lines...) Expand all
159 158
160 class RawCheckout(CheckoutBase): 159 class RawCheckout(CheckoutBase):
161 """Used to apply a patch locally without any intent to commit it. 160 """Used to apply a patch locally without any intent to commit it.
162 161
163 To be used by the try server. 162 To be used by the try server.
164 """ 163 """
165 def prepare(self, revision): 164 def prepare(self, revision):
166 """Stubbed out.""" 165 """Stubbed out."""
167 pass 166 pass
168 167
169 def apply_patch(self, patches, post_processors=None, verbose=False, 168 def apply_patch(self, patches, post_processors=None, verbose=False):
170 name=None, email=None):
171 """Ignores svn properties.""" 169 """Ignores svn properties."""
172 post_processors = post_processors or self.post_processors or [] 170 post_processors = post_processors or self.post_processors or []
173 for p in patches: 171 for p in patches:
174 stdout = [] 172 stdout = []
175 try: 173 try:
176 filepath = os.path.join(self.project_path, p.filename) 174 filepath = os.path.join(self.project_path, p.filename)
177 if p.is_delete: 175 if p.is_delete:
178 os.remove(filepath) 176 os.remove(filepath)
179 stdout.append('Deleted.') 177 stdout.append('Deleted.')
180 else: 178 else:
(...skipping 163 matching lines...) Expand 10 before | Expand all | Expand 10 after
344 assert bool(self.commit_user) >= bool(self.commit_pwd) 342 assert bool(self.commit_user) >= bool(self.commit_pwd)
345 343
346 def prepare(self, revision): 344 def prepare(self, revision):
347 # Will checkout if the directory is not present. 345 # Will checkout if the directory is not present.
348 assert self.svn_url 346 assert self.svn_url
349 if not os.path.isdir(self.project_path): 347 if not os.path.isdir(self.project_path):
350 logging.info('Checking out %s in %s' % 348 logging.info('Checking out %s in %s' %
351 (self.project_name, self.project_path)) 349 (self.project_name, self.project_path))
352 return self._revert(revision) 350 return self._revert(revision)
353 351
354 def apply_patch(self, patches, post_processors=None, verbose=False, 352 def apply_patch(self, patches, post_processors=None, verbose=False):
355 name=None, email=None):
356 post_processors = post_processors or self.post_processors or [] 353 post_processors = post_processors or self.post_processors or []
357 for p in patches: 354 for p in patches:
358 stdout = [] 355 stdout = []
359 try: 356 try:
360 filepath = os.path.join(self.project_path, p.filename) 357 filepath = os.path.join(self.project_path, p.filename)
361 # It is important to use credentials=False otherwise credentials could 358 # It is important to use credentials=False otherwise credentials could
362 # leak in the error message. Credentials are not necessary here for the 359 # leak in the error message. Credentials are not necessary here for the
363 # following commands anyway. 360 # following commands anyway.
364 if p.is_delete: 361 if p.is_delete:
365 stdout.append(self._check_output_svn( 362 stdout.append(self._check_output_svn(
(...skipping 183 matching lines...) Expand 10 before | Expand all | Expand 10 after
549 ['log', '-q', self.svn_url, '-r', '%s:%s' % (rev1, rev2)]) 546 ['log', '-q', self.svn_url, '-r', '%s:%s' % (rev1, rev2)])
550 except subprocess.CalledProcessError: 547 except subprocess.CalledProcessError:
551 return None 548 return None
552 # Ignore the '----' lines. 549 # Ignore the '----' lines.
553 return len([l for l in out.splitlines() if l.startswith('r')]) - 1 550 return len([l for l in out.splitlines() if l.startswith('r')]) - 1
554 551
555 552
556 class GitCheckout(CheckoutBase): 553 class GitCheckout(CheckoutBase):
557 """Manages a git checkout.""" 554 """Manages a git checkout."""
558 def __init__(self, root_dir, project_name, remote_branch, git_url, 555 def __init__(self, root_dir, project_name, remote_branch, git_url,
559 commit_user, post_processors=None, base_ref=None): 556 commit_user, post_processors=None):
560 super(GitCheckout, self).__init__(root_dir, project_name, post_processors) 557 super(GitCheckout, self).__init__(root_dir, project_name, post_processors)
561 self.base_ref = base_ref
562 self.git_url = git_url 558 self.git_url = git_url
563 self.commit_user = commit_user 559 self.commit_user = commit_user
564 self.remote_branch = remote_branch 560 self.remote_branch = remote_branch
565 # The working branch where patches will be applied. It will track the 561 # The working branch where patches will be applied. It will track the
566 # remote branch. 562 # remote branch.
567 self.working_branch = 'working_branch' 563 self.working_branch = 'working_branch'
568 # There is no reason to not hardcode origin. 564 # There is no reason to not hardcode origin.
569 self.remote = 'origin' 565 self.remote = 'origin'
570 # There is no reason to not hardcode master. 566 # There is no reason to not hardcode master.
571 self.master_branch = 'master' 567 self.master_branch = 'master'
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after
624 self.remote, self.remote_branch) 620 self.remote, self.remote_branch)
625 self._check_call_git( 621 self._check_call_git(
626 ['pull', self.remote, 622 ['pull', self.remote,
627 '%s:%s' % (self.remote_branch, remote_tracked_path), 623 '%s:%s' % (self.remote_branch, remote_tracked_path),
628 '--quiet']) 624 '--quiet'])
629 625
630 def _get_head_commit_hash(self): 626 def _get_head_commit_hash(self):
631 """Gets the current revision (in unicode) from the local branch.""" 627 """Gets the current revision (in unicode) from the local branch."""
632 return unicode(self._check_output_git(['rev-parse', 'HEAD']).strip()) 628 return unicode(self._check_output_git(['rev-parse', 'HEAD']).strip())
633 629
634 def apply_patch(self, patches, post_processors=None, verbose=False, 630 def apply_patch(self, patches, post_processors=None, verbose=False):
635 name=None, email=None):
636 """Applies a patch on 'working_branch' and switches to it. 631 """Applies a patch on 'working_branch' and switches to it.
637 632
638 Also commits the changes on the local branch. 633 The changes remain staged on the current branch.
639 634
640 Ignores svn properties and raise an exception on unexpected ones. 635 Ignores svn properties and raise an exception on unexpected ones.
641 """ 636 """
642 post_processors = post_processors or self.post_processors or [] 637 post_processors = post_processors or self.post_processors or []
643 # It this throws, the checkout is corrupted. Maybe worth deleting it and 638 # It this throws, the checkout is corrupted. Maybe worth deleting it and
644 # trying again? 639 # trying again?
645 if self.remote_branch: 640 if self.remote_branch:
646 self._check_call_git( 641 self._check_call_git(
647 ['checkout', '-b', self.working_branch, '-t', self.remote_branch, 642 ['checkout', '-b', self.working_branch, '-t', self.remote_branch,
648 '--quiet']) 643 '--quiet'])
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
702 print align_stdout(stdout) 697 print align_stdout(stdout)
703 except OSError, e: 698 except OSError, e:
704 raise PatchApplicationFailed(p, '%s%s' % (align_stdout(stdout), e)) 699 raise PatchApplicationFailed(p, '%s%s' % (align_stdout(stdout), e))
705 except subprocess.CalledProcessError, e: 700 except subprocess.CalledProcessError, e:
706 raise PatchApplicationFailed( 701 raise PatchApplicationFailed(
707 p, 702 p,
708 'While running %s;\n%s%s' % ( 703 'While running %s;\n%s%s' % (
709 ' '.join(e.cmd), 704 ' '.join(e.cmd),
710 align_stdout(stdout), 705 align_stdout(stdout),
711 align_stdout([getattr(e, 'stdout', '')]))) 706 align_stdout([getattr(e, 'stdout', '')])))
712 # Once all the patches are processed and added to the index, commit the
713 # index.
714 cmd = ['commit', '-m', 'Committed patch']
715 if name and email:
716 cmd = ['-c', 'user.email=%s' % email, '-c', 'user.name=%s' % name] + cmd
717 if verbose:
718 cmd.append('--verbose')
719 self._check_call_git(cmd)
720 if self.base_ref:
721 base_ref = self.base_ref
722 else:
723 base_ref = '%s/%s' % (self.remote,
724 self.remote_branch or self.master_branch)
725 found_files = self._check_output_git( 707 found_files = self._check_output_git(
726 ['diff', base_ref, '--ignore-submodules', 708 ['diff', '--ignore-submodules',
727 '--name-only']).splitlines(False) 709 '--name-only', '--staged']).splitlines(False)
728 assert sorted(patches.filenames) == sorted(found_files), ( 710 assert sorted(patches.filenames) == sorted(found_files), (
729 'Found extra %s locally, %s not patched' % ( 711 'Found extra %s locally, %s not patched' % (
730 sorted(set(found_files) - set(patches.filenames)), 712 sorted(set(found_files) - set(patches.filenames)),
731 sorted(set(patches.filenames) - set(found_files)))) 713 sorted(set(patches.filenames) - set(found_files))))
732 714
733 def commit(self, commit_message, user): 715 def commit(self, commit_message, user):
734 """Commits, updates the commit message and pushes.""" 716 """Commits, updates the commit message and pushes."""
717 # TODO(hinoka): CQ no longer uses this, I think its deprecated.
718 # Delete this.
735 assert self.commit_user 719 assert self.commit_user
736 assert isinstance(commit_message, unicode) 720 assert isinstance(commit_message, unicode)
737 current_branch = self._check_output_git( 721 current_branch = self._check_output_git(
738 ['rev-parse', '--abbrev-ref', 'HEAD']).strip() 722 ['rev-parse', '--abbrev-ref', 'HEAD']).strip()
739 assert current_branch == self.working_branch 723 assert current_branch == self.working_branch
740 724
741 commit_cmd = ['commit', '--amend', '-m', commit_message] 725 commit_cmd = ['commit', '-m', commit_message]
742 if user and user != self.commit_user: 726 if user and user != self.commit_user:
743 # We do not have the first or last name of the user, grab the username 727 # We do not have the first or last name of the user, grab the username
744 # from the email and call it the original author's name. 728 # from the email and call it the original author's name.
745 # TODO(rmistry): Do not need the below if user is already in 729 # TODO(rmistry): Do not need the below if user is already in
746 # "Name <email>" format. 730 # "Name <email>" format.
747 name = user.split('@')[0] 731 name = user.split('@')[0]
748 commit_cmd.extend(['--author', '%s <%s>' % (name, user)]) 732 commit_cmd.extend(['--author', '%s <%s>' % (name, user)])
749 self._check_call_git(commit_cmd) 733 self._check_call_git(commit_cmd)
750 734
751 # Push to the remote repository. 735 # Push to the remote repository.
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after
819 self.checkout = checkout 803 self.checkout = checkout
820 self.post_processors = (post_processors or []) + ( 804 self.post_processors = (post_processors or []) + (
821 self.checkout.post_processors or []) 805 self.checkout.post_processors or [])
822 806
823 def prepare(self, revision): 807 def prepare(self, revision):
824 return self.checkout.prepare(revision) 808 return self.checkout.prepare(revision)
825 809
826 def get_settings(self, key): 810 def get_settings(self, key):
827 return self.checkout.get_settings(key) 811 return self.checkout.get_settings(key)
828 812
829 def apply_patch(self, patches, post_processors=None, verbose=False, 813 def apply_patch(self, patches, post_processors=None, verbose=False):
830 name=None, email=None):
831 return self.checkout.apply_patch( 814 return self.checkout.apply_patch(
832 patches, post_processors or self.post_processors, verbose) 815 patches, post_processors or self.post_processors, verbose)
833 816
834 def commit(self, message, user): # pylint: disable=R0201 817 def commit(self, message, user): # pylint: disable=R0201
835 logging.info('Would have committed for %s with message: %s' % ( 818 logging.info('Would have committed for %s with message: %s' % (
836 user, message)) 819 user, message))
837 return 'FAKE' 820 return 'FAKE'
838 821
839 def revisions(self, rev1, rev2): 822 def revisions(self, rev1, rev2):
840 return self.checkout.revisions(rev1, rev2) 823 return self.checkout.revisions(rev1, rev2)
841 824
842 @property 825 @property
843 def project_name(self): 826 def project_name(self):
844 return self.checkout.project_name 827 return self.checkout.project_name
845 828
846 @property 829 @property
847 def project_path(self): 830 def project_path(self):
848 return self.checkout.project_path 831 return self.checkout.project_path
OLDNEW
« no previous file with comments | « apply_issue.py ('k') | tests/checkout_test.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698