Created
October 30, 2011 01:36
-
-
Save codebrainz/1325346 to your computer and use it in GitHub Desktop.
Geany ChangeLog, AUTHORS & COMMITTERS from Git log
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
''' | |
Helper script for Geany's distribution files generated by Git. | |
TODO: Use .mailmap or other means to use preferred name and emails. | |
''' | |
AUTHORS_HEADER = 'The following people have authored commits:\n' | |
AUTHORS_FOOTER = '''\nSee the COMMITTERS, ChangeLog and THANKS files for \ | |
a full list of contributors.''' | |
COMMITTERS_HEADER = 'The following people have committed code:\n' | |
COMMITTERS_FOOTER = '''\nSee the AUTHORS, ChangeLog and THANKS files for \ | |
a full list of contributors.''' | |
import codecs | |
import os | |
import subprocess | |
import sys | |
from collections import namedtuple | |
from optparse import OptionParser | |
Person = namedtuple ('Person', 'name emails count') | |
def find_person (people, name, emails): | |
''' | |
Lookup person in people by name or any of their email addresses. | |
''' | |
for person in people: | |
if person.name == name: | |
return person | |
elif any (email in person.emails for email in emails): | |
return person | |
return None | |
def command_get_lines (args, workdir='.'): | |
''' | |
Get a list of UTF-8 encoded lines with trailing whitespace stripped | |
off from the stdout of a subprocess. | |
''' | |
cd = os.getcwd () | |
os.chdir (workdir) | |
proc = subprocess.Popen (args, stdout=subprocess.PIPE) | |
fobj = codecs.EncodedFile (proc.stdout, 'UTF-8', 'UTF-8', errors='replace') | |
lines = [ line.rstrip () for line in fobj ] | |
os.chdir (cd) | |
return lines | |
def utf8_ljust (s, length, fill_char=u' '): | |
''' | |
Pad the right side of s with fill_char until its as long as length. | |
Built-in string.ljust () doesn't seem to work properly with unicode. | |
''' | |
if len (fill_char) != 1: | |
raise ValueError ('fill_char must be exactly 1 character long') | |
s = unicode (s, 'UTF-8', errors='replace') | |
while len (s) < length: | |
s = s + fill_char | |
return s | |
def get_people (d, fmt): | |
''' | |
Gets a list of unique People from the git log in directory d. The | |
fmt is passed as the format for git log's --pretty argument. | |
''' | |
lines = command_get_lines ([ 'git', 'log', | |
'--encoding=UTF-8', | |
'--pretty=format:%s' % fmt ], d) | |
people = [] | |
for line in lines: | |
name = line.split ('|')[0] | |
emails = [line.split ('|')[1]] | |
person = find_person (people, name, emails) | |
if person: | |
people.remove (person) | |
person = Person (person.name, person.emails, person.count + 1) | |
for e in emails: | |
if e not in person.emails: | |
person.emails.append (e) | |
person.emails.sort () | |
people.append (person) | |
else: | |
people.append (Person (name, emails, 1)) | |
return sorted (people, key=lambda p: p.count, reverse=True) | |
def print_people (d, fmt, header='', footer=''): | |
''' | |
Prints the unique People for git log in directory d passing the fmt | |
as the format to git log's --pretty option. The people are printed | |
in the standard format of `Firstname Lastname <EmailAddress>` with | |
all of the email addresses left-aligned. | |
''' | |
if header: | |
print header | |
people = get_people (d, fmt) | |
max_len = max ([ len (person.name) for person in people ]) | |
for person in people: | |
name = utf8_ljust (person.name, max_len).encode ('utf8', 'replace') | |
emails = person.emails[0].encode ('utf8', 'replace') | |
sys.stdout.write ("%s <%s>\n" % (name, emails)) | |
if footer: | |
print footer | |
def print_changelog (d): | |
args = [ 'git', 'log', '--shortstat', '--no-color', '--encoding=UTF-8' ] | |
cd = os.getcwd () | |
os.chdir (d) | |
proc = subprocess.Popen (args, stdout=subprocess.PIPE) | |
fobj = codecs.EncodedFile (proc.stdout, 'UTF-8', 'UTF-8', errors='replace') | |
for line in fobj: | |
print line.strip () | |
os.chdir (cd) | |
def main (): | |
p = OptionParser(usage='Usage: %prog [options] GITDIR') | |
p.add_option ('-c', '--committers', default=False, action='store_true', | |
dest='committers', help='print a list of committers') | |
p.add_option ('-a', '--authors', default=False, action='store_true', | |
dest='authors', help='print a list of authors') | |
p.add_option ('-l', '--changlog', default=False, action='store_true', | |
dest='changelog', help='print a change log') | |
opts, args = p.parse_args () | |
if len (args) < 1: | |
p.error ('please specify the root Git directory') | |
elif not os.path.isdir (os.path.join (args[0], '.git')): | |
p.error ('.git directory is missing in %s' % args[0]) | |
if int (opts.committers) + int (opts.authors) + int (opts.changelog) > 1: | |
p.error ('options -c, -a and -l are mutually exclusive') | |
if opts.committers: | |
print_people (args[0], '%cn|%ce', COMMITTERS_HEADER, COMMITTERS_FOOTER) | |
elif opts.authors: | |
print_people (args[0], '%an|%ae', AUTHORS_HEADER, AUTHORS_FOOTER) | |
elif opts.changelog: | |
print_changelog (args[0]) | |
else: | |
p.error ('no option specified') | |
if __name__ == '__main__': main () |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment