use killall on hape after a build run to do what killbysubdir should do
[build-farm.git] / buildfarm / history.py
1 #!/usr/bin/python
2 # script to show recent checkins in git
3 #
4 # Copyright (C) Andrew Tridgell <tridge@samba.org>     2001
5 # Copyright (C) Martin Pool <mbp@samba.org>            2003
6 # Copyright (C) Jelmer Vernooij <jelmer@samba.org>     2007-2010
7 #
8 #   This program is free software; you can redistribute it and/or modify
9 #   it under the terms of the GNU General Public License as published by
10 #   the Free Software Foundation; either version 2 of the License, or
11 #   (at your option) any later version.
12 #
13 #   This program is distributed in the hope that it will be useful,
14 #   but WITHOUT ANY WARRANTY; without even the implied warranty of
15 #   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 #   GNU General Public License for more details.
17 #
18 #   You should have received a copy of the GNU General Public License
19 #   along with this program; if not, write to the Free Software
20 #   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21
22 from cStringIO import StringIO
23
24 from dulwich.objects import Tree
25 from dulwich.patch import write_tree_diff
26 from dulwich.repo import Repo
27
28
29 class Branch(object):
30     """A version control branch."""
31
32     def log(self, limit=None):
33         raise NotImplementedError(self.log)
34
35     def diff(self, revision):
36         raise NotImplementedError(self.diff)
37
38     def changes_summary(self, revision):
39         raise NotImplementedError(self.changes_summary)
40
41
42 class Revision(object):
43
44     def __init__(self, revision, date, committer, author, message):
45         self.revision = revision
46         self.date = date
47         self.author = author
48         self.committer = committer
49         self.message = message
50
51
52 class GitBranch(Branch):
53
54     def __init__(self, path, branch="master"):
55         self.repo = Repo(path)
56         self.store = self.repo.object_store
57         self.branch = branch
58
59     def _changes_for(self, commit):
60         if len(commit.parents) == 0:
61             parent_tree = Tree().id
62         else:
63             parent_tree = self.store[commit.parents[0]].tree
64         return self.store.tree_changes(parent_tree, commit.tree)
65
66     def _revision_from_commit(self, commit):
67         return Revision(commit.id, commit.commit_time,
68             committer=commit.committer, author=commit.author,
69             message=commit.message)
70
71     def log(self, from_rev=None, exclude_revs=None, limit=None):
72         if exclude_revs is None:
73             exclude_revs = set()
74         if from_rev is None:
75             try:
76                 commit = self.repo["refs/heads/%s" % self.branch]
77             except KeyError:
78                 return
79             from_rev = commit.id
80         done = set()
81         pending_commits = [from_rev]
82         while pending_commits != []:
83              commit_id = pending_commits.pop(0)
84              commit = self.repo[commit_id]
85              yield self._revision_from_commit(commit)
86              done.add(commit.id)
87              if len(done) >= limit:
88                  return
89              exclude_revs.add(commit.id)
90              # FIXME: Add sorted by commit_time
91              for p in commit.parents:
92                  if p in exclude_revs:
93                      continue
94                  pending_commits.append(p)
95                  exclude_revs.add(p)
96
97     def changes_summary(self, revision):
98         commit = self.repo[revision]
99         added = set()
100         modified = set()
101         removed = set()
102         for ((oldpath, newpath), (oldmode, newmode), (oldsha, newsha)) in self._changes_for(commit):
103             if oldpath is None:
104                 added.add(newpath)
105             elif newpath is None:
106                 removed.add(oldpath)
107             else:
108                 modified.add(newpath)
109         return (added, modified, removed)
110
111     def diff(self, revision):
112         commit = self.repo[revision]
113         f = StringIO()
114         if len(commit.parents) == 0:
115             parent_tree = Tree().id
116         else:
117             parent_tree = self.store[commit.parents[0]].tree
118         write_tree_diff(f, self.store, parent_tree, commit.tree)
119         return (self._revision_from_commit(commit), f.getvalue())