summaryrefslogtreecommitdiff
path: root/lib/git/objects/commit.py
diff options
context:
space:
mode:
Diffstat (limited to 'lib/git/objects/commit.py')
-rw-r--r--lib/git/objects/commit.py91
1 files changed, 53 insertions, 38 deletions
diff --git a/lib/git/objects/commit.py b/lib/git/objects/commit.py
index c3e97bf9..101014ab 100644
--- a/lib/git/objects/commit.py
+++ b/lib/git/objects/commit.py
@@ -6,14 +6,14 @@
import re
import time
-
+from git.utils import Iterable
from git.actor import Actor
-from tree import Tree
import git.diff as diff
import git.stats as stats
+from tree import Tree
import base
-class Commit(base.Object):
+class Commit(base.Object, Iterable):
"""
Wraps a git Commit object.
@@ -37,7 +37,7 @@ class Commit(base.Object):
The parameter documentation indicates the type of the argument after a colon ':'.
``id``
- is the sha id of the commit
+ is the sha id of the commit or a ref
``parents`` : tuple( Commit, ... )
is a tuple of commit ids or actual Commits
@@ -71,7 +71,7 @@ class Commit(base.Object):
# END for each parent to convert
if self.id and tree is not None:
- self.tree = Tree(repo, id=tree)
+ self.tree = Tree(repo, id=tree, path='')
# END id to tree conversion
def _set_cache_(self, attr):
@@ -80,8 +80,11 @@ class Commit(base.Object):
to be set.
We set all values at once.
"""
- if attr in self.__slots__:
- temp = Commit.find_all(self.repo, self.id, max_count=1)[0]
+ if attr in Commit.__slots__:
+ # prepare our data lines to match rev-list
+ data_lines = self.data.splitlines()
+ data_lines.insert(0, "commit %s" % self.id)
+ temp = self._iter_from_process_or_stream(self.repo, iter(data_lines)).next()
self.parents = temp.parents
self.tree = temp.tree
self.author = temp.author
@@ -120,7 +123,7 @@ class Commit(base.Object):
return len(repo.git.rev_list(ref, '--', path).strip().splitlines())
@classmethod
- def find_all(cls, repo, ref, path='', **kwargs):
+ def iter_items(cls, repo, ref, path='', **kwargs):
"""
Find all commits matching the given criteria.
@@ -128,7 +131,7 @@ class Commit(base.Object):
is the Repo
``ref``
- is the ref from which to begin (SHA1 or name)
+ is the ref from which to begin (SHA1, Head or name)
``path``
is an optinal path, if set only Commits that include the path
@@ -140,55 +143,67 @@ class Commit(base.Object):
``skip`` is the number of commits to skip
Returns
- git.Commit[]
+ iterator yielding Commit items
"""
- options = {'pretty': 'raw'}
+ options = {'pretty': 'raw', 'as_process' : True }
options.update(kwargs)
- output = repo.git.rev_list(ref, '--', path, **options)
- return cls._list_from_string(repo, output)
+ # the test system might confront us with string values -
+ proc = repo.git.rev_list(ref, '--', path, **options)
+ return cls._iter_from_process_or_stream(repo, proc)
@classmethod
- def _list_from_string(cls, repo, text):
+ def _iter_from_process_or_stream(cls, repo, proc_or_stream):
"""
Parse out commit information into a list of Commit objects
``repo``
is the Repo
- ``text``
- is the text output from the git-rev-list command (raw format)
+ ``proc``
+ git-rev-list process instance (raw format)
Returns
- git.Commit[]
+ iterator returning Commit objects
"""
- lines =text.splitlines(False)
- commits = []
-
- while lines:
- id = lines.pop(0).split()[1]
- tree = lines.pop(0).split()[1]
+ stream = proc_or_stream
+ if not hasattr(stream,'next'):
+ stream = proc_or_stream.stdout
+
+ for line in stream:
+ id = line.split()[1]
+ assert line.split()[0] == "commit"
+ tree = stream.next().split()[1]
parents = []
- while lines and lines[0].startswith('parent'):
- parents.append(lines.pop(0).split()[-1])
- # END while there are parent lines
- author, authored_date = cls._actor(lines.pop(0))
- committer, committed_date = cls._actor(lines.pop(0))
+ next_line = None
+ for parent_line in stream:
+ if not parent_line.startswith('parent'):
+ next_line = parent_line
+ break
+ # END abort reading parents
+ parents.append(parent_line.split()[-1])
+ # END for each parent line
+
+ author, authored_date = cls._actor(next_line)
+ committer, committed_date = cls._actor(stream.next())
- # free line
- lines.pop(0)
+ # empty line
+ stream.next()
message_lines = []
- while lines and not lines[0].startswith('commit'):
- message_lines.append(lines.pop(0).strip())
+ next_line = None
+ for msg_line in stream:
+ if not msg_line.startswith(' '):
+ break
+ # END abort message reading
+ message_lines.append(msg_line.strip())
# END while there are message lines
- message = '\n'.join(message_lines[:-1]) # last line is empty
-
- commits.append(Commit(repo, id=id, parents=parents, tree=tree, author=author, authored_date=authored_date,
- committer=committer, committed_date=committed_date, message=message))
- # END while lines
- return commits
+ message = '\n'.join(message_lines)
+
+ yield Commit(repo, id=id, parents=parents, tree=tree, author=author, authored_date=authored_date,
+ committer=committer, committed_date=committed_date, message=message)
+ # END for each line in stream
@classmethod
def diff(cls, repo, a, b=None, paths=None):