diff options
author | Sebastian Thiel <byronimo@gmail.com> | 2009-10-27 20:46:26 +0100 |
---|---|---|
committer | Sebastian Thiel <byronimo@gmail.com> | 2009-10-27 20:46:26 +0100 |
commit | 038f183313f796dc0313c03d652a2bcc1698e78e (patch) | |
tree | 11eeaeaec4512e9764d4be568ed24034bd356306 | |
parent | 5047344a22ed824735d6ed1c91008767ea6638b7 (diff) | |
download | gitpython-038f183313f796dc0313c03d652a2bcc1698e78e.tar.gz |
implemented test for rejection handling and fixed a bug when parsing remote reference paths
-rw-r--r-- | TODO | 7 | ||||
-rw-r--r-- | lib/git/remote.py | 39 | ||||
-rw-r--r-- | test/git/test_remote.py | 33 |
3 files changed, 58 insertions, 21 deletions
@@ -107,10 +107,9 @@ Remote * Fetch should return heads that where updated, pull as well. * Creation and deletion methods for references should be part of the interface, allowing repo.create_head(...) instaed of Head.create(repo, ...). Its a convenience thing, clearly -* When parsing fetch-info, the regex will have problems properly handling white-space in the - actual head or tag name as it does not know when the optional additional message will begin. - This can possibly improved by making stronger assumptions about the possible messages or - by using the data from FETCH_HEAD instead or as additional source of information +* When parsing fetch-info, the regex will not allow spaces in the target remote ref as + I couldn't properly parse the optional space separated note in that case. Probably + the regex should be improved to handle this gracefully. Repo ---- diff --git a/lib/git/remote.py b/lib/git/remote.py index 90b43467..36c71e7a 100644 --- a/lib/git/remote.py +++ b/lib/git/remote.py @@ -8,6 +8,7 @@ Module implementing a remote object allowing easy access to git remotes """ from git.utils import LazyMixin, Iterable, IterableList +from objects import Commit from refs import Reference, RemoteReference import re import os @@ -58,24 +59,39 @@ class Remote(LazyMixin, Iterable): info = remote.fetch()[0] info.remote_ref # Symbolic Reference or RemoteReference to the changed remote head or FETCH_HEAD info.flags # additional flags to be & with enumeration members, i.e. info.flags & info.REJECTED - info.note # additional notes given by git-fetch intended for the user + info.note # additional notes given by git-fetch intended for the user + info.commit_before_forced_update # if info.flags & info.FORCED_UPDATE, field is set to the + # previous location of remote_ref, otherwise None """ - __slots__ = ('remote_ref', 'flags', 'note') + __slots__ = ('remote_ref','commit_before_forced_update', 'flags', 'note') + BRANCH_UPTODATE, REJECTED, FORCED_UPDATE, FAST_FORWARD, NEW_TAG, \ TAG_UPDATE, NEW_BRANCH, ERROR = [ 1 << x for x in range(1,9) ] # %c %-*s %-*s -> %s (%s) - re_fetch_result = re.compile("^(.) (\[?[\w\s]+\]?)\s+(.+) -> (.+/.+)( \(.*\)?$)?") + re_fetch_result = re.compile("^(.) (\[?[\w\s\.]+\]?)\s+(.+) -> (.+/[\w_\.-]+)( \(.*\)?$)?") _flag_map = { '!' : ERROR, '+' : FORCED_UPDATE, '-' : TAG_UPDATE, '*' : 0, '=' : BRANCH_UPTODATE, ' ' : FAST_FORWARD } - def __init__(self, remote_ref, flags, note = ''): + def __init__(self, remote_ref, flags, note = '', old_commit = None): """ Initialize a new instance """ self.remote_ref = remote_ref self.flags = flags self.note = note + self.commit_before_forced_update = old_commit + + def __str__(self): + return self.name + + @property + def name(self): + """ + Returns + Name of our remote ref + """ + return self.remote_ref.name @classmethod def _from_line(cls, repo, line): @@ -112,14 +128,18 @@ class Remote(LazyMixin, Iterable): # END control char exception hanlding # parse operation string for more info + old_commit = None if 'rejected' in operation: flags |= cls.REJECTED if 'new tag' in operation: flags |= cls.NEW_TAG if 'new branch' in operation: flags |= cls.NEW_BRANCH + if '...' in operation: + old_commit = Commit(repo, operation.split('...')[0]) + # END handle refspec - return cls(remote_local_ref, flags, note) + return cls(remote_local_ref, flags, note, old_commit) # END FetchInfo definition @@ -275,7 +295,10 @@ class Remote(LazyMixin, Iterable): def _get_fetch_info_from_stderr(self, stderr): # skip first line as it is some remote info we are not interested in - return [ self.FetchInfo._from_line(self.repo, line) for line in stderr.splitlines()[1:] ] + print stderr + output = IterableList('name') + output.extend(self.FetchInfo._from_line(self.repo, line) for line in stderr.splitlines()[1:]) + return output def fetch(self, refspec=None, **kwargs): """ @@ -297,7 +320,7 @@ class Remote(LazyMixin, Iterable): Additional arguments to be passed to git-fetch Returns - list(FetchInfo, ...) list of FetchInfo instances providing detailed + IterableList(FetchInfo, ...) list of FetchInfo instances providing detailed information about the fetch results """ status, stdout, stderr = self.repo.git.fetch(self, refspec, with_extended_output=True, v=True, **kwargs) @@ -315,7 +338,7 @@ class Remote(LazyMixin, Iterable): Additional arguments to be passed to git-pull Returns - list(Fetch + Please see 'fetch' method """ status, stdout, stderr = self.repo.git.pull(self, refspec, v=True, with_extended_output=True, **kwargs) return self._get_fetch_info_from_stderr(stderr) diff --git a/test/git/test_remote.py b/test/git/test_remote.py index ae828cbc..3b145468 100644 --- a/test/git/test_remote.py +++ b/test/git/test_remote.py @@ -17,13 +17,18 @@ class TestRemote(TestBase): fp.close() - def _check_fetch_results(self, results, remote): - self._print_fetchhead(remote.repo) + def _test_fetch_result(self, results, remote): + # self._print_fetchhead(remote.repo) assert len(results) > 0 and isinstance(results[0], remote.FetchInfo) - for result in results: - assert result.flags != 0 - assert isinstance(result.remote_ref, (SymbolicReference, Reference)) - # END for each result + for info in results: + assert info.flags != 0 + assert isinstance(info.remote_ref, (SymbolicReference, Reference)) + if info.flags & info.FORCED_UPDATE: + assert isinstance(info.commit_before_forced_update, Commit) + else: + assert info.commit_before_forced_update is None + # END forced update checking + # END for each info def _test_fetch_info(self, repo): self.failUnlessRaises(ValueError, Remote.FetchInfo._from_line, repo, "nonsense") @@ -33,10 +38,20 @@ class TestRemote(TestBase): # specialized fetch testing to de-clutter the main test self._test_fetch_info(rw_repo) - fetch_result = remote.fetch() - self._check_fetch_results(fetch_result, remote) + # put remote head to master as it is garantueed to exist + remote_repo.head.reference = remote_repo.heads.master + + res = remote.fetch() + self._test_fetch_result(res, remote) + + # rewind remote head to trigger rejection + # index must be false as remote is a bare repo + remote_repo.head.reset("HEAD~2", index=False) + res = remote.fetch() + self._test_fetch_result(res, remote) + master_info = res["%s/master" % remote] + assert master_info.flags & Remote.FetchInfo.FORCED_UPDATE and master_info.note is not None - self.fail("rejected parsing") self.fail("test parsing of each individual flag") self.fail("tag handling") |