1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
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()
|