#!/usr/bin/env python
# (c) 2008, 2009, 2010 Keith Yang (http://keitheis.org)
# Licensed under MIT license: http://www.opensource.org/licenses/mit-license.php

import os
import re
import sys
import logging
import time
import shlex, subprocess

_ignore_patterns = [r'.*\.swp$', r'.*\.pyc$']
ignore_patterns = [re.compile(pattern, re.UNICODE) for pattern in _ignore_patterns]
monitored_files = {}

def get_mtime(filepath):
    try:
        mtime = os.path.getmtime(filepath)
        if mtime:
            return mtime
        stat = os.stat(filepath)
        if stat:
            mtime = stat.st_mtime
        else:
            mtime = 0
    except (OSError, IOError):
        logging.warn('Give up %s' % filepath)
        mtime = 0
    return mtime

def is_modified(files):

    for file in files:
        mtime = get_mtime(file)
        if mtime == 0:
            return False

        if file not in monitored_files:
            monitored_files[file] = mtime
        elif monitored_files[file] < mtime:
            print "%s changed; meowww..." % file
            monitored_files[file] = mtime
            return True

    return False

def _check_output(args):
    return subprocess.Popen(args, stdout=subprocess.PIPE).communicate()[0]

def run_commands(callback_commands):
    for command in callback_commands:
        print command
        args = shlex.split(command)
        #cmdOutput = subprocess.check_output(args) # python 2.7 needed!
        cmdOutput = _check_output(args)
        print cmdOutput

def match_ignored(f):
    for p in ignore_patterns:
        if p.match(f):
            return True
    return False

def scan_dir(path):
    allfiles = []
    for path, dirs, files in os.walk(path):
        for f in files:
            allfiles.append(os.path.join(path, f))
    return allfiles

def _gather_files(path):
    files = []
    if not os.path.exists(path):
        return files

    if os.path.isdir(path):
        files += scan_dir(path)
    else:
        files.append(path)
    filtered_files = [f for f in files if not match_ignored(f)]
    return filtered_files

def gather_files(paths):
    files = []
    for target in paths:
        got_files = _gather_files(target)
        files += got_files
    return files

def main():
    """Usage:
    noscat 'nosetests -w app/tests/lib' app/lib/
    """
    if len(sys.argv) < 3:
        print main.__doc__
        return

    cmd = sys.argv[1]
    files = gather_files(sys.argv[2:])

    for file in files:
        monitored_files[file] = get_mtime(file)
    callback_commands = []
    callback_commands.append(sys.argv[1])
    print "Looking at\n%s\nnow (~%d files). meowww~" % ("\n".join(sys.argv[2:]), len(files))

    run_commands(callback_commands)
    while 1:
        #if is_modified(monitored_files):
        #input_data = raw_input()
        if is_modified(monitored_files):
            run_commands(callback_commands)
            time.sleep(3)

if __name__ == '__main__':
    try:
        main()
    except KeyboardInterrupt, e:
        print
