Skip to content

Instantly share code, notes, and snippets.

@aquinzi
Last active December 29, 2015 22:09
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save aquinzi/7734823 to your computer and use it in GitHub Desktop.
Save aquinzi/7734823 to your computer and use it in GitHub Desktop.
Create svn changelog
# Create svn changelog (Python 2.7, 3.3)
"""
Takes the svn log [options] and turns them into a changelog.
Basic:
--------
2013-11-25:
changed arguments (better handling)
fix: output path with one file
fix: finding <h1>
2013-11-19:
fixed: now files are saved according to source dir tree
+ option to save files in one depth dir
2013-11-19:
+ relative links for book
Options:
---------
Show author with --author, revision with --rev, time with --time. You can prefix a char with --prefix.
The default order is new to old, but you can reverse it with --reverse
Specify the date (in ISO 8601) with --date. You can include a range as date1:date2, or leave date2 empty (date1:) to include today.
Specify the revision with --revision, or a range as rev1:rev2 or leave rev2 empty to include HEAD revision
Group them
----------
You can group the dates with --group. This will show revs in a list. If you want to group them, use --subgroup ([rev][msg]).
If you want to show them inline (besides grouping with date), use --inline ([rev][msg][author])
"""
import subprocess
import sys
import argparse
import datetime
from collections import namedtuple
__version__ = "0.2"
logItemDetails = namedtuple('logItemDetails', 'rev,author,msgs')
groupit = {}
def format_strings(option, value, grouping=False):
""" Format the option: adds space to value or make it blank
if grouping, dont add the space
"""
if option:
if not grouping:
return " " + value
else:
return value
return ""
def prepare_range(option, value):
"""Prepares the options with range, or the ones that use them """
if len(value.split(":")) == 1:
part1 = value
part2 = ""
else:
part1, part2 = value.split(":")
if option == 'date':
if part2:
part2 = datetime.datetime.strptime(part2, "%Y-%m-%d").date()
else:
part2 = datetime.date.today()
part2 = part2 + datetime.timedelta(days=1)
if option == 'revision':
if not part2:
try:
#head revision
svnversion = subprocess.check_output(['svnversion']).strip()
except subprocess.CalledProcessError:
sys.exit()
if svnversion.endswith('M') or svnversion.endswith('S') \
or svnversion.endswith('P') or svnversion.endswith('MSP'):
if not svnversion.endswith('MSP'):
svnversion = svnversion[0:len(svnversion)-1]
else:
svnversion = svnversion[0:len(svnversion)-3]
value = part1 + ":" + svnversion
if option == 'date':
#add one day so it's really that day and not the one before it
# see http://svnbook.red-bean.com/en/1.5/svn.tour.revs.specifiers.html#svn.tour.revs.dates
part1 = datetime.datetime.strptime(part1, "%Y-%m-%d").date()
part1 = part1 + datetime.timedelta(days=1)
if part2:
part2 = ":{" + part2.isoformat() + '}'
value = '{' + part1.isoformat() + '}' + part2
return value
def clean_svnlog_item(item):
"""returns necessary data (rev, author, date, time, msgs) from svn log item"""
item = item.splitlines()
item_title = item[1]
item_msgs = item[3:]
rev, author, date_all, totallines = item_title.split(" | ")
date, time, diftime, hdayname, hday, hmonth, hyear = date_all.split(" ")
time = time[0:len(time)-3] # remove seconds
if not OPTIONS.group:
rev = format_strings(OPTIONS.show_rev, rev)
author = format_strings(OPTIONS.show_author, author)
time = format_strings(OPTIONS.show_time, time)
else:
rev = format_strings(OPTIONS.show_rev, rev, True)
author = format_strings(OPTIONS.show_author, author, True)
return rev, author, date, time, item_msgs
parser = argparse.ArgumentParser(formatter_class=argparse.RawTextHelpFormatter, description=''' Make a changelog from svn.
You\'re using '''+__version__+''' version''')
parser.add_argument("path", help="The working dir or file")
exclusive = parser.add_mutually_exclusive_group()
exclusive.add_argument("--date", help="Specify date (ISO 8601) or range (date1:date2) to show from. Can leave second date in range (date1:) empty to include today")
exclusive.add_argument("--revision", help="Specify revision or range (rev1:rev2) to show from. Can leave second rev in range (rev1:) to include latest")
parser.add_argument("--show-author", "-a", action='store_true', help="Show author")
parser.add_argument("--show-rev", "-r", action='store_true', help="Show revision")
parser.add_argument("--show-time", "-t", action='store_true', help="Show time (HH:MM)")
parser.add_argument("--group" , "-g", action='store_true', help="Group by date, show revs and authors in list (if enabled).")
parser.add_argument("--subgroup", "-s", action='store_true', help="Subgroup date grouping revs. Authors show below (if enabled)")
parser.add_argument("--inline", "-i", action='store_true', help="Items grouped by date: [rev][msg][author] for each message (if properties enabled)")
parser.add_argument("--prefix", default="", help="prefix all lines with char")
parser.add_argument("--reverse", action="store_false", help="old to new instead of new to old")
OPTIONS = parser.parse_args()
PREFIX = OPTIONS.prefix
command = ['svn', 'log', OPTIONS.path]
#check belonging to group and auto activate view:
if OPTIONS.subgroup or OPTIONS.inline:
OPTIONS.group = True
if OPTIONS.subgroup:
OPTIONS.rev = True
if OPTIONS.date or OPTIONS.revision:
if OPTIONS.date:
the_option = prepare_range('date', OPTIONS.date)
if OPTIONS.revision:
the_option = prepare_range('revision', OPTIONS.revision)
command += ['-r', the_option]
try:
output = subprocess.check_output(command)
# to show svn error
except subprocess.CalledProcessError:
sys.exit()
output = output.split("------------------------------------------------------------------------")
output = [s for s in output if s.strip()] # bye blank lines
ouputNice = list()
for line in output:
rev, author, date, time, msgs = clean_svnlog_item(line)
if not OPTIONS.group:
print (PREFIX + "{0}{1}{2}{3}:".format(date, time, rev, author))
for msg in msgs:
print (PREFIX + " " + msg)
print (PREFIX)
else:
if not date in groupit:
groupit[date] = list()
groupit[date].append(logItemDetails(rev,author,msgs))
# for group
for date, items in sorted(groupit.items(), reverse=OPTIONS.reverse):
if not OPTIONS.subgroup and not OPTIONS.inline:
revs = list()
authors = list()
msgs = list()
for log in items:
revs.append(log.rev)
authors.append(log.author)
msgs.append(log.msgs)
# remove duplicated authors
authors = list(set(authors))
#remove blank items
revs = [s for s in revs if s.strip()]
revs = " (" + " ".join(revs) + ") " if revs else ""
authors = ", ".join(authors) if authors else ""
print ("{0}{1}{2}{3}:".format(PREFIX, date, revs, authors))
for list_msgs in msgs:
for msg in list_msgs:
print (PREFIX + " " + msg)
else:
print (PREFIX+ date)
for log in items:
for msg in log.msgs:
printhis = ""
if OPTIONS.subgroup or (OPTIONS.inline and not OPTIONS.show_author):
printhis = PREFIX + " {0} {1}"
else:
printhis = PREFIX + " {0} {1} ({2})"
print (printhis.format(log.rev, msg, log.author))
if OPTIONS.subgroup and OPTIONS.show_author:
print (PREFIX + " ------- " + log.author + "\n" + PREFIX)
else:
print (PREFIX + "")
print (PREFIX)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment