Index: checkout.py |
diff --git a/checkout.py b/checkout.py |
index 6f82383db37000d65d2e6b9c2c7c983ae15a7bec..c61552f32cbe8064e044fcfb29ef99230e5685c5 100644 |
--- a/checkout.py |
+++ b/checkout.py |
@@ -120,6 +120,15 @@ class CheckoutBase(object): |
"""Commits the patch upstream, while impersonating 'user'.""" |
raise NotImplementedError() |
+ def revisions(self, rev1, rev2): |
+ """Returns the count of revisions from rev1 to rev2, e.g. len(]rev1, rev2]). |
+ |
+ If rev2 is None, it means 'HEAD'. |
+ |
+ Returns None if there is no link between the two. |
+ """ |
+ raise NotImplementedError() |
+ |
class RawCheckout(CheckoutBase): |
"""Used to apply a patch locally without any intent to commit it. |
@@ -182,6 +191,9 @@ class RawCheckout(CheckoutBase): |
"""Stubbed out.""" |
raise NotImplementedError('RawCheckout can\'t commit') |
+ def revisions(self, _rev1, _rev2): |
+ return None |
+ |
class SvnConfig(object): |
"""Parses a svn configuration file.""" |
@@ -425,6 +437,21 @@ class SvnCheckout(CheckoutBase, SvnMixIn): |
self._last_seen_revision = revision |
return revision |
+ def revisions(self, rev1, rev2): |
+ """Returns the number of actual commits, not just the difference between |
+ numbers. |
+ """ |
+ rev2 = rev2 or 'HEAD' |
+ # Revision range is inclusive and ordering doesn't matter, they'll appear in |
+ # the order specified. |
+ try: |
+ out = self._check_output_svn( |
+ ['log', '-q', self.svn_url, '-r', '%s:%s' % (rev1, rev2)]) |
+ except subprocess.CalledProcessError: |
+ return None |
+ # Ignore the '----' lines. |
+ return len([l for l in out.splitlines() if l.startswith('r')]) - 1 |
+ |
class GitCheckoutBase(CheckoutBase): |
"""Base class for git checkout. Not to be used as-is.""" |
@@ -565,6 +592,30 @@ class GitCheckoutBase(CheckoutBase): |
break |
return branches, active |
+ def revisions(self, rev1, rev2): |
+ """Returns the number of actual commits between both hash.""" |
+ self._fetch_remote() |
+ |
+ rev2 = rev2 or '%s/%s' % (self.remote, self.remote_branch) |
+ # Revision range is ]rev1, rev2] and ordering matters. |
+ try: |
+ out = self._check_output_git( |
+ ['log', '--format="%H"' , '%s..%s' % (rev1, rev2)]) |
+ except subprocess.CalledProcessError: |
+ return None |
+ return len(out.splitlines()) |
+ |
+ def _fetch_remote(self): |
+ """Fetches the remote without rebasing.""" |
+ raise NotImplementedError() |
+ |
+ |
+class GitCheckout(GitCheckoutBase): |
+ """Git checkout implementation.""" |
+ def _fetch_remote(self): |
+ # git fetch is always verbose even with -q -q so redirect its output. |
+ self._check_output_git(['fetch', self.remote, self.remote_branch]) |
+ |
class ReadOnlyCheckout(object): |
"""Converts a checkout into a read-only one.""" |
@@ -589,6 +640,9 @@ class ReadOnlyCheckout(object): |
user, message)) |
return 'FAKE' |
+ def revisions(self, rev1, rev2): |
+ return self.checkout.revisions(rev1, rev2) |
+ |
@property |
def project_name(self): |
return self.checkout.project_name |