Skip to content

Instantly share code, notes, and snippets.

@statico
Created May 1, 2014 00:28
Show Gist options
  • Save statico/4a04da4265e09688606e to your computer and use it in GitHub Desktop.
Save statico/4a04da4265e09688606e to your computer and use it in GitHub Desktop.
Multi-threaded CoffeeScript syntactical grep
#!/usr/bin/env coffee
# {{{1 Cluster fun!
{walk} = require 'walk'
cs = require 'coffee-script'
pathlib = require 'path'
fs = require 'fs'
cluster = require 'cluster'
NUM_WORKERS = require('os').cpus().length
if cluster.isMaster
debug = (args...) ->
console.log('[MASTER]', args...) if process.env.DEBUG
workers = []
filesFound = 0
filesDone = 0
process.execPath = 'coffee'
cluster.on 'online', (worker) ->
debug "worker #{ worker.id } online"
worker.on 'message', (msg) ->
if msg.ready
workers.push worker
debug "#{ workers.length } workers ready"
begin() if workers.length == NUM_WORKERS
else if msg.text?
process.stdout.write msg.text
filesDone++
debug "filesDone=", filesDone
process.exit() if filesDone == filesFound
else
console.error "unknown message: #{ JSON.stringify msg }"
[1..NUM_WORKERS].forEach (i) ->
debug "forking worker #{ i }"
cluster.fork()
begin = ->
dir = process.argv[2] ? '.'
debug "beginning walk of #{ dir }..."
walker = walk dir,
followLinks: false
filters: ['node_modules']
walker.on 'file', (root, stats, next) ->
return next() if not /\.coffee$/.test stats.name
return next() if /^\./.test stats.name
path = pathlib.join root, stats.name
workers[Math.floor(Math.random() * workers.length)].send path
filesFound++
debug "filesFound =", filesFound
next()
else
debug = (args...) ->
console.log("[WORKER #{ cluster.worker.id }]", args...) if process.env.DEBUG
debug 'hello'
process.send ready: true
process.on 'message', (path) ->
debug "processing #{ path }"
content = fs.readFileSync path, 'utf8'
try
root = cs.nodes content
catch e
console.error "Could not read #{ path }: #{ e }"
return next()
log = ""
# }}}
root.traverseChildren true, (node) ->
cls = node.variable?.base?.value
method = node.variable?.properties?[0]?.name?.compile?()
arglen = node.args?.length
line = node.locationData?.first_line + 1
try
js = node.compile()
catch e
js = "[can't compile]"
report = -> log += "#{ path }:#{line}:#{js}\n"
return unless node.constructor.name is 'Call'
return unless cls in ['Vec2', 'Vec3', 'Vec4', 'Mat3', 'Mat4', 'Quat']
report() if method is 'fromDirectionVecPair' #and arglen != 2
# {{{1 More cluster fun!
process.send text: log
# }}}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment