212 lines
5.4 KiB
Python
Executable File
212 lines
5.4 KiB
Python
Executable File
#!/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
|