grim/hggravatar

1edb76f6931b
Make this work with modern hg and some other stuff I hadn't commited yet
# vi:et:ts=4 st=4 sts=4
import errno
import hashlib
import json
import os
import os.path
import shutil
from collections import namedtuple
from mercurial.i18n import _
from mercurial import (
cmdutil,
error,
registrar,
scmutil,
util,
)
from mercurial.utils import stringutil
_CACHE_DIR = b'.hg/cache/gravatar'
urlreq = util.urlreq
urlencode = urlreq.urlencode
cmdtable = {}
command = registrar.command(cmdtable)
def find_authors(ui, repo, *pats, **opts):
ui.write(b'caching authors ... ')
# now walk the dag
m = scmutil.match(repo[None], pats, opts)
authors = {}
def prep(ctx, fns):
"""callback for cmdutil.walkchangerevs that just adds unique email
address to the authors dict."""
email = stringutil.email(ctx.user()).lower().strip()
if not email in authors:
c = namedtuple('Contributor', 'username email gravatar_id')
c.email = email
c.username = stringutil.person(ctx.user())
c.gravatar_id = hashlib.md5(email).hexdigest().encode('UTF-8')
authors[email] = c
for ctx in cmdutil.walkchangerevs(repo, m, opts, prep):
# we handle everything in the callback closure so nothing to do here
continue
path = os.path.join(repo.root, _CACHE_DIR)
try:
os.makedirs(path)
except os.error as err:
if err.errno != errno.EEXIST:
raise
# map_file = os.path.join(path, 'author_map')
# with open(map_file, 'w') as ofp:
# json.dump(authors, ofp, indent=2)
ui.write(b'done.\n')
return authors
def save_avatars(ui, repo, authors, *pats, **opts):
"""this function downloads all the avatars and stores them in the output
directory as pngs. """
url = opts.get('url')
params = {}
rating = opts.get('rating')
if rating != '':
params['r'] = rating
size = opts.get('size')
if size != '':
params['s'] = size
theme = opts.get('theme')
if theme != '':
params['d'] = theme
qs = urlencode(params)
for _, author in authors.items():
ui.write(b'downloading image for %s ... ' % author.username)
filename = b'%s.png' % author.username
uri = os.path.join(url, b'%s.png' % author.gravatar_id)
if qs != b'':
uri += b'?' + qs
img = urlreq.urlopen(uri.decode('UTF-8'))
if img.getcode() != 200:
img.close()
ui.write(b'failed.\n')
continue
with open(os.path.join(repo.root, _CACHE_DIR, filename), 'wb') as ofp:
ofp.write(img.read())
img.close()
ui.write(b'done.\n')
def validate_arguments(**opts):
rating = opts.get('rating')
valid = [b'g', b'pg', b'r', b'x']
if rating != '' and not rating in valid:
raise error.Abort(_('invalid rating %s, accepted values are %s' % (rating, ', '.join(valid))))
size = opts.get('size')
if size != b'':
try:
sz = int(size)
if sz < 1 or sz > 2048:
raise error.Abort(_('invalid size %d, it much be between 1 and 2048' % sz))
except ValueError:
raise error.Abort(_('invalid size %s, it is not an integer between 1 and 2048' % size))
theme = opts.get('theme')
valid = [b'404', b'mp', b'identicon', b'monsterid', b'wavatar', b'retro', b'robohash', b'blank']
if theme != '' and not theme in valid:
raise error.Abort(_('invalid theme %s, accepted values are %s' % (theme, ', '.join(valid))))
@command(
b'gravatar', [
(b'c', b'clean', b'', _('clean the cache'), None),
(b'r', b'rating', b'pg', _('minimum rating'), _('RATING')),
(b's', b'size', b'128', _('size of the images'), _('SIZE')),
(b't', b'theme', b'identicon', _('the theme to use'), _('THEME')),
(b'u', b'url', b'https://www.gravatar.com/avatar', _('the gravatar url'), _('URL')),
],
_("hg gravatar [-u URL] [-o DIR]"),
inferrepo=True,
)
def gravatar(ui, repo, *pats, **opts):
validate_arguments(**opts)
authors = find_authors(ui, repo, *pats, **opts)
save_avatars(ui, repo, authors, *pats, **opts)