[PATCH 2 of 2 STABLE] py3: use native strings when forming email headers in patchbomb
Denis Laxalde
denis at laxalde.org
Fri Oct 25 09:02:11 EDT 2019
# HG changeset patch
# User Denis Laxalde <denis at laxalde.org>
# Date 1572008488 -7200
# Fri Oct 25 15:01:28 2019 +0200
# Branch stable
# Node ID 6058175493d062dbaec2cb0e897e49da4596d147
# Parent 17fad3f1b4742d75db23e17a04c85223bcc239a2
py3: use native strings when forming email headers in patchbomb
We use raw strings for headers' keys and native strings for values. This
fixes "hg email" with a changeset with a message containing non-ascii
characters. This also removes the "if pycompat.ispy3:" TODO.
diff --git a/hgext/patchbomb.py b/hgext/patchbomb.py
--- a/hgext/patchbomb.py
+++ b/hgext/patchbomb.py
@@ -321,10 +321,12 @@ def makepatch(
subj = b' '.join([prefix, opts.get(b'subject') or subj])
else:
subj = b' '.join([prefix, subj])
- msg[b'Subject'] = mail.headencode(ui, subj, _charsets, opts.get(b'test'))
- msg[b'X-Mercurial-Node'] = node
- msg[b'X-Mercurial-Series-Index'] = b'%i' % idx
- msg[b'X-Mercurial-Series-Total'] = b'%i' % total
+ msg[r'Subject'] = encoding.strfromlocal(
+ mail.headencode(ui, subj, _charsets, opts.get(b'test'))
+ )
+ msg[r'X-Mercurial-Node'] = pycompat.sysstr(node)
+ msg[r'X-Mercurial-Series-Index'] = '%i' % idx
+ msg[r'X-Mercurial-Series-Total'] = '%i' % total
return msg, subj, ds
@@ -421,7 +423,9 @@ def _getbundlemsgs(repo, sender, bundle,
)
emailencoders.encode_base64(datapart)
msg.attach(datapart)
- msg[b'Subject'] = mail.headencode(ui, subj, _charsets, opts.get(r'test'))
+ msg[r'Subject'] = encoding.strfromlocal(
+ mail.headencode(ui, subj, _charsets, opts.get(r'test'))
+ )
return [(msg, subj, None)]
@@ -454,7 +458,9 @@ def _makeintro(repo, sender, revs, patch
body = _getdescription(repo, body, sender, **opts)
msg = mail.mimeencode(ui, body, _charsets, opts.get(r'test'))
- msg[b'Subject'] = mail.headencode(ui, subj, _charsets, opts.get(r'test'))
+ msg[r'Subject'] = encoding.strfromlocal(
+ mail.headencode(ui, subj, _charsets, opts.get(r'test'))
+ )
return (msg, subj, diffstat)
@@ -523,8 +529,10 @@ def _getoutgoing(repo, dest, revs):
def _msgid(node, timestamp):
hostname = encoding.strtolocal(socket.getfqdn())
- hostname = encoding.environ.get(b'HGHOSTNAME', hostname)
- return b'<%s.%d@%s>' % (node, timestamp, hostname)
+ hostname = encoding.strfromlocal(
+ encoding.environ.get(b'HGHOSTNAME', hostname)
+ )
+ return '<%s.%d@%s>' % (node, timestamp, hostname)
emailopts = [
@@ -854,7 +862,7 @@ def email(ui, repo, *revs, **opts):
showaddrs = []
- def getaddrs(header, ask=False, default=None):
+ def _getaddrs(header, ask=False, default=None):
configkey = header.lower()
opt = header.replace(b'-', b'_').lower()
addrs = opts.get(opt)
@@ -881,6 +889,12 @@ def email(ui, repo, *revs, **opts):
)
return []
+ def getaddrs(header, ask=False, default=None):
+ return [
+ encoding.strfromlocal(a)
+ for a in _getaddrs(header, ask=ask, default=default)
+ ]
+
to = getaddrs(b'To', ask=True)
if not to:
# we can get here in non-interactive mode
@@ -912,10 +926,11 @@ def email(ui, repo, *revs, **opts):
parent = opts.get(b'in_reply_to') or None
# angle brackets may be omitted, they're not semantically part of the msg-id
if parent is not None:
- if not parent.startswith(b'<'):
- parent = b'<' + parent
- if not parent.endswith(b'>'):
- parent += b'>'
+ parent = encoding.strfromlocal(parent)
+ if not parent.startswith('<'):
+ parent = '<' + parent
+ if not parent.endswith('>'):
+ parent += '>'
sender_addr = eutil.parseaddr(encoding.strfromlocal(sender))[1]
sender = mail.addressencode(ui, sender, _charsets, opts.get(b'test'))
@@ -926,47 +941,32 @@ def email(ui, repo, *revs, **opts):
)
for i, (m, subj, ds) in enumerate(msgs):
try:
- m[b'Message-Id'] = genmsgid(m[b'X-Mercurial-Node'])
+ m[r'Message-Id'] = genmsgid(m[r'X-Mercurial-Node'])
if not firstpatch:
- firstpatch = m[b'Message-Id']
- m[b'X-Mercurial-Series-Id'] = firstpatch
+ firstpatch = m[r'Message-Id']
+ m[r'X-Mercurial-Series-Id'] = firstpatch
except TypeError:
- m[b'Message-Id'] = genmsgid(b'patchbomb')
+ m[r'Message-Id'] = genmsgid('patchbomb')
if parent:
- m[b'In-Reply-To'] = parent
- m[b'References'] = parent
- if not parent or b'X-Mercurial-Node' not in m:
- parent = m[b'Message-Id']
+ m[r'In-Reply-To'] = parent
+ m[r'References'] = parent
+ if not parent or r'X-Mercurial-Node' not in m:
+ parent = m[r'Message-Id']
- m[b'User-Agent'] = b'Mercurial-patchbomb/%s' % util.version()
- m[b'Date'] = eutil.formatdate(start_time[0], localtime=True)
+ m[r'User-Agent'] = encoding.strfromlocal(
+ b'Mercurial-patchbomb/%s' % util.version()
+ )
+ m[r'Date'] = eutil.formatdate(start_time[0], localtime=True)
start_time = (start_time[0] + 1, start_time[1])
- m[b'From'] = sender
- m[b'To'] = b', '.join(to)
+ m[r'From'] = encoding.strfromlocal(sender)
+ m[r'To'] = ', '.join(to)
if cc:
- m[b'Cc'] = b', '.join(cc)
+ m[r'Cc'] = ', '.join(cc)
if bcc:
- m[b'Bcc'] = b', '.join(bcc)
+ m[r'Bcc'] = ', '.join(bcc)
if replyto:
- m[b'Reply-To'] = b', '.join(replyto)
- # Fix up all headers to be native strings.
- # TODO(durin42): this should probably be cleaned up above in the future.
- if pycompat.ispy3:
- for hdr, val in list(m.items()):
- change = False
- if isinstance(hdr, bytes):
- del m[hdr]
- hdr = pycompat.strurl(hdr)
- change = True
- if isinstance(val, bytes):
- val = pycompat.strurl(val)
- if not change:
- # prevent duplicate headers
- del m[hdr]
- change = True
- if change:
- m[hdr] = val
+ m[r'Reply-To'] = ', '.join(replyto)
if opts.get(b'test'):
ui.status(_(b'displaying '), subj, b' ...\n')
ui.pager(b'email')
@@ -984,12 +984,11 @@ def email(ui, repo, *revs, **opts):
progress.update(i, item=subj)
if not mbox:
# Exim does not remove the Bcc field
- del m[b'Bcc']
+ del m[r'Bcc']
fp = stringio()
generator = mail.Generator(fp, mangle_from_=False)
generator.flatten(m, 0)
alldests = to + bcc + cc
- alldests = [encoding.strfromlocal(d) for d in alldests]
sendmail(sender_addr, alldests, fp.getvalue())
progress.complete()
More information about the Mercurial-devel
mailing list