Index: mailer.py =================================================================== --- mailer.py (revision 35667) +++ mailer.py (working copy) @@ -182,7 +182,7 @@ def __init__(self, cfg, repos, prefix_param): OutputBase.__init__(self, cfg, repos, prefix_param) - def start(self, group, params): + def start(self, group, params, paths): # whitespace (or another character) separated list of addresses # which must be split into a clean list to_addr_in = self.cfg.get('to_addr', group, params) @@ -209,7 +209,60 @@ and self.reply_to[2] == ']': self.reply_to = self.reply_to[3:] - def mail_headers(self, group, params): + def mail_headers(self, group, params, paths): + h_path = self.cfg.get('headers_path', group, params) + if len(h_path) >= 3 and h_path[0] == '[' \ + and h_path[2] == ']': + headers_path= \ + [_f for _f in h_path[3:].split(h_path[1]) if _f] + else: + headers_path = [_f for _f in h_path.split() if _f] + try: + h_path = headers_path[0].split('/') + except IndexError: + pass + h_length = len(h_path) + header_list = [] + for p in paths: + plist = p.split('/') + for x in range(h_length): + # traverse from start to first h_path[x] == ... + if '_' == h_path[x]: + continue + if '...' == h_path[x]: + break + try: + name = h_path[x] + except IndexError: + name = '' + try: + value = plist[x] + except IndexError: + value = '' + if '' != name and '' != value: + extra_header = 'X-' + '%s: %s' % (name, value) + header_list.append(extra_header) + i=-1 + while i>=-h_length: + # traverse from end to first h_path[i] == ... + if '_' == h_path[i]: + i=i-1 + continue + if '...' == h_path[i]: + i=i-1 + break + try: + name = h_path[i] + except IndexError: + name = '' + try: + value = plist[i] + except IndexError: + value = '' + if '' != name and '' != value: + extra_header = 'X-' + '%s: %s' % (name, value) + header_list.append(extra_header) + i=i-1 subject = self.make_subject(group, params) try: subject.encode('ascii') @@ -222,22 +275,26 @@ 'MIME-Version: 1.0\n' \ 'Content-Type: text/plain; charset=UTF-8\n' \ 'Content-Transfer-Encoding: 8bit\n' \ - % (self.from_addr, ', '.join(self.to_addrs), subject) + 'X-author: %s\n' \ + 'X-group: %s' \ + % (self.from_addr, ', '.join(self.to_addrs), subject, params['author'], group) + for y in header_list: + hdrs = '%s\n%s' % (hdrs, y) if self.reply_to: - hdrs = '%sReply-To: %s\n' % (hdrs, self.reply_to) - return hdrs + '\n' + hdrs = '%s\nReply-To: %s\n' % (hdrs, self.reply_to) + return hdrs + '\n\n' class SMTPOutput(MailedOutput): "Deliver a mail message to an MTA using SMTP." - def start(self, group, params): - MailedOutput.start(self, group, params) + def start(self, group, params, paths): + MailedOutput.start(self, group, params, paths) self.buffer = StringIO() self.write = self.buffer.write - self.write(self.mail_headers(group, params)) + self.write(self.mail_headers(group, params, paths)) def finish(self): server = smtplib.SMTP(self.cfg.general.smtp_hostname) @@ -272,8 +329,8 @@ # figure out the command for delivery self.cmd = cfg.general.mail_command.split() - def start(self, group, params): - MailedOutput.start(self, group, params) + def start(self, group, params, paths): + MailedOutput.start(self, group, params, paths) ### gotta fix this. this is pretty specific to sendmail and qmail's ### mailwrapper program. should be able to use option param substitution @@ -285,7 +342,7 @@ self.write = self.pipe.stdin.write # start writing out the mail message - self.write(self.mail_headers(group, params)) + self.write(self.mail_headers(group, params, paths)) def finish(self): # signal that we're done sending content @@ -376,7 +433,7 @@ renderer = TextCommitRenderer(self.output) for (group, param_tuple), (params, paths) in self.groups.items(): - self.output.start(group, params) + self.output.start(group, params, paths) # generate the content for this group and set of params generate_content(renderer, self.cfg, self.repos, self.changelist, Index: mailer.conf.example =================================================================== --- mailer.conf.example (revision 35667) +++ mailer.conf.example (working copy) @@ -243,6 +243,56 @@ # Set to 0 to turn off. #truncate_subject = 200 +# extra headers in the emails with the names from the actual path like: +# real_path = trunk/tools/hook-scripts/mailer/mailer.py +# headers_path = branch/.../file +# this means that the emails would include these extra headers: +# X-branch: trunk +# X-file: mailer.py +# +# headers_path = branch/module/.../directory/file +# + the same real path would give: +# X-branch: trunk +# X-module: tools +# X-directory: mailer +# X-file: mailer.py +# +# the single char _ means a single pathsgment, aka what is between the 2 / +# but it is not used for anything in the headers. It is entirely possible +# to have one or more _ like a/_/_/b +# headers_path = branch/_/module/.../directory/file +# X-branch: trunk +# X-module: hook-scripts +# X-directory: mailer +# X-file: mailer.py +# +# The 3 chars ... means 0 or more pathsegments. These are not included +# in the email headers as well. However they also signal the end of +# processing the headers_path from this side. First the headers_path +# is processed from left to right, until the first ... or end of path +# Then the path is processed from right to left, until a ... or the +# beginning of path is reached. Lets see some new examples: +# headers_path = ... (same as empty headers_path) +# headers_path = branch/.../foobar/.../file +# foobar will not be an email header +# +# it is also perfectly legal to have a headers_path longer than the +# real path. If this happens, some fields will just have no value, +# and thus not included in the email +# +# overlapping pathsegments are also legal +# headers_path = branch/module/submod/directory/subdir/.../foo/bar/file +# X-branch: trunk +# X-module: tools +# X-submod: hook-scripts +# X-directory: mailer +# X-subdir: mailer.py +# X-foo: hook-scripts +# X-bar: mailer +# X-file: mailer.py +# +# The X-author: and X-group: header is always included. + # -------------------------------------------------------------------------- [maps]