3 """Helper for generating GNU ChangeLog entries."""
7 import importlib.machinery
9 from pathlib import Path
16 _loader = lambda *args: importlib.machinery.SourceFileLoader(*args).load_module()
17 mklog = _loader('mklog', '/usr/local/src/gnu/gcc/git/contrib/mklog.py')
21 NAME = 'Mike Frysinger <vapier@gentoo.org>'
22 DATE = datetime.datetime.now().strftime('%Y-%m-%d')
27 parser = argparse.ArgumentParser(description=__doc__)
32 """The main entry point for scripts."""
34 opts = parser.parse_args(argv)
36 # Get the patchset from git.
37 full_diff = subprocess.run(
38 ['git', 'log', '-p', '--relative', '-1'],
39 check=True, capture_output=True, encoding='utf-8').stdout
41 # Filter out entries we don't want.
42 patchset = unidiff.PatchSet(full_diff)
44 while i < len(patchset):
45 if Path(patchset[i].path).name.startswith('ChangeLog'):
50 # List of files that are always generated.
51 generated_files = {'aclocal.m4', 'config.in', 'configure'}
53 # Move the generated patches to the end of the patchset so the generated
54 # ChangeLog lists them at the end.
55 generated_patches = []
57 while i < len(patchset):
58 if Path(patchset[i].path).name in generated_files:
59 generated_patches.append(patchset.pop(i))
62 patchset.extend(generated_patches)
64 # Find the ChangeLog for each path.
65 all_dirs = {Path(x.path).parent for x in patchset}
67 for index_dir in all_dirs:
74 dirs_to_logs[index_dir] = log
76 # Group the patches based on the ChangeLogs they'll go into.
78 for pfile in patchset:
79 log = dirs_to_logs[Path(pfile.path).parent]
80 ps = logs_to_patches.setdefault(log, unidiff.PatchSet(''))
83 # Now generate the logs for each subdir.
84 for log, ps in logs_to_patches.items():
85 new_log = mklog.generate_changelog(str(ps))
86 new_log = '\n'.join(new_log.splitlines()[2:]).rstrip()
88 # Hack: If we rebased the changes to a subdir, strip the path down.
89 # e.g. bfin/foo.c goes into bfin/ChangeLog, so drop bfin/ prefix.
91 relpath = os.path.relpath(pfile.path, log.parent)
92 if relpath != pfile.path:
93 new_log = new_log.replace(pfile.path, relpath)
95 # Read the old ChangeLog file and strip spurious whitespace.
96 # Specify the whitespace to strip explciitly as we want to leave the
97 # \f (^L) characters alone.
98 with open(log, encoding='utf-8') as fp:
99 old_log = '\n'.join(x.rstrip(' \t\r')
100 for x in fp.read().strip().split('\n'))
102 # Now update the ChangeLog file with the new entry at top.
103 with open(log, 'w', encoding='utf-8') as fp:
104 fp.write(f'{DATE} {NAME}\n\n')
111 if __name__ == '__main__':
112 sys.exit(main(sys.argv[1:]))