Skip to content

Commit

Permalink
Merge pull request #509 from Appsilon/fix/installation-from-github
Browse files Browse the repository at this point in the history
Enable package installation from GitHub, Bioconductor and local directory.
  • Loading branch information
jakubnowicki committed Nov 13, 2023
2 parents b032a3c + 0cab5a8 commit 091f967
Show file tree
Hide file tree
Showing 6 changed files with 146 additions and 3 deletions.
2 changes: 1 addition & 1 deletion DESCRIPTION
@@ -1,6 +1,6 @@
Package: rhino
Title: A Framework for Enterprise Shiny Applications
Version: 1.5.0.9000
Version: 1.5.0.9001
Authors@R:
c(
person("Kamil", "Żyła", role = c("aut", "cre"), email = "opensource+kamil@appsilon.com"),
Expand Down
1 change: 1 addition & 0 deletions NEWS.md
@@ -1,6 +1,7 @@
# rhino (development)

1. Cypress updated to version 13.
2. `pkg_install` supports installation from local sources, GitHub, and Bioconductor.

# [rhino 1.5.0](https://github.com/Appsilon/rhino/releases/tag/v1.5.0)

Expand Down
37 changes: 35 additions & 2 deletions R/dependencies.R
Expand Up @@ -21,6 +21,23 @@ write_dependencies <- function(deps) {
writeLines(deps, "dependencies.R")
}

extract_package_name <- function(package) {
if (grepl("@", package)) package <- strsplit(package, "@")[[1]][1]

if (grepl("bioc::", package)) return(strsplit(package, "::")[[1]][2])

if (grepl("/", package)) {
package_splited <- strsplit(package, "/")[[1]]
return(package_splited[length(package_splited)])
}

package
}

extract_packages_names <- function(packages) {
purrr::map_chr(packages, extract_package_name)
}

# nolint start: line_length_linter
#' Manage dependencies
#'
Expand All @@ -47,6 +64,18 @@ write_dependencies <- function(deps) {
#' # Update shiny to the latest version
#' rhino::pkg_install("shiny")
#'
#' # Install a specific version of shiny
#' rhino::pkg_install("shiny@1.6.0")
#'
#' # Install shiny.i18n package from GitHub
#' rhino::pkg_install("Appsilon/shiny.i18n")
#'
#' # Install Biobase package from Bioconductor
#' rhino::pkg_install("bioc::Biobase")
#'
#' # Install shiny from local source
#' rhino::pkg_install("~/path/to/shiny")
#'
#' # Remove dplyr
#' rhino::pkg_remove("dplyr")
#' }
Expand All @@ -57,8 +86,10 @@ NULL
#' @export
pkg_install <- function(packages) {
stopifnot(is.character(packages))
packages_names <- extract_packages_names(packages)
cli::cli_alert_info("Installing packages: {packages_names}.")
renv::install(packages)
write_dependencies(c(packages, read_dependencies()))
write_dependencies(c(packages_names, read_dependencies()))
renv::snapshot()
invisible()
}
Expand All @@ -67,8 +98,10 @@ pkg_install <- function(packages) {
#' @export
pkg_remove <- function(packages) {
stopifnot(is.character(packages))
packages_names <- extract_packages_names(packages)
cli::cli_alert_info("Removing packages: {packages_names}.")
renv::remove(packages)
write_dependencies(setdiff(read_dependencies(), packages))
write_dependencies(setdiff(read_dependencies(), packages_names))
renv::snapshot()
invisible()
}
12 changes: 12 additions & 0 deletions man/dependencies.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

57 changes: 57 additions & 0 deletions tests/e2e/test-dependencies.R
Expand Up @@ -28,3 +28,60 @@ rhino::pkg_remove("dplyr")
testthat::expect_false(is_installed("dplyr"))
testthat::expect_identical(readLines("dependencies.R"), initial_dependencies)
testthat::expect_identical(readLines("renv.lock"), initial_lockfile)

# install package from GitHub

initial_dependencies <- readLines("dependencies.R")
initial_lockfile <- readLines("renv.lock")

# Check initial state.
testthat::expect_false(is_installed("shiny.i18n"))
testthat::expect_false(any(initial_dependencies == "library(shiny.i18n)"))
testthat::expect_false(any(initial_lockfile == ' "shiny.i18n": {'))

# Install package and check if it was done correctly.
rhino::pkg_install("Appsilon/shiny.i18n")
testthat::expect_true(is_installed("shiny.i18n"))
testthat::expect_setequal(
readLines("dependencies.R"),
c(initial_dependencies, "library(shiny.i18n)")
)
testthat::expect_contains(
readLines("renv.lock"),
' "shiny.i18n": {'
)

# Remove package and check if we're back to initial state.
rhino::pkg_remove("shiny.i18n")
testthat::expect_false(is_installed("shiny.i18n"))
testthat::expect_identical(readLines("dependencies.R"), initial_dependencies)
testthat::expect_identical(readLines("renv.lock"), initial_lockfile)


# install package from Bioconductor

initial_dependencies <- readLines("dependencies.R")
initial_lockfile <- readLines("renv.lock")

# Check initial state.
testthat::expect_false(is_installed("Biobase"))
testthat::expect_false(any(initial_dependencies == "library(Biobase)"))
testthat::expect_false(any(initial_lockfile == ' "Biobase": {'))

# Install package and check if it was done correctly.
rhino::pkg_install("bioc::Biobase")
testthat::expect_true(is_installed("Biobase"))
testthat::expect_setequal(
readLines("dependencies.R"),
c(initial_dependencies, "library(Biobase)")
)
testthat::expect_contains(
readLines("renv.lock"),
' "Biobase": {'
)

# Remove package and check if we're back to initial state.
rhino::pkg_remove("Biobase")
testthat::expect_false(is_installed("Biobase"))
testthat::expect_identical(readLines("dependencies.R"), initial_dependencies)
testthat::expect_identical(readLines("renv.lock"), initial_lockfile)
40 changes: 40 additions & 0 deletions tests/testthat/test-dependencies.R
@@ -0,0 +1,40 @@
describe("extract_package_name", {
it("returns the package name intact when using only the package name", {
expect_equal(extract_package_name("shiny"), "shiny")
})

it("returns the package name intact when using the package name and version", {
expect_equal(extract_package_name("shiny@1.6.0"), "shiny")
})

it("returns the package name when installing a package from GitHub", {
expect_equal(extract_package_name("r-lib/httr"), "httr")
expect_equal(extract_package_name("r-lib/testthat@c67018fa4970"), "testthat")
})

it("returns the package name when installing a package from a local path", {
expect_equal(extract_package_name("~/path/to/package"), "package")
})

it("returns the package name when installing a package from Bioconductor", {
expect_equal(extract_package_name("bioc::Biobase"), "Biobase")
})
})

describe("extract_packages_names", {
it("returns a vector of package names when installing multiple packages", {
expect_equal(extract_packages_names(c("shiny", "dplyr")), c("shiny", "dplyr"))
})
})

describe("pkg_install", {
it("throws an error when the argument is not a character vector", {
expect_error(pkg_install(1))
})
})

describe("pkg_remove", {
it("throws an error when the argument is not a character vector", {
expect_error(pkg_remove(1))
})
})

0 comments on commit 091f967

Please sign in to comment.