diff options
Diffstat (limited to 'CVSROOT/syncmail')
-rwxr-xr-x | CVSROOT/syncmail | 217 |
1 files changed, 0 insertions, 217 deletions
diff --git a/CVSROOT/syncmail b/CVSROOT/syncmail deleted file mode 100755 index fa24a8052a..0000000000 --- a/CVSROOT/syncmail +++ /dev/null | |||
@@ -1,217 +0,0 @@ | |||
1 | #! /usr/bin/python | ||
2 | # -*- Python -*- | ||
3 | |||
4 | """Complicated notification for CVS checkins. | ||
5 | |||
6 | This script is used to provide email notifications of changes to the CVS | ||
7 | repository. These email changes will include context diffs of the changes. | ||
8 | Really big diffs will be trimmed. | ||
9 | |||
10 | This script is run from a CVS loginfo file (see $CVSROOT/CVSROOT/loginfo). To | ||
11 | set this up, create a loginfo entry that looks something like this: | ||
12 | |||
13 | mymodule /path/to/this/script %%s some-email-addr@your.domain | ||
14 | |||
15 | In this example, whenever a checkin that matches `mymodule' is made, this | ||
16 | script is invoked, which will generate the diff containing email, and send it | ||
17 | to some-email-addr@your.domain. | ||
18 | |||
19 | Note: This module used to also do repository synchronizations via | ||
20 | rsync-over-ssh, but since the repository has been moved to SourceForge, | ||
21 | this is no longer necessary. The syncing functionality has been ripped | ||
22 | out in the 3.0, which simplifies it considerably. Access the 2.x versions | ||
23 | to refer to this functionality. Because of this, the script is misnamed. | ||
24 | |||
25 | It no longer makes sense to run this script from the command line. Doing so | ||
26 | will only print out this usage information. | ||
27 | |||
28 | Usage: | ||
29 | |||
30 | %(PROGRAM)s [options] <%%S> email-addr [email-addr ...] | ||
31 | |||
32 | Where options is: | ||
33 | |||
34 | --cvsroot=<path> | ||
35 | Use <path> as the environment variable CVSROOT. Otherwise this | ||
36 | variable must exist in the environment. | ||
37 | |||
38 | --help | ||
39 | -h | ||
40 | Print this text. | ||
41 | |||
42 | --context=# | ||
43 | -C # | ||
44 | Include # lines of context around lines that differ (default: 2). | ||
45 | |||
46 | -c | ||
47 | Produce a context diff (default). | ||
48 | |||
49 | -u | ||
50 | Produce a unified diff (smaller, but harder to read). | ||
51 | |||
52 | -U user | ||
53 | Mark diff as made by user. | ||
54 | |||
55 | <%%S> | ||
56 | CVS %%s loginfo expansion. When invoked by CVS, this will be a single | ||
57 | string containing the directory the checkin is being made in, relative | ||
58 | to $CVSROOT, followed by the list of files that are changing. If the | ||
59 | %%s in the loginfo file is %%{sVv}, context diffs for each of the | ||
60 | modified files are included in any email messages that are generated. | ||
61 | |||
62 | email-addrs | ||
63 | At least one email address. | ||
64 | |||
65 | """ | ||
66 | |||
67 | import os | ||
68 | import sys | ||
69 | import string | ||
70 | import time | ||
71 | import getopt | ||
72 | |||
73 | # Notification command | ||
74 | MAILCMD = '/bin/mail -s "%(username)s: %(SUBJECT)s" %(PEOPLE)s 2>&1 > /dev/null' | ||
75 | |||
76 | # Diff trimming stuff | ||
77 | DIFF_HEAD_LINES = 20 | ||
78 | DIFF_TAIL_LINES = 20 | ||
79 | DIFF_TRUNCATE_IF_LARGER = 1000 | ||
80 | |||
81 | PROGRAM = sys.argv[0] | ||
82 | |||
83 | |||
84 | |||
85 | def usage(code, msg=''): | ||
86 | print __doc__ % globals() | ||
87 | if msg: | ||
88 | print msg | ||
89 | sys.exit(code) | ||
90 | |||
91 | |||
92 | |||
93 | def calculate_diff(filespec, contextlines): | ||
94 | try: | ||
95 | file, oldrev, newrev = string.split(filespec, ',') | ||
96 | except ValueError: | ||
97 | # No diff to report | ||
98 | return '***** Bogus filespec: %s' % filespec | ||
99 | if oldrev == 'NONE': | ||
100 | try: | ||
101 | if os.path.exists(file): | ||
102 | fp = open(file) | ||
103 | else: | ||
104 | update_cmd = 'cvs -fn update -r %s -p %s' % (newrev, file) | ||
105 | fp = os.popen(update_cmd) | ||
106 | lines = fp.readlines() | ||
107 | fp.close() | ||
108 | lines.insert(0, '--- NEW FILE: %s ---\n' % file) | ||
109 | except IOError, e: | ||
110 | lines = ['***** Error reading new file: ', | ||
111 | str(e), '\n***** file: ', file, ' cwd: ', os.getcwd()] | ||
112 | elif newrev == 'NONE': | ||
113 | lines = ['--- %s DELETED ---\n' % file] | ||
114 | else: | ||
115 | # This /has/ to happen in the background, otherwise we'll run into CVS | ||
116 | # lock contention. What a crock. | ||
117 | if contextlines > 0: | ||
118 | difftype = "-C " + str(contextlines) | ||
119 | else: | ||
120 | difftype = "-uN" | ||
121 | diffcmd = '/usr/bin/cvs -f diff -kk %s -b -r %s -r %s %s' % ( | ||
122 | difftype, oldrev, newrev, file) | ||
123 | fp = os.popen(diffcmd) | ||
124 | lines = fp.readlines() | ||
125 | sts = fp.close() | ||
126 | # ignore the error code, it always seems to be 1 :( | ||
127 | ## if sts: | ||
128 | ## return 'Error code %d occurred during diff\n' % (sts >> 8) | ||
129 | if len(lines) > DIFF_TRUNCATE_IF_LARGER: | ||
130 | removedlines = len(lines) - DIFF_HEAD_LINES - DIFF_TAIL_LINES | ||
131 | del lines[DIFF_HEAD_LINES:-DIFF_TAIL_LINES] | ||
132 | lines.insert(DIFF_HEAD_LINES, | ||
133 | '[...%d lines suppressed...]\n' % removedlines) | ||
134 | return string.join(lines, '') | ||
135 | |||
136 | |||
137 | |||
138 | def blast_mail(mailcmd, filestodiff, contextlines): | ||
139 | # cannot wait for child process or that will cause parent to retain cvs | ||
140 | # lock for too long. Urg! | ||
141 | if not os.fork(): | ||
142 | # in the child | ||
143 | # give up the lock you cvs thang! | ||
144 | time.sleep(2) | ||
145 | fp = os.popen(mailcmd, 'w') | ||
146 | fp.write(sys.stdin.read()) | ||
147 | fp.write('\n') | ||
148 | # append the diffs if available | ||
149 | for file in filestodiff: | ||
150 | fp.write(calculate_diff(file, contextlines)) | ||
151 | fp.write('\n') | ||
152 | fp.close() | ||
153 | # doesn't matter what code we return, it isn't waited on | ||
154 | os._exit(0) | ||
155 | |||
156 | |||
157 | |||
158 | # scan args for options | ||
159 | def main(): | ||
160 | contextlines = 2 | ||
161 | try: | ||
162 | opts, args = getopt.getopt(sys.argv[1:], 'hC:cuU:', | ||
163 | ['context=', 'cvsroot=', 'help']) | ||
164 | except getopt.error, msg: | ||
165 | usage(1, msg) | ||
166 | |||
167 | username = 'unknown' | ||
168 | |||
169 | # parse the options | ||
170 | for opt, arg in opts: | ||
171 | if opt in ('-h', '--help'): | ||
172 | usage(0) | ||
173 | elif opt == '--cvsroot': | ||
174 | os.environ['CVSROOT'] = arg | ||
175 | elif opt in ('-C', '--context'): | ||
176 | contextlines = int(arg) | ||
177 | elif opt == '-c': | ||
178 | if contextlines <= 0: | ||
179 | contextlines = 2 | ||
180 | elif opt == '-u': | ||
181 | contextlines = 0 | ||
182 | elif opt == '-U': | ||
183 | username = arg | ||
184 | |||
185 | # What follows is the specification containing the files that were | ||
186 | # modified. The argument actually must be split, with the first component | ||
187 | # containing the directory the checkin is being made in, relative to | ||
188 | # $CVSROOT, followed by the list of files that are changing. | ||
189 | if not args: | ||
190 | usage(1, 'No CVS module specified') | ||
191 | SUBJECT = args[0] | ||
192 | specs = string.split(args[0]) | ||
193 | del args[0] | ||
194 | |||
195 | # The remaining args should be the email addresses | ||
196 | if not args: | ||
197 | usage(1, 'No recipients specified') | ||
198 | |||
199 | # Now do the mail command | ||
200 | PEOPLE = string.join(args) | ||
201 | mailcmd = MAILCMD % vars() | ||
202 | |||
203 | print 'Mailing %s...' % PEOPLE | ||
204 | if specs == ['-', 'Imported', 'sources']: | ||
205 | return | ||
206 | if specs[-3:] == ['-', 'New', 'directory']: | ||
207 | del specs[-3:] | ||
208 | print 'Generating notification message...' | ||
209 | blast_mail(mailcmd, specs[1:], contextlines) | ||
210 | print 'Generating notification message... done.' | ||
211 | |||
212 | |||
213 | |||
214 | if __name__ == '__main__': | ||
215 | main() | ||
216 | sys.exit(0) | ||
217 | |||