configuration option. The From address and the e-mail format are
generated from the template file passed as argument to '--template'
(defaulting to '.git/patchmail.tmpl' or
-'~/.stgit/templates/patchmail.tmpl' or or
-'/usr/share/stgit/templates/patchmail.tmpl'). The To/Cc/Bcc addresses
-can either be added to the template file or passed via the
-corresponding command line options.
+'~/.stgit/templates/patchmail.tmpl' or
+'/usr/share/stgit/templates/patchmail.tmpl').
+
+The To/Cc/Bcc addresses can either be added to the template file or
+passed via the corresponding command line options. They can be e-mail
+addresses or aliases which are automatically expanded to the values
+stored in the [mail "alias"] section of GIT configuration files.
A preamble e-mail can be sent using the '--cover' and/or
'--edit-cover' options. The first allows the user to specify a file to
'--smtp-password' options, also available as configuration settings:
'smtpuser' and 'smtppassword'.
-The template e-mail headers and body must be separated by
-'%(endofheaders)s' variable, which is replaced by StGIT with
-additional headers and a blank line. The patch e-mail template accepts
-the following variables:
+The patch e-mail template accepts the following variables:
%(patch)s - patch name
- %(maintainer)s - 'authname <authemail>' as read from the config file
+ %(sender)s - 'sender' or 'authname <authemail>' as per the config file
%(shortdescr)s - the first line of the patch description
%(longdescr)s - the rest of the patch description, after the first line
- %(endofheaders)s - delimiter between e-mail headers and body
%(diff)s - unified diff of the patch
%(diffstat)s - diff statistics
- %(date)s - current date/time
%(version)s - ' version' string passed on the command line (or empty)
%(prefix)s - 'prefix ' string passed on the command line
%(patchnr)s - patch number
%(totalnr)s - total number of patches to be sent
%(number)s - empty if only one patch is sent or ' patchnr/totalnr'
+ %(fromauth)s - 'From: author\\n\\n' if different from sender
%(authname)s - author's name
%(authemail)s - author's email
%(authdate)s - patch creation date
%(commname)s - committer's name
%(commemail)s - committer's e-mail
-For the preamble e-mail template, only the %(maintainer)s, %(date)s,
-%(endofheaders)s, %(version)s, %(patchnr)s, %(totalnr)s and %(number)s
-variables are supported."""
+For the preamble e-mail template, only the %(sender)s, %(version)s,
+%(patchnr)s, %(totalnr)s and %(number)s variables are supported."""
options = [make_option('-a', '--all',
help = 'e-mail all the applied patches',
help = 'username for SMTP authentication'),
make_option('-b', '--branch',
help = 'use BRANCH instead of the default one'),
+ make_option('--binary',
+ help = 'output a diff even for binary files',
+ action = 'store_true'),
make_option('-m', '--mbox',
help = 'generate an mbox file instead of sending',
action = 'store_true')]
-def __get_maintainer():
+def __get_sender():
"""Return the 'authname <authemail>' string as read from the
configuration file
"""
- if config.has_option('stgit', 'authname') \
- and config.has_option('stgit', 'authemail'):
- return '%s <%s>' % (config.get('stgit', 'authname'),
- config.get('stgit', 'authemail'))
- else:
- return None
+ sender=config.get('stgit.sender')
+ if not sender:
+ try:
+ sender = str(git.user())
+ except git.GitException:
+ sender = str(git.author())
+
+ if not sender:
+ raise CmdException, 'unknown sender details'
-def __parse_addresses(addresses):
+ return address_or_alias(sender)
+
+def __parse_addresses(msg):
"""Return a two elements tuple: (from, [to])
"""
- def __addr_list(addrs):
- m = re.search('[^@\s<,]+@[^>\s,]+', addrs);
- if (m == None):
- return []
- return [ m.group() ] + __addr_list(addrs[m.end():])
-
- from_addr_list = []
- to_addr_list = []
- for line in addresses.split('\n'):
- if re.match('from:\s+', line, re.I):
- from_addr_list += __addr_list(line)
- elif re.match('(to|cc|bcc):\s+', line, re.I):
- to_addr_list += __addr_list(line)
+ def __addr_list(msg, header):
+ return [name_addr[1] for name_addr in
+ email.Utils.getaddresses(msg.get_all(header, []))]
+ from_addr_list = __addr_list(msg, 'From')
if len(from_addr_list) == 0:
raise CmdException, 'No "From" address'
+
+ to_addr_list = __addr_list(msg, 'To') + __addr_list(msg, 'Cc') \
+ + __addr_list(msg, 'Bcc')
if len(to_addr_list) == 0:
raise CmdException, 'No "To/Cc/Bcc" addresses'
del msg[header]
if crt_addr:
- msg[header] = ', '.join([crt_addr, addr])
+ msg[header] = address_or_alias(', '.join([crt_addr, addr]))
else:
- msg[header] = addr
+ msg[header] = address_or_alias(addr)
to_addr = ''
cc_addr = ''
bcc_addr = ''
- if config.has_option('stgit', 'autobcc'):
- autobcc = config.get('stgit', 'autobcc')
- else:
- autobcc = ''
+ autobcc = config.get('stgit.autobcc') or ''
if options.to:
to_addr = ', '.join(options.to)
# encode the body and set the MIME and encoding headers
msg.set_charset(charset)
-def edit_message(msg):
+def __edit_message(msg):
fname = '.stgitmail.txt'
# create the initial file
f.write(msg)
f.close()
- # the editor
- if config.has_option('stgit', 'editor'):
- editor = config.get('stgit', 'editor')
- elif 'EDITOR' in os.environ:
- editor = os.environ['EDITOR']
- else:
- editor = 'vi'
- editor += ' %s' % fname
-
- print 'Invoking the editor: "%s"...' % editor,
- sys.stdout.flush()
- print 'done (exit code: %d)' % os.system(editor)
+ call_editor(fname)
# read the message back
f = file(fname)
def __build_cover(tmpl, total_nr, msg_id, options):
"""Build the cover message (series description) to be sent via SMTP
"""
- maintainer = __get_maintainer()
- if not maintainer:
- maintainer = ''
+ sender = __get_sender()
if options.version:
version_str = ' %s' % options.version
else:
number_str = ''
- tmpl_dict = {'maintainer': maintainer,
+ tmpl_dict = {'sender': sender,
+ # for backward template compatibility
+ 'maintainer': sender,
# for backward template compatibility
'endofheaders': '',
# for backward template compatibility
raise CmdException, 'Only "%(name)s" variables are ' \
'supported in the patch template'
+ if options.edit_cover:
+ msg_string = __edit_message(msg_string)
+
# The Python email message
try:
msg = email.message_from_string(msg_string)
__build_extra_headers(msg, msg_id, options.refid)
__encode_message(msg)
- msg_string = msg.as_string(options.mbox)
-
- if options.edit_cover:
- msg_string = edit_message(msg_string)
-
- return msg_string.strip('\n')
+ return msg
def __build_message(tmpl, patch, patch_nr, total_nr, msg_id, ref_id, options):
"""Build the message to be sent via SMTP
short_descr = descr_lines[0].rstrip()
long_descr = '\n'.join(descr_lines[1:]).lstrip()
- maintainer = __get_maintainer()
- if not maintainer:
- maintainer = '%s <%s>' % (p.get_commname(), p.get_commemail())
+ authname = p.get_authname();
+ authemail = p.get_authemail();
+ commname = p.get_commname();
+ commemail = p.get_commemail();
+
+ sender = __get_sender()
+
+ fromauth = '%s <%s>' % (authname, authemail)
+ if fromauth != sender:
+ fromauth = 'From: %s\n\n' % fromauth
+ else:
+ fromauth = ''
if options.version:
version_str = ' %s' % options.version
number_str = ''
tmpl_dict = {'patch': patch,
- 'maintainer': maintainer,
+ 'sender': sender,
+ # for backward template compatibility
+ 'maintainer': sender,
'shortdescr': short_descr,
'longdescr': long_descr,
# for backward template compatibility
'endofheaders': '',
'diff': git.diff(rev1 = git_id('%s//bottom' % patch),
- rev2 = git_id('%s//top' % patch)),
+ rev2 = git_id('%s//top' % patch),
+ binary = options.binary),
'diffstat': git.diffstat(rev1 = git_id('%s//bottom'%patch),
rev2 = git_id('%s//top' % patch)),
# for backward template compatibility
'patchnr': patch_nr_str,
'totalnr': total_nr_str,
'number': number_str,
- 'authname': p.get_authname(),
- 'authemail': p.get_authemail(),
+ 'fromauth': fromauth,
+ 'authname': authname,
+ 'authemail': authemail,
'authdate': p.get_authdate(),
- 'commname': p.get_commname(),
- 'commemail': p.get_commemail()}
+ 'commname': commname,
+ 'commemail': commemail}
# change None to ''
for key in tmpl_dict:
if not tmpl_dict[key]:
raise CmdException, 'Only "%(name)s" variables are ' \
'supported in the patch template'
+ if options.edit_patches:
+ msg_string = __edit_message(msg_string)
+
# The Python email message
try:
msg = email.message_from_string(msg_string)
__build_extra_headers(msg, msg_id, ref_id)
__encode_message(msg)
- msg_string = msg.as_string(options.mbox)
-
- if options.edit_patches:
- msg_string = edit_message(msg_string)
-
- return msg_string.strip('\n')
+ return msg
def func(parser, options, args):
"""Send the patches by e-mail using the patchmail.tmpl file as
a template
"""
- smtpserver = config.get('stgit', 'smtpserver')
-
- smtpuser = None
- smtppassword = None
- if config.has_option('stgit', 'smtpuser'):
- smtpuser = config.get('stgit', 'smtpuser')
- if config.has_option('stgit', 'smtppassword'):
- smtppassword = config.get('stgit', 'smtppassword')
+ smtpserver = config.get('stgit.smtpserver')
applied = crt_series.get_applied()
if options.all:
patches = applied
elif len(args) >= 1:
- patches = parse_patches(args, applied)
+ unapplied = crt_series.get_unapplied()
+ patches = parse_patches(args, applied + unapplied, len(applied))
else:
raise CmdException, 'Incorrect options. Unknown patches to send'
- if options.smtp_password:
- smtppassword = options.smtp_password
-
- if options.smtp_user:
- smtpuser = options.smtp_user
+ smtppassword = options.smtp_password or config.get('stgit.smtppassword')
+ smtpuser = options.smtp_user or config.get('stgit.smtpuser')
if (smtppassword and not smtpuser):
raise CmdException, 'SMTP password supplied, username needed'
else:
ref_id = options.refid
- if options.sleep != None:
- sleep = options.sleep
- else:
- sleep = config.getint('stgit', 'smtpdelay')
+ sleep = options.sleep or config.getint('stgit.smtpdelay')
# send the cover message (if any)
if options.cover or options.edit_cover:
msg = __build_cover(tmpl, total_nr, msg_id, options)
from_addr, to_addr_list = __parse_addresses(msg)
+ msg_string = msg.as_string(options.mbox)
+
# subsequent e-mails are seen as replies to the first one
if not options.noreply:
ref_id = msg_id
if options.mbox:
- print msg
- print
+ print msg_string
else:
print 'Sending the cover message...',
sys.stdout.flush()
- __send_message(smtpserver, from_addr, to_addr_list, msg, sleep,
- smtpuser, smtppassword)
+ __send_message(smtpserver, from_addr, to_addr_list, msg_string,
+ sleep, smtpuser, smtppassword)
print 'done'
# send the patches
options)
from_addr, to_addr_list = __parse_addresses(msg)
+ msg_string = msg.as_string(options.mbox)
+
# subsequent e-mails are seen as replies to the first one
if not options.noreply and not ref_id:
ref_id = msg_id
if options.mbox:
- print msg
- print
+ print msg_string
else:
print 'Sending patch "%s"...' % p,
sys.stdout.flush()
- __send_message(smtpserver, from_addr, to_addr_list, msg, sleep,
- smtpuser, smtppassword)
+ __send_message(smtpserver, from_addr, to_addr_list, msg_string,
+ sleep, smtpuser, smtppassword)
print 'done'