#!/usr/bin/env python

#http://tech.yipit.com/2011/11/16/183772396/

import os
import re
import subprocess
from distutils import spawn
from functools import partial
import sys

modified = re.compile('^(?:M|A)(\s+)(?P<name>.*)')

DISABLED_CHECKS = [
    {
        'output': 'Checking for pdbs...',
        'command': 'grep -n "import pdb" %s',
        'ignore_files': ['.*pre-commit'],
        'print_filename': True,
    },
    {
        'output': 'Checking for ipdbs...',
        'command': 'grep -n "import ipdb" %s',
        'ignore_files': ['.*pre-commit'],
        'print_filename': True,
    },
    {
        'output': 'Checking for print statements...',
        'command': 'grep -n print %s',
        'match_files': ['.*\.py$'],
        'ignore_files': ['.*migrations.*', '.*management/commands.*', '.*manage.py', '.*/scripts/.*'],
        'print_filename': True,
    },
    {
        'output': 'Checking for console.log()...',
        'command': 'grep -n console.log %s',
        'match_files': ['.*yipit/.*\.js$'],
        'print_filename': True,
    },
    {
        'output': 'Checking for debugger...',
        'command': 'grep -n debugger %s',
        'match_files': ['.*\.js$'],
        'print_filename': True,
    },
    {
        'output': 'Checking for Sass changes...',
        'command': 'sass --quiet --update %s',
        'match_files': ['.*\.scss$'],
        'print_filename': True,
    },
]
CHECKS = [
    {
        'output': 'Running Pyflakes...',
        'command': 'pyflakes %s',
        'match_files': ['.*\.py$'],
        'ignore_files': ['.*/build/.*'],
        'print_filename': False,
    },
    {
        'output': 'Running pep8...',
        'command': 'pep8 -r --ignore=E501,E251,E711,E712 %s',
        'match_files': ['.*\.py$'],
        'ignore_files': ['.*/build/.*'],
        'print_filename': False
    },
    {
        'output': 'Checking for python executable files...',
        'command': '[[ -x %s ]] && echo "This file should not be executable!"',
        'match_files': ['.*\.py$'],
        'ignore_files': ['.*/build/.*'],
        'print_filename': True
    }
]


def matches_file(file_name, match_files):
    return any(re.compile(match_file).match(file_name) for match_file in match_files)


def check_files(files, check):
    result = 0
    print check['output']
    for file_name in files:
        if not 'match_files' in check or matches_file(file_name, check['match_files']):
            if not 'ignore_files' in check or not matches_file(file_name, check['ignore_files']):
                popen = partial(subprocess.Popen,
                                check['command'] % file_name,
                                stdout=subprocess.PIPE,
                                stderr=subprocess.PIPE,
                                shell=True)

                if check.get('use_dirname_cwd', None):
                    process = popen(cwd=os.path.dirname(file_name))
                else:
                    process = popen()
                out, err = process.communicate()
                if out or err:
                    if check['print_filename']:
                        prefix = '\t%s:' % file_name
                    else:
                        prefix = '\t'
                    output_lines = ['%s%s' % (prefix, line) for line in out.splitlines()]

                    print '\n'.join(output_lines)

                    if err:
                        print err
                    result = 1
    return result


def main(all_files, exclude=None):
    if not exclude:
        exclude = []

    files = []
    if all_files:
        for root, dirs, file_names in os.walk('.'):
            for ex in exclude:
                if ex in dirs:
                    dirs.remove(ex)
            for file_name in file_names:
                files.append(os.path.join(root, file_name))
    else:
        p = subprocess.Popen(['git', 'rev-parse', '--show-toplevel'], stdout=subprocess.PIPE)
        out, err = p.communicate()
        rc = p.wait()
        if rc != 0:
            raise RuntimeError("Cannot invoke git %s" % out)
        git_root = out.strip()

        p = subprocess.Popen(['git', 'status', '--porcelain'], stdout=subprocess.PIPE)
        out, err = p.communicate()
        for line in out.splitlines():
            match = modified.match(line)
            if match:
                files.append(os.path.join(git_root, match.group('name')))

    result = 0

    for check in CHECKS:
        result = check_files(files, check) or result

    sys.exit(result)


if __name__ == '__main__':
    all_files = False
    exclude = ['.git']
    n = 1
    while n < len(sys.argv):
        if sys.argv[n] == '--all-files':
            all_files = True
        elif sys.argv[n] == '--exclude':
            exclude.append(sys.argv[n + 1])
            n = n + 1
        n = n + 1

    print "exclude %s" % exclude
    main(all_files, exclude)
