123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139 |
- #!/usr/bin/env python3
- #
- # This file is part of GCC.
- #
- # GCC is free software; you can redistribute it and/or modify it under
- # the terms of the GNU General Public License as published by the Free
- # Software Foundation; either version 3, or (at your option) any later
- # version.
- #
- # GCC is distributed in the hope that it will be useful, but WITHOUT ANY
- # WARRANTY; without even the implied warranty of MERCHANTABILITY or
- # FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- # for more details.
- #
- # You should have received a copy of the GNU General Public License
- # along with GCC; see the file COPYING3. If not see
- # <http://www.gnu.org/licenses/>. */
- import os
- import re
- import sys
- from itertools import takewhile
- from dateutil.parser import parse
- from git_commit import GitCommit, GitInfo, decode_path
- from unidiff import PatchSet, PatchedFile
- DATE_PREFIX = 'Date: '
- FROM_PREFIX = 'From: '
- SUBJECT_PREFIX = 'Subject: '
- subject_patch_regex = re.compile(r'^\[PATCH( \d+/\d+)?\] ')
- unidiff_supports_renaming = hasattr(PatchedFile(), 'is_rename')
- class GitEmail(GitCommit):
- def __init__(self, filename):
- self.filename = filename
- diff = PatchSet.from_filename(filename)
- date = None
- author = None
- subject = ''
- subject_last = False
- with open(self.filename, 'r') as f:
- lines = f.read().splitlines()
- lines = list(takewhile(lambda line: line != '---', lines))
- for line in lines:
- if line.startswith(DATE_PREFIX):
- date = parse(line[len(DATE_PREFIX):])
- elif line.startswith(FROM_PREFIX):
- author = GitCommit.format_git_author(line[len(FROM_PREFIX):])
- elif line.startswith(SUBJECT_PREFIX):
- subject = line[len(SUBJECT_PREFIX):]
- subject_last = True
- elif subject_last and line.startswith(' '):
- subject += line
- elif line == '':
- break
- else:
- subject_last = False
- if subject:
- subject = subject_patch_regex.sub('', subject)
- header = list(takewhile(lambda line: line != '', lines))
- # Note: commit message consists of email subject, empty line, email body
- message = [subject] + lines[len(header):]
- modified_files = []
- for f in diff:
- # Strip "a/" and "b/" prefixes
- source = decode_path(f.source_file)[2:]
- target = decode_path(f.target_file)[2:]
- if f.is_added_file:
- t = 'A'
- elif f.is_removed_file:
- t = 'D'
- elif unidiff_supports_renaming and f.is_rename:
- # Consider that renamed files are two operations: the deletion
- # of the original name and the addition of the new one.
- modified_files.append((source, 'D'))
- t = 'A'
- else:
- t = 'M'
- modified_files.append((target if t != 'D' else source, t))
- git_info = GitInfo(None, date, author, message, modified_files)
- super().__init__(git_info,
- commit_to_info_hook=lambda x: None)
- def show_help():
- print("""usage: git_email.py [--help] [patch file ...]
- Check git ChangeLog format of a patch
- With zero arguments, process every patch file in the
- ./patches directory.
- With one argument, process the named patch file.
- Patch files must be in 'git format-patch' format.""")
- sys.exit(0)
- if __name__ == '__main__':
- if len(sys.argv) == 2 and (sys.argv[1] == '-h' or sys.argv[1] == '--help'):
- show_help()
- if len(sys.argv) == 1:
- allfiles = []
- for root, _dirs, files in os.walk('patches'):
- for f in files:
- full = os.path.join(root, f)
- allfiles.append(full)
- success = 0
- for full in sorted(allfiles):
- email = GitEmail(full, False)
- print(email.filename)
- if email.success:
- success += 1
- print(' OK')
- else:
- for error in email.errors:
- print(' ERR: %s' % error)
- print()
- print('Successfully parsed: %d/%d' % (success, len(allfiles)))
- else:
- email = GitEmail(sys.argv[1])
- if email.success:
- print('OK')
- email.print_output()
- else:
- if not email.info.lines:
- print('Error: patch contains no parsed lines', file=sys.stderr)
- email.print_errors()
- sys.exit(1)
|