##// END OF EJS Templates
Expand import * to allow Pyflakes to find problems
Expand import * to allow Pyflakes to find problems

File last commit:

r6211:f89fd07f default
r6211:f89fd07f default
Show More
notify.py
285 lines | 10.2 KiB | text/x-python | PythonLexer
Vadim Gelfer
add email notification hook. hook written in python....
r2203 # notify.py - email notifications for mercurial
#
# Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com>
#
# This software may be used and distributed according to the terms
# of the GNU General Public License, incorporated herein by reference.
#
# hook extension to email notifications to people when changesets are
# committed to a repo they subscribe to.
#
# default mode is to print messages to stdout, for testing and
# configuring.
#
# to use, configure notify extension and enable in hgrc like this:
#
# [extensions]
# hgext.notify =
#
# [hooks]
# # one email for each incoming changeset
# incoming.notify = python:hgext.notify.hook
# # batch emails when many changesets incoming at one time
# changegroup.notify = python:hgext.notify.hook
#
# [notify]
# # config items go in here
#
# config items:
#
# REQUIRED:
# config = /path/to/file # file containing subscriptions
#
# OPTIONAL:
# test = True # print messages to stdout for testing
# strip = 3 # number of slashes to strip for url paths
# domain = example.com # domain to use if committer missing domain
# style = ... # style file to use when formatting email
# template = ... # template to use when formatting email
# incoming = ... # template to use when run as incoming hook
# changegroup = ... # template when run as changegroup hook
# maxdiff = 300 # max lines of diffs to include (0=none, -1=all)
# maxsubject = 67 # truncate subject line longer than this
Aurelien Jacobs
document the diffstat option of the notify extension
r3397 # diffstat = True # add a diffstat before the diff content
Vadim Gelfer
localrepository.addchangegroup: add more source infos to hooks
r2230 # sources = serve # notify if source of incoming changes in this list
# # (serve == ssh or http, push, pull, bundle)
Vadim Gelfer
add email notification hook. hook written in python....
r2203 # [email]
# from = user@host.com # email address to send as if none given
# [web]
# baseurl = http://hgserver/... # root of hg web site for browsing commits
#
# notify config file has same format as regular hgrc. it has two
# sections so you can express subscriptions in whatever way is handier
# for you.
#
# [usersubs]
# # key is subscriber email, value is ","-separated list of glob patterns
# user@host = pattern
#
# [reposubs]
# # key is glob pattern, value is ","-separated list of subscriber emails
# pattern = user@host
#
# glob patterns are matched against path to repo root.
#
# if you like, you can put notify config file in repo that users can
# push changes to, they can manage their own subscriptions.
Matt Mackall
Simplify i18n imports
r3891 from mercurial.i18n import _
Joel Rosdahl
Expand import * to allow Pyflakes to find problems
r6211 from mercurial.node import bin, short
Matt Mackall
Replace demandload with new demandimport
r3877 from mercurial import patch, cmdutil, templater, util, mail
import email.Parser, fnmatch, socket, time
Vadim Gelfer
add email notification hook. hook written in python....
r2203
# template for single changeset can include email headers.
single_template = '''
Subject: changeset in {webroot}: {desc|firstline|strip}
From: {author}
changeset {node|short} in {root}
details: {baseurl}{webroot}?cmd=changeset;node={node|short}
description:
\t{desc|tabindent|strip}
'''.lstrip()
# template for multiple changesets should not contain email headers,
# because only first set of headers will be used and result will look
# strange.
multiple_template = '''
changeset {node|short} in {root}
details: {baseurl}{webroot}?cmd=changeset;node={node|short}
summary: {desc|firstline}
'''
deftemplates = {
'changegroup': multiple_template,
Thomas Arendsen Hein
Fixed indentation in hgext/notify.py
r4498 }
Bryan O'Sullivan
patch queue: notify.patch
r2201
class notifier(object):
Vadim Gelfer
add email notification hook. hook written in python....
r2203 '''email notification class.'''
def __init__(self, ui, repo, hooktype):
Bryan O'Sullivan
patch queue: notify.patch
r2201 self.ui = ui
Vadim Gelfer
notify: add debug output. do not fail if no config file....
r2329 cfg = self.ui.config('notify', 'config')
if cfg:
Alexis S. L. Carvalho
use ui.readsections in the notify extension
r3434 self.ui.readsections(cfg, 'usersubs', 'reposubs')
Bryan O'Sullivan
patch queue: notify.patch
r2201 self.repo = repo
Vadim Gelfer
add email notification hook. hook written in python....
r2203 self.stripcount = int(self.ui.config('notify', 'strip', 0))
Bryan O'Sullivan
patch queue: notify.patch
r2201 self.root = self.strip(self.repo.root)
Vadim Gelfer
add email notification hook. hook written in python....
r2203 self.domain = self.ui.config('notify', 'domain')
self.subs = self.subscribers()
mapfile = self.ui.config('notify', 'style')
template = (self.ui.config('notify', hooktype) or
self.ui.config('notify', 'template'))
Matt Mackall
fix notify with new ui buffering
r3739 self.t = cmdutil.changeset_templater(self.ui, self.repo,
Matt Mackall
Remove deprecated old-style branch support
r3876 False, mapfile, False)
Vadim Gelfer
add email notification hook. hook written in python....
r2203 if not mapfile and not template:
template = deftemplates.get(hooktype) or single_template
if template:
template = templater.parsestring(template, quoted=False)
self.t.use_template(template)
Bryan O'Sullivan
patch queue: notify.patch
r2201
def strip(self, path):
Vadim Gelfer
add email notification hook. hook written in python....
r2203 '''strip leading slashes from local path, turn into web-safe path.'''
Bryan O'Sullivan
patch queue: notify.patch
r2201 path = util.pconvert(path)
count = self.stripcount
Vadim Gelfer
notify: fix off by one error.
r2326 while count > 0:
Bryan O'Sullivan
patch queue: notify.patch
r2201 c = path.find('/')
if c == -1:
break
path = path[c+1:]
count -= 1
return path
Vadim Gelfer
add email notification hook. hook written in python....
r2203 def fixmail(self, addr):
'''try to clean up email addresses.'''
Matt Mackall
templater: move email function to util
r5975 addr = util.email(addr.strip())
Alexis S. L. Carvalho
notify: don't try to fix addresses if notify.domain is not set
r4094 if self.domain:
a = addr.find('@localhost')
if a != -1:
addr = addr[:a]
if '@' not in addr:
return addr + '@' + self.domain
Vadim Gelfer
add email notification hook. hook written in python....
r2203 return addr
Bryan O'Sullivan
patch queue: notify.patch
r2201 def subscribers(self):
Vadim Gelfer
add email notification hook. hook written in python....
r2203 '''return list of email addresses of subscribers to this repo.'''
subs = {}
for user, pats in self.ui.configitems('usersubs'):
for pat in pats.split(','):
if fnmatch.fnmatch(self.repo.root, pat.strip()):
subs[self.fixmail(user)] = 1
Bryan O'Sullivan
patch queue: notify.patch
r2201 for pat, users in self.ui.configitems('reposubs'):
Vadim Gelfer
add email notification hook. hook written in python....
r2203 if fnmatch.fnmatch(self.repo.root, pat):
for user in users.split(','):
subs[self.fixmail(user)] = 1
subs = subs.keys()
Bryan O'Sullivan
patch queue: notify.patch
r2201 subs.sort()
return subs
def url(self, path=None):
return self.ui.config('web', 'baseurl') + (path or self.root)
Vadim Gelfer
add email notification hook. hook written in python....
r2203 def node(self, node):
'''format one changeset.'''
self.t.show(changenode=node, changes=self.repo.changelog.read(node),
baseurl=self.ui.config('web', 'baseurl'),
root=self.repo.root,
webroot=self.root)
Vadim Gelfer
localrepository.addchangegroup: add more source infos to hooks
r2230 def skipsource(self, source):
'''true if incoming changes from this source should be skipped.'''
ok_sources = self.ui.config('notify', 'sources', 'serve').split()
return source not in ok_sources
Matt Mackall
fix notify with new ui buffering
r3739 def send(self, node, count, data):
Vadim Gelfer
add email notification hook. hook written in python....
r2203 '''send message.'''
p = email.Parser.Parser()
Matt Mackall
fix notify with new ui buffering
r3739 msg = p.parsestr(data)
Vadim Gelfer
add email notification hook. hook written in python....
r2203
def fix_subject():
'''try to make subject line exist and be useful.'''
subject = msg['Subject']
if not subject:
if count > 1:
subject = _('%s: %d new changesets') % (self.root, count)
else:
changes = self.repo.changelog.read(node)
s = changes[4].lstrip().split('\n', 1)[0].rstrip()
subject = '%s: %s' % (self.root, s)
maxsubject = int(self.ui.config('notify', 'maxsubject', 67))
if maxsubject and len(subject) > maxsubject:
subject = subject[:maxsubject-3] + '...'
del msg['Subject']
msg['Subject'] = subject
def fix_sender():
'''try to make message have proper sender.'''
sender = msg['From']
if not sender:
sender = self.ui.config('email', 'from') or self.ui.username()
if '@' not in sender or '@localhost' in sender:
sender = self.fixmail(sender)
del msg['From']
msg['From'] = sender
Mathieu Clabaut
Add sending date to notify message....
r4479 msg['Date'] = util.datestr(date=util.makedate(),
Thomas Arendsen Hein
Fixed indentation in hgext/notify.py
r4498 format="%a, %d %b %Y %H:%M:%S",
timezone=True)
Vadim Gelfer
add email notification hook. hook written in python....
r2203 fix_subject()
fix_sender()
msg['X-Hg-Notification'] = 'changeset ' + short(node)
if not msg['Message-Id']:
msg['Message-Id'] = ('<hg.%s.%s.%s@%s>' %
(short(node), int(time.time()),
hash(self.repo.root), socket.getfqdn()))
Vadim Gelfer
localrepository.addchangegroup: add more source infos to hooks
r2230 msg['To'] = ', '.join(self.subs)
Vadim Gelfer
add email notification hook. hook written in python....
r2203
msgtext = msg.as_string(0)
if self.ui.configbool('notify', 'test', True):
self.ui.write(msgtext)
if not msgtext.endswith('\n'):
self.ui.write('\n')
Bryan O'Sullivan
patch queue: notify.patch
r2201 else:
Vadim Gelfer
notify: add debug output. do not fail if no config file....
r2329 self.ui.status(_('notify: sending %d subscribers %d changes\n') %
Thomas Arendsen Hein
Fixed indentation in hgext/notify.py
r4498 (len(self.subs), count))
Matt Mackall
templater: move email function to util
r5975 mail.sendmail(self.ui, util.email(msg['From']),
Matt Mackall
Move ui.sendmail to mail.connect/sendmail
r2889 self.subs, msgtext)
Bryan O'Sullivan
patch queue: notify.patch
r2201
"Aurelien Jacobs "
notify changeset diff should be against current node instead of tip
r2296 def diff(self, node, ref):
Vadim Gelfer
add email notification hook. hook written in python....
r2203 maxdiff = int(self.ui.config('notify', 'maxdiff', 300))
if maxdiff == 0:
return
Vadim Gelfer
notify extension: generate right number of diffs
r2224 prev = self.repo.changelog.parents(node)[0]
Matt Mackall
fix notify with new ui buffering
r3739 self.ui.pushbuffer()
patch.diff(self.repo, prev, ref)
difflines = self.ui.popbuffer().splitlines(1)
Matt Doar
Add support for diffstat in commit emails, and move diffstat from...
r3096 if self.ui.configbool('notify', 'diffstat', True):
s = patch.diffstat(difflines)
Sean Dague
Prevent type exception on concatenation if diffstat returns None....
r4077 # s may be nil, don't include the header if it is
if s:
self.ui.write('\ndiffstat:\n\n%s' % s)
Vadim Gelfer
add email notification hook. hook written in python....
r2203 if maxdiff > 0 and len(difflines) > maxdiff:
Matt Mackall
fix notify with new ui buffering
r3739 self.ui.write(_('\ndiffs (truncated from %d to %d lines):\n\n') %
(len(difflines), maxdiff))
Vadim Gelfer
add email notification hook. hook written in python....
r2203 difflines = difflines[:maxdiff]
elif difflines:
Matt Mackall
fix notify with new ui buffering
r3739 self.ui.write(_('\ndiffs (%d lines):\n\n') % len(difflines))
self.ui.write(*difflines)
Bryan O'Sullivan
patch queue: notify.patch
r2201
Vadim Gelfer
localrepository.addchangegroup: add more source infos to hooks
r2230 def hook(ui, repo, hooktype, node=None, source=None, **kwargs):
Vadim Gelfer
add email notification hook. hook written in python....
r2203 '''send email notifications to interested subscribers.
if used as changegroup hook, send one email for all changesets in
changegroup. else send one email per changeset.'''
n = notifier(ui, repo, hooktype)
Vadim Gelfer
notify: add debug output. do not fail if no config file....
r2329 if not n.subs:
Marcos Chaves
fix warnings generated by pygettext.py.
r3679 ui.debug(_('notify: no subscribers to repo %s\n') % n.root)
Vadim Gelfer
notify: add debug output. do not fail if no config file....
r2329 return
if n.skipsource(source):
ui.debug(_('notify: changes have source "%s" - skipping\n') %
Thomas Arendsen Hein
Fixed indentation in hgext/notify.py
r4498 source)
Vadim Gelfer
localrepository.addchangegroup: add more source infos to hooks
r2230 return
Vadim Gelfer
add email notification hook. hook written in python....
r2203 node = bin(node)
Matt Mackall
fix notify with new ui buffering
r3739 ui.pushbuffer()
Vadim Gelfer
add email notification hook. hook written in python....
r2203 if hooktype == 'changegroup':
start = repo.changelog.rev(node)
end = repo.changelog.count()
count = end - start
for rev in xrange(start, end):
n.node(repo.changelog.node(rev))
"Aurelien Jacobs "
notify changeset diff should be against current node instead of tip
r2296 n.diff(node, repo.changelog.tip())
Vadim Gelfer
add email notification hook. hook written in python....
r2203 else:
count = 1
n.node(node)
"Aurelien Jacobs "
notify changeset diff should be against current node instead of tip
r2296 n.diff(node, node)
Matt Mackall
fix notify with new ui buffering
r3739 data = ui.popbuffer()
n.send(node, count, data)