#!/bin/bash # NVM/NPM/NodeJS/Yarn installation script # by Yuchen Jin (cainmagi) / 09092024 # --------------------------------------------------------- # This script has been tested on # `ubuntu:focal` and `python:3.12-slim` # docker image. # --------------------------------------------------------- # Currently, it is designed for installing: # nvm, npm, nodejs, and yarn # The version can be specified by users. # --------------------------------------------------------- # For those users who want to install all latest tools, # please run: # ```bash # ./install-nodejs.sh --all # ``` # ------------------------ # NodeJS is installed by NVM and NPM. For those users who # do not want to install yarn, please run: # ```bash # ./install-nodejs.sh --basic --nodejs # ``` # ------------------------ # For installing a specific version, please run: # ```bash # ./install-nodejs.sh --all nvm=0.40.1 nodejs=20.17.0 yarn=4.4.1 # ``` # Note that the version will take effect only when the tool # will be installed. For example, if --yarn or --all is not # specified, yarn=? will not take effects. # ------------------------ # For those users using root mode, please add the option # --sudofix like this:: # ```bash # ./install-nodejs.sh ... --sudofix # ``` # Make bashline configurations. set -e RESET='\033[0m' COLOR='\033[1;32m' COLOR_WARN='\033[1;33m' COLOR_ERR='\033[1;31m' COLOR_OPT='\033[1;34m' COLOR_OPT_TEXT='\033[0;34m' DEBIAN_FRONTEND=noninteractive BASH_PREFIX="" # PS1=# && source ~/.bashrc && function msg { echo -e "${COLOR}$(date): $1${RESET}" } function msg_warn { echo -e "${COLOR_WARN}$(date): $1${RESET}" } function msg_err { echo -e "${COLOR_ERR}$(date): $1${RESET}" } function fail { msg_err "Error : $?" exit 1 } function mcd { mkdir -p "$1" || fail cd "$1" || fail } function nvm_has { type "$1" > /dev/null 2>&1 } function nvm_default_install_dir { [ -z "${XDG_CONFIG_HOME-}" ] && printf %s "${HOME}/.nvm" || printf %s "${XDG_CONFIG_HOME}/nvm" } function nvm_install_dir { if [ -n "$NVM_DIR" ]; then printf %s "${NVM_DIR}" else printf %s "$(echo "${BASH_PREFIX} echo \$NVM_DIR" | bash --login -i)" fi } function install_nvm { msg "Installing NVM, version: $1" wget -O- https://raw.githubusercontent.com/nvm-sh/nvm/$1/install.sh | bash || fail RUN_NVM_DIR="$(nvm_install_dir)" || fail if [ "x${RUN_NVM_DIR}" != "x" ]; then ${SUDO} chmod ugo+rwx "${RUN_NVM_DIR}" --recursive || fail fi } function nvm_exist_nvm { if [ "x$(echo "${BASH_PREFIX} type nvm 2>/dev/null" | bash --login -i)" != "x" ]; then true; else false; fi } function nvm_exist_corepack { if [ "x$(echo "${BASH_PREFIX} type corepack 2>/dev/null" | bash --login -i)" != "x" ]; then true; else false; fi } function nodejs_version { RUN_NVM_DIR="$(nvm_install_dir)" || fail if [ -d "$RUN_NVM_DIR" ]; then printf %s "$(echo "${BASH_PREFIX} nvm version" | bash --login -i)" else printf %s "" fi } function yarn_version { RUN_NVM_DIR="$(nvm_install_dir)" || fail if [ -d "$RUN_NVM_DIR" ]; then if [ "x$(echo "${BASH_PREFIX} type yarn 2>/dev/null" | bash --login -i)" != "x" ]; then printf %s "$(echo "${BASH_PREFIX} yarn --version" | bash --login -i)" else printf %s "" fi else printf %s "" fi } function install_nodejs { msg "Installing NPM and Node.js, version: $1" RUN_NVM_DIR="$(nvm_install_dir)" || fail if [ "x${RUN_NVM_DIR}" != "x" ]; then msg "Finding NVM in: ${RUN_NVM_DIR}". if [ "x$1" = "xlatest" ]; then echo "${BASH_PREFIX} nvm install --lts" | bash --login -i || fail echo "${BASH_PREFIX} nvm use --lts" | bash --login -i || fail else echo "${BASH_PREFIX} nvm install v$1" | bash --login -i || fail echo "${BASH_PREFIX} nvm alias default v$1" | bash --login -i || fail echo "${BASH_PREFIX} nvm use default" | bash --login -i || fail fi else msg_warn "Skip installation for Node.js because NVM is not found." fi } function install_corepack { msg "Attempt to install corepack." if [ "x$(echo "${BASH_PREFIX} type npm 2>/dev/null" | bash --login -i)" != "x" ]; then echo "${BASH_PREFIX} npm install -g corepack" | bash --login -i || fail else msg_warn "Skip installation for Corepack because NPM is not found." fi } function install_yarn { msg "Update Yarn to the version: $1" echo "${BASH_PREFIX} yarn set version $1" | bash --login -i || fail echo "${BASH_PREFIX} yarn install" | bash --login -i || fail } SET_HELP=false SET_DEBUG=false SET_SUDOFIX=false SET_ALL=false SET_BASIC=false SET_NODEJS=false SET_YARN=false VER_NVM="latest" VER_NODEJS="latest" VER_YARN="latest" LIBRARY_PATH=${LIBRARY_PATH}:/usr/local/cuda/lib64/stubs LD_LIBRARY_PATH="${LD_LIBRARY_PATH}:/usr/local/cuda/compat/lib.real:/usr/local/cuda/compat/lib:/usr/local/nvidia/lib:/usr/local/nvidia/lib64:/usr/lib/x86_64-linux-gnu:/usr/local/cuda/lib64:/usr/local/cuda/nvvm/lib64:/usr/local/lib64:/usr/lib:/usr/local/lib:/lib:/lib/x86_64-linux-gnu:/lib/i386-linux-gnu" MKL_CBWR=AUTO # Pass options from command line for ARGUMENT in "$@" do KEY=$(echo $ARGUMENT | cut -f1 -d=) if [[ $KEY != '--*' ]] then VALUE=$(echo $ARGUMENT | cut -f2 -d=) fi case "$KEY" in --help) SET_HELP=true ;; --debug) SET_DEBUG=true ;; --sudofix) SET_SUDOFIX=true ;; --all) SET_ALL=true ;; --basic) SET_BASIC=true ;; --nodejs) SET_NODEJS=true ;; --yarn) SET_YARN=true ;; nvm) VER_NVM=${VALUE} ;; nodejs) VER_NODEJS=${VALUE} ;; yarn) VER_YARN=${VALUE} ;; *) esac done # Help mode. if [ "x${SET_HELP}" = "xtrue" ] then THIS_NAME="$(basename "$(test -L "$0" && readlink "$0" || echo "$0")")" HELP_MESSAGE="${COLOR}NodeJS/Yarn installation script - by Yuchen Jin (cainmagi) / 09092024${RESET} Use as \"${COLOR_OPT}bash ${THIS_NAME} --flag1 --flag2 ... option1=val1 option2=val2 ...${RESET}\" where the usages are: ${COLOR_OPT}--all${RESET}: Run the full script, installing both nodejs and yarn. ${COLOR_OPT}--basic${RESET}: Install the basic dependencies by apt. ${COLOR_OPT}--nodejs${RESET}: Install NodeJS. ${COLOR_OPT}--yarn${RESET}: Install Yarn. This flag will not take effect if --nodejs is not specified. ${COLOR_OPT}--sudofix${RESET} [not included by --all]: Install sudo (should be specified only when using root mode). ${COLOR_OPT}--help${RESET}: Display the help message. ${COLOR_OPT} nvm=${COLOR_OPT_TEXT}${RESET}: Configure the version of the NVM to be installed. NVM is required by NodeJS. ${COLOR_OPT_TEXT}Current value${RESET}: ${VER_NODEJS} ${COLOR_OPT}nodejs=${COLOR_OPT_TEXT}${RESET}: Configure the version of the NodeJS to be installed. ${COLOR_OPT_TEXT}Current value${RESET}: ${VER_NODEJS} ${COLOR_OPT} yarn=${COLOR_OPT_TEXT}${RESET}: Configure the version of the Yarn to be installed. ${COLOR_OPT_TEXT}Current value${RESET}: ${VER_YARN} " echo -e "$HELP_MESSAGE" exit 1 fi # Configure the options when {flag:SET_ALL} has been configured. if [ "x${SET_ALL}" = "xtrue" ] then msg "${COLOR_ERR}--all): ${COLOR_OPT_TEXT}Install all tools." SET_BASIC=true # SET_SUDOFIX=true # should not be specified when not using root mode. SET_NODEJS=true SET_YARN=true fi # If run with root and sudo is not installed if [ "x${SET_SUDOFIX}" = "xtrue" ]; then msg "${COLOR_OPT}--sudofix): ${COLOR_OPT_TEXT}Install sudo (only used in root mode)." apt-get update -qq || fail apt-get -y install sudo || fail fi # Determine whether sudo should be used. SUDO="" if nvm_has "sudo"; then SUDO="sudo" fi # Install apt dependencies if [ "x${SET_BASIC}" = "xtrue" ]; then msg "${COLOR_OPT}--basic): ${COLOR_OPT_TEXT}Install apt packages." ${SUDO} apt-get update -qq || fail ${SUDO} apt-get -y full-upgrade || fail ${SUDO} apt-get -y install wget jq tar xz-utils || fail ${SUDO} apt-get update -qq || fail ${SUDO} apt-get -y upgrade || fail ${SUDO} apt-get -y dist-upgrade || fail ${SUDO} apt-get -y autoremove || fail ${SUDO} apt-get -y autoclean || fail fi # Fetch the latest version if [ "x${VER_NVM}" = "x" ] || [ "x${VER_NVM}" = "xlatest" ]; then VER_NVM=$(wget -qO- https://api.github.com/repos/nvm-sh/nvm/releases/latest | jq .name -r) fi if [ "x${VER_NODEJS}" = "x" ] || [ "x${VER_NODEJS}" = "xlatest" ]; then VER_NODEJS="latest" fi if [ "x${VER_YARN}" = "x" ] || [ "x${VER_YARN}" = "xlatest" ]; then VER_YARN="stable" fi # Case when installing NodeJS is specified. if [ "x${SET_NODEJS}" = "xtrue" ]; then msg "${COLOR_OPT}--nodejs): ${COLOR_OPT_TEXT}Install nvm, npm, and nodejs." # Install NVM if ! nvm_has nvm; then if ! nvm_exist_nvm; then install_nvm ${VER_NVM} || fail else msg "Skip installation for NVM because NVM is detected." fi else msg "Skip installation for NVM because NVM is detected." fi # Install NodeJS CUR_NODEJS_VER="$(nodejs_version)" if [ "x${CUR_NODEJS_VER}" = "x" ] || [ "x${CUR_NODEJS_VER}" = "xnone" ] || [ "x${CUR_NODEJS_VER}" = "xN/A" ]; then install_nodejs ${VER_NODEJS} || fail else if [ "x${VER_NODEJS}" != "xlatest" ] && [ "x${CUR_NODEJS_VER}" != "xv${VER_NODEJS}" ]; then install_nodejs ${VER_NODEJS} || fail else msg "Skip installation for NodeJS because detect the version: ${CUR_NODEJS_VER}" fi fi fi # Case when installing Yarn is specified. if [ "x${SET_YARN}" = "xtrue" ]; then msg "${COLOR_OPT}--yarn): ${COLOR_OPT_TEXT}Install yarn." if ! nvm_exist_corepack; then install_corepack || fail fi if nvm_exist_corepack; then CUR_YARN_VER="$(yarn_version)" echo "${BASH_PREFIX} corepack enable" | bash --login -i || fail echo "${BASH_PREFIX} corepack prepare yarn --activate" | bash --login -i || fail if [ -s "package.json" ] && [ "$(pwd)" != "/" ]; then if [ "x${CUR_YARN_VER}" = "x" ]; then install_yarn ${VER_YARN} || fail else if [ "x${VER_YARN}" != "xstable" ] && [ "x${CUR_YARN_VER}" != "x${VER_YARN}" ]; then install_yarn ${VER_YARN} || fail else msg "Skip installation for Yarn because detect the version: ${CUR_YARN_VER}" fi fi fi else msg_warn "Cannot install Yarn if NodeJS with Corepack is not installed." fi fi msg "Installation finished." if [ "x${SET_NODEJS}" = "xtrue" ]; then msg "If you have newly installed NodeJS, rememeber to restart bash to make it take effects." fi