#!/bin/bash # vi: se fdm=marker # R front script for biodb extensions packages, version 1.1.2 SCRIPT_FILE=$(basename $0) SCRIPT_DIR=$(dirname $0) VERSION=1.0 DEBUG=0 R_BUILD_FOLDER=${R_BUILD_FOLDER:-$HOME/.local/opt/r} VERSIONS_INFO_FILENAME=VERSION-INFO.dcf VERSIONS_FILE="$R_BUILD_FOLDER/$VERSIONS_INFO_FILENAME" R=R MIRROR="https://cloud.r-project.org/" R_VERSION=${R_VERSION:-current} declare -a ACTIONS=() # Print help {{{1 ################################################################ function print_help { cat <<END_HELP_MSG $SCRIPT_FILE, version $VERSION, is a front end for R, allowing to choose between installed R or R beta or R devel versions. Usage: $SCRIPT_FILE [options] [-- [options passed to R]] Options: --beta Install and use beta version of R. --clean Remove everything from build folder. --devel Install and use devel version of R. -g, --debug Debug mode. -h, --help Print this help message. -n, --no-current Do not use the R binary currently installed on system. --print-bin Print path to R bin. --print-home Print path to R folder. --r-version <version> Choose the version of R to run. Either a version number (4.0, 4.1, ...) or one of "current" (version installed), "release" (official release), "beta" (official prerelease) or "devel" (official development). Default is "current". --run Run the R binary, passing any remaining arguments to it. -u, --update-versions Update the versions file, that lists downloadable versions of R. END_HELP_MSG } # Error {{{1 ################################################################ error() { local msg="$*" echo "[ERROR] $msg at ${BASH_SOURCE[1]}:${BASH_LINENO[0]}" >&2 quit 1 } # Warning {{{1 ################################################################ warning() { local msg="$*" [[ -n $QUIET ]] || echo "[WARNING] $msg at"\ "${BASH_SOURCE[1]}:${BASH_LINENO[0]}" >&2 } # Debug {{{1 ################################################################ debug() { local lvl=$1 local msg="$*" [[ $DEBUG -ge $lvl ]] && echo "[DEBUG] $msg" >&2 } # Info {{{1 ################################################################ info() { local msg="$*" [[ -n $QUIET ]] || echo "[INFO] $msg" >&2 } # Quit {{{1 ################################################################ function quit { local mystatus=$1 [[ ${#ACTIONS[@]} -eq 0 ]] || warning "Some remaining actions where not run: ${ACTIONS[@]}." exit $mystatus } # Read args {{{1 ################################################################ function read_args { local args="$*" # save arguments for debugging purpose local print= while true ; do case $1 in --beta) R_VERSION=beta ;; --clean) ACTIONS+=('clean') ;; --devel) R_VERSION=devel ;; -g|--debug) DEBUG=$((DEBUG + 1)) ;; -h|--help) print_help ; exit 0 ;; -n|--no-current) NO_CURRENT=1 ;; --print-bin) ACTIONS+=('select_r' 'print_bin') ;; --print-home) ACTIONS+=('select_r' 'print_home') ;; --r-version) R_VERSION="$2" ; shift ;; --run) ACTIONS+=('select_r' 'run_r') ;; -u|--update-versions) ACTIONS+=('download_versions_file') ;; -[^-]*) split_opt=$(echo $1 | sed 's/^-//' | sed 's/\([a-zA-Z]\)/ -\1/g') ; set -- $1$split_opt "${@:2}" ;; --) shift ; break ;; *) break esac shift done # Read remaining arguments R_ARGS=("$@") # Debug debug 1 "Arguments are : $args" debug 1 "ACTIONS=${ACTIONS}" debug 1 "DEBUG=$DEBUG" debug 1 "NO_CURRENT=$NO_CURRENT" debug 1 "R_ARGS=$R_ARGS" debug 1 "R_VERSION=$R_VERSION" } # Download versions file {{{1 ################################################################ function download_versions_file { mkdir -p "$R_BUILD_FOLDER" if [[ -f "$VERSIONS_FILE" ]] ; then curl -o "$VERSIONS_FILE" -z "$VERSIONS_FILE" "$MIRROR/src/base/$VERSIONS_INFO_FILENAME" else curl -o "$VERSIONS_FILE" "$MIRROR/src/base/$VERSIONS_INFO_FILENAME" fi } # Select version {{{1 ################################################################ function select_version { if [[ -z $SELECTED_VERSION ]] ; then # Version name if [[ $R_VERSION =~ ^(beta|devel|release|current)$ ]] ; then SELECTED_VERSION=$R_VERSION # Version number elif [[ $R_VERSION =~ ^[0-9]+\.[0-9]+(\.[0-9]+)?$ ]] ; then local version_name= # Try current version if [[ -z $NO_CURRENT ]] ; then local current_version=$(R --version | head -n 1 | sed 's/^.*version \([^ ]*\).*$/\1/') debug 1 current_version=$current_version if [[ $current_version =~ ^$R_VERSION(\.[0-9]+)?$ ]] ; then version_name=current fi fi # Try downloadable versions if [[ -z $version_name ]] ; then [[ -f $VERSIONS_FILE ]] || download_versions_file version_name=$(grep ": $R_VERSION" "$VERSIONS_FILE" | sed 's/^\(.*\):.*$/\1/') [[ -n $version_name ]] || error "Cannot find any version name"\ "in \"$VERSIONS_FILE\" for version \"$R_VERSION\"." fi # Set selected version case $version_name in Next-release) SELECTED_VERSION=beta ;; Devel) SELECTED_VERSION=devel ;; Release) SELECTED_VERSION=release ;; current) SELECTED_VERSION=current ;; *) error "Unknown version name \"$version_name\"." ;; esac # Unknown version else error "Unknown version $R_VERSION." fi fi debug 1 "select_version SELECTED_VERSION=$SELECTED_VERSION" } # Extract real version {{{1 ################################################################ function extract_real_version { [[ -n $SELECTED_VERSION ]] || select_version if [[ -z $REAL_VERSION ]] ; then [[ -f $VERSIONS_FILE ]] || download_versions_file case $SELECTED_VERSION in beta) version_name=Next-release ;; devel) version_name=Devel ;; release) version_name=Release ;; *) error "Unknown version $SELECTED_VERSION to download." ;; esac REAL_VERSION=$(grep "^$version_name:" "$VERSIONS_FILE" | sed 's/^[^:]*: *\(.*\)$/\1/') fi debug 1 "extract_real_version real_version=$REAL_VERSION" } # Get download URL {{{1 ################################################################ function get_download_url { local url= [[ -n $SELECTED_VERSION ]] || select_version case $SELECTED_VERSION in beta) url=$MIRROR/src/base-prerelease/R-latest.tar.gz ;; devel) url=$MIRROR/src/base-prerelease/R-devel.tar.gz ;; release) url=$MIRROR/src/base/R-latest.tar.gz ;; current) url= ;; esac debug 1 "get_download_url URL=$url" echo "$url" } # Set R folder {{{1 ################################################################ function set_r_folder { if [[ -z $R_FOLDER ]] ; then [[ -n $SELECTED_VERSION ]] || select_version if [[ $SELECTED_VERSION == current ]] ; then R_FOLDER=$(/usr/bin/env R --slave --no-restore RHOME) else [[ -n $REAL_VERSION ]] || extract_real_version R_FOLDER=$R_BUILD_FOLDER/R-$REAL_VERSION fi fi debug 1 "get_r_folder R_FOLDER=$R_FOLDER" } # Set R bin path {{{1 ################################################################ function set_r_bin_path { if [[ -z $R_BIN_PATH ]] ; then R_BIN_PATH=R [[ -n $SELECTED_VERSION ]] || select_version if [[ $SELECTED_VERSION != current ]] ; then set_r_folder R_BIN_PATH="$R_FOLDER/bin/R" fi fi debug 1 "set_r_bin_path R_BIN_PATH=$R_BIN_PATH" } # Install R {{{1 ################################################################ function install_r { [[ -d $R_BUILD_FOLDER ]] || mkdir -p "$R_BUILD_FOLDER" set_r_folder set_r_bin_path debug 1 "install_r R_BUILD_FOLDER=$R_BUILD_FOLDER" if [[ ! -x $R_BIN_PATH ]] ; then debug 1 "install_r R_BIN_PATH=$R_BIN_PATH" # Remove possible existing destination folder rm -rf "$R_FOLDER" # Make temporary folder for extraction tmp="$R_BUILD_FOLDER/extract_folder" mkdir -p "$tmp" # Move to temporary folder oldpwd=$(pwd) cd "$tmp" # Extract curl "$(get_download_url)" | tar -xz # Create destination folder mkdir -p "$R_FOLDER" # Move code mv "$tmp"/*/* "$R_FOLDER"/. # Exit temporary folder cd "$oldpwd" # Remove temporary folder rm -r "$tmp" # Build cd "$R_FOLDER" && ./configure --prefix="$HOME/.local" >&2 make -C "$R_FOLDER" >&2 fi } # Select R {{{1 ################################################################ function select_r { set_r_folder set_r_bin_path R="$R_BIN_PATH" R_HOME="$R_FOLDER" [[ $R_VERSION == current ]] || install_r $R_VERSION debug 1 "select_r R=$R" debug 1 "select_r R_HOME=$R_HOME" } # Print bin path {{{1 ################################################################ function print_bin { echo "$R" } # Print path to home {{{1 ################################################################ function print_home { echo "$R_HOME" } # Run R {{{1 ################################################################ function run_r { export R_HOME debug 1 "R_HOME=$R_HOME" debug 1 "$R $R_ARGS" $R "${R_ARGS[@]}" } # Clean build folder {{{1 ################################################################ function clean { [[ -n $R_BUILD_FOLDER ]] && rm -rf "$R_BUILD_FOLDER" } # Run actions {{{1 ################################################################ function run_actions { # Loop on all actions in the submitted order while [[ ${#ACTIONS[@]} -gt 0 ]] ; do # Pop first action local action=${ACTIONS[0]} # Index starts at 1 in zsh, 0 in bash. ACTIONS=("${ACTIONS[@]:1}") # Remove first element debug 1 "action=$action" # Run case $action in clean) ;& print_bin) ;& print_home) ;& select_r) ;& download_versions_file) ;& run_r) $action ;; *) error "Unknown action \"$action\"." ;; esac done } # Move action to start of array {{{1 ################################################################ function move_action_to_start { local action="$1" if [[ " ${ACTIONS[@]} " == *" $action "* ]] ; then declare -a new_actions=($action) for a in ${ACTIONS[@]} ; do [[ $a == $action ]] || new_actions+=($a) done ACTIONS=("${new_actions[@]}") unset new_actions fi } # Order actions {{{1 ################################################################ function order_actions { move_action_to_start "select_r" move_action_to_start "download_versions_file" move_action_to_start "clean" } # Main {{{1 ################################################################ read_args "$@" order_actions run_actions quit 0