diff options
Diffstat (limited to 'roles/git/hooks/files/util.py')
-rw-r--r-- | roles/git/hooks/files/util.py | 153 |
1 files changed, 153 insertions, 0 deletions
diff --git a/roles/git/hooks/files/util.py b/roles/git/hooks/files/util.py new file mode 100644 index 000000000..f35019634 --- /dev/null +++ b/roles/git/hooks/files/util.py @@ -0,0 +1,153 @@ +# General Utility Functions used in our Git scripts +# +# Copyright (C) 2008 Owen Taylor +# Copyright (C) 2009 Red Hat, Inc +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, If not, see +# http://www.gnu.org/licenses/. + +import os +import sys +from subprocess import Popen +import tempfile +import time + +def die(message): + print >>sys.stderr, message + sys.exit(1) + +# This cleans up our generation code by allowing us to use the same indentation +# for the first line and subsequent line of a multi-line string +def strip_string(str): + start = 0 + end = len(str) + if len(str) > 0 and str[0] == '\n': + start += 1 + if len(str) > 1 and str[end - 1] == '\n': + end -= 1 + + return str[start:end] + +# How long to wait between mails (in seconds); the idea of waiting +# is to try to make the sequence of mails we send out in order +# actually get delivered in order. The waiting is done in a forked +# subprocess and doesn't stall completion of the main script. +EMAIL_DELAY = 5 + +# Some line that can never appear in any email we send out +EMAIL_BOUNDARY="---@@@--- gnome-git-email ---@@@---\n" + +# Run in subprocess +def _do_send_emails(email_in): + email_files = [] + current_file = None + last_line = None + + # Read emails from the input pipe and write each to a file + for line in email_in: + if current_file is None: + current_file, filename = tempfile.mkstemp(suffix=".mail", prefix="gnome-post-receive-email-") + email_files.append(filename) + + if line == EMAIL_BOUNDARY: + # Strip the last line if blank; see comment when writing + # the email boundary for rationale + if last_line.strip() != "": + os.write(current_file, last_line) + last_line = None + os.close(current_file) + current_file = None + else: + if last_line is not None: + os.write(current_file, last_line) + last_line = line + + if current_file is not None: + if last_line is not None: + os.write(current_file, last_line) + os.close(current_file) + + # We're done interacting with the parent process, the rest happens + # asynchronously; send out the emails one by one and remove the + # temporary files + for i, filename in enumerate(email_files): + if i != 0: + time.sleep(EMAIL_DELAY) + + f = open(filename, "r") + process = Popen(["/usr/sbin/sendmail", "-t"], + stdout=None, stderr=None, stdin=f) + process.wait() + f.close() + + os.remove(filename) + +email_file = None + +# Start a new outgoing email; returns a file object that the +# email should be written to. Call end_email() when done +def start_email(): + global email_file + if email_file is None: + email_pipe = os.pipe() + pid = os.fork() + if pid == 0: + # The child + + os.close(email_pipe[1]) + email_in = os.fdopen(email_pipe[0]) + + # Redirect stdin/stdout/stderr to/from /dev/null + devnullin = os.open("/dev/null", os.O_RDONLY) + os.close(0) + os.dup2(devnullin, 0) + + devnullout = os.open("/dev/null", os.O_WRONLY) + os.close(1) + os.dup2(devnullout, 1) + os.close(2) + os.dup2(devnullout, 2) + os.close(devnullout) + + # Fork again to daemonize + if os.fork() > 0: + sys.exit(0) + + try: + _do_send_emails(email_in) + except Exception: + import syslog + import traceback + + syslog.openlog(os.path.basename(sys.argv[0])) + syslog.syslog(syslog.LOG_ERR, "Unexpected exception sending mail") + for line in traceback.format_exc().strip().split("\n"): + syslog.syslog(syslog.LOG_ERR, line) + + sys.exit(0) + + email_file = os.fdopen(email_pipe[1], "w") + else: + # The email might not end with a newline, so add one. We'll + # strip the last line, if blank, when emails, so the net effect + # is to add a newline to messages without one + email_file.write("\n") + email_file.write(EMAIL_BOUNDARY) + + return email_file + +# Finish an email started with start_email +def end_email(): + global email_file + email_file.flush() |