]> git.wh0rd.org - home.git/commitdiff
gnu-mklog: helper for GNU ChangeLogs
authorMike Frysinger <vapier@gentoo.org>
Mon, 15 Feb 2021 04:07:54 +0000 (23:07 -0500)
committerMike Frysinger <vapier@gentoo.org>
Mon, 15 Feb 2021 04:07:54 +0000 (23:07 -0500)
.bin/gnu-mklog [new file with mode: 0755]

diff --git a/.bin/gnu-mklog b/.bin/gnu-mklog
new file mode 100755 (executable)
index 0000000..52fd7ce
--- /dev/null
@@ -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  <vapier@gentoo.org>'
+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:]))