A script that detects file updates and automatically compiles Coffee and Sass or reloads your browser

: warning: The content of this article is quite old. Use another tool like gulp or live reload


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.

How to install and how to use
  1. Install selenium and watchdog with easy_install.
  2. Place the Chrome Driver in your PATH.
  3. $ 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

A script that detects file updates and automatically compiles Coffee and Sass or reloads your browser
A Python script that reads a SQL file, executes BigQuery and saves the csv
A bot that automatically detects typos hidden in Pull Request and acts as a correction
A script that combines your favorite python modules and binaries into one Lambda Layer