#!/bin/bash set +x set +e txt_red='\033[0;31m' # Red txt_grn='\033[0;32m' # Green txt_ylw='\033[0;33m' # Yellow txt_rst='\033[0m' # Text Reset cache_dir="$HOME/.nodemagic" bin_dir="${cache_dir}/node_modules/.bin" node_root="http://nodejs.org/dist" log () { [ -z "$1" ] || echo -e "[NODEMAGIC LOG] $1" } err () { [ -z "$1" ] || echo -e "${txt_red}[NODEMAGIC ERROR]${txt_rst} $1" } warn () { [ -z "$1" ] || echo -e "${txt_ylw}[NODEMAGIC WARNING]${txt_rst} $1" } die () { err "$1" exit -1 } host_npm_install="npm install \ --registry=https://registry.npmjs.org \ --always-auth=false \ --loglevel=error" # Let's make sure we're running something [ "$1" == "npm" ] || \ [ "$1" == "node" ] || \ [ "$1" == "iojs" ] || \ die "usage: nodemagic node|iojs|npm ..." # Verify that you have at least some kind of node which node 2>&1>/dev/null || \ die "\"node\" command not found. \ Node.js/io.js is probably not installed on this system." # Verify that package.json exists. Otherwise just run the command [ -f ./package.json ] || exec "$@" # Set up cache directory [ -d $cache_dir ] || mkdir -p $cache_dir/node_modules/.bin # Read host node and NPM versions host_node_version=$(node -v | tr -d v) host_npm_version=$(npm -v) download_node_versions () { curl -s http://nodejs.org/dist/ \ | grep -Po 'v\d+\.\d+\.\d+' \ | uniq \ | sort } all_node_versions () { local versions if [ -f ${cache_dir}/versions ]; then versions=$(cat ${cache_dir}/versions) # shadow-populate the cache download_node_versions > ${cache_dir}/versions & else versions="$(download_node_versions)" echo $versions > ${cache_dir}/versions fi echo $versions } read_target_version () { local version version=$(node -e "console.log(require('./package.json').engines.${1} || '')" 2>/dev/null) [ -z "$version" ] && return -1 echo $version return 0 } # Read target node and NPM versions target_node_version="$(read_target_version node || echo $host_node_version)" target_npm_version="$(read_target_version npm || echo $host_npm_version)" # Bootstrap semver if [ ! -f "${bin_dir}/semver" ]; then log "Bootstrapping semver..." $host_npm_install --prefix=${cache_dir} semver > /dev/null fi resolve_node_version () { local versions="$(all_node_versions)" target_node_version=$(${bin_dir}/semver -r $target_node_version $versions) target_node_version=$(echo $target_node_version | awk '{print $NF}') } # Determine proper version based on range if (echo $target_node_version | grep -q -P '[x^~<>=]'); then semver_version=$target_node_version resolve_node_version # No valid version found. Blow away the cache and resolve again if [ -z "$target_node_version" ]; then rm -rf ${cache_dir}/versions resolve_node_version fi # Still no valid version found. Bail out if [ -z "$target_node_version" ]; then die "No valid node version matches the range $semver_version specified in package.json/versions/node" fi fi # log "Host node version ${txt_ylw}$host_node_version${txt_rst}" log "Target node version ${txt_grn}$target_node_version${txt_rst}" # log "Host npm version ${txt_ylw}$host_npm_version${txt_rst}" log "Target npm version ${txt_grn}$target_npm_version${txt_rst}" # Install/set npm if $(${bin_dir}/semver $host_npm_version -r $target_npm_version > /dev/null); then target_npm="npm" else target_npm_dir=${cache_dir}/npm/${target_npm_version} target_npm="${target_npm_dir}/node_modules/.bin/npm" if [ ! -f ${target_npm} ]; then mkdir -p ${target_npm_dir}/node_modules log "Installing npm@${target_npm_version}..." $host_npm_install --prefix=${target_npm_dir} npm@${target_npm_version} fi fi # Install/set node if $(${bin_dir}/semver $host_node_version -r $target_node_version > /dev/null); then target_node="node" else target_node_dir=${cache_dir}/node/${target_node_version} target_node="${target_node_dir}/bin/node" if [ ! -f ${target_node} ]; then mkdir -p ${target_node_dir} log "Installing node@${target_node_version}..." local_arch=$(node -e "console.log(require('os').platform() + '-' + require('os').arch())") node_url=${node_root}/v${target_node_version}/node-v${target_node_version}-${local_arch}.tar.gz pushd ${target_node_dir} > /dev/null curl -s ${node_url} | tar xz --strip-components=1 if [ "$?" -ne "0" ]; then rm -rf ${target_node_dir} >/dev/null die "Unable to download and extract $node_url" fi popd > /dev/null fi fi if [ "$1" == "npm" ]; then $target_npm ${*:2} else $target_node ${*:2} fi