# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+from cStringIO import StringIO
-from buildfarm import util
+from dulwich.objects import Tree
+from dulwich.patch import write_tree_diff
+from dulwich.repo import Repo
-import commands
-import os
-BASEDIR = "/home/build/master"
-HISTORYDIR = "/home/build/master/cache"
-TIMEZONE = "PST"
-TIMEOFFSET = 0
-UNPACKED_DIR = "/home/ftp/pub/unpacked"
+class Branch(object):
+ """A version control branch."""
-class History(object):
+ def log(self, limit=None):
+ raise NotImplementedError(self.log)
- def __init__(self, db):
- self.db = db
+ def diff(self, revision):
+ raise NotImplementedError(self.diff)
- def _log(self, tree):
- return util.LoadStructure(os.path.join(HISTORYDIR, "history.%s" % tree))
+ def changes_summary(self, revision):
+ raise NotImplementedError(self.changes_summary)
- def diff(self, author, date, tree, revision):
- """get recent git entries"""
- # validate the tree
- t = self.db.trees[tree]
- if t.scm == "git":
- self._git_diff(t, revision, tree)
- else:
- raise Exception("Unknown VCS %s" % t.scm)
+class Revision(object):
+
+ def __init__(self, revision, date, committer, author, message):
+ self.revision = revision
+ self.date = date
+ self.author = author
+ self.committer = committer
+ self.message = message
- def _git_diff(self, t, revision, tree):
- """show recent git entries"""
- log = self._log(tree)
+class GitBranch(Branch):
- # backwards? why? well, usually our users are looking for the newest
- # stuff, so it's most likely to be found sooner
- for i in range(len(log), 0, -1):
- if log[i]["REVISION"] == revision:
- entry = log[i]
- break
+ def __init__(self, path, branch="master"):
+ self.repo = Repo(path)
+ self.store = self.repo.object_store
+ self.branch = branch
+
+ def _changes_for(self, commit):
+ if len(commit.parents) == 0:
+ parent_tree = Tree().id
+ else:
+ parent_tree = self.store[commit.parents[0]].tree
+ return self.store.tree_changes(parent_tree, commit.tree)
+
+ def _revision_from_commit(self, commit):
+ 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, 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
+ done = set()
+ pending_commits = [from_rev]
+ while pending_commits != []:
+ commit_id = pending_commits.pop(0)
+ 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 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()
+ if len(commit.parents) == 0:
+ parent_tree = Tree().id
else:
- raise Exception("Unable to locate commit information revision[%s]." % revision)
-
- # get information about the current diff
- title = "GIT Diff in %s:%s for revision %s" % (
- tree, t.branch, revision)
-
- pwd = os.environ["PWD"]
- ret = None
- try:
- os.chdir(os.path.join(UNPACKED_DIR, tree))
- cmd = "git diff %s^ %s ./" % (revision, revision)
- ret = (title, entry, tree, [(cmd, commands.getoutput("%s 2> /dev/null" % cmd))])
-
- finally:
- os.chdir(pwd)
- return ret
-
- def authors(self, tree):
- log = self._log(tree)
- authors = set()
- for entry in log:
- authors.add(entry["AUTHOR"])
- return authors
-
- def history(self, tree, author=None):
- """get commit history for the given tree"""
- log = self._log(tree)
-
- # what? backwards? why is that? oh... I know... we want the newest first
- for i in range(len(log), 0, -1):
- entry = log[i]
- if (author is None or
- (author == "") or
- (author == "ALL") or
- (author == entry["AUTHOR"])):
- yield entry, tree
+ 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())