# # old_revision [33513953412998e03c1027d4e802fca6da9e9d1c] # # add_file "contrib/monotone-mail-notify-standalone.sh" # content [7de62a542b7b20d9cf2b8d2bc14c685bd34efdb8] # # patch "contrib/monotone-mail-notify-standalone.lua" # from [89e0cd79a1a44761c15a9f3556e6b62313c6e605] # to [b451b8b6da1a0f92dcb9d372fe1935972f9eafaa] # ============================================================ --- contrib/monotone-mail-notify-standalone.sh 7de62a542b7b20d9cf2b8d2bc14c685bd34efdb8 +++ contrib/monotone-mail-notify-standalone.sh 7de62a542b7b20d9cf2b8d2bc14c685bd34efdb8 @@ -0,0 +1,121 @@ +#! /bin/sh + +# Create a file "notify" next to "read-permissions" and ensure +# its contents are in the same format as "read-permissions", +# except that the values for allow and deny must be real email +# addresses. Install the corresponding .lua file in monotone. +# +# Call this script from cron or similar to process files +# generated by the .lua file. +# +# Copyright (c) 2007, Matthew Sackman (matthew at wellquite dot org) +# LShift Ltd (http://www.lshift.net) +# License: GPLv2 or later + +DB="/path/to/a/private/unused/db.mtn" +MTN="/usr/bin/mtn" +SERVER="localhost" +HIGHLIGHT="/usr/bin/source-highlight" +MIMECONSTRUCT="/usr/bin/mime-construct" +BASE="/tmp/notify" + +function processFile() { + local fileBase=$1 + + local hdr="$fileBase.hdr.txt" + local rev="$fileBase.rev.txt" + if [ ! -f $hdr ] + then + echo "Specified header file '$hdr' does not exist" + exit 1 + fi + + if [ ! -f $rev ] + then + echo "Specified revision file '$hdr' does not exist" + exit 1 + fi + + local revision=$(cat $rev | grep '^revision:' | sed -e 's/^revision:[ ]\+//') + + local parts=() + local files=() + let fIdx=0 + let pIdx=0 + local parents=$($MTN --reallyquiet -d $DB automate parents $revision) + if [ "x" == "x$parents" ] + then + local plainDiff="$revision.noparent.diff" + local htmlDiff="$revision.noparent.html" + local partFile="$revision.noparent.part" + files[0]=$plainDiff + files[1]=$htmlDiff + parts[0]=$partFile + $MTN --reallyquiet -d $DB log --diffs --brief --no-graph --from $revision --to $revision > $plainDiff + cat $plainDiff | $HIGHLIGHT -s diff -f html > $htmlDiff + $MIMECONSTRUCT --subpart --multipart multipart/alternative \ + --type text/plain --part-header "Content-Type: text/plain" --encoding quoted-printable --file $plainDiff \ + --type text/html --encoding quoted-printable --file $htmlDiff \ + > $partFile + else + for p in $parents + do + local plainDiff="$revision.$p.diff" + local htmlDiff="$revision.$p.html" + local partFile="$revision.$p.part" + files[$fIdx]=$plainDiff + files[$fIdx+1]=$htmlDiff + let fIdx+=2 + $MTN --reallyquiet -d $DB diff -r $p -r $revision > $plainDiff + cat $plainDiff | $HIGHLIGHT -s diff -f html > $htmlDiff + $MIMECONSTRUCT --subpart --multipart multipart/alternative \ + --type text/plain --part-header "Content-Type: text/plain" --encoding quoted-printable --file $plainDiff \ + --type text/html --encoding quoted-printable --file $htmlDiff \ + > $partFile + parts[$pIdx]=$partFile + let pIdx+=1 + done + fi + + local margs="" + for p in address@hidden + do + margs="$margs --subpart-file $p" + done + + local hdrargs=$(cat $hdr) + $MIMECONSTRUCT --embedded-to --header "$hdrargs" --multipart multipart/mixed \ + --type text/plain --part-header "Content-Type: text/plain" --encoding quoted-printable --file $rev \ + $margs + + for p in address@hidden + do + rm $p + done + + for f in address@hidden + do + rm $f + done + + rm $hdr + rm $rev +} + +if [ "x" == "x$(ls $BASE)" ] +then + exit 0 +fi + +$MTN --reallyquiet -d $DB pull $SERVER '*' + +cwd=$(pwd) +cd $BASE + +for f in $(ls $BASE | grep '.hdr.txt$') +do + name=$(basename "$f" '.hdr.txt') + processFile "$BASE/$name" +done + +cd "$cwd" ============================================================ --- contrib/monotone-mail-notify-standalone.lua 89e0cd79a1a44761c15a9f3556e6b62313c6e605 +++ contrib/monotone-mail-notify-standalone.lua b451b8b6da1a0f92dcb9d372fe1935972f9eafaa @@ -1,9 +1,10 @@ -- Create a file "notify" next to "read-permissions" and ensure -- its contents are in the same format as "read-permissions", -- except that the values for allow and deny must be real email -- addresses. -- --- Requires a "mail" executable +-- This will splat out files in _base. Use the .sh file from +-- cron to process those files -- -- Copyright (c) 2007, Matthew Sackman (matthew at wellquite dot org) -- LShift Ltd (http://www.lshift.net) @@ -11,9 +12,8 @@ -- Whoever wrote the function "get_netsync_read_permitted" -- License: GPLv2 or later -_outfile = "/tmp/processor-out" -_errfile = "/tmp/processor-err" _from = "address@hidden" +_base = "/tmp/notify/" function get_notify_recipients(branch) local emailfile = io.open(get_confdir() .. "/notify", "r") @@ -85,53 +85,76 @@ function note_netsync_revision_received if cert["name"] == "branch" then rev_data["recipients"] = get_notify_recipients(cert["value"]) end - if cert["name"] ~= nil then + if cert["name"] ~= nil then if nil == rev_data["certs"][cert["name"]] then - rev_data["certs"][cert["name"]] = {} - end + rev_data["certs"][cert["name"]] = {} + end table.insert(rev_data["certs"][cert["name"]], cert["value"]) end end _emails_to_send[session_id][new_id] = rev_data end -function note_netsync_end (session_id, status, bytes_in, bytes_out, certs_in, certs_out, revs_in, revs_out, keys_in, keys_out) - if _emails_to_send[session_id] == nil then - -- no session present - return - end +do + local saved_note_netsync_end = note_netsync_end - if status ~= 200 then - -- some error occured, no further processing takes place - return - end + function note_netsync_end (session_id, status, bytes_in, bytes_out, certs_in, certs_out, revs_in, revs_out, keys_in, keys_out, ...) + if saved_note_netsync_end then + saved_note_netsync_end(session_id, status, + bytes_in, bytes_out, + certs_in, certs_out, + revs_in, revs_out, + keys_in, keys_out, + unpack(arg)) + end - if _emails_to_send[session_id] == "" then - -- we got no interesting revisions - return - end - - for rev_id,rev_data in pairs(_emails_to_send[session_id]) do - if # (rev_data["recipients"]) > 0 then - file,filename = temp_file("notify") - file:write(summarize_certs(rev_data)) - file:close() - local subject = make_subject_line(rev_data) - local reply_to = "Reply-To: " - for j,auth in pairs(rev_data["certs"]["author"]) do - reply_to = reply_to .. auth - if j < # (rev_data["certs"]["author"]) then reply_to = reply_to .. ", " end - end - for j,addr in pairs(rev_data["recipients"]) do - spawn_redirected(filename, _outfile, _errfile, "/usr/bin/mail", "-e", "-a", reply_to, "-a", "From: " .. _from, "-s", subject, addr) - end + if _emails_to_send[session_id] == nil then + -- no session present + return + end - os.remove(filename) - end - end - - _emails_to_send[session_id] = nil + if status ~= 200 then + -- some error occured, no further processing takes place + return + end + + if _emails_to_send[session_id] == "" then + -- we got no interesting revisions + return + end + + for rev_id,rev_data in pairs(_emails_to_send[session_id]) do + if # (rev_data["recipients"]) > 0 then + local subject = make_subject_line(rev_data) + local reply_to = "" + for j,auth in pairs(rev_data["certs"]["author"]) do + reply_to = reply_to .. auth + if j < # (rev_data["certs"]["author"]) then reply_to = reply_to .. ", " end + end + + local outputFileRev = io.open(_base .. rev_data["revision"] .. os.time() .. ".rev.txt", "w+") + local outputFileHdr = io.open(_base .. rev_data["revision"] .. os.time() .. ".hdr.txt", "w+") + + local to = "" + for j,addr in pairs(rev_data["recipients"]) do + to = to .. addr + if j < # (rev_data["recipients"]) then to = to .. ", " end + end + + outputFileHdr:write("BCC: " .. to .. "\n") + outputFileHdr:write("From: " .. _from .. "\n") + outputFileHdr:write("Subject: " .. subject .. "\n") + outputFileHdr:write("Reply-To: " .. reply_to .. "\n") + outputFileHdr:close() + + outputFileRev:write(summarize_certs(rev_data)) + outputFileRev:close() + end + end + + _emails_to_send[session_id] = nil + end end function summarize_certs(t) @@ -140,10 +163,10 @@ function summarize_certs(t) for name,values in pairs(t["certs"]) do local formatted_value = "" for j,val in pairs(values) do - formatted_value = formatted_value .. name .. ":" - if string.match(val, "\n") - then formatted_value = formatted_value .. "\n" - else formatted_value = formatted_value .. (string.rep(" ", 20 - (# name))) end + formatted_value = formatted_value .. name .. ":" + if string.match(val, "\n") + then formatted_value = formatted_value .. "\n" + else formatted_value = formatted_value .. (string.rep(" ", 20 - (# name))) end formatted_value = formatted_value .. val .. "\n" end if name == "changelog" then changelog = formatted_value else str = str .. formatted_value end