from cStringIO import StringIO
from dulwich.objects import Tree
-from dulwich.patch import write_blob_diff
+from dulwich.patch import write_tree_diff
from dulwich.repo import Repo
class Branch(object):
"""A version control branch."""
- def authors(self):
- """Determine all authors that have contributed to this project.
- """
- ret = set()
- for rev in self.log():
- ret.add(rev.author)
- return ret
-
- def log(self):
+ def log(self, limit=None):
raise NotImplementedError(self.log)
def diff(self, revision):
raise NotImplementedError(self.diff)
+ def changes_summary(self, revision):
+ raise NotImplementedError(self.changes_summary)
+
class Revision(object):
- def __init__(self, revision, date, author, message, modified=[], added=[],
- removed=[]):
+ def __init__(self, revision, date, committer, author, message):
self.revision = revision
self.date = date
self.author = author
+ self.committer = committer
self.message = message
- self.modified = modified
- self.added = added
- self.removed = removed
-class GitBranch(object):
+class GitBranch(Branch):
def __init__(self, path, branch="master"):
self.repo = Repo(path)
return self.store.tree_changes(parent_tree, commit.tree)
def _revision_from_commit(self, commit):
- added = set()
- modified = set()
- removed = set()
- for ((oldpath, newpath), (oldmode, newmode), (oldsha, newsha)) in self._changes_for(commit):
- if oldpath is None:
- added.add(newpath)
- elif newpath is None:
- removed.add(oldpath)
- else:
- modified.add(newpath)
- return Revision(commit.id, commit.commit_time, commit.author,
- commit.message, modified=modified, removed=removed,
- added=added)
+ return Revision(commit.id, commit.commit_time,
+ committer=commit.committer, author=commit.author,
+ message=commit.message)
- def log(self, from_rev=None, exclude_revs=None):
+ def log(self, from_rev=None, exclude_revs=None, limit=None):
+ if exclude_revs is None:
+ exclude_revs = set()
if from_rev is None:
try:
commit = self.repo["refs/heads/%s" % self.branch]
except KeyError:
return
from_rev = commit.id
- else:
- from_rev = commit.id
done = set()
pending_commits = [from_rev]
while pending_commits != []:
commit = self.repo[commit_id]
yield self._revision_from_commit(commit)
done.add(commit.id)
+ if len(done) >= limit:
+ return
+ exclude_revs.add(commit.id)
# FIXME: Add sorted by commit_time
for p in commit.parents:
- if exclude_revs is not None and p in exclude_revs:
+ if p in exclude_revs:
continue
pending_commits.append(p)
+ exclude_revs.add(p)
+
+ def changes_summary(self, revision):
+ commit = self.repo[revision]
+ added = set()
+ modified = set()
+ removed = set()
+ for ((oldpath, newpath), (oldmode, newmode), (oldsha, newsha)) in self._changes_for(commit):
+ if oldpath is None:
+ added.add(newpath)
+ elif newpath is None:
+ removed.add(oldpath)
+ else:
+ modified.add(newpath)
+ return (added, modified, removed)
def diff(self, revision):
commit = self.repo[revision]
f = StringIO()
- changes = self._changes_for(commit)
- for (oldpath, newpath), (oldmode, newmode), (oldsha, newsha) in changes:
- write_blob_diff(f, (oldpath, oldmode, self.store[oldsha]),
- (newpath, newmode, self.store[newsha]))
+ if len(commit.parents) == 0:
+ parent_tree = Tree().id
+ else:
+ parent_tree = self.store[commit.parents[0]].tree
+ write_tree_diff(f, self.store, parent_tree, commit.tree)
return (self._revision_from_commit(commit), f.getvalue())