Skip to content

Instantly share code, notes, and snippets.

@chaseholdren
Forked from assaf/nvmish
Created May 14, 2024 05:21
Show Gist options
  • Save chaseholdren/d8ac781a2591926e703719a8ebeb3c40 to your computer and use it in GitHub Desktop.
Save chaseholdren/d8ac781a2591926e703719a8ebeb3c40 to your computer and use it in GitHub Desktop.
nvm use <package.json>
#!/usr/bin/env bash
#
# Run nvmish in your current project directory to use the version of io.js/Node
# as specified in package.json. It will also install that version, if not
# already installed.
#
# If package.json specifies engines.iojs, uses the corresponding version of
# io.js, otherwise, if package.json specifies engines.node, uses the
# corresponding version of Node.js.
#
# You can specify an exact version number, or any semver-compatible range, in
# which case it will pick the most recent version available.
#
# $ source ./nvmish
# $ cd <project directory>
# $ cat package.json | jq --raw-output .engines.iojs
# > 1.6.2
# $ nvmish
# > Installing io.js v1.6.2 ...
# > ######################################################################## 100.0%
# > Now using io.js v1.6.2
#
# $ cat package.json | jq --raw-output .engines.node
# > 1.2.x
# $ nvmish
# > Now using node v0.12.0
source $(brew --prefix nvm)/nvm.sh
# Adapted from JSON.sh https://github.com/dominictarr/JSON.sh
nvm_json_throw () {
echo "$*" >&2
exit 1
}
nvm_json_awk_egrep () {
local pattern_string=$1
gawk '{
while ($0) {
start=match($0, pattern);
token=substr($0, start, RLENGTH);
print token;
$0=substr($0, start+RLENGTH);
}
}' pattern=$pattern_string
}
nvm_json_tokenize () {
local GREP
local ESCAPE
local CHAR
if echo "test string" | egrep -ao --color=never "test" &>/dev/null
then
GREP='egrep -ao --color=never'
else
GREP='egrep -ao'
fi
if echo "test string" | egrep -o "test" &>/dev/null
then
ESCAPE='(\\[^u[:cntrl:]]|\\u[0-9a-fA-F]{4})'
CHAR='[^[:cntrl:]"\\]'
else
GREP=nvm_json_awk_egrep
ESCAPE='(\\\\[^u[:cntrl:]]|\\u[0-9a-fA-F]{4})'
CHAR='[^[:cntrl:]"\\\\]'
fi
local STRING="\"$CHAR*($ESCAPE$CHAR*)*\""
local NUMBER='-?(0|[1-9][0-9]*)([.][0-9]*)?([eE][+-]?[0-9]*)?'
local KEYWORD='null|false|true'
local SPACE='[[:space:]]+'
$GREP "$STRING|$NUMBER|$KEYWORD|$SPACE|." | egrep -v "^$SPACE$"
}
_json_parse_array () {
local index=0
local ary=''
read -r token
case "$token" in
']') ;;
*)
while :
do
_json_parse_value "$1" "$index"
index=$((index+1))
ary="$ary""$value"
read -r token
case "$token" in
']') break ;;
',') ary="$ary," ;;
*) nvm_json_throw "EXPECTED , or ] GOT ${token:-EOF}" ;;
esac
read -r token
done
;;
esac
:
}
_json_parse_object () {
local key
local obj=''
read -r token
case "$token" in
'}') ;;
*)
while :
do
case "$token" in
'"'*'"') key=$token ;;
*) nvm_json_throw "EXPECTED string GOT ${token:-EOF}" ;;
esac
read -r token
case "$token" in
':') ;;
*) nvm_json_throw "EXPECTED : GOT ${token:-EOF}" ;;
esac
read -r token
_json_parse_value "$1" "$key"
obj="$obj$key:$value"
read -r token
case "$token" in
'}') break ;;
',') obj="$obj," ;;
*) nvm_json_throw "EXPECTED , or } GOT ${token:-EOF}" ;;
esac
read -r token
done
;;
esac
:
}
_json_parse_value () {
local jpath="${1:+$1,}$2" isleaf=0 isempty=0 print=0
case "$token" in
'{') _json_parse_object "$jpath" ;;
'[') _json_parse_array "$jpath" ;;
# At this point, the only valid single-character tokens are digits.
''|[!0-9]) nvm_json_throw "EXPECTED value GOT ${token:-EOF}" ;;
*) value=$token
isleaf=1
[ "$value" = '""' ] && isempty=1
;;
esac
[ "$value" = '' ] && return
[ "$isleaf" -eq 1 ] && [ $isempty -eq 0 ] && print=1
[ "$print" -eq 1 ] && printf "[%s]\t%s\n" "$jpath" "$value"
:
}
_json_parse () {
read -r token
_json_parse_value
read -r token
case "$token" in
'') ;;
*) nvm_json_throw "EXPECTED EOF GOT $token" ;;
esac
}
nvm_json_extract () {
local parsed=$(nvm_json_tokenize | _json_parse)
echo "$parsed" | grep -e "$1" | awk '{print $2 $3}'
}
# Install io.js/Node version specified in package.json
#
# Exit code:
# 0 Successfully installed and using latest version
# 1 No package.json in current directory
# 2 Found package.json but no engines specified
nvmish () {
if [[ ! -f package.json ]] ; then
echo "No package.json found in current directory"
return 1
fi
local INSTALL_VERSION
local NVM_VERSION_DIR
local IOJS_VERSION=$(nvm_json_extract '\["engines","iojs"\]' < package.json | tr -d '"')
if [[ -n "$IOJS_VERSION" ]] ; then
if ! [[ "$IOJS_VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
IOJS_VERSION=$(curl --silent --get --data-urlencode "range=${IOJS_VERSION}" https://semver.herokuapp.com/iojs/resolve)
fi
NVM_VERSION="iojs-v$IOJS_VERSION"
NVM_VERSION_DIR="$(nvm_version_path "$NVM_VERSION")"
if [ ! -d "$NVM_VERSION_DIR" ]; then
echo "Installing io.js v$IOJS_VERSION ..."
nvm install $NVM_VERSION
else
nvm use $NVM_VERSION
fi
return $?
fi
local NODE_VERSION=$(nvm_json_extract '\["engines","node"\]' < package.json | tr -d '"')
if [[ -n "$NODE_VERSION" ]] ; then
if ! [[ "$NODE_VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
NODE_VERSION=$(curl --silent --get --data-urlencode "range=${NODE_VERSION}" https://semver.herokuapp.com/node/resolve)
fi
NVM_VERSION="v$NODE_VERSION"
NVM_VERSION_DIR="$(nvm_version_path "$NVM_VERSION")"
if [ ! -d "$NVM_VERSION_DIR" ]; then
echo "Installing node v$NODE_VERSION ..."
nvm install $NVM_VERSION
else
nvm use $NVM_VERSION
fi
return $?
fi
echo "No engines.iojs or engine.node in package.json"
return 2
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment