diff options
author | Laurent Pinchart <laurent.pinchart@ideasonboard.com> | 2022-11-28 07:59:26 +0200 |
---|---|---|
committer | Laurent Pinchart <laurent.pinchart@ideasonboard.com> | 2022-11-28 08:27:13 +0200 |
commit | 48df8095d4e50a3c98a14939ed046f2e100615f7 (patch) | |
tree | 040abf8e56f43d79c7d96b43072290048d0845b1 | |
parent | 39bf2ecc06663ac859290ca3b3a05fd775246766 (diff) |
Add patch-save.py script
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
-rwxr-xr-x | patch-save.py | 90 |
1 files changed, 90 insertions, 0 deletions
diff --git a/patch-save.py b/patch-save.py new file mode 100755 index 0000000..1c0516f --- /dev/null +++ b/patch-save.py @@ -0,0 +1,90 @@ +#!/usr/bin/python3 +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (C) 2022 Laurent Pinchart +# +# Author: Laurent Pinchart <laurent.pinchart@ideasonboard.com> +# +# Patch save script for mutt that handles mailman From header mangling. +# +# To install, copy the script to ~/.mutt/, and add the following lines to your +# .muttrc to bind to ctrl-h. +# +# set pipe_split=yes +# macro index \Ch "<enter-command>unset wait_key<enter> +# <enter-command>set pipe_decode<enter> +# <tag-prefix><pipe-entry>~/.mutt/patch-save.py<enter> +# <enter-command>unset pipe_decode<enter> +# <enter-command>set wait_key<enter>" "output git patches" +# + +import email +import pathlib +import re +import sys + + +def sanitize(s): + out = '' + + for c in s: + if c in '[]': + continue + + if c in "'": + c = '.' + elif c in '/:': + c = '-' + elif c in '*()" \t\n\r': + c = '_' + + out += c + + return out + + +def main(argv): + + # Parse the message from stdin as binary, as we can't assume any particular + # encoding. + msg = email.message_from_binary_file(sys.stdin.buffer) + + # mailman can mangle the From header to work around DMARC rejection rules. + # It then formats From as "Name via mailing-list <mailing-list@domain>" and + # stores the original sender in the Reply-to header. Restore the original + # author in the From header to please git-am. + from_header = msg.get('From') + reply_to = msg.get('Reply-to') + if reply_to and ' via ' in from_header: + msg.replace_header('From', reply_to) + + subject = msg.get('Subject') + if not subject: + return 1 + + # The subject can be an str instance or an email.header.Header instance. + # Convert it to str in all cases. + subject = str(subject) + + # Strip everything before the [PATCH] or [RESEND] tag. + match = re.search(r'\[(PATCH|RESEND) [^]]*\].*', subject) + if match: + subject = match.group(0) + + # Sanitize the subject. + subject = sanitize(subject) + + subject = subject.replace('..', '.') + subject = subject.replace('-_', '_') + subject = subject.replace('__', '_') + + subject = subject.strip() + subject = subject.rstrip('.') + + file_name = pathlib.Path.home() / '.maildir' / 'patches' / (subject + '.patch') + open(file_name, 'wb').write(bytes(msg)) + + return 0 + + +if __name__ == '__main__': + sys.exit(main(sys.argv)) |