Skip to content

Instantly share code, notes, and snippets.

@codebrainz
Created October 30, 2011 01:36
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 codebrainz/1325346 to your computer and use it in GitHub Desktop.
Save codebrainz/1325346 to your computer and use it in GitHub Desktop.
Geany ChangeLog, AUTHORS & COMMITTERS from Git log
#!/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