#!/bin/bash n_version=7.0.2 n_install_dir="/opt/node_n" node_version_path="$n_install_dir/n/versions/node" # N_PREFIX is the directory of n, it needs to be loaded as a environment variable. export N_PREFIX="$n_install_dir" # Install Node version management # # [internal] # # usage: ynh_install_n # # Requires YunoHost version 2.7.12 or higher. ynh_install_n () { ynh_print_info --message="Installation of N - Node.js version management" # Build an app.src for n echo "SOURCE_URL=https://github.com/tj/n/archive/v${n_version}.tar.gz SOURCE_SUM=fa80a8685f0fb1b4187fc0a1228b44f0ea2f244e063fe8f443b8913ea595af89" > "$YNH_APP_BASEDIR/conf/n.src" # Download and extract n ynh_setup_source --dest_dir="$n_install_dir/git" --source_id=n # Install n (cd "$n_install_dir/git" PREFIX=$N_PREFIX make install 2>&1) } # Load the version of node for an app, and set variables. # # ynh_use_nodejs has to be used in any app scripts before using node for the first time. # This helper will provide alias and variables to use in your scripts. # # To use npm or node, use the alias `ynh_npm` and `ynh_node` # Those alias will use the correct version installed for the app # For example: use `ynh_npm install` instead of `npm install` # # With `sudo` or `ynh_exec_as`, use instead the fallback variables `$ynh_npm` and `$ynh_node` # And propagate $PATH to sudo with $ynh_node_load_PATH # Exemple: `ynh_exec_as $app $ynh_node_load_PATH $ynh_npm install` # # $PATH contains the path of the requested version of node. # However, $PATH is duplicated into $node_PATH to outlast any manipulation of $PATH # You can use the variable `$ynh_node_load_PATH` to quickly load your node version # in $PATH for an usage into a separate script. # Exemple: $ynh_node_load_PATH $final_path/script_that_use_npm.sh` # # # Finally, to start a nodejs service with the correct version, 2 solutions # Either the app is dependent of node or npm, but does not called it directly. # In such situation, you need to load PATH # `Environment="__NODE_ENV_PATH__"` # `ExecStart=__FINALPATH__/my_app` # You will replace __NODE_ENV_PATH__ with $ynh_node_load_PATH # # Or node start the app directly, then you don't need to load the PATH variable # `ExecStart=__YNH_NODE__ my_app run` # You will replace __YNH_NODE__ with $ynh_node # # # 2 other variables are also available # - $nodejs_path: The absolute path to node binaries for the chosen version. # - $nodejs_version: Just the version number of node for this app. Stored as 'nodejs_version' in settings.yml. # # usage: ynh_use_nodejs # # Requires YunoHost version 2.7.12 or higher. ynh_use_nodejs () { nodejs_version=$(ynh_app_setting_get --app=$app --key=nodejs_version) # Get the absolute path of this version of node nodejs_path="$node_version_path/$nodejs_version/bin" # Allow alias to be used into bash script shopt -s expand_aliases # Create an alias for the specific version of node and a variable as fallback ynh_node="$nodejs_path/node" alias ynh_node="$ynh_node" # And npm ynh_npm="$nodejs_path/npm" alias ynh_npm="$ynh_npm" # Load the path of this version of node in $PATH if [[ :$PATH: != *":$nodejs_path"* ]]; then PATH="$nodejs_path:$PATH" fi node_PATH="$PATH" # Create an alias to easily load the PATH ynh_node_load_PATH="PATH=$node_PATH" } # Install a specific version of nodejs # # ynh_install_nodejs will install the version of node provided as argument by using n. # # usage: ynh_install_nodejs --nodejs_version=nodejs_version # | arg: -n, --nodejs_version= - Version of node to install. When possible, your should prefer to use major version number (e.g. 8 instead of 8.10.0). The crontab will then handle the update of minor versions when needed. # # n (Node version management) uses the PATH variable to store the path of the version of node it is going to use. # That's how it changes the version # # Refer to ynh_use_nodejs for more information about available commands and variables # # Requires YunoHost version 2.7.12 or higher. ynh_install_nodejs () { # Use n, https://github.com/tj/n to manage the nodejs versions # Declare an array to define the options of this helper. local legacy_args=n local -A args_array=( [n]=nodejs_version= ) local nodejs_version # Manage arguments with getopts ynh_handle_getopts_args "$@" # Create $n_install_dir mkdir --parents "$n_install_dir" # Load n path in PATH CLEAR_PATH="$n_install_dir/bin:$PATH" # Remove /usr/local/bin in PATH in case of node prior installation PATH=$(echo $CLEAR_PATH | sed 's@/usr/local/bin:@@') # Move an existing node binary, to avoid to block n. test -x /usr/bin/node && mv /usr/bin/node /usr/bin/node_n test -x /usr/bin/npm && mv /usr/bin/npm /usr/bin/npm_n # If n is not previously setup, install it if ! $n_install_dir/bin/n --version > /dev/null 2>&1 then ynh_install_n elif dpkg --compare-versions "$($n_install_dir/bin/n --version)" lt $n_version then ynh_install_n fi # Modify the default N_PREFIX in n script ynh_replace_string --match_string="^N_PREFIX=\${N_PREFIX-.*}$" --replace_string="N_PREFIX=\${N_PREFIX-$N_PREFIX}" --target_file="$n_install_dir/bin/n" # Restore /usr/local/bin in PATH PATH=$CLEAR_PATH # And replace the old node binary. test -x /usr/bin/node_n && mv /usr/bin/node_n /usr/bin/node test -x /usr/bin/npm_n && mv /usr/bin/npm_n /usr/bin/npm # Install the requested version of nodejs uname=$(uname --machine) if [[ $uname =~ aarch64 || $uname =~ arm64 ]] then n $nodejs_version --arch=arm64 else n $nodejs_version fi # Find the last "real" version for this major version of node. real_nodejs_version=$(find $node_version_path/$nodejs_version* -maxdepth 0 | sort --version-sort | tail --lines=1) real_nodejs_version=$(basename $real_nodejs_version) # Create a symbolic link for this major version if the file doesn't already exist if [ ! -e "$node_version_path/$nodejs_version" ] then ln --symbolic --force --no-target-directory $node_version_path/$real_nodejs_version $node_version_path/$nodejs_version fi # Store the ID of this app and the version of node requested for it echo "$YNH_APP_INSTANCE_NAME:$nodejs_version" | tee --append "$n_install_dir/ynh_app_version" # Store nodejs_version into the config of this app ynh_app_setting_set --app=$app --key=nodejs_version --value=$nodejs_version # Build the update script and set the cronjob ynh_cron_upgrade_node ynh_use_nodejs } # Remove the version of node used by the app. # # This helper will check if another app uses the same version of node, # if not, this version of node will be removed. # If no other app uses node, n will be also removed. # # usage: ynh_remove_nodejs # # Requires YunoHost version 2.7.12 or higher. ynh_remove_nodejs () { nodejs_version=$(ynh_app_setting_get --app=$app --key=nodejs_version) # Remove the line for this app sed --in-place "/$YNH_APP_INSTANCE_NAME:$nodejs_version/d" "$n_install_dir/ynh_app_version" # If no other app uses this version of nodejs, remove it. if ! grep --quiet "$nodejs_version" "$n_install_dir/ynh_app_version" then $n_install_dir/bin/n rm $nodejs_version fi # If no other app uses n, remove n if [ ! -s "$n_install_dir/ynh_app_version" ] then ynh_secure_remove --file="$n_install_dir" ynh_secure_remove --file="/usr/local/n" sed --in-place "/N_PREFIX/d" /root/.bashrc rm --force /etc/cron.daily/node_update fi } # Set a cron design to update your node versions # # [internal] # # This cron will check and update all minor node versions used by your apps. # # usage: ynh_cron_upgrade_node # # Requires YunoHost version 2.7.12 or higher. ynh_cron_upgrade_node () { # Build the update script cat > "$n_install_dir/node_update.sh" << EOF #!/bin/bash version_path="$node_version_path" n_install_dir="$n_install_dir" # Log the date date # List all real installed version of node all_real_version="\$(find \$version_path/* -maxdepth 0 -type d | sed "s@\$version_path/@@g")" # Keep only the major version number of each line all_real_version=\$(echo "\$all_real_version" | sed 's/\..*\$//') # Remove double entries all_real_version=\$(echo "\$all_real_version" | sort --unique) # Read each major version while read version do echo "Update of the version \$version" sudo \$n_install_dir/bin/n \$version # Find the last "real" version for this major version of node. real_nodejs_version=\$(find \$version_path/\$version* -maxdepth 0 | sort --version-sort | tail --lines=1) real_nodejs_version=\$(basename \$real_nodejs_version) # Update the symbolic link for this version sudo ln --symbolic --force --no-target-directory \$version_path/\$real_nodejs_version \$version_path/\$version done <<< "\$(echo "\$all_real_version")" EOF chmod +x "$n_install_dir/node_update.sh" # Build the cronjob cat > "/etc/cron.daily/node_update" << EOF #!/bin/bash $n_install_dir/node_update.sh >> $n_install_dir/node_update.log EOF chmod +x "/etc/cron.daily/node_update" }