Skip to content

Instantly share code, notes, and snippets.

@reduxdj
Created June 14, 2012 11:51
Show Gist options
  • Save reduxdj/2929835 to your computer and use it in GitHub Desktop.
Save reduxdj/2929835 to your computer and use it in GitHub Desktop.
WatcherUtil
fs = require 'fs'
fileUtil = require 'file'
path = require 'path'
nodeWatch = require 'nodewatch'
child_process = require 'child_process'
_ = require 'underscore'
glob = require 'glob'
util = require 'util'
exec = require('child_process').exec
class Watcher
constructor: (@options, @templates) ->
@paths = @options?.paths
watch: ->
@runCompass @options.compass if @options.compass
console.log root
@watchOutputTree @options.client
@log 'running'
watchOutputTree: (root) ->
console.log 'WatcherUtil.watchTree'
console.log "Watching for changes under root : "+root+"\n"
nodeWatch.add(root,true)
@startListening()
startListening: =>
console.log 'Watcher.startListening'
nodeWatch.onChange (file, prev, curr, action) =>
console.log 'Watcher :: nodeWatch.onChange:'
console.log 'action: '+action
console.log 'detecting change to:'+file
console.log prev.mtime.getTime()
console.log curr.mtime.getTime()
nodeWatch.clearListeners()
@handleFile(file)
package: ->
console.log 'packaging files'
@compileTemplates()
runCompass: (config) ->
console.log "Starting compass with config file '#{config}'"
@spawn 'compass', ['watch', '-c', config]
spawn: (command, args, callback) ->
child = child_process.spawn command, args
child.stdout.on 'data', (data) =>
@log "stdout from '#{command}': #{data}"
child.stderr.on 'data', (data) =>
console.error "stderr from '#{command}': #{data}"
child.on 'exit', (code) =>
@log "'#{command}' exited with code #{code}"
callback?(code)
findMatch: (file) ->
@log _.detect @paths, (value, pattern) => @globToRegExp(pattern).test file
_.detect @paths, (value, pattern) => @globToRegExp(pattern).test file
handleFile: (file) =>
options = @findMatch file
pathName = path.dirname(file)
@log @options.client
@log pathName.indexOf @options.client
if pathName.indexOf @options.client isnt -1
pathName = pathName.replace @options.client, ''
options.out = options.out + pathName
@log 'pathName->'+pathName
@processFile file, options
globToRegExp: (glob) ->
regex = glob.replace /\./g, '\\.' # escape dots
regex = regex.replace /\?/g, '.' # replace ? with dots
regex = regex.replace /\*/g, '.*' # replace * with .*
regex = regex.replace /\.\*\.\*\//g, '(.*\/)*' # replace .*.*/ (which used to be **/) with (.*/)*
new RegExp regex
processFile: (file, options) ->
#success = (=> @packageFiles(file) if options.package)
if options.type is 'coffee'
@compileCoffee file, options, success
_.delay (->@packageFiles), 1000
compileCoffee: (file, options, callback) ->
@log "compileCoffee: '#{file}': #{options.out}"
@spawn 'coffee', ['-c','-o', file, options.out ], callback
compileTemplates: ->
@log "Compiling all templates"
@processTemplatePattern(pattern, value) for pattern, value of @paths
deleteFile: (file, callback) ->
fs.unlink file, (err) =>
return @log "Couldn't delete file '#{file}': #{JSON.stringify err}" if err
console.log "Calling callback #{callback}"
callback?()
processTemplatePattern: (pattern, value) ->
return if value.type != 'template'
glob pattern, (err, matches) =>
return console.log "#{err}" if err
for match in matches
@compileTemplate match, 'create', value.out
compileTemplate: (file, out, callback) ->
templateName = path.basename file, path.extname(file)
@writeTemplateHeader()
@log "Compiling template file '#{file}' to '#{out}' and adding it to templates object '#{templateName}' "
fs.readFile file, 'utf8', (err, data) =>
return console.log(err) if err
compiled = _.template data
@templates[templateName] = compiled
@writeTemplate(templateName, compiled, out, callback,data) if out
writeTemplateHeader: ()->
fs.createWriteStream("public/js/templates.js",
flags: "w"
encoding: "utf8"
mode: 0666
).write "window.templates || (window.templates = {});\n"
fs.createWriteStream("dependencies/templates/templates.js",
flags: "w"
encoding: "utf8"
mode: 0666
).write "window.templates || (window.templates = {});\n"
outFile: (outDir, filename, ext) ->
console.log ("#{filename}.#{ext}")
path.join(outDir, "#{filename}.#{ext}")
escapeHTML: (string) ->
if string is null or typeof string is "undefined"
string = ""
else
string = String(string)
string.replace /[&<>"'\/`]/g, @htmlReplacer
templateSettings: ->
evaluate: /<%([\s\S]+?)%>/g
interpolate: /<%-([\s\S]+?)%>/g
autoEscape: /<%=([\s\S]+?)%>/g
HTML_CHARS: ->
"&": "&amp;"
"<": "&lt;"
">": "&gt;"
"\"": "&quot;"
"'": "&#x27;"
"/": "&#x2F;"
"`": "&#x60;"
_htmlReplacer = (match) ->
@HTML_CHARS[match]
template: (str, data) ->
c = @templateSettings
tmpl = "var __p=[],__e=_.escapeHTML,print=function(){__p.push.apply(__p,arguments);};" + "with(obj||{}){__p.push('" + str.replace(/\\/g, "\\\\").replace(/'/g, "\\'").replace(c.autoEscape, (match, code) ->
"',__e(" + code.replace(/\\'/g, "'") + "),'"
).replace(c.interpolate, (match, code) ->
"'," + code.replace(/\\'/g, "'") + ",'"
).replace(c.evaluate or null, (match, code) ->
"');" + code.replace(/\\'/g, "'").replace(/[\r\n\t]/g, " ") + "__p.push('"
).replace(/\r/g, "\\r").replace(/\n/g, "\\n").replace(/\t/g, "\\t") + "');}return __p.join('');"
return tmpl
writeTemplate: (templateName, compiled, out, callback,data) ->
asString = compiled.toString().replace('function anonymous', "window.templates || (window.templates = {});\nwindow.templates['#{templateName}'] = function") + ';'
if templateName is 'index'
fileUtil.mkdirs out, 0755, =>
fs.writeFile @outFile(out, templateName, 'js'), asString, 'utf8', callback
return
fs.createWriteStream("public/js/templates.js",
flags: "a"
encoding: "utf8"
mode: 0666
).write "window.templates['#{templateName}'] = function(obj){"+@template(data)+"};\n"
fs.createWriteStream("dependencies/templates/templates.js",
flags: "a"
encoding: "utf8"
mode: 0666
).write "window.templates['#{templateName}'] = function(obj){"+@template(data)+"};\n"
onDoneAssets: (msg) =>
@log 'File Copied'
packageFiles: () ->
@log 'Packaging files using jammit->'[email protected]
@spawn 'jammit', ['-c', @options.package, '-o', @options.packageOut]
fs.copy = (src, dst, cb) ->
copy = (err) ->
is_ = undefined
os = undefined
fs.stat src, (err) ->
return cb(err) if err
is_ = fs.createReadStream(src)
os = fs.createWriteStream(dst)
util.pump is_, os, cb
fs.stat dst, copy
@log 'public/js/assets.js' + " to " + @options.assetsOut
@startListening()
#fs.copy 'public/js/assets.js', @options.assetsOut+'assets.js', @onDoneAssets
log: (message) ->
console.log message if @options?.verbose
exports?.watcher = Watcher
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment