1#!/usr/bin/env python 2# SPDX-License-Identifier: LGPL-2.0-or-later 3# 4# -*- mode: python -*- 5# 6# This python program has been copied from 7# https://github.com/GNOME/gnet/blob/master/gen-changelog.py 8# 9# It has been authored by Edward Hervey, of GStreamer fame. I have 10# asked his permission to copy it and re-use it here, as part of the 11# Libabigail project. He granted me the permission to distribute the 12# program under the terms of the GNU Lesser Public License as 13# published by the Free Software Foundaion; either version 2, or (at 14# your option) any later version. 15# 16 17import sys 18import subprocess 19import re 20 21# Makes a GNU-Style ChangeLog from a git repository 22# Handles git-svn repositories also 23 24# Arguments : same as for git log 25release_refs={} 26 27def process_commit(lines, files): 28 # DATE NAME 29 # BLANK LINE 30 # Subject 31 # BLANK LINE 32 # ... 33 # FILES 34 fileincommit = False 35 lines = [x.strip() for x in lines if x.strip() and not x.startswith('git-svn-id')] 36 files = [x.strip() for x in files if x.strip()] 37 for l in lines: 38 if l.startswith('* '): 39 fileincommit = True 40 break 41 42 top_line = lines[0] 43 subject_line_index = 0 if lines[1].startswith('*') else 1; 44 first_cl_body_line_index = 0; 45 46 for i in range(1, len(lines)): 47 if lines[i].startswith('*'): 48 first_cl_body_line_index = i 49 break; 50 51 # Clean up top line of ChangeLog entry: 52 fields = top_line.split(' ') 53 54 # 1. remove the time and timezone stuff in "2008-05-13 07:10:28 +0000 name" 55 if fields[2].startswith('+') or fields[2].startswith('-'): 56 del fields[2] 57 if fields[1][2] == ':' and fields[1][5] == ':': 58 del fields[1] 59 60 # 2. munge at least my @src.gnome.org e-mail address... 61 if fields[-1] == '<tpm@src.gnome.org>': 62 fields[-1] = '<tim@centricular.net>' 63 64 top_line = ' '.join(fields) 65 print(top_line.strip()) 66 print() 67 68 if subject_line_index > 0: 69 print('\t%s' % lines[subject_line_index].strip()) 70 71 if not fileincommit: 72 for f in files: 73 print('\t* %s:' % f.strip()) 74 print() 75 76 if first_cl_body_line_index > 0: 77 for l in lines[first_cl_body_line_index:]: 78 if l.startswith('Signed-off-by:'): 79 continue 80 print('\t%s' % l.strip()) 81 print() 82 83def output_commits(): 84 cmd = ['git', 'log', '--pretty=format:--START-COMMIT--%H%n%ai %an <%ae>%n%n%s%n%b%n--END-COMMIT--', 85 '--date=short', '--name-only'] 86 87 start_tag = find_start_tag() 88 89 if start_tag is None: 90 cmd.extend(sys.argv[1:]) 91 else: 92 cmd.extend(["%s..HEAD" % (start_tag)]) 93 94 p = subprocess.Popen(args=cmd, shell=False, 95 stdout=subprocess.PIPE, 96 text=True) 97 buf = [] 98 files = [] 99 filemode = False 100 for lin in p.stdout.readlines(): 101 if lin.startswith("--START-COMMIT--"): 102 if buf != []: 103 process_commit(buf, files) 104 hash = lin[16:].strip() 105 try: 106 rel = release_refs[hash] 107 print("=== release %d.%d.%d ===\n" % (int(rel[0]), int(rel[1]), int(rel[2]))) 108 except: 109 pass 110 buf = [] 111 files = [] 112 filemode = False 113 elif lin.startswith("--END-COMMIT--"): 114 filemode = True 115 elif filemode == True: 116 files.append(lin) 117 else: 118 buf.append(lin) 119 if buf != []: 120 process_commit(buf, files) 121 122def get_rel_tags(): 123 # Populate the release_refs dict with the tags for previous releases 124 reltagre = re.compile("^([a-z0-9]{40}) refs\/tags\/GNET-([0-9]+)[-_.]([0-9]+)[-_.]([0-9]+)") 125 126 cmd = ['git', 'show-ref', '--tags', '--dereference'] 127 p = subprocess.Popen(args=cmd, shell=False, 128 stdout=subprocess.PIPE, 129 text=True) 130 for lin in p.stdout: 131 match = reltagre.search(lin) 132 if match: 133 (sha, maj, min, nano) = match.groups() 134 release_refs[sha] = (maj, min, nano) 135 136def find_start_tag(): 137 starttagre = re.compile("^([a-z0-9]{40}) refs\/tags\/CHANGELOG_START") 138 cmd = ['git', 'show-ref', '--tags'] 139 p = subprocess.Popen(args=cmd, shell=False, 140 stdout=subprocess.PIPE, 141 text=True) 142 for lin in p.stdout: 143 match = starttagre.search(lin) 144 if match: 145 return match.group(1) 146 return None 147 148if __name__ == "__main__": 149 get_rel_tags() 150 output_commits() 151