Calls the compiler when it detects an update for a file with the extensions coffee, less, sass, scss. Detects updates to files with extensions html, css, js and reloads the browser.
$ python watcher.py --dir=path/to/dir
watcher.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import sys
import time
import commands
from os.path import splitext, extsep, abspath
from watchdog.observers import Observer
from watchdog.events import FileSystemEventHandler
try:
from selenium import webdriver
selenium_enabled = True
except ImportError:
selenium_enabled = False
try:
import pynotify
except ImportError:
def notify(*args):
""" dummy """
else:
pynotify.init("Watcher")
def notify(filename, error):
notify = pynotify.Notification(filename, error, "dialog-warning")
notify.set_timeout(1000)
notify.show()
def get_ext(filename):
return splitext(filename)[1].lstrip(extsep).lower()
class Compiler(FileSystemEventHandler):
def __init__(self):
self.compilers = {}
def on_modified(self, event):
ext = get_ext(event.src_path)
if ext in self.compilers:
status, output = self.compilers[ext](event.src_path)
if status != 0:
self.fail(event.src_path, output)
else:
self.success(event.src_path)
def fail(self, filename, error):
print "\x1b[31mError!: %s" % filename
print error, "\x1b[39m"
notify(filename, error)
def success(self, filename):
print "\x1b[32mCompiled: %s\x1b[39m" % filename
def register(self, ext):
def _register(compiler):
self.compilers[ext] = compiler
return compiler
return _register
default_compiler = Compiler()
@default_compiler.register("coffee")
def coffee_compiler(path):
return commands.getstatusoutput("coffee -c %s" % path)
@default_compiler.register("sass")
def sass_compiler(path):
return commands.getstatusoutput("sass --update %s" % path)
@default_compiler.register("scss")
def sass_compiler(path):
return commands.getstatusoutput("scss --update %s" % path)
@default_compiler.register("less")
def sass_compiler(path):
out = splitext(path)[0]
return commands.getstatusoutput("lessc %s > %s.css" % (path, out))
class BrowserReloader(FileSystemEventHandler):
watch_ext = ["html", "js", "css"]
def __init__(self, browser_name, url):
super(BrowserReloader, self).__init__()
if browser_name == "Chrome":
self.browser = webdriver.Chrome()
elif browser_name == "Firefox":
self.browser = webdriver.Firefox()
else:
raise ValueError("Unknown browser '%s'" % browser_name)
self.browser.get(url)
def on_modified(self, event):
ext = get_ext(event.src_path)
if ext in self.watch_ext:
self.browser.refresh()
def watch(dir, url, browser):
observer = Observer()
if selenium_enabled:
reloader = BrowserReloader(browser.title(), url)
observer.schedule(reloader, path=dir, recursive=True)
observer.schedule(default_compiler, path=dir, recursive=True)
print "Watching for %s" % abspath(dir)
observer.start()
try:
while True:
time.sleep(1)
except KeyboardInterrupt:
observer.stop()
observer.join()
if __name__ == '__main__':
import optparse
parser = optparse.OptionParser()
parser.add_option("-d", "--dir", default=".")
parser.add_option("-u", "--url", default="http://localhost/")
parser.add_option("-b", "--browser", default="Chrome")
options, args = parser.parse_args()
watch(options.dir, options.url, options.browser)
Recommended Posts