| #!/usr/bin/env bash |
| |
| { # this ensures the entire script is downloaded # |
| |
| nvm_has() { |
| type "$1" > /dev/null 2>&1 |
| } |
| |
| nvm_grep() { |
| GREP_OPTIONS='' command grep "$@" |
| } |
| |
| nvm_default_install_dir() { |
| [ -z "${XDG_CONFIG_HOME-}" ] && printf %s "${HOME}/.nvm" || printf %s "${XDG_CONFIG_HOME}/nvm" |
| } |
| |
| nvm_install_dir() { |
| if [ -n "$NVM_DIR" ]; then |
| printf %s "${NVM_DIR}" |
| else |
| nvm_default_install_dir |
| fi |
| } |
| |
| nvm_latest_version() { |
| echo "v0.37.2" |
| } |
| |
| nvm_profile_is_bash_or_zsh() { |
| local TEST_PROFILE |
| TEST_PROFILE="${1-}" |
| case "${TEST_PROFILE-}" in |
| *"/.bashrc" | *"/.bash_profile" | *"/.zshrc") |
| return |
| ;; |
| *) |
| return 1 |
| ;; |
| esac |
| } |
| |
| # |
| # Outputs the location to NVM depending on: |
| # * The availability of $NVM_SOURCE |
| # * The method used ("script" or "git" in the script, defaults to "git") |
| # NVM_SOURCE always takes precedence unless the method is "script-nvm-exec" |
| # |
| nvm_source() { |
| local NVM_GITHUB_REPO |
| NVM_GITHUB_REPO="${NVM_INSTALL_GITHUB_REPO:-nvm-sh/nvm}" |
| local NVM_VERSION |
| NVM_VERSION="${NVM_INSTALL_VERSION:-$(nvm_latest_version)}" |
| local NVM_METHOD |
| NVM_METHOD="$1" |
| local NVM_SOURCE_URL |
| NVM_SOURCE_URL="$NVM_SOURCE" |
| if [ "_$NVM_METHOD" = "_script-nvm-exec" ]; then |
| NVM_SOURCE_URL="https://raw.githubusercontent.com/${NVM_GITHUB_REPO}/${NVM_VERSION}/nvm-exec" |
| elif [ "_$NVM_METHOD" = "_script-nvm-bash-completion" ]; then |
| NVM_SOURCE_URL="https://raw.githubusercontent.com/${NVM_GITHUB_REPO}/${NVM_VERSION}/bash_completion" |
| elif [ -z "$NVM_SOURCE_URL" ]; then |
| if [ "_$NVM_METHOD" = "_script" ]; then |
| NVM_SOURCE_URL="https://raw.githubusercontent.com/${NVM_GITHUB_REPO}/${NVM_VERSION}/nvm.sh" |
| elif [ "_$NVM_METHOD" = "_git" ] || [ -z "$NVM_METHOD" ]; then |
| NVM_SOURCE_URL="https://github.com/${NVM_GITHUB_REPO}.git" |
| else |
| echo >&2 "Unexpected value \"$NVM_METHOD\" for \$NVM_METHOD" |
| return 1 |
| fi |
| fi |
| echo "$NVM_SOURCE_URL" |
| } |
| |
| # |
| # Node.js version to install |
| # |
| nvm_node_version() { |
| echo "$NODE_VERSION" |
| } |
| |
| nvm_download() { |
| if nvm_has "curl"; then |
| curl --fail --compressed -q "$@" |
| elif nvm_has "wget"; then |
| # Emulate curl with wget |
| ARGS=$(nvm_echo "$@" | command sed -e 's/--progress-bar /--progress=bar /' \ |
| -e 's/--compressed //' \ |
| -e 's/--fail //' \ |
| -e 's/-L //' \ |
| -e 's/-I /--server-response /' \ |
| -e 's/-s /-q /' \ |
| -e 's/-sS /-nv /' \ |
| -e 's/-o /-O /' \ |
| -e 's/-C - /-c /') |
| # shellcheck disable=SC2086 |
| eval wget $ARGS |
| fi |
| } |
| |
| install_nvm_from_git() { |
| local INSTALL_DIR |
| INSTALL_DIR="$(nvm_install_dir)" |
| local NVM_VERSION |
| NVM_VERSION="${NVM_INSTALL_VERSION:-$(nvm_latest_version)}" |
| if [ -n "${NVM_INSTALL_VERSION:-}" ]; then |
| # Check if version is an existing ref |
| if command git ls-remote "$(nvm_source "git")" "$NVM_VERSION" | nvm_grep -q "$NVM_VERSION" ; then |
| : |
| # Check if version is an existing changeset |
| elif ! nvm_download -o /dev/null "$(nvm_source "script-nvm-exec")"; then |
| echo >&2 "Failed to find '$NVM_VERSION' version." |
| exit 1 |
| fi |
| fi |
| |
| local fetch_error |
| if [ -d "$INSTALL_DIR/.git" ]; then |
| # Updating repo |
| echo "=> nvm is already installed in $INSTALL_DIR, trying to update using git" |
| command printf '\r=> ' |
| fetch_error="Failed to update nvm with $NVM_VERSION, run 'git fetch' in $INSTALL_DIR yourself." |
| else |
| fetch_error="Failed to fetch origin with $NVM_VERSION. Please report this!" |
| echo "=> Downloading nvm from git to '$INSTALL_DIR'" |
| command printf '\r=> ' |
| mkdir -p "${INSTALL_DIR}" |
| if [ "$(ls -A "${INSTALL_DIR}")" ]; then |
| # Initializing repo |
| command git init "${INSTALL_DIR}" || { |
| echo >&2 'Failed to initialize nvm repo. Please report this!' |
| exit 2 |
| } |
| command git --git-dir="${INSTALL_DIR}/.git" remote add origin "$(nvm_source)" 2> /dev/null \ |
| || command git --git-dir="${INSTALL_DIR}/.git" remote set-url origin "$(nvm_source)" || { |
| echo >&2 'Failed to add remote "origin" (or set the URL). Please report this!' |
| exit 2 |
| } |
| else |
| # Cloning repo |
| command git clone "$(nvm_source)" --depth=1 "${INSTALL_DIR}" || { |
| echo >&2 'Failed to clone nvm repo. Please report this!' |
| exit 2 |
| } |
| fi |
| fi |
| # Try to fetch tag |
| if command git --git-dir="$INSTALL_DIR"/.git --work-tree="$INSTALL_DIR" fetch origin tag "$NVM_VERSION" --depth=1 2>/dev/null; then |
| : |
| # Fetch given version |
| elif ! command git --git-dir="$INSTALL_DIR"/.git --work-tree="$INSTALL_DIR" fetch origin "$NVM_VERSION" --depth=1; then |
| echo >&2 "$fetch_error" |
| exit 1 |
| fi |
| command git -c advice.detachedHead=false --git-dir="$INSTALL_DIR"/.git --work-tree="$INSTALL_DIR" checkout -f --quiet FETCH_HEAD || { |
| echo >&2 "Failed to checkout the given version $NVM_VERSION. Please report this!" |
| exit 2 |
| } |
| if [ -n "$(command git --git-dir="$INSTALL_DIR"/.git --work-tree="$INSTALL_DIR" show-ref refs/heads/master)" ]; then |
| if command git --git-dir="$INSTALL_DIR"/.git --work-tree="$INSTALL_DIR" branch --quiet 2>/dev/null; then |
| command git --git-dir="$INSTALL_DIR"/.git --work-tree="$INSTALL_DIR" branch --quiet -D master >/dev/null 2>&1 |
| else |
| echo >&2 "Your version of git is out of date. Please update it!" |
| command git --git-dir="$INSTALL_DIR"/.git --work-tree="$INSTALL_DIR" branch -D master >/dev/null 2>&1 |
| fi |
| fi |
| |
| echo "=> Compressing and cleaning up git repository" |
| if ! command git --git-dir="$INSTALL_DIR"/.git --work-tree="$INSTALL_DIR" reflog expire --expire=now --all; then |
| echo >&2 "Your version of git is out of date. Please update it!" |
| fi |
| if ! command git --git-dir="$INSTALL_DIR"/.git --work-tree="$INSTALL_DIR" gc --auto --aggressive --prune=now ; then |
| echo >&2 "Your version of git is out of date. Please update it!" |
| fi |
| return |
| } |
| |
| # |
| # Automatically install Node.js |
| # |
| nvm_install_node() { |
| local NODE_VERSION_LOCAL |
| NODE_VERSION_LOCAL="$(nvm_node_version)" |
| |
| if [ -z "$NODE_VERSION_LOCAL" ]; then |
| return 0 |
| fi |
| |
| echo "=> Installing Node.js version $NODE_VERSION_LOCAL" |
| nvm install "$NODE_VERSION_LOCAL" |
| local CURRENT_NVM_NODE |
| |
| CURRENT_NVM_NODE="$(nvm_version current)" |
| if [ "$(nvm_version "$NODE_VERSION_LOCAL")" == "$CURRENT_NVM_NODE" ]; then |
| echo "=> Node.js version $NODE_VERSION_LOCAL has been successfully installed" |
| else |
| echo >&2 "Failed to install Node.js $NODE_VERSION_LOCAL" |
| fi |
| } |
| |
| install_nvm_as_script() { |
| local INSTALL_DIR |
| INSTALL_DIR="$(nvm_install_dir)" |
| local NVM_SOURCE_LOCAL |
| NVM_SOURCE_LOCAL="$(nvm_source script)" |
| local NVM_EXEC_SOURCE |
| NVM_EXEC_SOURCE="$(nvm_source script-nvm-exec)" |
| local NVM_BASH_COMPLETION_SOURCE |
| NVM_BASH_COMPLETION_SOURCE="$(nvm_source script-nvm-bash-completion)" |
| |
| # Downloading to $INSTALL_DIR |
| mkdir -p "$INSTALL_DIR" |
| if [ -f "$INSTALL_DIR/nvm.sh" ]; then |
| echo "=> nvm is already installed in $INSTALL_DIR, trying to update the script" |
| else |
| echo "=> Downloading nvm as script to '$INSTALL_DIR'" |
| fi |
| nvm_download -s "$NVM_SOURCE_LOCAL" -o "$INSTALL_DIR/nvm.sh" || { |
| echo >&2 "Failed to download '$NVM_SOURCE_LOCAL'" |
| return 1 |
| } & |
| nvm_download -s "$NVM_EXEC_SOURCE" -o "$INSTALL_DIR/nvm-exec" || { |
| echo >&2 "Failed to download '$NVM_EXEC_SOURCE'" |
| return 2 |
| } & |
| nvm_download -s "$NVM_BASH_COMPLETION_SOURCE" -o "$INSTALL_DIR/bash_completion" || { |
| echo >&2 "Failed to download '$NVM_BASH_COMPLETION_SOURCE'" |
| return 2 |
| } & |
| for job in $(jobs -p | command sort) |
| do |
| wait "$job" || return $? |
| done |
| chmod a+x "$INSTALL_DIR/nvm-exec" || { |
| echo >&2 "Failed to mark '$INSTALL_DIR/nvm-exec' as executable" |
| return 3 |
| } |
| } |
| |
| nvm_try_profile() { |
| if [ -z "${1-}" ] || [ ! -f "${1}" ]; then |
| return 1 |
| fi |
| echo "${1}" |
| } |
| |
| # |
| # Detect profile file if not specified as environment variable |
| # (eg: PROFILE=~/.myprofile) |
| # The echo'ed path is guaranteed to be an existing file |
| # Otherwise, an empty string is returned |
| # |
| nvm_detect_profile() { |
| if [ "${PROFILE-}" = '/dev/null' ]; then |
| # the user has specifically requested NOT to have nvm touch their profile |
| return |
| fi |
| |
| if [ -n "${PROFILE}" ] && [ -f "${PROFILE}" ]; then |
| echo "${PROFILE}" |
| return |
| fi |
| |
| local DETECTED_PROFILE |
| DETECTED_PROFILE='' |
| |
| if [ -n "${BASH_VERSION-}" ]; then |
| if [ -f "$HOME/.bashrc" ]; then |
| DETECTED_PROFILE="$HOME/.bashrc" |
| elif [ -f "$HOME/.bash_profile" ]; then |
| DETECTED_PROFILE="$HOME/.bash_profile" |
| fi |
| elif [ -n "${ZSH_VERSION-}" ]; then |
| DETECTED_PROFILE="$HOME/.zshrc" |
| fi |
| |
| if [ -z "$DETECTED_PROFILE" ]; then |
| for EACH_PROFILE in ".profile" ".bashrc" ".bash_profile" ".zshrc" |
| do |
| if DETECTED_PROFILE="$(nvm_try_profile "${HOME}/${EACH_PROFILE}")"; then |
| break |
| fi |
| done |
| fi |
| |
| if [ -n "$DETECTED_PROFILE" ]; then |
| echo "$DETECTED_PROFILE" |
| fi |
| } |
| |
| # |
| # Check whether the user has any globally-installed npm modules in their system |
| # Node, and warn them if so. |
| # |
| nvm_check_global_modules() { |
| local NPM_COMMAND |
| NPM_COMMAND="$(command -v npm 2>/dev/null)" || return 0 |
| [ -n "${NVM_DIR}" ] && [ -z "${NPM_COMMAND%%$NVM_DIR/*}" ] && return 0 |
| |
| local NPM_VERSION |
| NPM_VERSION="$(npm --version)" |
| NPM_VERSION="${NPM_VERSION:--1}" |
| [ "${NPM_VERSION%%[!-0-9]*}" -gt 0 ] || return 0 |
| |
| local NPM_GLOBAL_MODULES |
| NPM_GLOBAL_MODULES="$( |
| npm list -g --depth=0 | |
| command sed -e '/ npm@/d' -e '/ (empty)$/d' |
| )" |
| |
| local MODULE_COUNT |
| MODULE_COUNT="$( |
| command printf %s\\n "$NPM_GLOBAL_MODULES" | |
| command sed -ne '1!p' | # Remove the first line |
| wc -l | command tr -d ' ' # Count entries |
| )" |
| |
| if [ "${MODULE_COUNT}" != '0' ]; then |
| # shellcheck disable=SC2016 |
| echo '=> You currently have modules installed globally with `npm`. These will no' |
| # shellcheck disable=SC2016 |
| echo '=> longer be linked to the active version of Node when you install a new node' |
| # shellcheck disable=SC2016 |
| echo '=> with `nvm`; and they may (depending on how you construct your `$PATH`)' |
| # shellcheck disable=SC2016 |
| echo '=> override the binaries of modules installed with `nvm`:' |
| echo |
| |
| command printf %s\\n "$NPM_GLOBAL_MODULES" |
| echo '=> If you wish to uninstall them at a later point (or re-install them under your' |
| # shellcheck disable=SC2016 |
| echo '=> `nvm` Nodes), you can remove them from the system Node as follows:' |
| echo |
| echo ' $ nvm use system' |
| echo ' $ npm uninstall -g a_module' |
| echo |
| fi |
| } |
| |
| nvm_do_install() { |
| if [ -n "${NVM_DIR-}" ] && ! [ -d "${NVM_DIR}" ]; then |
| if [ -e "${NVM_DIR}" ]; then |
| echo >&2 "File \"${NVM_DIR}\" has the same name as installation directory." |
| exit 1 |
| fi |
| |
| if [ "${NVM_DIR}" = "$(nvm_default_install_dir)" ]; then |
| mkdir "${NVM_DIR}" |
| else |
| echo >&2 "You have \$NVM_DIR set to \"${NVM_DIR}\", but that directory does not exist. Check your profile files and environment." |
| exit 1 |
| fi |
| fi |
| if [ -z "${METHOD}" ]; then |
| # Autodetect install method |
| if nvm_has git; then |
| install_nvm_from_git |
| elif nvm_has nvm_download; then |
| install_nvm_as_script |
| else |
| echo >&2 'You need git, curl, or wget to install nvm' |
| exit 1 |
| fi |
| elif [ "${METHOD}" = 'git' ]; then |
| if ! nvm_has git; then |
| echo >&2 "You need git to install nvm" |
| exit 1 |
| fi |
| install_nvm_from_git |
| elif [ "${METHOD}" = 'script' ]; then |
| if ! nvm_has nvm_download; then |
| echo >&2 "You need curl or wget to install nvm" |
| exit 1 |
| fi |
| install_nvm_as_script |
| else |
| echo >&2 "The environment variable \$METHOD is set to \"${METHOD}\", which is not recognized as a valid installation method." |
| exit 1 |
| fi |
| |
| echo |
| |
| local NVM_PROFILE |
| NVM_PROFILE="$(nvm_detect_profile)" |
| local PROFILE_INSTALL_DIR |
| PROFILE_INSTALL_DIR="$(nvm_install_dir | command sed "s:^$HOME:\$HOME:")" |
| |
| SOURCE_STR="\\nexport NVM_DIR=\"${PROFILE_INSTALL_DIR}\"\\n[ -s \"\$NVM_DIR/nvm.sh\" ] && \\. \"\$NVM_DIR/nvm.sh\" # This loads nvm\\n" |
| |
| # shellcheck disable=SC2016 |
| COMPLETION_STR='[ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion" # This loads nvm bash_completion\n' |
| BASH_OR_ZSH=false |
| |
| if [ -z "${NVM_PROFILE-}" ] ; then |
| local TRIED_PROFILE |
| if [ -n "${PROFILE}" ]; then |
| TRIED_PROFILE="${NVM_PROFILE} (as defined in \$PROFILE), " |
| fi |
| echo "=> Profile not found. Tried ${TRIED_PROFILE-}~/.bashrc, ~/.bash_profile, ~/.zshrc, and ~/.profile." |
| echo "=> Create one of them and run this script again" |
| echo " OR" |
| echo "=> Append the following lines to the correct file yourself:" |
| command printf "${SOURCE_STR}" |
| echo |
| else |
| if nvm_profile_is_bash_or_zsh "${NVM_PROFILE-}"; then |
| BASH_OR_ZSH=true |
| fi |
| if ! command grep -qc '/nvm.sh' "$NVM_PROFILE"; then |
| echo "=> Appending nvm source string to $NVM_PROFILE" |
| command printf "${SOURCE_STR}" >> "$NVM_PROFILE" |
| else |
| echo "=> nvm source string already in ${NVM_PROFILE}" |
| fi |
| # shellcheck disable=SC2016 |
| if ${BASH_OR_ZSH} && ! command grep -qc '$NVM_DIR/bash_completion' "$NVM_PROFILE"; then |
| echo "=> Appending bash_completion source string to $NVM_PROFILE" |
| command printf "$COMPLETION_STR" >> "$NVM_PROFILE" |
| else |
| echo "=> bash_completion source string already in ${NVM_PROFILE}" |
| fi |
| fi |
| if ${BASH_OR_ZSH} && [ -z "${NVM_PROFILE-}" ] ; then |
| echo "=> Please also append the following lines to the if you are using bash/zsh shell:" |
| command printf "${COMPLETION_STR}" |
| fi |
| |
| # Source nvm |
| # shellcheck source=/dev/null |
| \. "$(nvm_install_dir)/nvm.sh" |
| |
| nvm_check_global_modules |
| |
| nvm_install_node |
| |
| nvm_reset |
| |
| echo "=> Close and reopen your terminal to start using nvm or run the following to use it now:" |
| command printf "${SOURCE_STR}" |
| if ${BASH_OR_ZSH} ; then |
| command printf "${COMPLETION_STR}" |
| fi |
| } |
| |
| # |
| # Unsets the various functions defined |
| # during the execution of the install script |
| # |
| nvm_reset() { |
| unset -f nvm_has nvm_install_dir nvm_latest_version nvm_profile_is_bash_or_zsh \ |
| nvm_source nvm_node_version nvm_download install_nvm_from_git nvm_install_node \ |
| install_nvm_as_script nvm_try_profile nvm_detect_profile nvm_check_global_modules \ |
| nvm_do_install nvm_reset nvm_default_install_dir nvm_grep |
| } |
| |
| [ "_$NVM_ENV" = "_testing" ] || nvm_do_install |
| |
| } # this ensures the entire script is downloaded # |