More debug
[build-farm.git] / buildfarm / history.py
1 #!/usr/bin/python
2 # script to show recent checkins in cvs / svn / 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
23 from buildfarm import util
24
25 import commands
26 import os
27 import time
28
29 BASEDIR = "/home/build/master"
30 HISTORYDIR = "/home/build/master/cache"
31 TIMEZONE = "PST"
32 TIMEOFFSET = 0
33 UNPACKED_DIR = "/home/ftp/pub/unpacked"
34
35 class History(object):
36
37     def __init__(self, db):
38         self.db = db
39
40     def _log(self, tree):
41         return util.LoadStructure(os.path.join(HISTORYDIR, "history.%s" % tree))
42
43     def diff(self, author, date, tree, revision):
44         """get recent cvs/svn entries"""
45         # validate the tree
46         t = self.db.trees[tree]
47
48         if t.scm == "cvs":
49             self._cvs_diff(t, author, date, tree)
50         elif t.scm == "svn":
51             self._svn_diff(t, revision, tree)
52         elif t.scm == "git":
53             self._git_diff(t, revision, tree)
54         else:
55             raise Exception("Unknown VCS %s" % t.scm)
56
57     def _svn_diff(self, t, revision, tree):
58         """show recent svn entries"""
59
60         os.chdir(os.path.join(UNPACKED_DIR, tree))
61
62         # determine the most recent version known to this database
63         for l in commands.getoutput("svn info").splitlines():
64             if l.startswith("Revision"):
65                 current_revision = l.strip().split(":")
66                 break
67         else:
68             raise Exception("Unable to find current revision")
69
70         if (not revision.isdigit() or int(revision) < 0 or
71             int(revision) > int(current_revision)):
72             raise Exception("unknown revision[%s]" % revision)
73
74         log = self._log(tree)
75
76         # backwards? why? well, usually our users are looking for the newest
77         # stuff, so it's most likely to be found sooner
78         for i in range(len(log), 0, -1):
79             if log[i]["REVISION"] == revision:
80                 entry = log[i]
81                 break
82         else:
83             raise Exception("Unable to locate commit information revision[%s]." % revision)
84
85         # get information about the current diff
86         title = "SVN Diff in %s:%s for revision r%s" % (
87             tree, t.branch, revision)
88
89         old_revision = revision - 1
90         cmd = "svn diff -r %s:%s" % (old_revision, revision)
91
92         return (title, entry, tree, [(cmd, commands.getoutput("%s 2> /dev/null" % cmd))])
93
94     def _cvs_diff(self, t, author, date, tree):
95         """show recent cvs entries"""
96         os.chdir(os.path.join(UNPACKED_DIR, tree))
97
98         log = self._log(tree)
99
100         # for paranoia, check that the date string is a valid date
101         if not date[0].isdigit():
102             raise Exception("unknown date")
103
104         for i in range(log):
105             if author == log[i]["AUTHOR"] and date == log[i]["DATE"]:
106                 entry = log[i]
107                 break
108         else:
109             raise Exception("Unable to locate commit information author[%s] data[%s]." % (
110                 author, date))
111
112         t1 = time.ctime(date-60+(TIMEOFFSET*60*60)).strip()
113         t2 = time.ctime(date+60+(TIMEOFFSET*60*60)).strip()
114
115         title = "CVS Diff in %s:%s for %s" % (tree, t.branch, t1)
116
117         if entry["TAG"] != "" and entry["REVISIONS"] != "":
118             raise Exception("sorry, cvs diff on branches not currently possible due to a limitation in cvs")
119
120         os.environ['CVS_PASSFILE'] = os.path.join(BASEDIR, ".cvspass")
121
122         if entry["REVISIONS"]:
123             diffs = []
124             for f in entry["REVISIONS"].keys():
125                 if entry["REVISIONS"][f]["REV1"] == "NONE":
126                     cmd = "cvs rdiff -u -r 0 -r %s %s" % (entry["REVISIONS"][f]["REV2"], f)
127                 elif entry["REVISIONS"][f]["REV2"] == "NONE":
128                     cmd = "cvs rdiff -u -r %s -r 0 %s" % (
129                         entry["REVISIONS"][f]["REV1"], f)
130                 else:
131                     cmd = "cvs diff -b -u -r %s -r %s %s" % (
132                         entry["REVISIONS"][f]["REV1"], entry["REVISIONS"][f]["REV2"], f)
133
134                 diffs.append((cmd, commands.getoutput("%s 2> /dev/null" % cmd)))
135         else:
136             cmd = "cvs diff -b -u -D \"%s %s\" -D \"%s %s\" %s" % (
137                 t1, TIMEZONE, t2, TIMEZONE, entry["FILES"])
138
139             diffs = [(cmd, commands.getoutput("%s 2> /dev/null" % cmd))]
140         return (title, entry, tree, diffs)
141
142     def _git_diff(self, t, revision, tree):
143         """show recent git entries"""
144         os.chdir(os.path.join(UNPACKED_DIR, tree))
145
146         log = self._log(tree)
147
148         # backwards? why? well, usually our users are looking for the newest
149         # stuff, so it's most likely to be found sooner
150         for i in range(len(log), 0, -1):
151             if log[i]["REVISION"] == revision:
152                 entry = log[i]
153                 break
154         else:
155             raise Exception("Unable to locate commit information revision[%s]." % revision)
156
157         # get information about the current diff
158         title = "GIT Diff in %s:%s for revision %s" % (
159             tree, t.branch, revision)
160
161         cmd = "git diff %s^ %s ./" % (revision, revision)
162         return (title, entry, tree, [(cmd, commands.getoutput("%s 2> /dev/null" % cmd))])
163
164     def authors(self, tree):
165         log = self._log(tree)
166         authors = set()
167         for entry in log:
168             authors.add(entry["AUTHOR"])
169         return authors
170
171     def history(self, tree, author=None):
172         """get commit history for the given tree"""
173         log = self._log(tree)
174
175         # what? backwards? why is that? oh... I know... we want the newest first
176         for i in range(len(log), 0, -1):
177             entry = log[i]
178             if (author is None or
179                 (author == "") or
180                 (author == "ALL") or
181                 (author == entry["AUTHOR"])):
182                 yield entry, tree