#!/usr/bin/python # Copyright 2008 Marcus D. Hanwell # Distributed under the terms of the GNU General Public License v2 or later # Modified by (C) 2012-2017 TAMUKI Shoichi import os, re, unicodedata, subprocess, shlex def get_chr_width(c): return 2 if unicodedata.east_asian_width(c) in ["F", "W", "A"] else 1 def get_str_width(s): w = 0 for c in s: w += get_chr_width(c) return w # Execute git log with the desired command line options. fin = os.popen("git log --date=short --stat --summary " "--since=\"1970-01-01 00:00:00\" admin", "r") # Create a ChangeLog file in the current directory. fout = open("ChangeLog", "w") # Set up the loop variables in order to locate the blocks we want authorFound = False dateFound = False messageFound = False messageNL = False messageItem = False message = "" filesFound = False files = "" prevAuthorLine = "" commitSet = "" # The main part of the loop for line in fin: try: line = unicode(line, "utf-8") except NameError: pass # The commit line marks the start of a new commit object. if re.search("^commit ", line): # Start all over again... authorFound = False dateFound = False messageFound = False messageNL = False messageItem = False message = "" filesFound = False files = "" # Match the author line and extract the part we want elif re.search("^Author: ", line): author = line[8:].strip() authorFound = True # Match the date line elif re.search("^Date: ", line): date = line[8:].strip() dateFound = True # Extract the actual commit message for this commit elif authorFound and dateFound and not messageFound: # Find the commit message if we can if line == "\n": if messageNL: messageFound = True else: messageNL = True elif line == " \n": if not message.endswith("\n"): message += "\n" # The sign off line is ignored elif re.search("^ Signed-off-by: ", line): pass elif re.search("^ Acked-by: ", line): pass elif re.search("^ Cc: ", line): pass elif re.search("^ Reported-by: ", line): pass elif re.search("^ Tested-by: ", line): pass elif re.search("^ Reviewed-by: ", line): pass elif re.search("^ Suggested-by: ", line): pass else: if messageItem: if not message.endswith("\n"): if not re.search("^ \s*[^*-]", line): message += "\n" if not re.search("^ \s*[*-]", line): messageItem = False else: if re.search("^ \s*[*-]", line): if not message.endswith("\n"): message += "\n" messageItem = True if message.endswith("."): message += " " elif not message.endswith("\n"): message += " " message += line.strip() # Collect the files for this commit. FIXME: Still need to add +/- to files elif authorFound and dateFound and messageFound and not filesFound: fileList = line.split(" | ", 1) if len(fileList) == 2: if files: files += ", " files += fileList[0].strip() # If this line is hit all of the files have been stored for this commit elif re.search("^ [0-9]* files? changed, ", line): filesFound = True # All of the parts of the commit have been found - write out the entry if authorFound and dateFound and messageFound and filesFound: # First the author line, only outputted if it is the first for that # author on this day authorLine = date + " " + author if not prevAuthorLine: try: fout.write(authorLine.encode("utf-8") + "\n") except TypeError: fout.write(authorLine + "\n") commitSet = "" elif authorLine != prevAuthorLine: # Write out the commit lines try: fout.write(commitSet.encode("utf-8") + "\n") except TypeError: fout.write(commitSet + "\n") try: fout.write("\n" + authorLine.encode("utf-8") + "\n") except TypeError: fout.write("\n" + authorLine + "\n") commitSet = "" # Assemble the actual commit message line(s) and limit the line length # to 78 characters. commitLine = files + ":" + message lc = len(commitLine) commit = "" i = j = 0 while i < lc: if i == j: lv = 0 commit += "\n\t* " if i == 0 else "\n\t " if lv == 1: commit += " " if get_str_width(commitLine[i:]) <= 68 - lv * 2: i2 = lc - 1 n = lc - i else: w = n = 0 while w < 68 - lv * 2: w += get_chr_width(commitLine[i + n]) n += 1 p = -1 for s in re.finditer("\s", commitLine[i:i + n + 1]): p = i + s.start() i2 = i + n - 1 if p == -1 else p p = commitLine.find("\n", i, i + n) if 0 <= p < i2: i2 = p if i == j: p = commitLine.find("\n", i) j = lc if p == -1 else p + 1 if re.search("^[*-]", commitLine[i:i + j - 1]): lv = 1 commit += commitLine[i:i2 + 1].strip() i = i2 + 1 # Concatenate the commit lines in ascending order by time commitSet = commit + commitSet # Now reset all the variables ready for a new commit block. authorFound = False dateFound = False messageFound = False messageNL = False messageItem = False message = "" filesFound = False files = "" prevAuthorLine = authorLine # Write out the commit lines try: fout.write(commitSet.encode("utf-8") + "\n") except TypeError: fout.write(commitSet + "\n") # Write out the relay message #fout.write("\nFor the changes before 1.0.0, see ChangeLog.1\n") # Close the input and output lines now that we are finished. fin.close() fout.close() # Set mtime of ChangeLog mtime = int(subprocess.check_output(shlex.split("git log -n1 " "--since=\"1970-01-01 00:00:00\" --pretty=format:%ct " "admin")).strip()) os.utime("ChangeLog", (mtime, mtime))