Control: tags -1 + patch

On Fri, 11 Feb 2022 at 14:55:08 +0100, Guido Günther wrote:
> On Tue, Nov 30, 2021 at 11:59:16AM +0000, Simon McVittie wrote:
> > Would it be possible to tell the email modules to avoid using this encoding,
> > or explicitly decode UTF-8 in the email headers during DEP-3
> > formatting?
> 
> I'd welcome patches here.

Try these?

I initially tried to do this with the Python-3.2-compatible ("Compat32")
interface that gbp-pq was already using, but couldn't work out how, and
using the modern interface seemed simpler and more future-proof anyway.

This might potentially make git-buildpackage incompatible with Python 3.5,
which it currently declares support for (the "new" interface was considered
provisional in 3.4 and 3.5, and only finalized in 3.6), but 3.5 has been
EOL since 2020 anyway.

test.diff might be useful while testing this. I can successfully `git am`
and `gbp pq export` it, with UTF-8 encoding.

    smcv
>From 27f8509632e3b4248ccaefbb5902b80e2e345df4 Mon Sep 17 00:00:00 2001
From: Simon McVittie <[email protected]>
Date: Thu, 17 Mar 2022 12:20:29 +0000
Subject: [PATCH 1/2] pq: Use Python 3.6 email interface

As well as being simpler and avoiding backwards-compatibility glue, this
will give us finer control over the output encoding.

This interface was available since Python 3.4 with provisional status
(and Python versions older than 3.7 have reached end-of-life in any case).

Signed-off-by: Simon McVittie <[email protected]>
---
 gbp/scripts/common/pq.py | 39 +++++++++++----------------------------
 1 file changed, 11 insertions(+), 28 deletions(-)

diff --git a/gbp/scripts/common/pq.py b/gbp/scripts/common/pq.py
index 1a80ec0..d2f48ac 100644
--- a/gbp/scripts/common/pq.py
+++ b/gbp/scripts/common/pq.py
@@ -22,10 +22,8 @@ import re
 import os
 import datetime
 import time
-from email.message import Message
-from email.header import Header
-from email.charset import Charset, QP
-from email.policy import Compat32
+from email.message import EmailMessage
+from email.policy import EmailPolicy
 
 from gbp.git import GitRepositoryError
 from gbp.git.modifier import GitModifier, GitTz
@@ -143,10 +141,7 @@ def write_patch_file(filename, commit_info, diff):
         return None
     try:
         with open(filename, 'wb') as patch:
-            msg = Message()
-            charset = Charset('utf-8')
-            charset.body_encoding = None
-            charset.header_encoding = QP
+            msg = EmailMessage()
 
             # Write headers
             name = commit_info['author']['name']
@@ -154,31 +149,19 @@ def write_patch_file(filename, commit_info, diff):
             # Git compat: put name in quotes if special characters found
             if re.search(r'[,.@()\[\]\\\:;]', name):
                 name = '"%s"' % name
-            from_header = Header(header_name='from')
-            try:
-                from_header.append(name, 'us-ascii')
-            except UnicodeDecodeError:
-                from_header.append(name, charset)
-            from_header.append('<%s>' % email)
-            msg['From'] = from_header
+            msg['From'] = '%s <%s>' % (name, email)
             date = commit_info['author'].datetime
-            datestr = date.strftime('%a, %-d %b %Y %H:%M:%S %z')
-            msg['Date'] = Header(datestr, 'us-ascii', 'date')
-            subject_header = Header(header_name='subject')
-            try:
-                subject_header.append(commit_info['subject'], 'us-ascii')
-            except UnicodeDecodeError:
-                subject_header.append(commit_info['subject'], charset)
-            msg['Subject'] = subject_header
+            msg['Date'] = date.strftime('%a, %-d %b %Y %H:%M:%S %z')
+            msg['Subject'] = commit_info['subject']
             # Write message body
             if commit_info['body']:
                 # Strip extra linefeeds
                 body = commit_info['body'].rstrip() + '\n'
-                try:
-                    msg.set_payload(body.encode('us-ascii'))
-                except (UnicodeEncodeError):
-                    msg.set_payload(body, charset)
-            policy = Compat32(max_line_length=77)
+                msg.set_content(body)
+            del msg['Content-Transfer-Encoding']
+            del msg['Content-Type']
+            del msg['MIME-Version']
+            policy = EmailPolicy(max_line_length=77)
             patch.write(msg.as_bytes(unixfrom=False, policy=policy))
 
             # Write diff
-- 
2.35.1

>From bef65ea6920712b288778c18a91ce954555a50dd Mon Sep 17 00:00:00 2001
From: Simon McVittie <[email protected]>
Date: Thu, 17 Mar 2022 12:25:33 +0000
Subject: [PATCH 2/2] pq: Serialize headers as UTF-8

This is not identical to `git format-patch` output, but `git am` can
apply it, and it makes the patch a lot more readable if the author
has multiple non-ASCII characters in their name.

Closes: #1000865
Signed-off-by: Simon McVittie <[email protected]>
---
 gbp/scripts/common/pq.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/gbp/scripts/common/pq.py b/gbp/scripts/common/pq.py
index d2f48ac..b857562 100644
--- a/gbp/scripts/common/pq.py
+++ b/gbp/scripts/common/pq.py
@@ -161,7 +161,7 @@ def write_patch_file(filename, commit_info, diff):
             del msg['Content-Transfer-Encoding']
             del msg['Content-Type']
             del msg['MIME-Version']
-            policy = EmailPolicy(max_line_length=77)
+            policy = EmailPolicy(max_line_length=77, utf8=True)
             patch.write(msg.as_bytes(unixfrom=False, policy=policy))
 
             # Write diff
-- 
2.35.1

From: I ♥ Unicode <¬@µ.invalid>
Date: Thu, 17 Mar 2022 13:11:14 +0000
Subject: ⸘Why encode when you can use UTF-8‽

— test test test —
---
 test.txt | 1 +
 1 file changed, 1 insertion(+)
 create mode 100644 test.txt

diff --git a/test.txt b/test.txt
new file mode 100644
index 0000000..53de6c6
--- /dev/null
+++ b/test.txt
@@ -0,0 +1 @@
+use Unicode ∵ we can

Reply via email to