# plugs/hg.py 
#
# (c) Wijnand 'tehmaze' Modderman - http://tehmaze.com
# BSD License

""" only works on hg version of the bot """

from gozerbot.generic import gozerpopen
from gozerbot.aliases import aliases
from gozerbot.commands import cmnds
from gozerbot.examples import examples
from gozerbot.plughelp import plughelp
import os

__author__ = "Wijnand 'tehmaze' Modderman - http://tehmaze.com"
__license__ = 'BSD'

plughelp.add('hg', 'hg related information')

def check_hg(ievent):
    """ check if the bot is a mercurial repository """
    if not os.path.isdir('.hg'):
        ievent.reply('this only works on the HG version of gozerbot')
        return False
    return True

def handle_hg_annotate(bot, ievent):
    """ call hg annotate """
    if not check_hg(ievent):
        return
    if len(ievent.args) == 0:
        ievent.missing('[<rel>] <file>')
        return
    rel1 = ''
    file = ''
    if len(ievent.args) == 1:
        file = ievent.args[0]
    else:
        rel1 = ievent.args[0]
        file = ievent.args[1]
        if rel1 != 'tip':
            try:
                rel1 = int(rel1)
            except ValueError:
                ievent.reply('rel has to be a valid number or tip')
                return
    realfile = os.path.abspath(file)
    if not realfile.startswith(os.path.abspath(os.getcwd())):
        ievent.reply('permission denied')
        return
    if not os.path.isfile(realfile):
        ievent.reply('file not found')
        return
    cmndlist = ['hg', 'annotate', '-u']
    if rel1:
        cmndlist += ['-r', str(rel1)]
    cmndlist += [file, ]
    try:
        proces = gozerpopen(cmndlist)
    except Exception, ex:
        ievent.reply('error running popen: %s' % str(ex))
        return
    data = proces.fromchild.readlines()
    returncode = proces.close()
    if returncode != 0:
        ievent.reply(' '.join(cmndlist) + ' returned code %s' % \
str(returncode))
        return
    result = []
    first = True
    for line in data:
        line = line.strip()
        if first and 'No such file in rev' in line:
            ievent.reply('no such file in this revision')
            return
        user = line.split(':')[0]
        if not user in result:
            result.append(user)
        first = False
    result.sort()
    ievent.reply('%s is changed by: %s' % (file, ', '.join(result)))

cmnds.add('hg-annotate', handle_hg_annotate, 'USER')
examples.add('hg-annotate', 'annotate the changes of a file', \
'hg-annotate gozerbot/bot.py')
aliases.data['hg-blame'] = 'hg-annotate'

def handle_hg_changes(bot, ievent):
    """ call hg diff """
    if not check_hg(ievent):
        return
    if not ievent.args:
        ievent.missing('<rel> [<rel>]')
        return
    rel1 = ievent.args[0].lower()
    rel2 = rel1
    if len(ievent.args) >= 2:
        rel2 = ievent.args[1]
    if rel1 != 'tip':
        try:
            rel1 = int(rel1)
        except ValueError:
            ievent.reply('rel has to be a valid number or tip')
            return
    if rel2 != 'tip':
        try:
            rel2 = int(rel2)
        except ValueError:
            ievent.reply('rel has to be a valid number or tip')
            return
    cmndlist = ['hg', 'diff', '-p', '-r', str(rel1)]
    if rel1 != rel2:
        cmndlist += ['-r', str(rel2)]
    try:
        proces = gozerpopen(cmndlist)
    except Exception, ex:
        ievent.reply('error running popen: %s' % str(ex))
        return
    data = proces.fromchild.readlines()
    returncode = proces.close()
    if returncode != 0:
        ievent.reply(' '.join(cmndlist) + ' returned code %s' % \
str(returncode))
        return
    result = []
    prev   = ''
    for line in data:
        if line.startswith('--- '):
            prev = line.split()[1]
        elif line.startswith('+++ '):
            curr = line.split()[1][2:]
            if prev == '/dev/null':
                result.append('add %s' % curr)
            elif curr == '/dev/null':
                result.append('del %s' % prev)
            else:
                result.append('mod %s' % curr)
    if not result:
        ievent.reply('no changes found')
    else:
        if rel1 == rel2:
            rel2 = 'tip'
        ievent.reply('%s - %s: %s' % (str(rel1), str(rel2), ', '.join(result)))

cmnds.add('hg-changes', handle_hg_changes, 'USER')
examples.add('hg-changes', 'show changes in the current release (tip) or \
between two releases', '1) hg-changes tip 2) hg-changes 1900 tip')

def handle_hg_committers(bot, ievent):
    """ show hg committers and the number of commits they made """
    if not check_hg(ievent):
        return
    short = ievent.rest.lower().strip() == 'short'
    cmndlist = ['hg', 'log']
    try:
        proces = gozerpopen(cmndlist)
    except Exception, ex:
        ievent.reply('error running popen: %s' % str(ex))
        return
    data = proces.fromchild.readlines()
    returncode = proces.close()
    if returncode != 0:
        ievent.reply(' '.join(cmndlist) + ' returned code %s' % \
str(returncode))
        return
    counts = {}
    for i in data:
        if 'user:' in i:
            user = i.split('user:')[1].strip()
            if short:
                user = user.split('@', 1)[0]
                if '<' in user:
                    user = user.split('<')[-1]
            if not counts.has_key(user):
                counts[user] = 1
            else:
                counts[user] += 1
    counts = [[v, k] for k, v in counts.iteritems()]
    counts.sort()
    counts.reverse()
    result = []
    for count, user in counts: 
        result.append('%s: %d' % (user, count))
    if result:
        ievent.reply('top committers: %s' % ', '.join(result))
    else:
        ievent.reply('no result')

cmnds.add('hg-committers', handle_hg_committers, 'USER')
examples.add('hg-committers', 'shows hg committer statistics', 'hg-committers')
aliases.data['committers'] = 'hg-committers'

def handle_hglog(bot, ievent):
    """ show hg log """
    if not check_hg(ievent):
        return
    # check if the given file is within our path
    if ievent.args:
        file = ievent.args[0]
        realfile = os.path.abspath(file)
        if not realfile.startswith(os.path.abspath(os.getcwd())):
            ievent.reply('permission denied')
            return
        if not os.path.isfile(realfile):
            ievent.reply('file not found')
            return
        file = [file]
    else:
        file = []
    cmndlist = ['hg', 'log', '-l', '10']
    try:
        proces = gozerpopen(cmndlist, file)
    except Exception, ex:
        ievent.reply('error running popen: %s' % str(ex))
        return
    data = proces.fromchild.readlines()
    returncode = proces.close()
    if returncode != 0:
        ievent.reply(' '.join(cmndlist) + ' returned code %s' % \
str(returncode))
        return
    result = []
    last_changeset = ''
    last_user = ''
    for line in data:
        if line.startswith('changeset:'):
            last_changeset = line.split(':', 1)[1].strip()
        elif line.startswith('user:'):
            last_user = line.split(':', 1)[1].strip().split('@')[0]
        elif line.startswith('summary:'):
            summary = line.split(':', 1)[1].strip()
            result.append('r%s %s: %s' % (last_changeset, last_user, summary))
    if not result:
        ievent.reply('no changes found')
    else:
        ievent.reply('log result: ' + ' .. '.join(result))

cmnds.add('hg-log', handle_hglog, 'USER')
examples.add('hg-log', 'show the changelog for the repo, or for a file', \
'hg-log gozerplugs/plugs/hg.py')
