Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 113 | 113 |
| 114 Args: | 114 Args: |
| 115 patches: patch.PatchSet object. | 115 patches: patch.PatchSet object. |
| 116 """ | 116 """ |
| 117 raise NotImplementedError() | 117 raise NotImplementedError() |
| 118 | 118 |
| 119 def commit(self, commit_message, user): | 119 def commit(self, commit_message, user): |
| 120 """Commits the patch upstream, while impersonating 'user'.""" | 120 """Commits the patch upstream, while impersonating 'user'.""" |
| 121 raise NotImplementedError() | 121 raise NotImplementedError() |
| 122 | 122 |
| 123 def revisions(self, rev1, rev2): | |
| 124 """Returns the count of revisions from rev1 to rev2, e.g. len(]rev1, rev2]). | |
| 125 | |
| 126 If rev2 is None, it means 'HEAD'. | |
| 127 | |
| 128 Returns None if there is no link between the two. | |
| 129 """ | |
| 130 raise NotImplementedError() | |
| 131 | |
| 123 | 132 |
| 124 class RawCheckout(CheckoutBase): | 133 class RawCheckout(CheckoutBase): |
| 125 """Used to apply a patch locally without any intent to commit it. | 134 """Used to apply a patch locally without any intent to commit it. |
| 126 | 135 |
| 127 To be used by the try server. | 136 To be used by the try server. |
| 128 """ | 137 """ |
| 129 def prepare(self, revision): | 138 def prepare(self, revision): |
| 130 """Stubbed out.""" | 139 """Stubbed out.""" |
| 131 pass | 140 pass |
| 132 | 141 |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 175 except OSError, e: | 184 except OSError, e: |
| 176 raise PatchApplicationFailed(p, '%s%s' % (stdout, e)) | 185 raise PatchApplicationFailed(p, '%s%s' % (stdout, e)) |
| 177 except subprocess.CalledProcessError, e: | 186 except subprocess.CalledProcessError, e: |
| 178 raise PatchApplicationFailed( | 187 raise PatchApplicationFailed( |
| 179 p, '%s%s' % (stdout, getattr(e, 'stdout', None))) | 188 p, '%s%s' % (stdout, getattr(e, 'stdout', None))) |
| 180 | 189 |
| 181 def commit(self, commit_message, user): | 190 def commit(self, commit_message, user): |
| 182 """Stubbed out.""" | 191 """Stubbed out.""" |
| 183 raise NotImplementedError('RawCheckout can\'t commit') | 192 raise NotImplementedError('RawCheckout can\'t commit') |
| 184 | 193 |
| 194 def revisions(self, _rev1, _rev2): | |
| 195 return None | |
|
cmp
2012/07/25 20:03:01
should this raise NotImplementedError, instead?
M-A Ruel
2012/07/25 20:25:03
I prefer to keep None being returned when it's imp
| |
| 196 | |
| 185 | 197 |
| 186 class SvnConfig(object): | 198 class SvnConfig(object): |
| 187 """Parses a svn configuration file.""" | 199 """Parses a svn configuration file.""" |
| 188 def __init__(self, svn_config_dir=None): | 200 def __init__(self, svn_config_dir=None): |
| 189 super(SvnConfig, self).__init__() | 201 super(SvnConfig, self).__init__() |
| 190 self.svn_config_dir = svn_config_dir | 202 self.svn_config_dir = svn_config_dir |
| 191 self.default = not bool(self.svn_config_dir) | 203 self.default = not bool(self.svn_config_dir) |
| 192 if not self.svn_config_dir: | 204 if not self.svn_config_dir: |
| 193 if sys.platform == 'win32': | 205 if sys.platform == 'win32': |
| 194 self.svn_config_dir = os.path.join(os.environ['APPDATA'], 'Subversion') | 206 self.svn_config_dir = os.path.join(os.environ['APPDATA'], 'Subversion') |
| (...skipping 223 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 418 return self._get_revision() | 430 return self._get_revision() |
| 419 | 431 |
| 420 def _get_revision(self): | 432 def _get_revision(self): |
| 421 out = self._check_output_svn(['info', '.']) | 433 out = self._check_output_svn(['info', '.']) |
| 422 revision = int(self._parse_svn_info(out, 'revision')) | 434 revision = int(self._parse_svn_info(out, 'revision')) |
| 423 if revision != self._last_seen_revision: | 435 if revision != self._last_seen_revision: |
| 424 logging.info('Updated to revision %d' % revision) | 436 logging.info('Updated to revision %d' % revision) |
| 425 self._last_seen_revision = revision | 437 self._last_seen_revision = revision |
| 426 return revision | 438 return revision |
| 427 | 439 |
| 440 def revisions(self, rev1, rev2): | |
| 441 """Returns the number of actual commits, not just the difference between | |
| 442 numbers. | |
| 443 """ | |
| 444 rev2 = rev2 or 'HEAD' | |
| 445 # Revision range is inclusive and ordering doesn't matter, they'll appear in | |
| 446 # the order specified. | |
| 447 out = self._check_output_svn( | |
| 448 ['log', '-q', self.svn_url, '-r', '%s:%s' % (rev1, rev2)]) | |
| 449 # Ignore the '----' lines. | |
| 450 return len([l for l in out.splitlines() if l.startswith('r')]) - 1 | |
| 451 | |
| 428 | 452 |
| 429 class GitCheckoutBase(CheckoutBase): | 453 class GitCheckoutBase(CheckoutBase): |
| 430 """Base class for git checkout. Not to be used as-is.""" | 454 """Base class for git checkout. Not to be used as-is.""" |
| 431 def __init__(self, root_dir, project_name, remote_branch, | 455 def __init__(self, root_dir, project_name, remote_branch, |
| 432 post_processors=None): | 456 post_processors=None): |
| 433 super(GitCheckoutBase, self).__init__( | 457 super(GitCheckoutBase, self).__init__( |
| 434 root_dir, project_name, post_processors) | 458 root_dir, project_name, post_processors) |
| 435 # There is no reason to not hardcode it. | 459 # There is no reason to not hardcode it. |
| 436 self.remote = 'origin' | 460 self.remote = 'origin' |
| 437 self.remote_branch = remote_branch | 461 self.remote_branch = remote_branch |
| (...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 558 """Returns the list of branches and the active one.""" | 582 """Returns the list of branches and the active one.""" |
| 559 out = self._check_output_git(['branch']).splitlines(False) | 583 out = self._check_output_git(['branch']).splitlines(False) |
| 560 branches = [l[2:] for l in out] | 584 branches = [l[2:] for l in out] |
| 561 active = None | 585 active = None |
| 562 for l in out: | 586 for l in out: |
| 563 if l.startswith('*'): | 587 if l.startswith('*'): |
| 564 active = l[2:] | 588 active = l[2:] |
| 565 break | 589 break |
| 566 return branches, active | 590 return branches, active |
| 567 | 591 |
| 592 def revisions(self, rev1, rev2): | |
| 593 """Returns the number of actual commits between both hash.""" | |
| 594 self._fetch_remote() | |
| 595 | |
| 596 rev2 = rev2 or '%s/%s' % (self.remote, self.remote_branch) | |
| 597 # Revision range is ]rev1, rev2] and ordering matters. | |
| 598 out = self._check_output_git( | |
| 599 ['log', '--format="%H"' , '%s..%s' % (rev1, rev2)]) | |
| 600 return len(out.splitlines()) | |
| 601 | |
| 602 def _fetch_remote(self): | |
| 603 """Fetches the remote without rebasing.""" | |
| 604 raise NotImplementedError() | |
| 605 | |
| 606 | |
| 607 class GitCheckout(GitCheckoutBase): | |
| 608 """Git checkout implementation.""" | |
| 609 def _fetch_remote(self): | |
| 610 # git fetch is always verbose even with -q -q so redirect its output. | |
| 611 self._check_output_git(['fetch', self.remote, self.remote_branch]) | |
| 612 | |
| 568 | 613 |
| 569 class ReadOnlyCheckout(object): | 614 class ReadOnlyCheckout(object): |
| 570 """Converts a checkout into a read-only one.""" | 615 """Converts a checkout into a read-only one.""" |
| 571 def __init__(self, checkout, post_processors=None): | 616 def __init__(self, checkout, post_processors=None): |
| 572 super(ReadOnlyCheckout, self).__init__() | 617 super(ReadOnlyCheckout, self).__init__() |
| 573 self.checkout = checkout | 618 self.checkout = checkout |
| 574 self.post_processors = (post_processors or []) + ( | 619 self.post_processors = (post_processors or []) + ( |
| 575 self.checkout.post_processors or []) | 620 self.checkout.post_processors or []) |
| 576 | 621 |
| 577 def prepare(self, revision): | 622 def prepare(self, revision): |
| 578 return self.checkout.prepare(revision) | 623 return self.checkout.prepare(revision) |
| 579 | 624 |
| 580 def get_settings(self, key): | 625 def get_settings(self, key): |
| 581 return self.checkout.get_settings(key) | 626 return self.checkout.get_settings(key) |
| 582 | 627 |
| 583 def apply_patch(self, patches, post_processors=None): | 628 def apply_patch(self, patches, post_processors=None): |
| 584 return self.checkout.apply_patch( | 629 return self.checkout.apply_patch( |
| 585 patches, post_processors or self.post_processors) | 630 patches, post_processors or self.post_processors) |
| 586 | 631 |
| 587 def commit(self, message, user): # pylint: disable=R0201 | 632 def commit(self, message, user): # pylint: disable=R0201 |
| 588 logging.info('Would have committed for %s with message: %s' % ( | 633 logging.info('Would have committed for %s with message: %s' % ( |
| 589 user, message)) | 634 user, message)) |
| 590 return 'FAKE' | 635 return 'FAKE' |
| 591 | 636 |
| 637 def revisions(self, rev1, rev2): | |
| 638 return self.checkout.revisions(rev1, rev2) | |
| 639 | |
| 592 @property | 640 @property |
| 593 def project_name(self): | 641 def project_name(self): |
| 594 return self.checkout.project_name | 642 return self.checkout.project_name |
| 595 | 643 |
| 596 @property | 644 @property |
| 597 def project_path(self): | 645 def project_path(self): |
| 598 return self.checkout.project_path | 646 return self.checkout.project_path |
| OLD | NEW |