From bd4ce675297c1efa16daa66f31cee2cc351f6a1f Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Sun, 14 Feb 2021 23:07:54 -0500 Subject: [PATCH] gnu-mklog: helper for GNU ChangeLogs --- .bin/gnu-mklog | 109 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 109 insertions(+) create mode 100755 .bin/gnu-mklog diff --git a/.bin/gnu-mklog b/.bin/gnu-mklog new file mode 100755 index 0000000..52fd7ce --- /dev/null +++ b/.bin/gnu-mklog @@ -0,0 +1,109 @@ +#!/usr/bin/env python3 + +"""Helper for generating GNU ChangeLog entries.""" + +import argparse +import datetime +import importlib.machinery +import os +from pathlib import Path +import subprocess +import sys + +import unidiff + + +_loader = lambda *args: importlib.machinery.SourceFileLoader(*args).load_module() +mklog = _loader('mklog', '/usr/local/src/gnu/gcc/git/contrib/mklog.py') +del _loader + + +NAME = 'Mike Frysinger ' +DATE = datetime.datetime.now().strftime('%Y-%m-%d') + + +def get_parser(): + """Get CLI parser.""" + parser = argparse.ArgumentParser(description=__doc__) + return parser + + +def main(argv): + """The main entry point for scripts.""" + parser = get_parser() + opts = parser.parse_args(argv) + + # Get the patchset from git. + full_diff = subprocess.run( + ['git', 'log', '-p', '--relative', '-1'], + check=True, capture_output=True, encoding='utf-8').stdout + + # Filter out entries we don't want. + patchset = unidiff.PatchSet(full_diff) + i = 0 + while i < len(patchset): + if Path(patchset[i].path).name.startswith('ChangeLog'): + patchset.pop(i) + else: + i += 1 + + # List of files that are always generated. + generated_files = {'aclocal.m4', 'config.in', 'configure'} + + # Move the generated patches to the end of the patchset so the generated + # ChangeLog lists them at the end. + generated_patches = [] + i = 0 + while i < len(patchset): + if Path(patchset[i].path).name in generated_files: + generated_patches.append(patchset.pop(i)) + else: + i += 1 + patchset.extend(generated_patches) + + # Find the ChangeLog for each path. + all_dirs = {Path(x.path).parent for x in patchset} + dirs_to_logs = {} + for index_dir in all_dirs: + d = index_dir + while True: + log = d / 'ChangeLog' + if log.is_file(): + break + d = d.parent + dirs_to_logs[index_dir] = log + + # Group the patches based on the ChangeLogs they'll go into. + logs_to_patches = {} + for pfile in patchset: + log = dirs_to_logs[Path(pfile.path).parent] + ps = logs_to_patches.setdefault(log, unidiff.PatchSet('')) + ps.append(pfile) + + # Now generate the logs for each subdir. + for log, ps in logs_to_patches.items(): + new_log = mklog.generate_changelog(str(ps)) + new_log = '\n'.join(new_log.splitlines()[2:]).rstrip() + + # Hack: If we rebased the changes to a subdir, strip the path down. + # e.g. bfin/foo.c goes into bfin/ChangeLog, so drop bfin/ prefix. + for pfile in ps: + relpath = os.path.relpath(pfile.path, log.parent) + if relpath != pfile.path: + new_log = new_log.replace(pfile.path, relpath) + + # Read the old ChangeLog file and strip spurious whitespace. + with open(log, encoding='utf-8') as fp: + old_log = '\n'.join(x.rstrip() for x in fp.read().strip().splitlines()) + + # Now update the ChangeLog file with the new entry at top. + with open(log, 'w', encoding='utf-8') as fp: + fp.write(f'{DATE} {NAME}\n\n') + fp.write(new_log) + fp.write('\n\n') + fp.write(old_log) + fp.write('\n') + + +if __name__ == '__main__': + sys.exit(main(sys.argv[1:])) -- 2.39.5