| #!/usr/bin/env python3 |
| |
| # Copyright (C) 2020 Agilent Technologies, Inc. |
| # Author: Chris Laplante <chris.laplante@agilent.com> |
| |
| # This sendemail-validate hook injects 'From: ' header lines into outgoing |
| # emails sent via 'git send-email', to ensure that accurate commit authorship |
| # information is present. It was created because some email servers |
| # (notably Microsoft Exchange / Office 360) seem to butcher outgoing patches, |
| # resulting in incorrect authorship. |
| |
| # Current limitations: |
| # 1. Assumes one per patch per email |
| # 2. Minimal error checking |
| # |
| # Installation: |
| # 1. Copy to .git/hooks/sendemail-validate |
| # 2. chmod +x .git/hooks/sendemail-validate |
| |
| |
| import enum |
| import re |
| import subprocess |
| import sys |
| |
| |
| class Subject(enum.IntEnum): |
| NOT_SEEN = 0 |
| CONSUMING = 1 |
| SEEN = 2 |
| |
| |
| def make_from_line(): |
| cmd = ["git", "var", "GIT_COMMITTER_IDENT"] |
| proc = subprocess.run(cmd, check=True, stdout=subprocess.PIPE, universal_newlines=True) |
| regex = re.compile(r"^(.*>).*$") |
| match = regex.match(proc.stdout) |
| assert match is not None |
| return "From: {0}".format(match.group(1)) |
| |
| |
| def main(): |
| email = sys.argv[1] |
| |
| with open(email, "r") as f: |
| email_lines = f.read().split("\n") |
| |
| subject_seen = Subject.NOT_SEEN |
| first_body_line = None |
| for i, line in enumerate(email_lines): |
| if (subject_seen == Subject.NOT_SEEN) and line.startswith("Subject: "): |
| subject_seen = Subject.CONSUMING |
| continue |
| if subject_seen == Subject.CONSUMING: |
| if not line.strip(): |
| subject_seen = Subject.SEEN |
| continue |
| if subject_seen == Subject.SEEN: |
| first_body_line = i |
| break |
| |
| assert subject_seen == Subject.SEEN |
| assert first_body_line is not None |
| |
| from_line = make_from_line() |
| # Only add FROM line if it is not already there |
| if email_lines[first_body_line] != from_line: |
| email_lines.insert(first_body_line, from_line) |
| email_lines.insert(first_body_line + 1, "") |
| with open(email, "w") as f: |
| f.write("\n".join(email_lines)) |
| |
| return 0 |
| |
| |
| if __name__ == "__main__": |
| sys.exit(main()) |
| |