]> git.ipfire.org Git - thirdparty/gcc.git/blame - contrib/gcc-changelog/git_email.py
gcc-changelog/git_email.py: Support older unidiff.PatchSet
[thirdparty/gcc.git] / contrib / gcc-changelog / git_email.py
CommitLineData
c10aa1f0 1#!/usr/bin/env python3
81f86cb9
ML
2
3# Copyright (C) 2020 Free Software Foundation, Inc.
c10aa1f0
ML
4#
5# This file is part of GCC.
6#
7# GCC is free software; you can redistribute it and/or modify it under
8# the terms of the GNU General Public License as published by the Free
9# Software Foundation; either version 3, or (at your option) any later
10# version.
11#
12# GCC is distributed in the hope that it will be useful, but WITHOUT ANY
13# WARRANTY; without even the implied warranty of MERCHANTABILITY or
14# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15# for more details.
16#
17# You should have received a copy of the GNU General Public License
18# along with GCC; see the file COPYING3. If not see
19# <http://www.gnu.org/licenses/>. */
20
21import os
d554f43c 22import re
c10aa1f0
ML
23import sys
24from itertools import takewhile
25
26from dateutil.parser import parse
27
57706dd7 28from git_commit import GitCommit, GitInfo, decode_path
c10aa1f0 29
84ed8d2c 30from unidiff import PatchSet, PatchedFile
c10aa1f0
ML
31
32DATE_PREFIX = 'Date: '
33FROM_PREFIX = 'From: '
d554f43c
TB
34SUBJECT_PREFIX = 'Subject: '
35subject_patch_regex = re.compile(r'^\[PATCH( \d+/\d+)?\] ')
84ed8d2c 36unidiff_supports_renaming = hasattr(PatchedFile(), 'is_rename')
c10aa1f0
ML
37
38
39class GitEmail(GitCommit):
8f67bf25 40 def __init__(self, filename):
c10aa1f0 41 self.filename = filename
8f2a8be5
TB
42 try:
43 diff = PatchSet.from_filename(filename, newline='\n')
44 except TypeError:
45 # Older versions don't have the newline argument
46 diff = PatchSet.from_filename(filename)
c10aa1f0
ML
47 date = None
48 author = None
d554f43c 49 subject = ''
c10aa1f0 50
d554f43c 51 subject_last = False
bb07057a
PMR
52 with open(self.filename, 'r') as f:
53 lines = f.read().splitlines()
c10aa1f0
ML
54 lines = list(takewhile(lambda line: line != '---', lines))
55 for line in lines:
56 if line.startswith(DATE_PREFIX):
57 date = parse(line[len(DATE_PREFIX):])
58 elif line.startswith(FROM_PREFIX):
59 author = GitCommit.format_git_author(line[len(FROM_PREFIX):])
d554f43c
TB
60 elif line.startswith(SUBJECT_PREFIX):
61 subject = line[len(SUBJECT_PREFIX):]
62 subject_last = True
63 elif subject_last and line.startswith(' '):
64 subject += line
65 elif line == '':
66 break
67 else:
68 subject_last = False
69
70 if subject:
71 subject = subject_patch_regex.sub('', subject)
c10aa1f0 72 header = list(takewhile(lambda line: line != '', lines))
d554f43c
TB
73 # Note: commit message consists of email subject, empty line, email body
74 message = [subject] + lines[len(header):]
c10aa1f0
ML
75
76 modified_files = []
77 for f in diff:
a634157d 78 # Strip "a/" and "b/" prefixes
57706dd7
ML
79 source = decode_path(f.source_file)[2:]
80 target = decode_path(f.target_file)[2:]
a634157d 81
c10aa1f0
ML
82 if f.is_added_file:
83 t = 'A'
84 elif f.is_removed_file:
85 t = 'D'
84ed8d2c 86 elif unidiff_supports_renaming and f.is_rename:
a634157d
PMR
87 # Consider that renamed files are two operations: the deletion
88 # of the original name and the addition of the new one.
89 modified_files.append((source, 'D'))
90 t = 'A'
c10aa1f0
ML
91 else:
92 t = 'M'
a7ac3e92 93 modified_files.append((target if t != 'D' else source, t))
d554f43c 94 git_info = GitInfo(None, date, author, message, modified_files)
8f67bf25 95 super().__init__(git_info,
de4676c9 96 commit_to_info_hook=lambda x: None)
c10aa1f0
ML
97
98
8300c346 99def show_help():
0fd1a54b 100 print("""usage: git_email.py [--help] [patch file ...]
8300c346
TB
101
102Check git ChangeLog format of a patch
103
104With zero arguments, process every patch file in the
105./patches directory.
106With one argument, process the named patch file.
107
0fd1a54b 108Patch files must be in 'git format-patch' format.""")
8300c346
TB
109 sys.exit(0)
110
111
c10aa1f0 112if __name__ == '__main__':
8300c346
TB
113 if len(sys.argv) == 2 and (sys.argv[1] == '-h' or sys.argv[1] == '--help'):
114 show_help()
115
c10aa1f0
ML
116 if len(sys.argv) == 1:
117 allfiles = []
118 for root, _dirs, files in os.walk('patches'):
119 for f in files:
120 full = os.path.join(root, f)
121 allfiles.append(full)
122
123 success = 0
124 for full in sorted(allfiles):
125 email = GitEmail(full, False)
126 print(email.filename)
127 if email.success:
128 success += 1
129 print(' OK')
130 else:
131 for error in email.errors:
132 print(' ERR: %s' % error)
133
134 print()
135 print('Successfully parsed: %d/%d' % (success, len(allfiles)))
136 else:
7b4bae0a 137 email = GitEmail(sys.argv[1])
c10aa1f0
ML
138 if email.success:
139 print('OK')
140 email.print_output()
141 else:
de4676c9 142 if not email.info.lines:
c10aa1f0
ML
143 print('Error: patch contains no parsed lines', file=sys.stderr)
144 email.print_errors()
62963c60 145 sys.exit(1)