#!/bin/sh # A wrapper that will invoke node with `--inspect=xxx` if $NODE_DEBUG_PORT # is set and the script is an application script and not a node_module. # The assumption is that node_modules are likely things like nodemon or # other helper scripts. # output debug logging if DEBUG is set debug() { if [ -n "$DEBUG" ]; then echo "node-wrapper: $*" 1>&2 fi } # find the real node executable (not this wrapper) findNode() { (IFS=:; for dir in $PATH; do \ # if not the same file as this wrapper; `-ef` is not POSIX but widely supported if [ -f "$dir/node" -a -x "$dir/node" ] && ! [ "$dir/node" -ef "$0" ]; then \ debug "found node in $dir/node" echo "$dir/node"; \ return; \ fi; \ done) } # find the node script that will be executed # TODO: use readlink to resolve symlinks? findScript() { for arg in "$@"; do case "$arg" in -*) # skip option ;; /*) # absolute path echo "$arg" return ;; *) echo "$(pwd -P)/$arg" return ;; esac done } # return 0 if appears to be an application script or 1 if a library (node_modules) script isApplicationScript() { case "$1" in */node_modules/*) return 1 ;; *) return 0 ;; esac } # check node arguments for an --inspect style argument; return 0 if found and 1 if not findInspectArg() { for arg in "$@"; do case "$arg" in --inspect|--inspect=*) debug "found $arg" echo "$arg" return 0 ;; --) # end of node options debug "no --inspect found (reached -- end of arguments)" return 1 ;; -*) # some other option continue ;; *) debug "no --inspect found (reached file name)" return 1 ;; esac done return 1 } # rewrite node-nodemon command-line to add $NODE_DEBUG as first arg to nodemon # TODO: pretty sure this won't properly pass args with spaces rewriteNodemon() { for arg in "$@"; do case "$arg" in -*) # node option echo "$arg" ;; */nodemon*) echo "$arg" echo "$NODE_DEBUG" ;; *) echo "$arg" ;; esac done } # strip --inspect argument from command-line # TODO: pretty sure this won't properly pass args with spaces stripInspectArg() { for arg in "$@"; do case "$arg" in --inspect*) continue ;; *) echo "$arg" ;; esac done } debug "cwd: $PWD" debug "args: $*" realNode=$(findNode) if [ -z "$realNode" ]; then echo "error: cannot find real node" 1>&2 exit 255 fi debug "looking for --inspect in command-line" inspectArg=$(findInspectArg "$@") if [ -z "$inspectArg" -a -n "$NODE_OPTIONS" ]; then debug "looking for --inspect in NODE_OPTIONS" inspectArg=$(findInspectArg $NODE_OPTIONS) export NODE_OPTIONS=$(stripInspectArg $NODE_OPTIONS) fi # script will be an absolute path script=$(findScript "$@") debug "script file: $script" if $(isApplicationScript "$script"); then if [ -n "$inspectArg" ]; then debug "app script with --inspect: executing '$realNode $*'" exec "$realNode" "$@" elif [ -n "$NODE_DEBUG" ]; then debug "app script with NODE_DEBUG: executing '$realNode $NODE_DEBUG $*'" exec "$realNode" "$NODE_DEBUG" "$@" else debug "app script but no NODE_DEBUG: executing '$realNode $*'" exec "$realNode" "$@" fi #NOTREACHED fi # About to execute a node library script (in node_modules) # If the script is nodemon then propagate to nodemon # If we have --inspect, stash it in NODE_DEBUG and continue on if [ -n "$inspectArg" ]; then set -- $(stripInspectArg "$@") export NODE_DEBUG="$inspectArg" debug "script is in node_modules: setting NODE_DEBUG and stripping $inspectArg" fi case "$script" in */nodemon*) debug "script is nodemon: running '$realNode $(rewriteNodemon "$@")'" eval exec "$realNode" $(rewriteNodemon "$@") ;; *) debug "script is in node_modules: executing '$realNode $*'" exec "$realNode" "$@" ;; esac