#!/bin/python

__requires__ = ['moncov > 0.1']

import moncov; moncov.ctl.disable()
import aaargh
import re
import argparse
import sys
import logging
import functools
import distutils

logging.basicConfig(level=logging.INFO)
log = logging.getLogger(__file__)


def catching(func):
    '''decorating in try/exept&log err'''
    @functools.wraps(func)
    def decorated(*args, **kvs):
        try:
            ret = func(*args, **kvs)
        except Exception as e:
            log.error(func.func_name + ' failed: %r' % e)
            ret = 1
        return ret
    return decorated

class ReAction(argparse.Action):
    '''custom Re.compiling argparse action'''
    def __call__(self, parser, namespace, values, option_string=None):
        '''Re.compile action'''
        setattr(namespace, self.dest, [re.compile(value) for value in values])

app = aaargh.App(description='moncov collects coverage remotelly')
app.arg('-a', '--dbhost', help='Host name of the MongoDB to use', default=moncov.conf.DBHOST)
app.arg('-b', '--dbport', help='Port of the MongoDB service', type=int, default=moncov.conf.DBPORT)
app.arg('-c', '--dbname', help='Name of the db to collect stats in', default=moncov.conf.DBNAME)

@app.cmd(help='cobertura xml output')
@app.cmd_arg('-o', '--output', help='output xml filename', default='moncov.xml')
@catching
def cobertura(dbhost, dbport, dbname, output):
    moncov.stats.cobertura.generate_xml(dbhost, dbport, dbname, output)

@app.cmd(help='reset traces counting')
@catching
def reset(dbhost, dbport, dbname):
    db = moncov.conf.get_db(dbhost=dbhost, dbport=dbport, dbname=dbname)
    moncov.ctl.drop(db=db)

@app.cmd(help='enable collecting')
@app.cmd_arg('-e', '--system', help='apply sytem-wide', default=True, action='store_true')
@app.cmd_arg('-f', '--whitelist', help='filter regexps', default=moncov.conf.WHITELIST, action=ReAction, nargs='+')
@app.cmd_arg('-g', '--blacklist', help='filter regexps', default=moncov.conf.BLACKLIST, action=ReAction, nargs='+')
@catching
def enable(dbhost, dbport, dbname, system, whitelist, blacklist):
    moncov.ctl.sys_enable(dbhost=dbhost, dbport=dbport, dbname=dbname, whitelist=whitelist, blacklist=blacklist)

@app.cmd(help='disable collecting')
@app.cmd_arg('-e', '--system', help='apply sytem-wide', default=True, action='store_true')
@catching
def disable(*args, **kvs):
    moncov.ctl.sys_disable()

@app.cmd(help='simple stats')
@app.cmd_arg('-f', '--whitelist', help='filter regexps', default=moncov.conf.WHITELIST, action=ReAction, nargs='+')
@app.cmd_arg('-g', '--blacklist', help='filter regexps', default=moncov.conf.BLACKLIST, action=ReAction, nargs='+')
@catching
def simple(dbhost, dbport, dbname, whitelist, blacklist):
    db = moncov.conf.get_db(dbhost=dbhost, dbport=dbport, dbname=dbname)
    moncov.stats.simple.print_stats(db=db, whitelist=whitelist, blacklist=blacklist)

@app.cmd(help='simple xml stats')
@app.cmd_arg('-f', '--whitelist', help='filter regexps', default=moncov.conf.WHITELIST, action=ReAction, nargs='+')
@app.cmd_arg('-g', '--blacklist', help='filter regexps', default=moncov.conf.BLACKLIST, action=ReAction, nargs='+')
@app.cmd_arg('-o', '--output', help='output xml filename', default='moncov.xml')
@catching
def simple_xml(dbhost, dbport, dbname, whitelist, blacklist, output):
    db = moncov.conf.get_db(dbhost=dbhost, dbport=dbport, dbname=dbname)
    with open(output, 'w+') as fd:
        fd.write(moncov.stats.simple.get_stats_xml(db=db, whitelist=whitelist, blacklist=blacklist))

@app.cmd(help="Ned Batchelder's coveragepy report")
@app.cmd_arg('-o', '--output', help='output stats to file')
@app.cmd_arg('--omit', help='omit specified files', metavar='"PATH1,PATH2,..."')
@app.cmd_arg('--include', help='include specified files', metavar='"PATH1,PATH2,..."')
@app.cmd_arg('--source', help='source directories --- such as repos --- to consider for measured files', metavar='"SRC1,SRC2,..."') 
@app.cmd_arg('--morfs', help='morfs')
@app.cmd_arg('--ignore-errors', help='ingore errors', action='store_true')
@app.cmd_arg('--report', help='print report', action='store_true')
@app.cmd_arg('--xml', help='output in cobertura xml', action='store_true')
@app.cmd_arg('--html', help='output in html format', action='store_true')
@app.cmd_arg('--fail-under', help='fail if coverage rate is under specified treshold', metavar='MIN', type=int, default=None)
@app.cmd_arg('--directory', help='output to directory')
@app.cmd_arg('--annotate', help='annotate source code', action='store_true')
@app.cmd_arg('--show-missing', help='show linenumbers that were not executed', action='store_true')
@app.cmd_arg('--title', help='set title for html output')
@app.cmd_arg('--rcfile', help='coverage rc file to use')
@app.cmd_arg('--pylib', help='include pylib', action='store_true')
@app.cmd_arg('--debug', help='coveragepy debug options')
@app.cmd_arg('--ned-version', help='show coveragepy version', action='store_true')
@catching
def ned(dbhost, dbport, dbname, output, omit, include, source, morfs, ignore_errors, report, xml, html, fail_under,
        directory, annotate, show_missing, title, rcfile, pylib, debug, ned_version):
    '''call monkey-patched coveragepy reports'''
    import coverage

    if ned_version:
        print coverage.__version__
        return 0

    moncov.monkey.patch_coveragepy(dbhost=dbhost, dbport=dbport, dbname=dbname)

    # process list options
    source = coverage.cmdline.unshell_list(source)
    include = coverage.cmdline.unshell_list(include)
    omit = coverage.cmdline.unshell_list(omit)
    debug = coverage.cmdline.unshell_list(debug)
    # process morfs options
    if distutils.version.LooseVersion(coverage.__version__) >= '4.0':
        morfs = coverage.cmdline.unglob_args(morfs)

    coverage_ = coverage.coverage(
        cover_pylib = pylib,
        config_file = rcfile,
        source = source,
        omit = omit,
        include = include,
        debug = debug
    )
    coverage_.load()
    report_args = dict (
        morfs = morfs,
        ignore_errors = ignore_errors,
        omit = omit,
        include = include
    )
    if report:
        total = coverage_.report(show_missing=show_missing, **report_args)
    if annotate:
        coverage_.annotate(directory=directory, **report_args)
    if html:
        total = coverage_.html_report(directory=directory, title=title, **report_args)
    if xml:
        total = coverage_.xml_report(outfile=output, **report_args)

    if fail_under is not None:
        if 0 < total < 1:
            total = 1
        elif 99 < total < 100:
            total = 100
        else:
            total = round(total)
        if total >= fail_under:
            return 0
        else:
            return 2
    else:
        return 0

if __name__ == '__main__':
    sys.exit(app.run())
