#!/usr/bin/env python
"""
Run selected checks on the current git index

This pre-commit hook was originally based on a hook by Lorenzo Bolla
https://github.com/lbolla/dotfiles/blob/master/githooks/pre-commit

"""
import json
import tempfile
import os
import shutil
import sys
import subprocess
import contextlib
import fnmatch

CONF_FILE = 'gitbox.conf'


@contextlib.contextmanager
def pushd(directory):
    """ CD into the directory inside a 'with' block """
    curdir = os.getcwd()
    os.chdir(directory)
    try:
        yield
    finally:
        os.chdir(curdir)


def get_modified(pattern):
    """Get a list of new and modified files for this commit"""
    out = subprocess.check_output(['git', 'diff', '--cached', '--name-only',
                                   '--diff-filter=ACMRT'])
    modifieds = []
    for line in out.splitlines():
        stripped_line = line.strip()
        if fnmatch.fnmatch(stripped_line, pattern):
            modifieds.append(stripped_line)
    return modifieds


def run_checks(conf, tmpdir):
    """ Run selected checks on the current git index """
    modified = subprocess.check_output(['git', 'diff', '--cached',
                                        '--name-only', '--diff-filter=ACMRT'])
    modified = [name.strip() for name in modified.splitlines()]
    retcode = 0
    path = os.environ['PATH']
    if 'env' in conf:
        binpath = os.path.join(os.path.abspath(conf['env']['path']), 'bin')
        path = binpath + ':' + path
    with pushd(tmpdir):
        for pattern, commands in conf['modified'].iteritems():
            for filename in modified:
                if not fnmatch.fnmatch(filename, pattern):
                    continue
                printed_filename = False
                for command in commands:
                    proc = subprocess.Popen(command + [filename],
                                            env={'PATH': path},
                                            stdout=subprocess.PIPE,
                                            stderr=subprocess.STDOUT)
                    output, _ = proc.communicate()
                    if proc.returncode != 0:
                        if not printed_filename:
                            print filename
                            print '=' * len(filename)
                            printed_filename = True
                        print command[0]
                        print '-' * len(command[0])
                        print output
                        retcode |= proc.returncode

        for command in conf['all']:
            retcode |= subprocess.call(command)

    return retcode


def load_conf():
    """ Load configuration parameters from the conf file """
    if os.path.exists(CONF_FILE):
        with open(CONF_FILE, 'r') as infile:
            return json.load(infile)
    else:
        return {}


def precommit(exit=True):
    """ Run all the pre-commit checks """
    tmpdir = tempfile.mkdtemp()

    try:
        # Put the code being checked-in into the temp dir
        subprocess.check_call(['git', 'checkout-index', '-a', '--prefix=%s/' %
                              tmpdir, '--'])
        submodule_output = subprocess.check_output(['git', 'submodule'])
        # TODO: Use git clone on the submodules as well
        for line in submodule_output.splitlines():
            sub_parts = line.split()
            if len(sub_parts) > 0:
                target = os.path.join(tmpdir, sub_parts[1])
                os.rmdir(target)
                shutil.copytree(sub_parts[1], target)
        retcode = run_checks(load_conf(), tmpdir)
        if exit:
            sys.exit(retcode)
        else:
            return retcode
    finally:
        shutil.rmtree(tmpdir)

if __name__ == '__main__':
    precommit()

@@ -217,20 +217,23 @@
 ort 
-json
+fnmatch
 %0Aimport 
 temp
@@ -232,26 +232,65 @@
 ort 
-tempfile%0Aimport os
+os%0Aimport sys%0A%0Aimport contextlib%0Aimport json%0Aimport shlex
 %0Aimp
@@ -300,27 +300,16 @@
  shutil%0A
-import sys%0A
 import s
@@ -329,33 +329,17 @@
 ort 
-contextlib%0Aimport fnmatch
+tempfile%0A
 %0A%0ACO
@@ -364,16 +364,204 @@
 conf'%0A%0A%0A
+def convert_command(cmd):%0A    %22%22%22 If a command is a string, convert it to list form for subprocess %22%22%22%0A    if isinstance(cmd, basestring):%0A        return shlex.split(cmd)%0A    return cmd%0A%0A%0A
 @context
@@ -1976,16 +1976,71 @@
 mmands:%0A
+                    command = convert_command(command)%0A
         
@@ -2811,16 +2811,63 @@
 'all'%5D:%0A
+            command = convert_command(command)%0A
         

Allow hook commands to be strings or lists