diff --git a/.github/workflows/R-CMD-check.yaml b/.github/workflows/R-CMD-check.yaml index 1c9d160..0c9eda3 100644 --- a/.github/workflows/R-CMD-check.yaml +++ b/.github/workflows/R-CMD-check.yaml @@ -59,3 +59,9 @@ jobs: with: args: 'c("--no-manual")' upload-snapshots: false + + - name: Check installation + if: runner.os != 'Windows' + run: | + chmod a+x ./inst/installer.sh + ./inst/installer.sh diff --git a/DESCRIPTION b/DESCRIPTION index aa8313d..22dbb72 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,6 +1,6 @@ Package: ravemanager Title: Manage 'RAVE' Packages -Version: 1.0.35 +Version: 1.0.36 Authors@R: person("Zhengjia", "Wang", email = "dipterix.wang@gmail.com", role = c("aut", "cre")) @@ -14,6 +14,8 @@ Roxygen: list(markdown = TRUE) RoxygenNote: 7.2.3 URL: https://dipterix.org/ravemanager/, http://dipterix.org/ravemanager/ +Imports: + utils Suggests: learnr, pkgload, diff --git a/NAMESPACE b/NAMESPACE index 89491a6..9db37b9 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -12,6 +12,7 @@ export(ravemanager_version) export(remove_conda) export(run_tutorials) export(system_requirements) +export(uninstall) export(update_rave) export(upgrade_installer) export(validate_python) diff --git a/R/check.R b/R/check.R index 5d33318..b95265f 100644 --- a/R/check.R +++ b/R/check.R @@ -6,17 +6,10 @@ is_installed <- function(pkg) { } #' Print out 'RAVE' version information -#' @param nightly whether to check 'nightly' build which contains the newest -#' experimental features. However, 'nightly' builds are not stable. This -#' option is only recommended for zero-day bug fixes. #' @param vanilla whether to use vanilla packages in this function #' @export -version_info <- function(nightly = FALSE, vanilla = FALSE) { - if( nightly ) { - options("ravemanager.nightly" = TRUE) - } else { - options("ravemanager.nightly" = FALSE) - } +version_info <- function(vanilla = FALSE) { + options("ravemanager.nightly" = FALSE) versions <- new.env() versions$ravemanager <- list( @@ -102,10 +95,10 @@ version_info <- function(nightly = FALSE, vanilla = FALSE) { # message(' lib_path <- Sys.getenv("RAVE_LIB_PATH", unset = Sys.getenv("R_LIBS_USER", unset = .libPaths()[[1]]))') # message(' loadNamespace("ravemanager", lib.loc = lib_path)') cli$cli_text(cli$col_cyan(sprintf('loadNamespace("ravemanager", lib.loc = "%s")', get_libpaths(first = TRUE, check = TRUE)))) - if( nightly ) { - cli$cli_text(cli$col_cyan('ravemanager::update_rave(nightly = TRUE)')) - } else { + if( isFALSE(ravemanager_needsUpdate) ) { cli$cli_text(cli$col_cyan('ravemanager::update_rave()')) + } else { + cli$cli_text(cli$col_cyan('ravemanager::update_rave(allow_cache = FALSE)')) } cat("\n") } @@ -136,9 +129,9 @@ version_info <- function(nightly = FALSE, vanilla = FALSE) { ' lib_path <- Sys.getenv("RAVE_LIB_PATH", unset = Sys.getenv("R_LIBS_USER", unset = .libPaths()[[1]]))', ' loadNamespace("ravemanager", lib.loc = lib_path)', ifelse( - nightly, - ' ravemanager::update_rave(nightly = TRUE)', - ' ravemanager::update_rave()' + isFALSE(ravemanager_needsUpdate), + ' ravemanager::update_rave()', + ' ravemanager::update_rave(allow_cache = FALSE)' ), sep = "\n" ), diff --git a/R/install.R b/R/install.R index edc7a51..1a56719 100644 --- a/R/install.R +++ b/R/install.R @@ -3,7 +3,7 @@ #' @description Installs the newest version of 'RAVE' and its dependence #' packages; executes the scripts to finalize installation to update #' configuration files. -#' @param nightly whether to install the nightly build +#' @param allow_cache whether to allow cache; default is true #' @param upgrade_manager whether to upgrade the installer (\code{ravemanager}) #' before updating other packages #' @param force whether to force updating packages even the installed have @@ -306,11 +306,25 @@ assert_r_version <- function(min = "4.0.0") { return(TRUE) } +pak_cache_dir <- function() { + tools <- asNamespace("tools") + tools$R_user_dir("ravemanager", which = "cache") +} + +pak_cache_remove <- function() { + cache_path <- pak_cache_dir() + if(file.exists(cache_path)) { + message("Removing package cache...") + unlink(cache_path, recursive = TRUE) + } + invisible() +} + try_setup_pak <- function(lib_path = get_libpaths(check = TRUE)) { cdir <- NULL tryCatch({ - tools <- asNamespace("tools") - cdir <- dir_create2(tools$R_user_dir("ravemanager", which = "cache")) + + cdir <- dir_create2(pak_cache_dir()) # Try to install package `pak` if(system.file(package = "pak") == "") { @@ -357,6 +371,11 @@ installer_unload_packages <- function() { install_internal <- function(nightly = FALSE, upgrade_manager = FALSE, finalize = TRUE, force = FALSE, python = FALSE, ...) { + # DIPSAUS DEBUG START + # list2env(list(nightly = FALSE, upgrade_manager = FALSE, + # finalize = TRUE, force = FALSE, python = FALSE), envir=.GlobalEnv) + + if( nightly ) { options("ravemanager.nightly" = TRUE) } else { @@ -472,8 +491,15 @@ install_internal <- function(nightly = FALSE, upgrade_manager = FALSE, #' @rdname RAVE-install #' @export -install <- function(nightly = FALSE, upgrade_manager = FALSE, +install <- function(allow_cache = TRUE, upgrade_manager = FALSE, finalize = TRUE, force = FALSE, python = FALSE, ...) { + + if(!allow_cache) { + pak_cache_remove() + } + + + nightly <- FALSE tryCatch({ install_internal( nightly = nightly, @@ -597,3 +623,110 @@ upgrade_installer <- function(reload = TRUE) { } return(invisible(FALSE)) } + +#' Uninstall RAVE components +#' @description +#' Remove cache, python, and/or all settings. Please be aware that +#' R, 'RStudio', and already installed R packages will not be uninstalled. +#' Please carefully read printed messages. +#' @param components which component to remove, see example for choices. +#' @examples +#' +#' if( FALSE ) { +#' +#' # remove cache only +#' ravemanager::uninstall("cache") +#' +#' # remove python environment +#' ravemanager::uninstall("python") +#' +#' # remove all sample data, settings files +#' ravemanager::uninstall("all") +#' +#' } +#' +#' +#' @export +uninstall <- function(components = c("cache", "python", "all")) { + components <- match.arg(components) + remove_cache <- components %in% c("cache", "all") + remove_python <- components %in% c("python", "all") + remove_all <- components %in% c("all") + + if( remove_all ) { + ans <- utils::askYesNo("You are uninstalling RAVE. Please enter Y or yes to confirm: ") + if(!isTRUE(ans)) { + return(invisible()) + } + } + + tools <- asNamespace("tools") + R_user_dir <- tools$R_user_dir + + remove_files <- function(paths) { + lapply(paths, function(path) { + if(!file.exists(path)) { return() } + if(dir.exists(path)) { + unlink(path, recursive = TRUE) + } else { + unlink(path) + } + return() + }) + } + if( remove_cache ) { + message("Removing cache...") + + # ravemanager + pak_cache_remove() + + # raveio + d <- R_user_dir(package = "raveio", which = "data") + fs <- list.files(d, pattern = "^(dipterix|rave-ieeg)-rave-pipelines", include.dirs = TRUE, full.names = TRUE, recursive = FALSE) + remove_files(fs) + if(is_installed("raveio")) { + raveio <- asNamespace("raveio") + raveio$clear_cached_files() + } + } + + if( remove_python ) { + message("Removing python...") + remove_conda(ask = FALSE) + + # rpymat + d <- R_user_dir(package = "rpymat", which = "config") + remove_files(file.path(d, "jupyter-configurations")) + } + + if( remove_all ) { + message("Uninstalling RAVE (we are sorry to say goodbye)...") + + # remove ~/rave_modules + remove_files("~/rave_modules") + + remove_files( R_user_dir("raveio", "data") ) + remove_files( R_user_dir("rpyANTs", "data") ) + remove_files( R_user_dir("threeBrain", "data") ) + + remove_files( R_user_dir("raveio", "config") ) + remove_files( R_user_dir("ravemanager", "config") ) + remove_files( R_user_dir("rpymat", "config") ) + + remove_files( R_user_dir("dipsaus", "cache") ) + remove_files( R_user_dir("ravemanager", "cache") ) + remove_files( R_user_dir("readNSx", "cache") ) + + message("R and RStudio are not managed by RAVE. Please uninstall them by yourself if necessary.") + msg <- paste( + c( + "There are some files that may contain your data or used other packages. ", + "Please check them manually:\n", + .libPaths(), + normalizePath("~/rave_data", mustWork = FALSE) + ), + collapse = "\n" + ) + message(msg) + } +} diff --git a/R/python.R b/R/python.R index 4289063..694f46b 100644 --- a/R/python.R +++ b/R/python.R @@ -159,12 +159,11 @@ system_pkgpath <- function(package, ..., alternative = TRUE) { #' @rdname configure-python #' @export -configure_python <- function(python_ver = "3.9", verbose = TRUE) { +configure_python <- function(python_ver = "auto", verbose = TRUE) { if(!is_installed("rpymat")) { install_packages("rpymat") } - rpymat <- asNamespace("rpymat") # Install conda and create a conda environment diff --git a/inst/installer.sh b/inst/installer.sh new file mode 100644 index 0000000..da3e64c --- /dev/null +++ b/inst/installer.sh @@ -0,0 +1,55 @@ +#!/bin/bash + +set -e +set -u + +SCRIPT_DIR=$(dirname "$0") +R_CMD=$(which Rscript || echo $1) +OS_TYPE=$(/usr/bin/uname) + +if [ "$2" == "--skip-sysreq" ]; then + echo "Skipping system requisites" +elif [ "$OS_TYPE" == "Darwin" ]; then + echo "Operating System: macOS" + . "${SCRIPT_DIR}/shell/installer-prerequisites-osx.sh" +elif [ "$OS_TYPE" == "Linux" ]; then + echo "Operating System: Linux" + # . "${SCRIPT_DIR}/shell/installer-prerequisites-linux.sh" +fi + + +# Load installer commons +. "${SCRIPT_DIR}/shell/installer-common.sh" + + +ohai "Operating System: ${OS_TYPE}" +ohai "R binary path: ${R_CMD}" + + +# Create a temporary directory +tmpdir=$(mktemp -d -t "rave-installer") +cd "${tmpdir}" + +ohai "Current directory: ${tmpdir}" + +# Install ravemanager +lib_path=$(${R_CMD} --no-save --no-restore -e 'cat(Sys.getenv("RAVE_LIB_PATH", unset = Sys.getenv("R_LIBS_USER", unset = .libPaths()[[1]])))') + +ohai "R Library path: $lib_path" + +mkdir -p "$lib_path" + + +cmd_str=" +lib_path <- '$lib_path' +if( system.file(package = 'ravemanager', lib.loc = lib_path) == '' ) { + install.packages('ravemanager', repos = 'https://rave-ieeg.r-universe.dev', lib = lib_path) +} +loadNamespace('ravemanager', lib.loc = lib_path) +ravemanager::install(allow_cache = FALSE) +" +ohai "Running R command: ${cmd_str}" +${R_CMD} --no-save --no-restore -e "${cmd_str}" + + + diff --git a/inst/shell/installer-prerequisites-osx.sh b/inst/shell/installer-prerequisites-osx.sh new file mode 100644 index 0000000..0639397 --- /dev/null +++ b/inst/shell/installer-prerequisites-osx.sh @@ -0,0 +1,35 @@ +#!/bin/bash + +set -u + +SCRIPT_DIR=$(dirname "$0") + +# Load installer commons +. "${SCRIPT_DIR}/installer-common.sh" + +ohai "Checking sudo access (may require your password): " +have_sudo_access true + +UNAME_MACHINE="$(/usr/bin/uname -m)" +if [[ "$UNAME_MACHINE" == "arm64" ]]; then + # On ARM macOS, this script installs to /opt/homebrew only + HOMEBREW_PREFIX="/opt/homebrew" + HOMEBREW_REPOSITORY="${HOMEBREW_PREFIX}" +else + # On Intel macOS, this script installs to /usr/local only + HOMEBREW_PREFIX="/usr/local" + HOMEBREW_REPOSITORY="${HOMEBREW_PREFIX}/Homebrew" +fi + +# Install brew +execute_sudo echo | /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" + + +# Add brew to zsh (z-shell), bash, and sh +# execute echo "eval \"\$($HOMEBREW_PREFIX/bin/brew shellenv)\"" >> "$HOME/.zprofile" +# execute echo "eval \"\$($HOMEBREW_PREFIX/bin/brew shellenv)\"" >> "$HOME/.bash_profile" +# execute echo "eval \"\$($HOMEBREW_PREFIX/bin/brew shellenv)\"" >> "$HOME/.profile" +# Activate brew +eval "$($HOMEBREW_PREFIX/bin/brew shellenv)" + +execute $HOMEBREW_PREFIX/bin/brew install hdf5 fftw libgit2 libxml2 pkg-config libjpeg libpng libtiff cmake diff --git a/man/RAVE-install.Rd b/man/RAVE-install.Rd index 94dc2db..39f9481 100644 --- a/man/RAVE-install.Rd +++ b/man/RAVE-install.Rd @@ -22,7 +22,7 @@ finalize_installation( clear_cache() install( - nightly = FALSE, + allow_cache = TRUE, upgrade_manager = FALSE, finalize = TRUE, force = FALSE, @@ -31,7 +31,7 @@ install( ) update_rave( - nightly = FALSE, + allow_cache = TRUE, upgrade_manager = FALSE, finalize = TRUE, force = FALSE, @@ -51,7 +51,7 @@ processes} \item{...}{passed to internal functions} -\item{nightly}{whether to install the nightly build} +\item{allow_cache}{whether to allow cache; default is true} \item{upgrade_manager}{whether to upgrade the installer (\code{ravemanager}) before updating other packages} diff --git a/man/configure-python.Rd b/man/configure-python.Rd index 98c1dad..6b4ab03 100644 --- a/man/configure-python.Rd +++ b/man/configure-python.Rd @@ -10,7 +10,7 @@ \usage{ validate_python(verbose = TRUE) -configure_python(python_ver = "3.9", verbose = TRUE) +configure_python(python_ver = "auto", verbose = TRUE) remove_conda(ask = TRUE) @@ -36,8 +36,7 @@ safe and it will not affect any existing configurations on the computer. In this isolated environment, the following packages will be installed: \code{numpy}, \code{scipy}, \code{pandas}, \code{h5py}, \code{jupyterlab}, -\code{pynwb}, \code{nipype}, \code{dipy}, \code{nibabel}, \code{nipy}, -\code{nitime}, \code{nilearn}, \code{mne}, \code{niwidgets}. You can always +\code{pynwb}, \code{mat73}, \code{mne}. You can always add more \code{conda} packages via \code{rpymat::add_packages(...)} or \code{pip} packages via \code{rpymat::add_packages(..., pip = TRUE)}. diff --git a/man/uninstall.Rd b/man/uninstall.Rd new file mode 100644 index 0000000..7e3fdc7 --- /dev/null +++ b/man/uninstall.Rd @@ -0,0 +1,33 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/install.R +\name{uninstall} +\alias{uninstall} +\title{Uninstall RAVE components} +\usage{ +uninstall(components = c("cache", "python", "all")) +} +\arguments{ +\item{components}{which component to remove, see example for choices.} +} +\description{ +Remove cache, python, and/or all settings. Please be aware that +R, 'RStudio', and already installed R packages will not be uninstalled. +Please carefully read printed messages. +} +\examples{ + +if( FALSE ) { + + # remove cache only + ravemanager::uninstall("cache") + + # remove python environment + ravemanager::uninstall("python") + + # remove all sample data, settings files + ravemanager::uninstall("all") + +} + + +} diff --git a/man/version_info.Rd b/man/version_info.Rd index 3dfc42f..9a1b50c 100644 --- a/man/version_info.Rd +++ b/man/version_info.Rd @@ -4,13 +4,9 @@ \alias{version_info} \title{Print out 'RAVE' version information} \usage{ -version_info(nightly = FALSE, vanilla = FALSE) +version_info(vanilla = FALSE) } \arguments{ -\item{nightly}{whether to check 'nightly' build which contains the newest -experimental features. However, 'nightly' builds are not stable. This -option is only recommended for zero-day bug fixes.} - \item{vanilla}{whether to use vanilla packages in this function} } \description{