#!/usr/bin/python # vi: ts=4 expandtab # A crappy little script # that changes bzr 'log' # into someting that rpm spec files can use (best effort) import os import re import sys from datetime import datetime from datetime import date import subprocess E_TYPES = ['tags', 'revno', 'author', 'timestamp', 'committer'] def tiny_p(cmd): # Darn python 2.6 doesn't have check_output (argggg) sp = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=None) (out, err) = sp.communicate() return (out, err) def extract_entry(collecting): entry = {} for t in E_TYPES: look_for = "%s:" % (t) for v in collecting: if v.startswith(look_for): entry[t] = v[len(look_for):].strip() break i = -1 # Messages seem to be the last element so suck # those all up for a, v in enumerate(collecting): if v.startswith("message:"): i = a break if i != -1: msg_lines = collecting[i + 1:] entry['message'] = "\n".join(msg_lines) return entry def clean_authors(authors): if not authors: return '' auth_cleaned = set() for a in authors: a = a.strip() if a: auth_cleaned.add(a) if not auth_cleaned: return '' uniq_authors = list(auth_cleaned) if len(uniq_authors) == 1: return authors[0] auths = "(%s)" % ", ".join(uniq_authors) return auths def clean_revnos(revnos): novs = list() for r in revnos: r = r.strip() r = r.replace("[merge]", "") if r: novs.append(int(r)) entries = list(novs) if not entries: return '' entries.sort() if len(entries) == 1: return "%s" % (entries[0]) # Check if consecutive start = entries[0] consec = True for (i, v) in enumerate(entries): if v != start + i: consec = False break if consec: end = entries[-1] return "%s => %s" % (start, end) v = [str(b) for b in entries] return ", ".join(v) def spacey(am): return " " * am def justify(text, space_wanted): c_bef = len(text) t_c = len(text.lstrip()) space_am = (c_bef - t_c) needed = (space_wanted - space_am) if needed < 0: return text return (" " * (needed) + text) def clean_messages(messages): contents = [] for msg in messages: # Split into sub-messages... # if we can lines = [] pieces = msg.splitlines() if len(pieces) == 1: lines.append("%s- %s " % (spacey(4), msg.strip())) else: n_lines = [] n_lines.append(pieces[0].strip()) for line in pieces[1:]: line = line.lstrip() if not line: continue n_lines.append(justify(line, 6)) lines.append("%s- %s" % (spacey(4), "\n".join(n_lines))) contents.extend(lines) return "\n".join(contents) def build_changelog(history=-1): cmd = ['bzr', 'log', '--timezone=utc'] (stdout, _stderr) = tiny_p(cmd) # Clean the format up entries = stdout.splitlines() all_entries = [] collecting = [] for e in entries: if e.startswith("---"): if collecting: a_entry = extract_entry(collecting) if a_entry: all_entries.append(a_entry) collecting = [] else: collecting.append(e) # Anything that we left behind?? entry = extract_entry(collecting) if entry: all_entries.append(entry) if history > 0: take_entries = list(all_entries[0:history]) else: take_entries = list(all_entries) # Merge those with same date date_entries = {} for e in take_entries: author = e.get('author') if not author: author = e.get('committer') if not author: continue timestamp = e.get('timestamp') if not timestamp: continue msg = e.get('message') if not msg: continue revno = e.get('revno') if not revno: continue # http://bugs.python.org/issue6641 timestamp = timestamp.replace("+0000", '').strip() ds = datetime.strptime(timestamp, '%a %Y-%m-%d %H:%M:%S') ds = ds.date() if ds not in date_entries: entry = {} entry['messages'] = [] entry['authors'] = [] entry['revnos'] = [] date_entries[ds] = entry entry = date_entries[ds] entry['messages'].append(msg) entry['authors'].append(author) entry['revnos'].append(revno) # It wants them in chronological order... dates = sorted(date_entries.keys()) chglog = [] for ds in reversed(dates): e = date_entries[ds] authors = clean_authors(e['authors']) revnos = clean_revnos(e['revnos']) top_line = "%s %s - [revison %s]" % (ds.strftime("%a %b %d %Y"), authors, revnos) chglog.append("* %s" % (top_line)) chglog.append(clean_messages(e['messages'])) return "\n".join(chglog) if __name__ == '__main__': args = sys.argv[1:] history_am = -1 if args: history_am = int(args[0]) chglog = build_changelog(history_am) print chglog