|
| 1 | +#!/usr/bin/env r |
| 2 | +# |
| 3 | +# Install a package from BioConductor |
| 4 | +# |
| 5 | +# Copyright (C) 2020 - 2022 Dirk Eddelbuettel |
| 6 | +# Copyright (C) 2022 - 2022 Dirk Eddelbuettel and Pieter Moris |
| 7 | +# |
| 8 | +# Released under GPL (>= 2) |
| 9 | + |
| 10 | +## load docopt package from CRAN |
| 11 | +library(docopt) |
| 12 | + |
| 13 | +## default to first library location in .libPaths() |
| 14 | +libloc <- .libPaths()[1] |
| 15 | + |
| 16 | +## configuration for docopt |
| 17 | +doc <- paste0("Usage: installBioc.r [-l LIBLOC] [-d DEPS] [-n NCPUS] [-r REPO ...] [--error] [--skipinstalled] [-m METHOD] [--force] [--update] [-h] [-x] [PACKAGES ...] |
| 18 | +-l --libloc LIBLOC location in which to install [default: ", libloc, "] |
| 19 | +-d --deps DEPS install suggested dependencies as well [default: NA] |
| 20 | +-n --ncpus NCPUS number of processes to use for parallel install [default: getOption] |
| 21 | +-r --repo REPO additional repository to use [default: getOption] |
| 22 | +-e --error throw error and halt instead of a warning [default: FALSE] |
| 23 | +-s --skipinstalled skip installing already installed packages (takes priority over --force) [default: FALSE] |
| 24 | +-m --method METHOD method to be used for downloading files [default: auto] |
| 25 | +-f --force force re-download of packages that are currently up-to-date [default: FALSE] |
| 26 | +-u --update update old already installed packages [default: FALSE] |
| 27 | +-h --help show this help text |
| 28 | +-x --usage show help and short example usage") |
| 29 | +opt <- docopt(doc) # docopt parsing |
| 30 | + |
| 31 | +if (opt$usage) { |
| 32 | + cat(doc, "\n\n") |
| 33 | + cat("where PACKAGES... can be one or more BioConductor names. Functionality depends on |
| 34 | +package 'BiocManger' which has be installed. |
| 35 | +
|
| 36 | +Examples: |
| 37 | + installBioc.r -l /tmp/lib S4Vectors # install into given library |
| 38 | + installBioc.r --update Biobase # install package and update older packages |
| 39 | + installBioc.r --deps NA --error --skipinstalled # install package without suggested dependencies, |
| 40 | + # throw an error on installation failure and skip |
| 41 | + # packages that are already present |
| 42 | +
|
| 43 | +installBioC.r is part of littler which brings 'r' to the command-line. |
| 44 | +See http://dirk.eddelbuettel.com/code/littler.html for more information.\n") |
| 45 | + q("no") |
| 46 | +} |
| 47 | + |
| 48 | +if (!requireNamespace("BiocManager", quietly=TRUE)) { |
| 49 | + stop("Please install 'BiocManager' first, for example via 'install.r BiocManager'.", call.=FALSE) |
| 50 | +} |
| 51 | + |
| 52 | +## set repository to empty character vector if not supplied, since |
| 53 | +## this is the input expected by BiocManager::install(site_repository=) |
| 54 | +## (does not accept NA) |
| 55 | +## the custom repository must be a sub-repository of a main BioC_mirror |
| 56 | +## e.g. software: https://bioconductor.statistik.tu-dortmund.de/packages/3.15/bioc/ |
| 57 | +## annotation: https://ftp.gwdg.de/pub/misc/bioconductor/packages/3.14/data/annotation |
| 58 | +if (opt$repo == "getOption") { |
| 59 | + opt$repo = character() |
| 60 | +} |
| 61 | + |
| 62 | +## check if dependencies need to be installed, see |
| 63 | +## https://www.rdocumentation.org/packages/utils/versions/3.6.2/topics/install.packages |
| 64 | +## the default, NA, means c("Depends", "Imports", "LinkingTo"), but not "Suggests" |
| 65 | +if (opt$deps == "TRUE" || opt$deps == "FALSE") { |
| 66 | + opt$deps <- as.logical(opt$deps) |
| 67 | +} else if (opt$deps == "NA") { |
| 68 | + opt$deps <- NA |
| 69 | +} |
| 70 | + |
| 71 | +## set the number of parallel processes to use for a parallel install of |
| 72 | +## more than one source package, see |
| 73 | +## https://www.rdocumentation.org/packages/utils/versions/3.6.2/topics/install.packages |
| 74 | +if (opt$ncpus == "getOption") { |
| 75 | + opt$ncpus <- getOption("Ncpus", 1L) |
| 76 | +} else if (opt$ncpus == "-1") { |
| 77 | + ## parallel comes with R 2.14+ |
| 78 | + opt$ncpus <- max(1L, parallel::detectCores()) |
| 79 | +} |
| 80 | + |
| 81 | +## helper function to catch errors that could arise when package installation has failed |
| 82 | +## and to skip installation of packages that are already present (for BiocManager::install() |
| 83 | +## these would otherwise result in additional warnings) |
| 84 | +install_bioc <- function(pkgs, ..., error = FALSE, skipinstalled = FALSE) { |
| 85 | + e <- NULL |
| 86 | + capture <- function(e) { |
| 87 | + if (error) { |
| 88 | + catch <- |
| 89 | + grepl("installation of .* packages failed", e$message) || |
| 90 | + grepl("is not available", e$message) || |
| 91 | + grepl("had non-zero exit status", e$message) || |
| 92 | + grepl("compilation failed for package.*", e$message) || |
| 93 | + grepl("fatal error", e$message) || |
| 94 | + grepl("No such file or directory", e$message) |
| 95 | + if (catch) { |
| 96 | + e <<- e |
| 97 | + } |
| 98 | + } |
| 99 | + } |
| 100 | + if (skipinstalled) { |
| 101 | + pkgs <- setdiff(pkgs, installed.packages()[,1]) |
| 102 | + } |
| 103 | + if (length(pkgs) > 0) { |
| 104 | + withCallingHandlers(BiocManager::install(pkgs, ...), warning = capture) |
| 105 | + if (!is.null(e)) { |
| 106 | + stop(e$message, call. = FALSE) |
| 107 | + } |
| 108 | + } |
| 109 | +} |
| 110 | + |
| 111 | +## ensure installation is stripped |
| 112 | +Sys.setenv("_R_SHLIB_STRIP_"="true") |
| 113 | + |
| 114 | +## install requested packages using helper function |
| 115 | +## ask must be set to FALSE because user prompts do not appear when calling |
| 116 | +## R from the CLI, e.g. |
| 117 | +## `R -e 'BiocManager::install("Biobase", ask=TRUE, update=TRUE)'` |
| 118 | +## might warn that MASS is out of date, but would not show a user prompt |
| 119 | +install_bioc(pkgs = opt$PACKAGES, |
| 120 | + lib = opt$libloc, |
| 121 | + site_repository = opt$repo, |
| 122 | + update = opt$update, |
| 123 | + ask = FALSE, |
| 124 | + force = opt$force, |
| 125 | + dependencies = opt$deps, |
| 126 | + Ncpus = opt$ncpus, |
| 127 | + method = opt$method, |
| 128 | + error = opt$error, |
| 129 | + skipinstalled = opt$skipinstalled) |
0 commit comments