1111#
1212# This script is meant to be run either in a post-commit hook or in an
1313# update hook. If there's nothing unusual about your hosting setup,
14- # you can specify the project name with a -p option and avoid having
15- # to modify this script. Try it with -n to see the notification mail
16- # dumped to stdout and verify that it looks sane. With -V it dumps its
17- # version and exits.
14+ # you can specify the project name and repo with config variables and
15+ # avoid having to modify this script. Try it with -n to see the
16+ # notification mail dumped to stdout and verify that it looks
17+ # sane. With -V it dumps its version and exits.
1818#
19- # In post-commit, run it without arguments (other than possibly a -p
20- # option). It will query for current HEAD and the latest commit ID to
21- # get the information it needs.
19+ # In post-commit, run it without arguments. It will query for
20+ # current HEAD and the latest commit ID to get the information it
21+ # needs.
2222#
2323# In update, call it with a refname followed by a list of commits:
24- # You want to reverse the order git rev-list emits becxause it lists
24+ # You want to reverse the order git rev-list emits because it lists
2525# from most recent to oldest.
2626#
2727# /path/to/ciabot.py ${refname} $(git rev-list ${oldhead}..${newhead} | tac)
2828#
29- # Note: this script uses mail, not XML-RPC, in order to avoid stalling
30- # until timeout when the CIA XML-RPC server is down.
29+ # Configuration variables affecting this script:
30+ # ciabot.project = name of the project (required)
31+ # ciabot.repo = name of the project repo for gitweb/cgit purposes
32+ # ciabot.xmlrpc = if true (default), ship notifications via XML-RPC
33+ # ciabot.revformat = format in which the revision is shown
3134#
32-
33- #
34- # The project as known to CIA. You will either want to change this
35- # or invoke the script with a -p option to set it.
35+ # The ciabot.repo value defaults to ciabot.project lowercased.
3636#
37- project = None
38-
37+ # The revformat variable may have the following values
38+ # raw -> full hex ID of commit
39+ # short -> first 12 chars of hex ID
40+ # describe = -> describe relative to last tag, falling back to short
41+ # The default is 'describe'.
3942#
40- # You may not need to change these:
43+ # Note: the CIA project now says only XML-RPC is reliable, so
44+ # we default to that.
4145#
42- import os , sys , commands , socket , urllib
43-
44- # Name of the repository.
45- # You can hardwire this to make the script faster.
46- repo = os .path .basename (os .getcwd ())
4746
48- # Fully-qualified domain name of this host.
49- # You can hardwire this to make the script faster.
50- host = socket .getfqdn ()
47+ import os , sys , commands , socket , urllib
48+ from xml .sax .saxutils import escape
5149
5250# Changeset URL prefix for your repo: when the commit ID is appended
5351# to this, it should point at a CGI that will display the commit
7270 <message>
7371 <generator>
7472 <name>CIA Python client for Git</name>
75- <version>%(gitver )s</version>
73+ <version>%(version )s</version>
7674 <url>%(generator)s</url>
7775 </generator>
7876 <source>
9896# No user-serviceable parts below this line:
9997#
10098
101- # Addresses for the e-mail. The from address is a dummy, since CIA
102- # will never reply to this mail.
103- fromaddr = "CIABOT-NOREPLY@" + host
104- 99+ # Where to ship e-mail notifications.
100+ 105101
106102# Identify the generator script.
107103# Should only change when the script itself gets a new home and maintainer.
108- generator = "http://www.catb.org/~esr/ciabot.py"
104+ generator = "http://www.catb.org/~esr/ciabot.py"
105+ version = "3.5"
109106
110107def do (command ):
111108 return commands .getstatusoutput (command )[1 ]
112109
113- def report (refname , merged ):
110+ def report (refname , merged , xmlrpc = True ):
114111 "Generate a commit notification to be reported to CIA"
115112
116113 # Try to tinyfy a reference to a web view for this commit.
@@ -121,32 +118,27 @@ def report(refname, merged):
121118
122119 branch = os .path .basename (refname )
123120
124- # Compute a shortnane for the revision
125- rev = do ("git describe '" + merged + "' 2>/dev/null" ) or merged [:12 ]
126-
127- # Extract the neta-information for the commit
128- rawcommit = do ("git cat-file commit " + merged )
121+ # Compute a description for the revision
122+ if revformat == 'raw' :
123+ rev = merged
124+ elif revformat == 'short' :
125+ rev = ''
126+ else : # revformat == 'describe'
127+ rev = do ("git describe %s 2>/dev/null" % merged )
128+ if not rev :
129+ rev = merged [:12 ]
130+
131+ # Extract the meta-information for the commit
129132 files = do ("git diff-tree -r --name-only '" + merged + "' | sed -e '1d' -e 's-.*-<file>&</file>-'" )
130- inheader = True
131- headers = {}
132- logmsg = ""
133- for line in rawcommit .split ("\n " ):
134- if inheader :
135- if line :
136- fields = line .split ()
137- headers [fields [0 ]] = " " .join (fields [1 :])
138- else :
139- inheader = False
140- else :
141- logmsg = line
142- break
143- (author , ts ) = headers ["author" ].split (">" )
133+ metainfo = do ("git log -1 '--pretty=format:%an <%ae>%n%at%n%s' " + merged )
134+ (author , ts , logmsg ) = metainfo .split ("\n " )
135+ logmsg = escape (logmsg )
144136
145- # This discards the part of the authors addrsss after @.
146- # Might be bnicece to ship the full email address, if not
137+ # This discards the part of the author's address after @.
138+ # Might be be nice to ship the full email address, if not
147139 # for spammers' address harvesters - getting this wrong
148140 # would make the freenode #commits channel into harvester heaven.
149- author = author .replace ("<" , "" ).split ("@" )[0 ].split ()[- 1 ]
141+ author = escape ( author .replace ("<" , "" ).split ("@" )[0 ].split ()[- 1 ])
150142
151143 # This ignores the timezone. Not clear what to do with it...
152144 ts = ts .strip ().split ()[0 ]
@@ -155,8 +147,7 @@ def report(refname, merged):
155147 context .update (globals ())
156148
157149 out = xml % context
158-
159- message = '''\
150+ mail = '''\
160151 Message-ID: <%(merged)s.%(author)s@%(project)s>
161152From: %(fromaddr)s
162153To: %(toaddr)s
@@ -165,34 +156,49 @@ def report(refname, merged):
165156
166157%(out)s''' % locals ()
167158
168- return message
159+ if xmlrpc :
160+ return out
161+ else :
162+ return mail
169163
170164if __name__ == "__main__" :
171165 import getopt
172166
167+ # Get all config variables
168+ revformat = do ("git config --get ciabot.revformat" )
169+ project = do ("git config --get ciabot.project" )
170+ repo = do ("git config --get ciabot.repo" )
171+ xmlrpc = do ("git config --get ciabot.xmlrpc" )
172+ xmlrpc = not (xmlrpc and xmlrpc == "false" )
173+
174+ host = socket .getfqdn ()
175+ fromaddr = "CIABOT-NOREPLY@" + host
176+
173177 try :
174- (options , arguments ) = getopt .getopt (sys .argv [1 :], "np:V " )
178+ (options , arguments ) = getopt .getopt (sys .argv [1 :], "np:xV " )
175179 except getopt .GetoptError , msg :
176180 print "ciabot.py: " + str (msg )
177181 raise SystemExit , 1
178182
179- mailit = True
183+ notify = True
180184 for (switch , val ) in options :
181185 if switch == '-p' :
182186 project = val
183187 elif switch == '-n' :
184- mailit = False
188+ notify = False
189+ elif switch == '-x' :
190+ xmlrpc = True
185191 elif switch == '-V' :
186- print "ciabot.py: version 3.2"
192+ print "ciabot.py: version" , version
187193 sys .exit (0 )
188194
189195 # Cough and die if user has not specified a project
190196 if not project :
191197 sys .stderr .write ("ciabot.py: no project specified, bailing out.\n " )
192198 sys .exit (1 )
193199
194- # We'll need the git version number.
195- gitver = do ( "git --version" ). split ()[ 0 ]
200+ if not repo :
201+ repo = project . lower ()
196202
197203 urlprefix = urlprefix % globals ()
198204
@@ -205,18 +211,29 @@ def report(refname, merged):
205211 refname = arguments [0 ]
206212 merges = arguments [1 :]
207213
208- if mailit :
209- import smtplib
210- server = smtplib .SMTP ('localhost' )
214+ if notify :
215+ if xmlrpc :
216+ import xmlrpclib
217+ server = xmlrpclib .Server ('http://cia.vc/RPC2' );
218+ else :
219+ import smtplib
220+ server = smtplib .SMTP ('localhost' )
211221
212222 for merged in merges :
213- message = report (refname , merged )
214- if mailit :
215- server .sendmail (fromaddr , [toaddr ], message )
216- else :
223+ message = report (refname , merged , xmlrpc )
224+ if not notify :
217225 print message
226+ elif xmlrpc :
227+ try :
228+ # RPC server is flaky, this can fail due to timeout.
229+ server .hub .deliver (message )
230+ except socket .error , e :
231+ sys .stderr .write ("%s\n " % e )
232+ else :
233+ server .sendmail (fromaddr , [toaddr ], message )
218234
219- if mailit :
220- server .quit ()
235+ if notify :
236+ if not xmlrpc :
237+ server .quit ()
221238
222239#End
0 commit comments