Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Installing executable scripts with R package

In most scripting languages (e.g. Ruby, Python, etc.) the package manager (e.g. gem, pip, etc.) can install scripts as executables and link them to a directory referenced in the PATH variable (e.g. /usr/local/bin). This turns those executable scripts into shell commands that the user can run in an standalone manner and outside the programming interface.

I wonder if there is such a possibility in R as well. Given that R uses standard Makefiles, I guess there must be a way to do so, albeit a non-standard one. I already know we can read command line arguments in a R script using the docopt package. But is there a way to install the script as an executable upon the installation of a package?

It would be great to have a lead on this topic, but a single working example from CRAN would suffice as well.

like image 942
retrography Avatar asked Jun 15 '17 11:06

retrography


1 Answers

I had a similar goal, this was the solution I settled on. I added a function to my R package that goes through and (verbosely) creates symlinks from ~/.local/bin to each script in my packages exec folder.

Other sensible default locations might be ~/.local/lib/R/bin or ~/bin, but I like ~/.local/bin the best.

So after installing the package, I direct users to run

Rscript -e 'mypackage::install_executable_scripts()'
#' @export
install_executable_scripts <- function(into = "~/.local/bin", overwrite = FALSE) {
  scripts <- dir(system.file("exec", package = "mypackage"),
                 full.names = TRUE)
  if (!dir.exists(into)) dir.create(into)
  into <- normalizePath(into)

  dests <- file.path(normalizePath(into), basename(scripts))
  if (any(already_exist <- file.exists(dests))) {
    if (overwrite) {
      to_del <- dests[already_exist]
      cli::cat_bullet("Deleting existing file: ", to_del,
                      bullet_col = "red")
      unlink(to_del)
    } else {
      cli::cat_bullet(sprintf(
        "Skipping script '%s' because a file by that name already exists at the destination",
        basename(scripts[already_exist])))
      scripts <- scripts[!already_exist]
      dests   <-   dests[!already_exist]
    }
  }
  if (length(scripts)) {
    file.symlink(scripts, dests)
    cli::cat_line("Created symlinks:")
    cli::cat_bullet(dests, " ->\n    ", scripts, bullet_col = "green")
  } else
    cli::cat_line("Nothing installed")

  PATHS <- normalizePath(strsplit(Sys.getenv("PATH"), ":", fixed = TRUE)[[1]],
                         mustWork = FALSE)
  if(!into %in% PATHS)
    warning(sprintf("destination '%s' is not on the PATH", into))
}
like image 135
t-kalinowski Avatar answered Nov 11 '22 16:11

t-kalinowski