Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

write - nearly working

  • Loading branch information...
commit 831151b0614032b075700428823be39472fc1fe6 1 parent 698502e
Jonah Fox authored
View
22 README.md
@@ -1,14 +1,14 @@
Bounce
====
-Reloads node upon changes to source files.
+Reloads process upon changes to source files and exceptions.
Great for development.
How?
----
-Runs node as child process whilst watching JS file in the current directory and below for changes.
-If a change is detected, the node child process is restarted. It also looks for new files JS every 10s.
+Runs node as child process whilst watching specified files changes.
+If a change is detected, the child process is restarted.
All STDOUT AND STDERR should be piped back to the console, so it shouldn't look any different.
@@ -20,24 +20,26 @@ sudo bin/install
Usage
----
-simply replace 'node' for 'bounce'. E.g.
-
-bounce lib/server.js
+bounce -w [-r] [-g] 'command_to_run -a -b arg1 arg2'
+-w: watch paths, comma separated. If using globs (*) then must be wrapped in quotes, e.g. 'lib/*.*'
+-r: respawn on child process exit
+-g: growl notify on child process exit (needs growlnotify)
+-h: show this usage
Running Tests
----
-* bin/bounce test/test.js
+* bin/bounce -r -g -w "node test/test.js"
Changes to test.js and watch/file.js should cause the counter to restart.
-* bin/bounce test/error.js
+* bin/bounce -w "node test/error.js"
Should throw an error and exit immediately
-Tested on Ubuntu/OSX on Node 0.2.0 and 0.1.104
+Tested on Ubuntu/OSX on Node 0.2.3
Todo
----
-* how to handle watching different directories than CWD ?
+* npm
View
111 bin/bounce
@@ -1,45 +1,63 @@
#!/usr/bin/env node
-var args = process.ARGV.slice(2),
- wdir = "./", //args.shift()
- prog = "node", //args.shift()
+// RUN LIKE
+var watchPaths,
child,
fs = require("fs"),
path = require("path"),
watching = {},
- steppedInto = {}
+ steppedInto = {},
+ respawnOnExit = false,
+ glob = require("glob"),
+ growlNotify = false
+
+var growl = require("growl")
+command = process.ARGV[process.ARGV.length-1]
+var args = process.ARGV
+for(var i=0; i <args.length; i++) {
+ var arg = args[i]
+ if(arg == "-w") watchPaths = args[i+1].split(",")
+ if(arg == "-r") respawnOnExit = true;
+ if(arg == "-g") growlNotify = true;
+ if(arg == "-h") usage()
+}
+
+function usage() {
+
+ log("bounce -w [-r] [-g] 'command_to_run -a -b arg1 arg2' ")
+ log("")
+ log("-w: watch paths, comma separated. If using globs (*) then must be wrapped in quotes, e.g. 'lib/*.*' ")
+ log("-r: respawn on child process exit")
+ log("-g: growl notify on child process exit (needs growlnotify)")
+ log("-h: show this usage")
+ process.exit(0)
+}
+
+
+if(!command || !watchPaths || !watchPaths.length) {
+ //log("Error: must provide command to run")
+ usage()
+}
+
+function log() {
+ console.log.apply(null, arguments)
+}
function debug(s) {
if(0)
- console.log(s)
+ log(s)
}
-function watchDir(dir) {
- debug("looking inside dir " + dir)
- if(steppedInto[dir]) {
- debug("we've already stepped in here, skipping")
- return
- }
- steppedInto[dir] = true
-
- var files = fs.readdirSync(dir)
- for(var i =0; i < files.length;i++) {
- var file = files[i]
- var fullPath = path.join(dir, file)
-
- try {
- var stats = fs.statSync(fullPath)
- if(stats.isDirectory()) {
- if(!file.match(/^\./)) // ignore folders starting with .
- watchDir(fullPath)
- }
- else if(file.match(/\.js$/))
- watch(fullPath)
- }
- catch(e) {
- debug(e.toString()) // statSync can throw exception e.g. with cyclic symbolic links
- debug("skipping")
- }
+var files = []
+
+for(var i in watchPaths) {
+ files = files.concat(glob.globSync(watchPaths[i]))
+}
+
+function watchFiles(files) {
+ for(var i in files) {
+ log("Watching: " + files[i]);
+ watch(files[i])
}
}
@@ -61,22 +79,35 @@ function watch(source) {
function spawn() {
+
+ var args = command.split(" ")
+ var prog = args.shift()
+ //log(prog, args)
child = require('child_process').spawn(prog, args);
- console.log('Spawned ' + prog + " " + args.join(" ") + ", with PID=" + child.pid);
+ log('Spawned ' + prog + " " + args.join(" ") + ", with PID=" + child.pid);
child.stdout.on('data', function(data) {
data = data.toString().replace(/\n$/,"")
- console.log(data);
+ log(data);
});
child.stderr.on('data', function(data) {
data = data.toString().replace(/\n$/,"")
- console.log(data);
+ log(data);
});
return child.on('exit', function(code, signal) {
if(code == null && signal == "SIGTERM")
respawn()
else {
- console.log('node exited with code ' + (code ? code.toString() : "null") + " and signal " + (signal ? signal.toString() : "null"));
- process.exit(0)
+ log('child exited with code ' + (code ? code.toString() : "null") + " and signal " + (signal ? signal.toString() : "null"));
+ if(growlNotify)
+ growl.notify(command + " child process exited with code " + (code ? code.toString() : "null"))
+ if(respawnOnExit) {
+ log("Respawning")
+ respawn()
+ }
+ else {
+ log("Exiting")
+ process.exit(0)
+ }
}
});
};
@@ -89,8 +120,8 @@ function respawn() {
}
spawn();
-watchDir(wdir);
-setInterval(function() {
- watchDir(wdir);
-}, 10000) // look for new files every 10s
+watchFiles(files);
+// setInterval(function() {
+// watchDir(wdir);
+// }, 10000) // look for new files every 10s
View
2  bin/install
@@ -1,3 +1,3 @@
cp bin/bounce /usr/local/bin
echo "Bounce installed"
-echo "now use 'bounce' instead of 'node' to reload"
+
View
79 lib/growl.js
@@ -0,0 +1,79 @@
+// Growl - Copyright TJ Holowaychuk <tj@vision-media.ca> (MIT Licensed)
+
+/**
+ * Module dependencies.
+ */
+
+var child_process = require('child_process'),
+ path = require('path')
+
+/**
+ * Node-growl version.
+ */
+
+exports.version = '1.0.2'
+
+/**
+ * Fetch the binary version when available.
+ *
+ * @param {function} callback
+ * @api public
+ */
+
+exports.binVersion = function(callback) {
+ child_process.exec('growlnotify -v', function(err, stdout, stderr){
+ if (err) callback(err)
+ else callback(null, stdout)
+ })
+}
+
+/**
+ * Send growl notification _msg_ with _options_.
+ *
+ * Options:
+ *
+ * - title Notification title
+ * - sticky Make the notification stick (defaults to false)
+ * - name Application name (defaults to growlnotify)
+ * - image
+ * - path to an icon sets --iconpath
+ * - path to an image sets --image
+ * - capitalized word sets --appIcon
+ * - filename uses extname as --icon
+ * - otherwise treated as --icon
+ *
+ * Examples:
+ *
+ * growl.notify('New email')
+ * growl.notify('5 new emails', { title: 'Thunderbird' })
+ * growl.notify('Email sent', function(){
+ * // ... notification sent
+ * })
+ *
+ * @param {string} msg
+ * @param {object} options
+ * @param {function} callback
+ * @api public
+ */
+
+exports.notify = function(msg, options, callback) {
+ var image,
+ args = ['growlnotify', '-m', '"' + msg + '"'],
+ options = options || {}
+ exports.binVersion(function(err, version){
+ if (err) return callback(err)
+ if (image = options.image) {
+ var flag, ext = path.extname(image).substr(1)
+ flag = flag || ext == 'icns' && 'iconpath'
+ flag = flag || /^[A-Z]/.test(image) && 'appIcon'
+ flag = flag || /^png|gif|jpe?g$/.test(ext) && 'image'
+ flag = flag || ext && (image = ext) && 'icon'
+ flag = flag || 'icon'
+ args.push('--' + flag, image)
+ }
+ if (options.sticky) args.push('--sticky')
+ if (options.name) args.push('--name', options.name)
+ if (options.title) args.push(options.title)
+ child_process.exec(args.join(' '), callback)
+ })
+}
View
2  test/error.js
@@ -1 +1 @@
-throw "error"
+throw "error"
View
3  test/test.js
@@ -9,6 +9,9 @@ function go() {
} else {
process.exit(0)
}
+
+ if(i == 10)
+ throw "error!"
}
Please sign in to comment.
Something went wrong with that request. Please try again.