monotone

monotone Mtn Source Tree

Root/contrib/monotone-notify-hookversion.lua

1-- Copyright (c) 2006 by Richard Levitte <richard@levitte.org>
2-- All rights reserved.
3--
4-- Redistribution and use in source and binary forms, with or without
5-- modification, are permitted provided that the following conditions
6-- are met:
7--
8-- 1. Redistributions of source code must retain the above copyright
9-- notice, this list of conditions and the following disclaimer.
10--
11-- 2. Redistributions in binary form must reproduce the above copyright
12-- notice, this list of conditions and the following disclaimer in the
13-- documentation and/or other materials provided with the distribution.
14--
15-- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16-- ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17-- LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
18-- A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
19-- OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20-- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
21-- LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22-- DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23-- THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24-- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25-- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26
27-------------------------------------------------------------------------------
28-- This software depends on the existence of the following programs:
29--
30-- mtn
31-- sed
32-- mime-construct
33-- mailx
34-------------------------------------------------------------------------------
35-- Usage:
36--
37-- in your monotonerc (or the monotonerc intended for the particular
38-- process), add the following include:
39--
40-- include("/PATH/TO/monotone-notify-hookversion.lua")
41--
42-- additionally, you can or must define the following variables for
43-- use by this software:
44--
45-- MN_workdir MUST be set to the path that can
46-- be used for work files.
47--
48-- MN_mail_address_diffs MAY be set to the mail address to
49-- send notifications WITH diffs to.
50-- MN_mail_address_nodiffs MAY be set to the mail address to
51-- send notifications WITHOUT diffs
52-- to.
53--
54-- NOTE: AT LEAST ONE OF the two
55-- address variables MUST be defined.
56--
57-- MN_database MUST be set to the database used.
58--
59-- MN_host MAY be set to the address of the
60-- host to mirror from.
61-- MN_collection MAY be set to the pattern of
62-- branches to include. This is
63-- currently only used for mirroring.
64--
65-- NOTE: IF YOU WANT TO MIRROR, BOTH
66-- MN_host AND MN_collection MUST BE
67-- DEFINED. If one of them isn't,
68-- both are ignored.
69--
70-- This software can only be used to send notifications for ALL
71-- data received through netsync. A future version will be able
72-- to have the user define several different collection-based
73-- criteria and this software will be able to filter according
74-- to those criteria.
75-------------------------------------------------------------------------------
76
77-------------------------------------------------------------------------------
78-- Variables
79-------------------------------------------------------------------------------
80
81-- True: script won't be executed, and a message saying its name will
82-- be displayed
83-- False: script will be executed upon completion
84_MN_debug = true
85
86-- A store for the data the belongs to each session.
87_MN_sessions = {}
88
89-------------------------------------------------------------------------------
90-- Templates for the script that this software creates.
91-- NOTE: every line where at least one @var@ thing can be replaced is discarded
92-------------------------------------------------------------------------------
93
94_MN_templates = {
95 script_start = {
96 "#! /bin/sh",
97 "",
98 "LANG=C; export LANG",
99 "mtn --db=@database@ --norc pull @host@ \"@collection@\""
100 },
101
102 do_revncert_init = {
103 "show_diffs=false",
104 },
105
106 do_revision = {
107 "mtn --db=@database@ log --last 1 --diffs --from @revision@ > @workdir@/@nonce@.tmp",
108 "cat @workdir@/@nonce@.tmp | sed -e '/^============================================================$/,$d' > @workdir@/@nonce@.with-diff.desc",
109 "cat @workdir@/@nonce@.tmp | sed -e '/^============================================================$/,$p;d' > @workdir@/@revision@.diff",
110 "rm -f @workdir@/@nonce@.tmp",
111 "(",
112 " cat @workdir@/@nonce@.with-diff.desc",
113 " echo",
114 " echo 'To get the patch for this revision, please do this:'",
115 " echo 'mtn log --last 1 --diffs --from @revision@'",
116 ") > @workdir@/@nonce@.without-diff.desc",
117 "if [ `grep '^Ancestor: ' @workdir@/@nonce@.with-diff.desc | wc -l` = '1' ]; then show_diffs=true; fi",
118 },
119
120 do_revcerts_start = {
121 "(echo 'Additional certs:'; echo) >> @workdir@/@nonce@.with-diff.desc"
122 },
123 do_norevcerts_start = {
124 "(echo 'Added certs:'; echo) > @workdir@/@nonce@.with-diff.desc"
125 },
126 do_cert = {
127 "prefix=' @cert_name@'; echo \"@cert_value@\" | while read L; do (echo; echo $prefix : $L) >> @workdir@/@nonce@.with-diff.desc; prefix=`echo \"$prefix\" | sed -e 's/./ /g'`; done"
128 },
129
130 do_revncert_end = {
131 "if $show_diffs; then",
132 " mime-construct --to @mail_address_diffs@ --subject 'Revision @revision@' --file @workdir@/@nonce@.with-diff.desc --file-attach @workdir@/@revision@.diff",
133 "else",
134 " cat @workdir@/@nonce@.without-diff.desc | mailx -s 'Revision @revision@' @mail_address_diffs@",
135 "fi",
136 "cat @workdir@/@nonce@.without-diff.desc | mailx -s 'Revision @revision@' @mail_address_nodiffs@",
137 "rm -f @workdir@/@nonce@.with-diff.desc",
138 "rm -f @workdir@/@nonce@.without-diff.desc",
139 "rm -f @workdir@/@revision@.diff",
140 ""
141 },
142
143 do_key_info_init = {
144 "(echo 'New public keys:'; echo) > @workdir@/@nonce@.pubkeys"
145 },
146 do_key_info = {
147 "echo \"@keyname@\" >> @workdir@/@nonce@.pubkeys"
148 },
149 do_key_info_end = {
150 "cat @workdir@/@nonce@.pubkeys | mailx -s 'New pubkeys' @mail_address_diffs@",
151 "cat @workdir@/@nonce@.pubkeys | mailx -s 'New pubkeys' @mail_address_nodiffs@",
152 "rm -f @workdir@/@nonce@.pubkeys",
153 ""
154 },
155 script_end = {
156 "rm -f @script@"
157 }
158}
159
160-------------------------------------------------------------------------------
161-- Helper functions
162-------------------------------------------------------------------------------
163
164-- These are called at the beginning and end of each hook to provide a trace
165function _MN_debug_start(name)
166 if _MN_debug then
167 io.stderr:write("DEBUG[MN]: ----- start ",name,"\n")
168 end
169end
170function _MN_debug_end(name)
171 if _MN_debug then
172 io.stderr:write("DEBUG[MN]: ------- end ",name,"\n")
173 end
174end
175
176-- This is the general function that takes a set of template names and writes
177-- all the script lines that were successfully mangled
178function _MN_write_script_lines(nonce,items)
179 if _MN_sessions[nonce].fd then
180 for _, name in pairs(items)
181 do
182 for _, line in pairs(_MN_templates[name])
183 do
184 line = string.gsub(line, "%@([_%w]+)%@", _MN_sessions[nonce])
185 if not string.match(line, "%@([_%w]+)%@") then
186 _MN_sessions[nonce].fd:write(line,"\n")
187 end
188 end
189 end
190 end
191end
192
193-- This provides a general check to see if anything needs to be written to
194-- the script, in a structured way. This was needed because we don't know
195-- when certain data end, and it would be a pity to create an email for each
196-- new pubkey, for example, when one containing all new pubkeys is enough.
197function _MN_checks(nonce,rev_id)
198 if table.maxn(_MN_sessions[nonce].pubkeys) ~= 0 then
199 _MN_write_script_lines(nonce,{"do_key_info_init"})
200 for _, keyname in pairs(_MN_sessions[nonce].pubkeys)
201 do
202 _MN_sessions[nonce].keyname = keyname
203 _MN_write_script_lines(nonce,{"do_key_info"})
204 end
205 _MN_write_script_lines(nonce,{"do_key_info_end"})
206 _MN_sessions[nonce].pubkeys = {}
207 end
208
209 if rev_id ~= _MN_sessions[nonce].revision and
210 _MN_sessions[nonce].revision ~= nil then
211 local do_end = false
212 if _MN_sessions[nonce].new_revision then
213 _MN_write_script_lines(nonce,{"do_revncert_init","do_revision"})
214 cert_start = "do_revcerts_start"
215 do_end = true
216 else
217 cert_start = "do_norevcerts_start"
218 end
219 if table.maxn(_MN_sessions[nonce].certs) ~= 0 then
220 _MN_write_script_lines(nonce,{cert_start})
221 for name, value in pairs(_MN_sessions[nonce].certs)
222 do
223 _MN_sessions[nonce].cert_name = name
224 _MN_sessions[nonce].cert_value = value
225 _MN_write_script_lines(nonce,{"do_cert"})
226 end
227 _MN_write_script_lines(nonce,{"do_revncert_end"})
228 _MN_sessions[nonce].certs = {}
229 do_end = true
230 end
231 _MN_write_script_lines(nonce,{"do_revncert_end"})
232 end
233
234 _MN_sessions[nonce].new_revision = false
235 _MN_sessions[nonce].revision = rev_id
236end
237
238-------------------------------------------------------------------------------
239-- The official hooks
240-------------------------------------------------------------------------------
241
242-- Store away the previous implementations, so we can call them first.
243_MN_old_note_netsync_start = note_netsync_start
244_MN_old_note_netsync_revision_received = note_netsync_revision_received
245_MN_old_note_netsync_cert_received = note_netsync_cert_received
246_MN_old_note_netsync_pubkey_received = note_netsync_pubkey_received
247_MN_old_note_netsync_end = note_netsync_end
248
249function note_netsync_start(nonce)
250 _MN_debug_start("MN_note_netsync_start")
251 if _MN_old_note_netsync_start then
252 _MN_old_note_netsync_start(nonce)
253 end
254 _MN_sessions[nonce] = {}
255 _MN_sessions[nonce].previous_certs = "false"
256 _MN_sessions[nonce].nonce = nonce
257 _MN_sessions[nonce].workdir = MN_workdir
258 _MN_sessions[nonce].mail_address_diffs = MN_mail_address_diffs
259 _MN_sessions[nonce].mail_address_nodiffs = MN_mail_address_nodiffs
260 _MN_sessions[nonce].database = MN_database
261 _MN_sessions[nonce].host = MN_host
262 _MN_sessions[nonce].collection = MN_collection
263 if not (MN_workdir and MN_database) then
264 io.stderr:write("Error: the variables MN_workdir and MN_database\n")
265 io.stderr:write("Error: are not set!\n")
266 io.stderr:write("There will be no script and therefore no mail\n")
267 else
268 _MN_sessions[nonce].script = _MN_sessions[nonce].workdir .. "/" .. nonce .. ".sh"
269 _MN_sessions[nonce].fd,message = io.open(_MN_sessions[nonce].script,"w")
270 if _MN_sessions[nonce].fd == nil then
271 io.stderr:write("Error: Couldn't create file ".._MN_sessions[nonce].script.."\n")
272 io.stderr:write("There will be no script and therefore no mail\n")
273 end
274 end
275 if not (MN_mail_address_diffs or MN_mail_address_nodiffs) then
276 io.stderr:write("Warning: the variables MN_mail_address_diffs and\n")
277 io.stderr:write("Warning: MN_mail_address_nodiffs are not set!\n")
278 io.stderr:write("There will be a script, but it won't mail anywhere!\n")
279 end
280 _MN_sessions[nonce].revision = nil
281 _MN_sessions[nonce].new_revision = false
282 _MN_sessions[nonce].pubkeys = {}
283 _MN_sessions[nonce].certs = {}
284 _MN_write_script_lines(nonce,{"script_start"})
285 _MN_debug_end("MN_note_netsync_start")
286end
287
288function note_netsync_revision_received(new_id,revision,certs,nonce)
289 _MN_debug_start("MN_note_netsync_revision_received\n "..new_id)
290 if _MN_old_note_netsync_revision_received then
291 _MN_old_note_netsync_revision_received(new_id,revision,certs,nonce)
292 end
293 _MN_checks(nonce,new_id)
294 _MN_sessions[nonce].new_revision = true
295 _MN_sessions[nonce].certs = {}
296 for _, item in pairs(certs)
297 do
298 if item.name ~= "author" and
299 item.name ~= "branch" and
300 item.name ~= "changelog" and
301 item.name ~= "date" and
302 item.name ~= "tag" then
303 if _MN_debug then
304 io.stderr:write("DEBUG[MN]: --- add cert\n "..new_id.."\n "..name.."\n "..value.."\n")
305 end
306 _MN_sessions[nonce].certs[item.name] = item.value
307 end
308 end
309 _MN_debug_end("MN_note_netsync_revision_received\n "..new_id)
310end
311
312function note_netsync_cert_received(rev_id,key,name,value,nonce)
313 _MN_debug_start("MN_note_netsync_cert_received\n "..rev_id.."\n "..name.."\n "..value)
314 if _MN_old_note_netsync_cert_received then
315 _MN_old_note_netsync_cert_received(rev_id,key,name,value,nonce)
316 end
317 _MN_checks(nonce,rev_id)
318 if _MN_debug then
319 io.stderr:write("DEBUG[MN]: --- add cert\n "..rev_id.."\n "..name.."\n "..value.."\n")
320 end
321 _MN_sessions[nonce].certs[name] = value
322 _MN_debug_end("MN_note_netsync_cert_received\n "..rev_id)
323end
324
325function note_netsync_pubkey_received(keyname,nonce)
326 _MN_debug_start("MN_note_netsync_pubkey_received\n "..keyname)
327 if _MN_old_note_netsync_pubkey_received then
328 _MN_old_note_netsync_pubkey_received(keyname,nonce)
329 end
330 table.insert(_MN_sessions[nonce].pubkeys,keyname)
331 _MN_debug_end("MN_note_netsync_pubkey_received\n "..keyname)
332end
333
334function note_netsync_end(nonce)
335 _MN_debug_start("MN_note_netsync_end")
336 if _MN_old_note_netsync_end then
337 _MN_old_note_netsync_end(nonce)
338 end
339 _MN_checks(nonce,nil)
340 _MN_write_script_lines(nonce,{"script_end"})
341 if _MN_sessions[nonce].fd then
342 io.close(_MN_sessions[nonce].fd)
343 if _MN_debug then
344 io.stderr:write("DEBUG[MN]: wrote script ",_MN_sessions[nonce].script,
345 "\n")
346 else
347 spawn("sh",_MN_sessions[nonce].script)
348 end
349 end
350 _MN_sessions[nonce] = nil
351 _MN_debug_end("MN_note_netsync_end")
352end

Archive Download this file

Branches

Tags

Quick Links:     www.monotone.ca    -     Downloads    -     Documentation    -     Wiki    -     Code Forge    -     Build Status