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