├── .github ├── .gitignore ├── workflows │ ├── pkgcheck.yaml │ ├── R-CMD-check-HTML5.yaml │ ├── pkgdown.yaml │ ├── render-README.yaml │ ├── R-CMD-check.yaml │ ├── update-citation-cff.yaml │ ├── java-live-tests.yml │ ├── test-coverage.yaml │ └── rhub.yaml ├── CONTRIBUTING.md └── CODE_OF_CONDUCT.md ├── vignettes ├── .gitignore ├── data-for-vignettes │ ├── get-data-for-vignettes.R │ ├── rJava_dlstats.csv │ ├── ggplot2_dlstats.csv │ └── data_table_dlstats.csv ├── bibliography.bib ├── multiple-java-with-targets-callr.qmd └── install-rjava-from-source.qmd ├── LICENSE ├── man ├── figures │ ├── card.png │ └── logo.png ├── urls_test_all.Rd ├── java_get_home.Rd ├── java_urls_load.Rd ├── global_quiet_param.Rd ├── java_version_check_rscript.Rd ├── java_env_set_session.Rd ├── rje_envvar_exists.Rd ├── platform_detect.Rd ├── java_build_env_set_rprofile.Rd ├── set_java_build_env_vars.Rd ├── rje_consent_check.Rd ├── java_env_set_rprofile.Rd ├── java_check_version_system.Rd ├── java_check_version_cmd.Rd ├── java_clear_in_project.Rd ├── java_clear_distrib_cache.Rd ├── java_clear_installed_cache.Rd ├── java_list_in_project.Rd ├── java_build_env_unset.Rd ├── java_list_distrib_cache.Rd ├── java_list_installed_cache.Rd ├── java_env_unset.Rd ├── java_check_version_rjava.Rd ├── java_clear.Rd ├── java_valid_major_versions_corretto.Rd ├── java_unpack.Rd ├── rje_consent.Rd ├── java_list.Rd ├── java_valid_versions.Rd ├── java_install.Rd ├── java_build_env_set.Rd ├── java_env_set.Rd ├── java_download.Rd ├── java_quick_install.Rd ├── use_java.Rd └── rJavaEnv-package.Rd ├── pkgdown ├── favicon │ ├── favicon.ico │ ├── favicon-16x16.png │ ├── favicon-32x32.png │ ├── favicon-96x96.png │ ├── apple-touch-icon.png │ ├── apple-touch-icon-60x60.png │ ├── apple-touch-icon-76x76.png │ ├── apple-touch-icon-120x120.png │ ├── apple-touch-icon-152x152.png │ ├── apple-touch-icon-180x180.png │ ├── web-app-manifest-192x192.png │ ├── web-app-manifest-512x512.png │ └── site.webmanifest └── assets │ └── images │ └── card.png ├── R ├── rJavaEnv-package.R ├── global_params.R ├── java_quick_install.R ├── use_java.R ├── onLoad.R ├── java_manage.R ├── java_manage_distrib_cache.R ├── consent.R ├── java_unpack.R ├── java_manage_installed_cache.R ├── java_manage_project.R ├── java_valid_versions.R └── internal_utilities.R ├── .gitignore ├── .editorconfig ├── tests ├── testthat │ ├── setup-mock-globals.R │ ├── test-java_env.R │ ├── test-java_unpack.R │ ├── test-onLoad.R │ ├── test-internal_utilities_extra.R │ ├── test-java_env_linux.R │ ├── test-java_valid_versions.R │ ├── test-java_wrappers.R │ ├── helper-mocks.R │ ├── test-java_download-mocked.R │ ├── test-internal_utilities_version.R │ ├── test-java_env_unit.R │ ├── test-java_full-cycle-live.R │ ├── test-internal_utilities.R │ └── test-java_manage.R └── testthat.R ├── rJavaEnv.Rproj ├── tools └── meta-data-update-and-submission.R ├── inst ├── CITATION ├── extdata │ └── java_urls.json ├── resources │ └── consent-info └── schemaorg.json ├── NAMESPACE ├── .Rbuildignore ├── cran-comments.md ├── LICENSE.md ├── _pkgdown.yml ├── DESCRIPTION └── NEWS.md /.github/.gitignore: -------------------------------------------------------------------------------- 1 | *.html 2 | -------------------------------------------------------------------------------- /vignettes/.gitignore: -------------------------------------------------------------------------------- 1 | /.quarto/ 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | YEAR: 2024 2 | COPYRIGHT HOLDER: rJavaEnv authors 3 | -------------------------------------------------------------------------------- /man/figures/card.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/e-kotov/rJavaEnv/HEAD/man/figures/card.png -------------------------------------------------------------------------------- /man/figures/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/e-kotov/rJavaEnv/HEAD/man/figures/logo.png -------------------------------------------------------------------------------- /pkgdown/favicon/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/e-kotov/rJavaEnv/HEAD/pkgdown/favicon/favicon.ico -------------------------------------------------------------------------------- /pkgdown/assets/images/card.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/e-kotov/rJavaEnv/HEAD/pkgdown/assets/images/card.png -------------------------------------------------------------------------------- /pkgdown/favicon/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/e-kotov/rJavaEnv/HEAD/pkgdown/favicon/favicon-16x16.png -------------------------------------------------------------------------------- /pkgdown/favicon/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/e-kotov/rJavaEnv/HEAD/pkgdown/favicon/favicon-32x32.png -------------------------------------------------------------------------------- /pkgdown/favicon/favicon-96x96.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/e-kotov/rJavaEnv/HEAD/pkgdown/favicon/favicon-96x96.png -------------------------------------------------------------------------------- /pkgdown/favicon/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/e-kotov/rJavaEnv/HEAD/pkgdown/favicon/apple-touch-icon.png -------------------------------------------------------------------------------- /pkgdown/favicon/apple-touch-icon-60x60.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/e-kotov/rJavaEnv/HEAD/pkgdown/favicon/apple-touch-icon-60x60.png -------------------------------------------------------------------------------- /pkgdown/favicon/apple-touch-icon-76x76.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/e-kotov/rJavaEnv/HEAD/pkgdown/favicon/apple-touch-icon-76x76.png -------------------------------------------------------------------------------- /pkgdown/favicon/apple-touch-icon-120x120.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/e-kotov/rJavaEnv/HEAD/pkgdown/favicon/apple-touch-icon-120x120.png -------------------------------------------------------------------------------- /pkgdown/favicon/apple-touch-icon-152x152.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/e-kotov/rJavaEnv/HEAD/pkgdown/favicon/apple-touch-icon-152x152.png -------------------------------------------------------------------------------- /pkgdown/favicon/apple-touch-icon-180x180.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/e-kotov/rJavaEnv/HEAD/pkgdown/favicon/apple-touch-icon-180x180.png -------------------------------------------------------------------------------- /pkgdown/favicon/web-app-manifest-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/e-kotov/rJavaEnv/HEAD/pkgdown/favicon/web-app-manifest-192x192.png -------------------------------------------------------------------------------- /pkgdown/favicon/web-app-manifest-512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/e-kotov/rJavaEnv/HEAD/pkgdown/favicon/web-app-manifest-512x512.png -------------------------------------------------------------------------------- /R/rJavaEnv-package.R: -------------------------------------------------------------------------------- 1 | #' @keywords internal 2 | "_PACKAGE" 3 | 4 | ## usethis namespace: start 5 | #' @import rlang 6 | #' @importFrom utils getFromNamespace 7 | ## usethis namespace: end 8 | NULL 9 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .Rproj.user 2 | .Rhistory 3 | .Rdata 4 | .httr-oauth 5 | .DS_Store 6 | .quarto 7 | docs 8 | bin 9 | private 10 | README_cache 11 | renv 12 | .Rprofile 13 | rjavaenv 14 | /doc/ 15 | /Meta/ 16 | 17 | /.quarto/ 18 | revdep 19 | .cache 20 | .config 21 | .jupyter 22 | .local 23 | .ipython 24 | .vscode 25 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf8 5 | end_of_line = lf 6 | insert_final_newline = true 7 | indent_style = space 8 | 9 | [*.{r,R,rmd,Rmd,qmd}] 10 | indent_size = 2 11 | trim_trailing_whitespace = true 12 | 13 | [*.{cpp,h,hpp}] 14 | indent_size = 2 15 | trim_trailing_whitespace = true 16 | 17 | [Makefile] 18 | indent_style = tab -------------------------------------------------------------------------------- /R/global_params.R: -------------------------------------------------------------------------------- 1 | #' @title Global Quiet Parameter 2 | #' 3 | #' @description 4 | #' Documentation for the `quiet` parameter, used globally. 5 | #' 6 | #' @param quiet A `logical` value indicating whether to suppress messages. Can be `TRUE` or `FALSE`. 7 | #' @keywords internal 8 | global_quiet_param <- function(quiet){ 9 | # this is just a placeholder for global quiet parameter 10 | } 11 | -------------------------------------------------------------------------------- /man/urls_test_all.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/internal_utilities.R 3 | \name{urls_test_all} 4 | \alias{urls_test_all} 5 | \title{Test all Java URLs} 6 | \usage{ 7 | urls_test_all() 8 | } 9 | \value{ 10 | A list with the results of testing all Java URLs. 11 | } 12 | \description{ 13 | Test all Java URLs 14 | } 15 | \keyword{internal} 16 | -------------------------------------------------------------------------------- /man/java_get_home.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/java_env.R 3 | \name{java_get_home} 4 | \alias{java_get_home} 5 | \title{Get JAVA_HOME} 6 | \usage{ 7 | java_get_home() 8 | } 9 | \value{ 10 | The value of the JAVA_HOME environment variable. 11 | } 12 | \description{ 13 | Get the current JAVA_HOME environment variable. 14 | } 15 | \examples{ 16 | java_get_home() 17 | } 18 | -------------------------------------------------------------------------------- /tests/testthat/setup-mock-globals.R: -------------------------------------------------------------------------------- 1 | # This file is run automatically by testthat before tests are run. 2 | # It's a good place for mocks that are used across multiple test files. 3 | 4 | # NOTE: Mocks defined here with local_mocked_bindings() will NOT persist 5 | # into the test files because the scope ends when this file finishes sourcing. 6 | # Instead, we use helper-mocks.R which defines functions to apply mocks 7 | # within the test scopes. 8 | -------------------------------------------------------------------------------- /tests/testthat.R: -------------------------------------------------------------------------------- 1 | # This file is part of the standard setup for testthat. 2 | # It is recommended that you do not modify it. 3 | # 4 | # Where should you do additional test configuration? 5 | # Learn more about the roles of various files in: 6 | # * https://r-pkgs.org/testing-design.html#sec-tests-files-overview 7 | # * https://testthat.r-lib.org/articles/special-files.html 8 | 9 | library(testthat) 10 | library(rJavaEnv) 11 | 12 | test_check("rJavaEnv") 13 | -------------------------------------------------------------------------------- /man/java_urls_load.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/internal_utilities.R 3 | \name{java_urls_load} 4 | \alias{java_urls_load} 5 | \title{Load Java URLs from JSON file} 6 | \usage{ 7 | java_urls_load() 8 | } 9 | \value{ 10 | A list with the Java URLs structured as in the JSON file by distribution, platform, and architecture. 11 | } 12 | \description{ 13 | Load Java URLs from JSON file 14 | } 15 | \keyword{internal} 16 | -------------------------------------------------------------------------------- /tests/testthat/test-java_env.R: -------------------------------------------------------------------------------- 1 | test_that("java_get_home() gets JAVA_HOME", { 2 | withr::with_envvar( 3 | c("JAVA_HOME" = "/path/to/java"), 4 | expect_equal(java_get_home(), "/path/to/java") 5 | ) 6 | }) 7 | 8 | test_that("java_get_home() returns empty string when JAVA_HOME is not set", { 9 | withr::with_envvar( 10 | c("JAVA_HOME" = NA), 11 | { 12 | Sys.unsetenv("JAVA_HOME") 13 | expect_equal(java_get_home(), "") 14 | } 15 | ) 16 | }) 17 | -------------------------------------------------------------------------------- /man/global_quiet_param.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/global_params.R 3 | \name{global_quiet_param} 4 | \alias{global_quiet_param} 5 | \title{Global Quiet Parameter} 6 | \usage{ 7 | global_quiet_param(quiet) 8 | } 9 | \arguments{ 10 | \item{quiet}{A \code{logical} value indicating whether to suppress messages. Can be \code{TRUE} or \code{FALSE}.} 11 | } 12 | \description{ 13 | Documentation for the \code{quiet} parameter, used globally. 14 | } 15 | \keyword{internal} 16 | -------------------------------------------------------------------------------- /man/java_version_check_rscript.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/internal_utilities.R 3 | \name{java_version_check_rscript} 4 | \alias{java_version_check_rscript} 5 | \title{Check Java version using rJava} 6 | \usage{ 7 | java_version_check_rscript(java_home) 8 | } 9 | \arguments{ 10 | \item{java_home}{} 11 | } 12 | \value{ 13 | A message with the Java version or an error message. 14 | } 15 | \description{ 16 | Check Java version using rJava 17 | } 18 | \keyword{internal} 19 | -------------------------------------------------------------------------------- /man/java_env_set_session.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/java_env.R 3 | \name{java_env_set_session} 4 | \alias{java_env_set_session} 5 | \title{Set the JAVA_HOME and PATH environment variables for the current session} 6 | \usage{ 7 | java_env_set_session(java_home) 8 | } 9 | \arguments{ 10 | \item{java_home}{The path to the desired JAVA_HOME.} 11 | } 12 | \description{ 13 | Set the JAVA_HOME and PATH environment variables for the current session 14 | } 15 | \keyword{internal} 16 | -------------------------------------------------------------------------------- /rJavaEnv.Rproj: -------------------------------------------------------------------------------- 1 | Version: 1.0 2 | 3 | RestoreWorkspace: No 4 | SaveWorkspace: No 5 | AlwaysSaveHistory: Default 6 | 7 | EnableCodeIndexing: Yes 8 | UseSpacesForTab: Yes 9 | NumSpacesForTab: 2 10 | Encoding: UTF-8 11 | 12 | RnwWeave: Sweave 13 | LaTeX: pdfLaTeX 14 | 15 | AutoAppendNewline: Yes 16 | StripTrailingWhitespace: Yes 17 | LineEndingConversion: Posix 18 | 19 | BuildType: Package 20 | PackageUseDevtools: Yes 21 | PackageInstallArgs: --no-multiarch --with-keep.source 22 | PackageRoxygenize: rd,collate,namespace,vignette 23 | -------------------------------------------------------------------------------- /pkgdown/favicon/site.webmanifest: -------------------------------------------------------------------------------- 1 | { 2 | "name": "", 3 | "short_name": "", 4 | "icons": [ 5 | { 6 | "src": "/web-app-manifest-192x192.png", 7 | "sizes": "192x192", 8 | "type": "image/png", 9 | "purpose": "maskable" 10 | }, 11 | { 12 | "src": "/web-app-manifest-512x512.png", 13 | "sizes": "512x512", 14 | "type": "image/png", 15 | "purpose": "maskable" 16 | } 17 | ], 18 | "theme_color": "#ffffff", 19 | "background_color": "#ffffff", 20 | "display": "standalone" 21 | } -------------------------------------------------------------------------------- /man/rje_envvar_exists.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/consent.R 3 | \name{rje_envvar_exists} 4 | \alias{rje_envvar_exists} 5 | \title{Helper for clean env var check} 6 | \usage{ 7 | rje_envvar_exists(key) 8 | } 9 | \arguments{ 10 | \item{key}{The environment variable key to check.} 11 | } 12 | \description{ 13 | #' The function is based on the code of the \code{renv} package. 14 | Copyright 2023 Posit Software, PBC 15 | License: https://github.com/rstudio/renv/blob/main/LICENSE 16 | } 17 | \keyword{internal} 18 | -------------------------------------------------------------------------------- /tools/meta-data-update-and-submission.R: -------------------------------------------------------------------------------- 1 | # before release 2 | # usethis::use_version("patch") 3 | # devtools::spell_check() 4 | usethis::use_tidy_description() 5 | cffr::cff_write() 6 | codemetar::write_codemeta(write_minimeta = T) 7 | # urlchecker::url_check() 8 | # devtools::check(remote = TRUE, manual = TRUE) 9 | # devtools::check_win_devel() 10 | # revdepcheck::revdep_check(num_workers = 4) 11 | # devtools::submit_cran() 12 | 13 | # usethis::use_github_release() 14 | # usethis::use_dev_version(push = TRUE) 15 | # rdocdump::rdd_to_txt(".", file = "private/rJavaEnv.txt") 16 | -------------------------------------------------------------------------------- /inst/CITATION: -------------------------------------------------------------------------------- 1 | bibentry( 2 | key = "rjavaenv", 3 | bibtype = "Manual", 4 | title = "rJavaEnv: Java Environments for R Projects", 5 | author = c( 6 | person("Egor", "Kotov", , "kotov.egor@gmail.com", role = c("aut", "cre", "cph"), 7 | comment = c(ORCID = "0000-0001-6690-5345")), 8 | person("Chung-hong", "Chan", , "chainsawtiney@gmail.com", role = "aut", 9 | comment = c(ORCID = "0000-0002-6232-7530")) 10 | ), 11 | year = "2024", 12 | url = "https://github.com/e-kotov/rJavaEnv", 13 | doi = "10.32614/CRAN.package.rJavaEnv" 14 | ) 15 | -------------------------------------------------------------------------------- /man/platform_detect.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/internal_utilities.R 3 | \name{platform_detect} 4 | \alias{platform_detect} 5 | \title{Detect platform and architecture} 6 | \usage{ 7 | platform_detect(quiet = TRUE) 8 | } 9 | \arguments{ 10 | \item{quiet}{A \code{logical} value indicating whether to suppress messages. Can be \code{TRUE} or \code{FALSE}.} 11 | } 12 | \value{ 13 | A list of length 2 with the detected platform and architecture. 14 | } 15 | \description{ 16 | Detect platform and architecture 17 | } 18 | \keyword{internal} 19 | -------------------------------------------------------------------------------- /NAMESPACE: -------------------------------------------------------------------------------- 1 | # Generated by roxygen2: do not edit by hand 2 | 3 | export(java_build_env_set) 4 | export(java_build_env_unset) 5 | export(java_check_version_cmd) 6 | export(java_check_version_rjava) 7 | export(java_clear) 8 | export(java_download) 9 | export(java_env_set) 10 | export(java_env_unset) 11 | export(java_get_home) 12 | export(java_install) 13 | export(java_list) 14 | export(java_quick_install) 15 | export(java_unpack) 16 | export(java_valid_versions) 17 | export(rje_consent) 18 | export(use_java) 19 | import(rlang) 20 | importFrom(utils,getFromNamespace) 21 | importFrom(utils,installed.packages) 22 | -------------------------------------------------------------------------------- /man/java_build_env_set_rprofile.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/java_build_env.R 3 | \name{java_build_env_set_rprofile} 4 | \alias{java_build_env_set_rprofile} 5 | \title{Helper function to write build environment settings to .Rprofile} 6 | \usage{ 7 | java_build_env_set_rprofile(java_home, project_path) 8 | } 9 | \arguments{ 10 | \item{java_home}{The path to the desired \code{JAVA_HOME}.} 11 | 12 | \item{project_path}{The path to the project directory.} 13 | } 14 | \description{ 15 | Helper function to write build environment settings to .Rprofile 16 | } 17 | \keyword{internal} 18 | -------------------------------------------------------------------------------- /.Rbuildignore: -------------------------------------------------------------------------------- 1 | ^rJavaEnv\.Rproj$ 2 | ^\.Rproj\.user$ 3 | ^LICENSE\.md$ 4 | ^README\.Rmd$ 5 | ^README\.qmd$ 6 | ^cran-comments\.md$ 7 | ^_pkgdown\.yml$ 8 | ^docs$ 9 | ^pkgdown$ 10 | ^\.github$ 11 | ^\.Rprofile$ 12 | ^rjavaenv$ 13 | ^private$ 14 | ^codemeta\.json$ 15 | ^CITATION\.cff$ 16 | ^doc$ 17 | ^Meta$ 18 | ^CODE_OF_CONDUCT\.md$ 19 | ^vignettes/why-rJavaEnv\.qmd$ 20 | ^vignettes/data-for-vignettes$ 21 | ^vignettes/bibliography.bib$ 22 | ^vignettes/media$ 23 | ^CRAN-SUBMISSION$ 24 | ^vignettes/.quarto$ 25 | ^revdep$ 26 | ^man/figures/card.png$ 27 | ^tools$ 28 | ^\.editorconfig$ 29 | ^revdep$ 30 | ^\.cache$ 31 | ^\.config$ 32 | ^\.local$ 33 | ^\.jupyter$ 34 | -------------------------------------------------------------------------------- /man/set_java_build_env_vars.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/java_build_env.R 3 | \name{set_java_build_env_vars} 4 | \alias{set_java_build_env_vars} 5 | \title{Helper function to set Java build environment variables} 6 | \usage{ 7 | set_java_build_env_vars(java_home, quiet = FALSE) 8 | } 9 | \arguments{ 10 | \item{java_home}{The path to the desired \code{JAVA_HOME}.} 11 | 12 | \item{quiet}{A \code{logical} value indicating whether to suppress messages. Can be \code{TRUE} or \code{FALSE}.} 13 | } 14 | \description{ 15 | Helper function to set Java build environment variables 16 | } 17 | \keyword{internal} 18 | -------------------------------------------------------------------------------- /man/rje_consent_check.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/consent.R 3 | \name{rje_consent_check} 4 | \alias{rje_consent_check} 5 | \title{Verify User Consent for rJavaEnv} 6 | \usage{ 7 | rje_consent_check() 8 | } 9 | \value{ 10 | \code{TRUE} if consent is verified, otherwise an error is raised. 11 | } 12 | \description{ 13 | Ensure that the user has granted permission for rJavaEnv to manage files on their file system. 14 | } 15 | \details{ 16 | The function is based on the code of the \code{renv} package. 17 | Copyright 2023 Posit Software, PBC 18 | License: https://github.com/rstudio/renv/blob/main/LICENSE 19 | } 20 | \keyword{internal} 21 | -------------------------------------------------------------------------------- /man/java_env_set_rprofile.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/java_env.R 3 | \name{java_env_set_rprofile} 4 | \alias{java_env_set_rprofile} 5 | \title{Update the .Rprofile file in the project directory} 6 | \usage{ 7 | java_env_set_rprofile(java_home, project_path = NULL) 8 | } 9 | \arguments{ 10 | \item{java_home}{The path to the desired JAVA_HOME.} 11 | 12 | \item{project_path}{A \code{character} vector of length 1 containing the project directory where Java should be installed. If not specified or \code{NULL}, defaults to the current working directory.} 13 | } 14 | \description{ 15 | Update the .Rprofile file in the project directory 16 | } 17 | \keyword{internal} 18 | -------------------------------------------------------------------------------- /man/java_check_version_system.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/java_env.R 3 | \name{java_check_version_system} 4 | \alias{java_check_version_system} 5 | \title{Check and print Java path and version using system commands} 6 | \usage{ 7 | java_check_version_system(quiet) 8 | } 9 | \arguments{ 10 | \item{quiet}{A \code{logical} value indicating whether to suppress messages. Can be \code{TRUE} or \code{FALSE}.} 11 | } 12 | \value{ 13 | A \code{character} vector of length 1 containing the major Java version. 14 | } 15 | \description{ 16 | This function checks the Java executable path and retrieves the Java version, 17 | then prints these details to the console. 18 | } 19 | \keyword{internal} 20 | -------------------------------------------------------------------------------- /tests/testthat/test-java_unpack.R: -------------------------------------------------------------------------------- 1 | test_that("bad java_distrib_path", { 2 | bad_path <- tempfile() 3 | expect_error(java_unpack(bad_path)) 4 | 5 | bad_path <- "/home/johndoe/.cache/R/rJavaEnv/distrib/amazon-corretto-21-x64-linux-jdk.tar.7z" 6 | expect_error(java_unpack(bad_path), "Unsupported file format") 7 | 8 | bad_path <- "/home/johndoe/.cache/R/rJavaEnv/distrib/amazon-corretto-x64-linux-jdk.tar.zip" 9 | expect_error(java_unpack(bad_path), "Java version") 10 | 11 | bad_path <- "/home/johndoe/.cache/R/rJavaEnv/distrib/amazon-corretto-21-linux-jdk.tar.zip" 12 | expect_error(java_unpack(bad_path), "architecture") 13 | 14 | bad_path <- "/home/johndoe/.cache/R/rJavaEnv/distrib/amazon-corretto-21-x64-msdos-jdk.tar.zip" 15 | expect_error(java_unpack(bad_path), "platform") 16 | 17 | }) 18 | -------------------------------------------------------------------------------- /man/java_check_version_cmd.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/java_env.R 3 | \name{java_check_version_cmd} 4 | \alias{java_check_version_cmd} 5 | \title{Check installed Java version using terminal commands} 6 | \usage{ 7 | java_check_version_cmd(java_home = NULL, quiet = FALSE) 8 | } 9 | \arguments{ 10 | \item{java_home}{Path to Java home directory. If NULL, the function uses the JAVA_HOME environment variable.} 11 | 12 | \item{quiet}{A \code{logical} value indicating whether to suppress messages. Can be \code{TRUE} or \code{FALSE}.} 13 | } 14 | \value{ 15 | A \code{character} vector of length 1 containing the major Java version. 16 | } 17 | \description{ 18 | Check installed Java version using terminal commands 19 | } 20 | \examples{ 21 | java_check_version_cmd() 22 | 23 | } 24 | -------------------------------------------------------------------------------- /.github/workflows/pkgcheck.yaml: -------------------------------------------------------------------------------- 1 | name: pkgcheck 2 | 3 | # This will cancel running jobs once a new run is triggered 4 | concurrency: 5 | group: ${{ github.workflow }}-${{ github.head_ref }} 6 | cancel-in-progress: true 7 | 8 | on: 9 | # Manually trigger the Action under Actions/pkgcheck 10 | workflow_dispatch: 11 | # Run on every push to main 12 | push: 13 | branches: 14 | - main 15 | pull_request: 16 | branches: 17 | - main 18 | 19 | jobs: 20 | pkgcheck: 21 | runs-on: ubuntu-latest 22 | env: 23 | GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} 24 | RUN_JAVA_DOWNLOAD_TESTS: "TRUE" 25 | RUN_JAVA_DOWNLOAD_TESTS_QUIET: "FALSE" 26 | RUN_JAVA_DOWNLOAD_TESTS_QUIET_DOWNLOAD: "TRUE" 27 | permissions: 28 | issues: write 29 | steps: 30 | - uses: ropensci-review-tools/pkgcheck-action@main 31 | -------------------------------------------------------------------------------- /man/java_clear_in_project.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/java_manage_project.R 3 | \name{java_clear_in_project} 4 | \alias{java_clear_in_project} 5 | \title{Clear the Java versions symlinked in the current project} 6 | \usage{ 7 | java_clear_in_project(project_path = NULL, check = TRUE, delete_all = FALSE) 8 | } 9 | \arguments{ 10 | \item{project_path}{The project directory to clear. Defaults to the current working directory.} 11 | 12 | \item{check}{Whether to list the symlinked Java versions before clearing them. Defaults to TRUE.} 13 | 14 | \item{delete_all}{Whether to delete all symlinks without prompting. Defaults to FALSE.} 15 | } 16 | \value{ 17 | A message indicating whether the symlinks were cleared or not. 18 | } 19 | \description{ 20 | Clear the Java versions symlinked in the current project 21 | } 22 | \keyword{internal} 23 | -------------------------------------------------------------------------------- /man/java_clear_distrib_cache.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/java_manage_distrib_cache.R 3 | \name{java_clear_distrib_cache} 4 | \alias{java_clear_distrib_cache} 5 | \title{Clear the Java distributions cache folder} 6 | \usage{ 7 | java_clear_distrib_cache( 8 | cache_path = getOption("rJavaEnv.cache_path"), 9 | check = TRUE, 10 | delete_all = FALSE 11 | ) 12 | } 13 | \arguments{ 14 | \item{cache_path}{The cache directory to clear. Defaults to the user-specific data directory.} 15 | 16 | \item{check}{Whether to list the contents of the cache directory before clearing it. Defaults to TRUE.} 17 | 18 | \item{delete_all}{Whether to delete all items without prompting. Defaults to FALSE.} 19 | } 20 | \value{ 21 | A message indicating whether the cache was cleared or not. 22 | } 23 | \description{ 24 | Clear the Java distributions cache folder 25 | } 26 | \keyword{internal} 27 | -------------------------------------------------------------------------------- /tests/testthat/test-onLoad.R: -------------------------------------------------------------------------------- 1 | test_that(".onLoad sets default options", { 2 | # Save original options to restore later 3 | op <- options() 4 | on.exit(options(op)) 5 | 6 | # Clear specific options to test if they get set 7 | options( 8 | rJavaEnv.fallback_valid_versions_current_platform = NULL, 9 | rJavaEnv.valid_versions_cache = NULL 10 | ) 11 | 12 | # Manually trigger .onLoad 13 | rJavaEnv:::.onLoad("rJavaEnv", "rJavaEnv") 14 | 15 | # Check if the platform fallback was set 16 | fallback <- getOption("rJavaEnv.fallback_valid_versions_current_platform") 17 | expect_false(is.null(fallback)) 18 | expect_true(length(fallback) > 0) 19 | 20 | # Check if valid_versions_cache was initialized (it's set to NULL, which removes it) 21 | # We just verify that .onLoad ran without error and set the other options correctly 22 | expect_true(is.null(getOption("rJavaEnv.valid_versions_cache"))) 23 | }) 24 | -------------------------------------------------------------------------------- /man/java_clear_installed_cache.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/java_manage_installed_cache.R 3 | \name{java_clear_installed_cache} 4 | \alias{java_clear_installed_cache} 5 | \title{Clear the Java installations cache folder} 6 | \usage{ 7 | java_clear_installed_cache( 8 | check = TRUE, 9 | delete_all = FALSE, 10 | cache_path = getOption("rJavaEnv.cache_path") 11 | ) 12 | } 13 | \arguments{ 14 | \item{check}{Whether to list the contents of the cache directory before clearing it. Defaults to TRUE.} 15 | 16 | \item{delete_all}{Whether to delete all installations without prompting. Defaults to FALSE.} 17 | 18 | \item{cache_path}{The cache directory to clear. Defaults to the user-specific data directory.} 19 | } 20 | \value{ 21 | A message indicating whether the cache was cleared or not. 22 | } 23 | \description{ 24 | Clear the Java installations cache folder 25 | } 26 | \keyword{internal} 27 | -------------------------------------------------------------------------------- /cran-comments.md: -------------------------------------------------------------------------------- 1 | # rJavaEnv 0.3.0 (2025-04-04) 2 | 3 | 4 | ## New features 5 | 6 | - `Java` version (currently still only for `Amazon Corretto`) is now determined dynamically using the official GitHub `json` with releases, so when new `Java` version becomes available, you will not be depenent on `rJavaEnv` to be updated. As a fallback, versions up to 24 are hardcoded. 7 | 8 | - Added `force` argument to `java_download()`. When set to `TRUE`, allows to overwrite the distribution file if it already exist in the cache. This save the trouble of deleting the cached file with `java_clear()` before re-downloading. 9 | 10 | - Added a new function `java_valid_versions()` allows to retrieve a list of all available `Java` versions for the current automatically detected OS and CPU architecture, or user-specified platform and architecture. 11 | 12 | ## Improvements 13 | 14 | - Better command line `Java` detection (thanks to Jonas Lieth) 15 | 16 | - Test coverage is now 7.2% 17 | -------------------------------------------------------------------------------- /man/java_list_in_project.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/java_manage_project.R 3 | \name{java_list_in_project} 4 | \alias{java_list_in_project} 5 | \title{List the Java versions symlinked in the current project} 6 | \usage{ 7 | java_list_in_project( 8 | project_path = NULL, 9 | output = c("data.frame", "vector"), 10 | quiet = TRUE 11 | ) 12 | } 13 | \arguments{ 14 | \item{project_path}{The project directory to list. Defaults to the current working directory.} 15 | 16 | \item{output}{The format of the output: "data.frame" or "vector". Defaults to "data.frame".} 17 | 18 | \item{quiet}{A \code{logical} value indicating whether to suppress messages. Can be \code{TRUE} or \code{FALSE}.} 19 | } 20 | \value{ 21 | A data frame or character vector with the symlinked Java versions in the project directory. 22 | } 23 | \description{ 24 | List the Java versions symlinked in the current project 25 | } 26 | \keyword{internal} 27 | -------------------------------------------------------------------------------- /man/java_build_env_unset.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/java_build_env.R 3 | \name{java_build_env_unset} 4 | \alias{java_build_env_unset} 5 | \title{Unset the Java build environment variables in the project .Rprofile} 6 | \usage{ 7 | java_build_env_unset(project_path = NULL, quiet = FALSE) 8 | } 9 | \arguments{ 10 | \item{project_path}{A \code{character} vector of length 1 containing the project directory where Java should be installed. If not specified or \code{NULL}, defaults to the current working directory.} 11 | 12 | \item{quiet}{A \code{logical} value indicating whether to suppress messages. Can be \code{TRUE} or \code{FALSE}.} 13 | } 14 | \value{ 15 | Does not return a value. Invisibly returns \code{NULL}. 16 | } 17 | \description{ 18 | Unset the Java build environment variables in the project .Rprofile 19 | } 20 | \examples{ 21 | \dontrun{ 22 | # Remove Java build environment settings from the current project 23 | java_build_env_unset() 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /man/java_list_distrib_cache.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/java_manage_distrib_cache.R 3 | \name{java_list_distrib_cache} 4 | \alias{java_list_distrib_cache} 5 | \title{List the contents of the Java distributions cache folder} 6 | \usage{ 7 | java_list_distrib_cache( 8 | cache_path = getOption("rJavaEnv.cache_path"), 9 | output = c("data.frame", "vector"), 10 | quiet = TRUE 11 | ) 12 | } 13 | \arguments{ 14 | \item{cache_path}{The destination directory to download the Java distribution to. Defaults to a user-specific data directory.} 15 | 16 | \item{output}{The format of the output: "data.frame" or "vector". Defaults to "data.frame".} 17 | 18 | \item{quiet}{A \code{logical} value indicating whether to suppress messages. Can be \code{TRUE} or \code{FALSE}.} 19 | } 20 | \value{ 21 | A character vector with the contents of the cache directory. 22 | } 23 | \description{ 24 | List the contents of the Java distributions cache folder 25 | } 26 | \keyword{internal} 27 | -------------------------------------------------------------------------------- /man/java_list_installed_cache.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/java_manage_installed_cache.R 3 | \name{java_list_installed_cache} 4 | \alias{java_list_installed_cache} 5 | \title{List the contents of the Java installations cache folder} 6 | \usage{ 7 | java_list_installed_cache( 8 | output = c("data.frame", "vector"), 9 | quiet = TRUE, 10 | cache_path = getOption("rJavaEnv.cache_path") 11 | ) 12 | } 13 | \arguments{ 14 | \item{output}{The format of the output: "data.frame" or "vector". Defaults to "data.frame".} 15 | 16 | \item{quiet}{A \code{logical} value indicating whether to suppress messages. Can be \code{TRUE} or \code{FALSE}.} 17 | 18 | \item{cache_path}{The cache directory to list. Defaults to the user-specific data directory. Not recommended to change.} 19 | } 20 | \value{ 21 | A data frame or character vector with the contents of the cache directory. 22 | } 23 | \description{ 24 | List the contents of the Java installations cache folder 25 | } 26 | \keyword{internal} 27 | -------------------------------------------------------------------------------- /man/java_env_unset.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/java_env.R 3 | \name{java_env_unset} 4 | \alias{java_env_unset} 5 | \title{Unset the JAVA_HOME and PATH environment variables in the project .Rprofile} 6 | \usage{ 7 | java_env_unset(project_path = NULL, quiet = FALSE) 8 | } 9 | \arguments{ 10 | \item{project_path}{A \code{character} vector of length 1 containing the project directory where Java should be installed. If not specified or \code{NULL}, defaults to the current working directory.} 11 | 12 | \item{quiet}{A \code{logical} value indicating whether to suppress messages. Can be \code{TRUE} or \code{FALSE}.} 13 | } 14 | \value{ 15 | Nothing. Removes the JAVA_HOME and PATH environment variables settings from the project .Rprofile. 16 | } 17 | \description{ 18 | Unset the JAVA_HOME and PATH environment variables in the project .Rprofile 19 | } 20 | \examples{ 21 | \dontrun{ 22 | # clear the JAVA_HOME and PATH environment variables in the specified project .Rprofile 23 | java_env_unset(project_path = tempdir()) 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | # MIT License 2 | 3 | Copyright (c) 2024 rJavaEnv authors 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /man/java_check_version_rjava.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/java_env.R 3 | \name{java_check_version_rjava} 4 | \alias{java_check_version_rjava} 5 | \title{Check Java Version with a Specified JAVA_HOME Using a Separate R Session} 6 | \usage{ 7 | java_check_version_rjava(java_home = NULL, quiet = FALSE) 8 | } 9 | \arguments{ 10 | \item{java_home}{Path to Java home directory. If NULL, the function uses the JAVA_HOME environment variable.} 11 | 12 | \item{quiet}{A \code{logical} value indicating whether to suppress messages. Can be \code{TRUE} or \code{FALSE}.} 13 | } 14 | \value{ 15 | A \code{character} vector of length 1 containing the major Java version. 16 | } 17 | \description{ 18 | This function sets the JAVA_HOME environment variable, initializes the JVM using rJava, and prints the Java version that would be used if the user sets the given JAVA_HOME in the current R session. This check is performed in a separate R session to avoid having to reload the current R session. The reason for this is that once Java is initialized in an R session, it cannot be uninitialized unless the current R session is restarted. 19 | } 20 | \examples{ 21 | \dontrun{ 22 | java_check_version_rjava() 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /vignettes/data-for-vignettes/get-data-for-vignettes.R: -------------------------------------------------------------------------------- 1 | if (!requireNamespace("pacman", quietly = TRUE)) { 2 | install.packages("pacman") 3 | } 4 | package_list <- c("devtools", "dlstats", "tidyverse") 5 | pacman::p_load(char = package_list) 6 | rm(package_list) 7 | 8 | 9 | dlstats::set_cran_start_year(2014) 10 | 11 | rJava_dependants <- devtools::revdep("rJava", dependencies = c("Imports", "Depends"), bioconductor = TRUE) 12 | 13 | rJava_dlstats <- dlstats::cran_stats("rJava", use_cache = FALSE) 14 | rJava_dependants_dlstats_cran <- dlstats::cran_stats(rJava_dependants, use_cache = FALSE) 15 | rJava_dependants_dlstats_bioc <- dlstats::bioc_stats(rJava_dependants, use_cache = FALSE, type = "Software") 16 | data_table_dlstats <- dlstats::cran_stats("data.table", use_cache = FALSE) 17 | ggplot2_dlstats <- dlstats::cran_stats("ggplot2", use_cache = FALSE) 18 | 19 | 20 | 21 | write_csv2(rJava_dlstats, "vignettes/data-for-vignettes/rJava_dlstats.csv") 22 | write_csv2(rJava_dependants_dlstats_cran, "vignettes/data-for-vignettes/rJava_dependants_dlstats_cran.csv") 23 | write_csv2(rJava_dependants_dlstats_bioc, "vignettes/data-for-vignettes/rJava_dependants_dlstats_bioc.csv") 24 | write_csv2(data_table_dlstats, "vignettes/data-for-vignettes/data_table_dlstats.csv") 25 | write_csv2(ggplot2_dlstats, "vignettes/data-for-vignettes/ggplot2_dlstats.csv") 26 | -------------------------------------------------------------------------------- /.github/workflows/R-CMD-check-HTML5.yaml: -------------------------------------------------------------------------------- 1 | # Workflow derived from https://github.com/r-lib/actions/tree/v2/examples 2 | # Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help 3 | on: 4 | push: 5 | branches: [main, master] 6 | pull_request: 7 | branches: [main, master] 8 | 9 | name: R-CMD-check-HTML5 10 | 11 | jobs: 12 | R-CMD-check: 13 | runs-on: ubuntu-latest 14 | env: 15 | GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} 16 | R_KEEP_PKG_SOURCE: yes 17 | _R_CHECK_RD_VALIDATE_RD2HTML_: TRUE 18 | steps: 19 | - uses: actions/checkout@v2 20 | 21 | - name: Install pdflatex 22 | run: sudo apt-get install texlive-latex-base texlive-fonts-recommended texlive-fonts-extra texlive-latex-extra 23 | 24 | - name: Install tidy 25 | run: sudo apt install tidy 26 | 27 | - uses: r-lib/actions/setup-r@v2 28 | with: 29 | r-version: 'devel' 30 | http-user-agent: 'release' 31 | use-public-rspm: true 32 | 33 | - uses: r-lib/actions/setup-r-dependencies@v2 34 | with: 35 | extra-packages: any::rcmdcheck 36 | needs: check 37 | 38 | - uses: r-lib/actions/check-r-package@v2 39 | with: 40 | args: '"--as-cran"' 41 | build_args: 'character()' 42 | error-on: '"note"' 43 | -------------------------------------------------------------------------------- /man/java_clear.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/java_manage.R 3 | \name{java_clear} 4 | \alias{java_clear} 5 | \title{Manage Java installations and distributions caches} 6 | \usage{ 7 | java_clear( 8 | type = c("project", "installed", "distrib"), 9 | target_dir = NULL, 10 | check = TRUE, 11 | delete_all = FALSE 12 | ) 13 | } 14 | \arguments{ 15 | \item{type}{What to clear: "project" - remove symlinks to install cache in the current project, "installed" - remove installed Java versions, "distrib" - remove downloaded Java distributions.} 16 | 17 | \item{target_dir}{The directory to clear. Defaults to current working directory for "project" and user-specific data directory for "installed" and "distrib". Not recommended to change.} 18 | 19 | \item{check}{Whether to list the contents of the cache directory before clearing it. Defaults to TRUE.} 20 | 21 | \item{delete_all}{Whether to delete all items without prompting. Defaults to FALSE.} 22 | } 23 | \value{ 24 | A message indicating whether the cache was cleared or not. 25 | } 26 | \description{ 27 | Wrapper function to clear the Java symlinked in the current project, installed, or distributions caches. 28 | } 29 | \examples{ 30 | \dontrun{ 31 | java_clear("project", target_dir = tempdir()) 32 | java_clear("installed", target_dir = tempdir()) 33 | java_clear("distrib", target_dir = tempdir()) 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /man/java_valid_major_versions_corretto.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/java_valid_versions.R 3 | \name{java_valid_major_versions_corretto} 4 | \alias{java_valid_major_versions_corretto} 5 | \title{Get Available Online Versions of Amazon Corretto} 6 | \usage{ 7 | java_valid_major_versions_corretto( 8 | arch = NULL, 9 | platform = NULL, 10 | imageType = "jdk" 11 | ) 12 | } 13 | \arguments{ 14 | \item{arch}{Optional character string for the target architecture (e.g., "x64"). 15 | If \code{NULL}, it is inferred using \code{platform_detect()}.} 16 | 17 | \item{platform}{Optional character string for the operating system (e.g., "windows", "macos", "linux"). 18 | If \code{NULL}, it is inferred using \code{platform_detect()}.} 19 | 20 | \item{imageType}{Optional character string to filter on; defaults to \code{"jdk"}. Can be set to \code{"jre"} for Windows Java Runtime Environment.} 21 | } 22 | \value{ 23 | A \code{character} vector of available major Corretto versions. 24 | } 25 | \description{ 26 | This function downloads the latest Amazon Corretto version information from the 27 | Corretto GitHub endpoint and returns a data frame with details for all eligible releases. 28 | } 29 | \details{ 30 | It leverages the existing \code{platform_detect()} function to infer the current operating 31 | system and architecture if these are not provided. 32 | } 33 | \keyword{internal} 34 | -------------------------------------------------------------------------------- /inst/extdata/java_urls.json: -------------------------------------------------------------------------------- 1 | { 2 | "Corretto": { 3 | "windows": { 4 | "x64": "https://corretto.aws/downloads/latest/amazon-corretto-{version}-x64-windows-jdk.zip" 5 | }, 6 | "linux": { 7 | "x64": "https://corretto.aws/downloads/latest/amazon-corretto-{version}-x64-linux-jdk.tar.gz", 8 | "aarch64": "https://corretto.aws/downloads/latest/amazon-corretto-{version}-aarch64-linux-jdk.tar.gz" 9 | }, 10 | "macos": { 11 | "x64": "https://corretto.aws/downloads/latest/amazon-corretto-{version}-x64-macos-jdk.tar.gz", 12 | "aarch64": "https://corretto.aws/downloads/latest/amazon-corretto-{version}-aarch64-macos-jdk.tar.gz" 13 | }, 14 | "alpine-linux": { 15 | "x64": "https://corretto.aws/downloads/latest/amazon-corretto-{version}-x64-alpine-jdk.tar.gz", 16 | "aarch64": "https://corretto.aws/downloads/latest/amazon-corretto-{version}-aarch64-alpine-jdk.tar.gz" 17 | }, 18 | "amazon-linux": { 19 | "x64": "https://corretto.aws/downloads/latest/amazon-corretto-{version}-x64-al2-jdk.rpm", 20 | "aarch64": "https://corretto.aws/downloads/latest/amazon-corretto-{version}-aarch64-al2-jdk.rpm" 21 | }, 22 | "amazon-linux-2023": { 23 | "x64": "https://corretto.aws/downloads/latest/amazon-corretto-{version}-x64-al2023-jdk.rpm", 24 | "aarch64": "https://corretto.aws/downloads/latest/amazon-corretto-{version}-aarch64-al2023-jdk.rpm" 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /man/java_unpack.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/java_unpack.R 3 | \name{java_unpack} 4 | \alias{java_unpack} 5 | \title{Unpack a Java distribution file into cache directory} 6 | \usage{ 7 | java_unpack(java_distrib_path, quiet = FALSE, force = FALSE) 8 | } 9 | \arguments{ 10 | \item{java_distrib_path}{A \code{character} vector of length 1 containing the path to the Java distribution file.} 11 | 12 | \item{quiet}{A \code{logical} value indicating whether to suppress messages. Can be \code{TRUE} or \code{FALSE}.} 13 | 14 | \item{force}{A logical. Whether to overwrite an existing installation. Defaults to \code{FALSE}.} 15 | } 16 | \value{ 17 | A \code{character} vector containing of length 1 containing the path to the unpacked Java directory. 18 | } 19 | \description{ 20 | Unpack the Java distribution file into cache directory and return the path to the unpacked Java directory with Java binaries. 21 | } 22 | \examples{ 23 | \dontrun{ 24 | 25 | # set cache dir to temporary directory 26 | options(rJavaEnv.cache_path = tempdir()) 27 | 28 | # download Java 17 distrib and unpack it into cache dir 29 | java_17_distrib <- java_download(version = "17") 30 | java_home <- java_unpack(java_distrib_path = java_17_distrib) 31 | 32 | # set the JAVA_HOME environment variable in the current session 33 | # to the cache dir without touching any files in the current project directory 34 | java_env_set(where = "session", java_home = java_home) 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /tests/testthat/test-internal_utilities_extra.R: -------------------------------------------------------------------------------- 1 | test_that("java_urls_load loads JSON correctly", { 2 | # Real test of the JSON file included in the package 3 | urls <- rJavaEnv:::java_urls_load() 4 | expect_type(urls, "list") 5 | expect_true("Corretto" %in% names(urls)) 6 | }) 7 | 8 | test_that("urls_test_all checks URLs without network", { 9 | # Mock internal loader to return small subset 10 | local_mocked_bindings( 11 | java_urls_load = function() list( 12 | TestDist = list( 13 | linux = list(x64 = "http://example.com/jdk-{version}.tar.gz") 14 | ) 15 | ), 16 | .package = "rJavaEnv" 17 | ) 18 | 19 | # Mock curl to avoid network 20 | local_mocked_bindings( 21 | curl_fetch_memory = function(...) list(status_code = 200), 22 | .package = "curl" 23 | ) 24 | 25 | res <- rJavaEnv:::urls_test_all() 26 | expect_type(res, "list") 27 | expect_equal(res[["TestDist-linux-x64"]]$status, 200) 28 | }) 29 | 30 | test_that("java_version_check_rscript function exists", { 31 | # We cannot safely test this function without loading rJava, which crashes when 32 | # Java is not configured. Testing the error path is also unsafe because mocking 33 | # base functions like Sys.setenv or list.files interferes with testthat's own operations. 34 | # Instead, we just verify the function exists and has correct structure. 35 | 36 | expect_true(exists("java_version_check_rscript", where = asNamespace("rJavaEnv"))) 37 | expect_type(rJavaEnv:::java_version_check_rscript, "closure") 38 | }) 39 | -------------------------------------------------------------------------------- /tests/testthat/test-java_env_linux.R: -------------------------------------------------------------------------------- 1 | test_that("java_env_set_session function exists and handles basic cases", { 2 | # Mocking base functions like file.exists or list.files interferes with R's package 3 | # loading system and testthat's operations. Instead, we test the non-Linux path which 4 | # doesn't require complex mocks. 5 | 6 | # Mock installed.packages to avoid rJava checks 7 | local_mocked_bindings( 8 | installed.packages = function(...) matrix(character(0), nrow=0, ncol=2), 9 | .package = "utils" 10 | ) 11 | 12 | # On non-Linux platforms, the function just sets environment variables 13 | # This should work without triggering libjvm.so loading 14 | skip_on_os("linux") # Skip on actual Linux to avoid system-specific issues 15 | 16 | expect_no_error( 17 | rJavaEnv:::java_env_set_session(java_home = "/mock/java") 18 | ) 19 | }) 20 | 21 | test_that("java_env_set_session warns if rJava is already loaded", { 22 | # Mock installed.packages to say rJava is installed 23 | local_mocked_bindings( 24 | installed.packages = function() matrix(c("rJava"), dimnames=list(NULL, "Package")), 25 | .package = "utils" 26 | ) 27 | 28 | # Mock loadedNamespaces to say rJava is loaded 29 | local_mocked_bindings( 30 | loadedNamespaces = function() c("base", "rJava"), 31 | .package = "base" 32 | ) 33 | 34 | # Expect the warning message 35 | expect_message( 36 | rJavaEnv:::java_env_set_session(java_home = "/mock/java"), 37 | "You have `rJava` R package loaded" 38 | ) 39 | }) 40 | -------------------------------------------------------------------------------- /.github/workflows/pkgdown.yaml: -------------------------------------------------------------------------------- 1 | # Workflow derived from https://github.com/r-lib/actions/tree/v2/examples 2 | # Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help 3 | on: 4 | push: 5 | branches: [main, master] 6 | pull_request: 7 | branches: [main, master] 8 | release: 9 | types: [published] 10 | workflow_dispatch: 11 | 12 | name: pkgdown 13 | 14 | permissions: read-all 15 | 16 | jobs: 17 | pkgdown: 18 | runs-on: ubuntu-latest 19 | # Only restrict concurrency for non-PR jobs 20 | concurrency: 21 | group: pkgdown-${{ github.event_name != 'pull_request' || github.run_id }} 22 | env: 23 | GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} 24 | permissions: 25 | contents: write 26 | steps: 27 | - uses: actions/checkout@v4 28 | 29 | - uses: r-lib/actions/setup-pandoc@v2 30 | 31 | - uses: r-lib/actions/setup-r@v2 32 | with: 33 | use-public-rspm: true 34 | 35 | - uses: r-lib/actions/setup-r-dependencies@v2 36 | with: 37 | extra-packages: any::pkgdown, any::bookdown, local::. 38 | needs: website 39 | 40 | - name: Build site 41 | run: pkgdown::build_site_github_pages(new_process = FALSE, install = FALSE) 42 | shell: Rscript {0} 43 | 44 | - name: Deploy to GitHub pages 🚀 45 | if: github.event_name != 'pull_request' 46 | uses: JamesIves/github-pages-deploy-action@v4.5.0 47 | with: 48 | clean: false 49 | branch: gh-pages 50 | folder: docs 51 | -------------------------------------------------------------------------------- /man/rje_consent.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/consent.R 3 | \name{rje_consent} 4 | \alias{rje_consent} 5 | \title{Obtain User Consent for rJavaEnv} 6 | \usage{ 7 | rje_consent(provided = FALSE) 8 | } 9 | \arguments{ 10 | \item{provided}{Logical indicating if consent is already provided. 11 | To provide consent in non-interactive \R sessions 12 | use \code{rJavaEnv::rje_consent(provided = TRUE)}. Default is \code{FALSE}.} 13 | } 14 | \value{ 15 | \code{TRUE} if consent is given, otherwise an error is raised. 16 | } 17 | \description{ 18 | Get user consent for rJavaEnv to write and update files on the file system. 19 | rJavaEnv needs permission to manage files in your project and cache directories 20 | to function correctly. 21 | } 22 | \details{ 23 | In line with \href{https://cran.r-project.org/web/packages/policies.html}{CRAN policies}, explicit user consent is required before making these changes. 24 | Please call \code{rJavaEnv::consent()} to provide consent. 25 | 26 | Alternatively, you can set the following \R option 27 | (especially useful for non-interactive R sessions): 28 | 29 | \if{html}{\out{
}}\preformatted{options(rJavaEnv.consent = TRUE) 30 | }\if{html}{\out{
}} 31 | 32 | The function is based on the code of the \code{renv} package. 33 | Copyright 2023 Posit Software, PBC 34 | License: https://github.com/rstudio/renv/blob/main/LICENSE 35 | } 36 | \examples{ 37 | \dontrun{ 38 | 39 | # to provide consent and prevent other functions from interrupting to get the consent 40 | rje_consent(provided = TRUE) 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /.github/workflows/render-README.yaml: -------------------------------------------------------------------------------- 1 | # Workflow derived from https://github.com/r-lib/actions/tree/master/examples 2 | # Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help 3 | on: 4 | push: 5 | paths: ['README.Rmd'] 6 | workflow_dispatch: 7 | paths: ['README.Rmd'] 8 | 9 | 10 | name: Render README 11 | 12 | jobs: 13 | render-rmarkdown: 14 | runs-on: ubuntu-latest 15 | env: 16 | GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} 17 | steps: 18 | - name: Checkout repo 19 | uses: actions/checkout@v3 20 | with: 21 | fetch-depth: 0 22 | 23 | - uses: r-lib/actions/setup-pandoc@v2 24 | 25 | - uses: r-lib/actions/setup-r@v2 26 | 27 | - name: install rmarkdown from PPM 28 | run: Rscript -e 'install.packages("rmarkdown", repos=c("https://packagemanager.rstudio.com/cran/__linux__/jammy/latest"))' 29 | 30 | - name: Install devtools and the target package 31 | run: | 32 | Rscript -e 'install.packages("rJavaEnv", repos=c("https://community.r-multiverse.org", "https://packagemanager.posit.co/cran/__linux__/jammy/latest"))' 33 | 34 | 35 | - name: Render README.Rmd 36 | run: | 37 | Rscript -e 'rmarkdown::render("README.Rmd")' 38 | 39 | - name: Commit results 40 | run: | 41 | git config --local user.name "github-actions[bot]" 42 | git config --local user.email "41898282+github-actions[bot]@users.noreply.github.com" 43 | git add README.md 44 | git commit -m 'Re-build README.Rmd' || echo "No changes to commit" 45 | git push origin || echo "No changes to commit" 46 | -------------------------------------------------------------------------------- /.github/workflows/R-CMD-check.yaml: -------------------------------------------------------------------------------- 1 | # Workflow derived from https://github.com/r-lib/actions/tree/v2/examples 2 | # Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help 3 | on: 4 | push: 5 | branches: [main] 6 | pull_request: 7 | branches: [main] 8 | 9 | name: R-CMD-check 10 | 11 | permissions: read-all 12 | 13 | jobs: 14 | R-CMD-check: 15 | runs-on: ${{ matrix.config.os }} 16 | 17 | name: ${{ matrix.config.os }} (${{ matrix.config.r }}) 18 | 19 | strategy: 20 | fail-fast: false 21 | matrix: 22 | config: 23 | - {os: macos-latest, r: 'release'} 24 | - {os: windows-latest, r: 'release'} 25 | - {os: windows-latest, r: 'oldrel-4'} 26 | - {os: ubuntu-latest, r: 'devel', http-user-agent: 'release'} 27 | - {os: ubuntu-latest, r: 'release'} 28 | - {os: ubuntu-latest, r: 'oldrel-1'} 29 | 30 | env: 31 | GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} 32 | R_KEEP_PKG_SOURCE: yes 33 | 34 | steps: 35 | - uses: actions/checkout@v4 36 | 37 | - uses: r-lib/actions/setup-pandoc@v2 38 | 39 | - uses: r-lib/actions/setup-r@v2 40 | with: 41 | r-version: ${{ matrix.config.r }} 42 | http-user-agent: ${{ matrix.config.http-user-agent }} 43 | use-public-rspm: true 44 | 45 | - uses: r-lib/actions/setup-r-dependencies@v2 46 | with: 47 | extra-packages: any::rcmdcheck 48 | needs: check 49 | 50 | - uses: r-lib/actions/check-r-package@v2 51 | with: 52 | upload-snapshots: true 53 | build_args: 'c("--no-manual","--compact-vignettes=gs+qpdf")' 54 | -------------------------------------------------------------------------------- /man/java_list.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/java_manage.R 3 | \name{java_list} 4 | \alias{java_list} 5 | \title{List the contents of the Java versions installed or cached} 6 | \usage{ 7 | java_list( 8 | type = c("project", "installed", "distrib"), 9 | output = c("data.frame", "vector"), 10 | quiet = TRUE, 11 | target_dir = NULL 12 | ) 13 | } 14 | \arguments{ 15 | \item{type}{The type of cache to list: "distrib", "installed", or "project". Defaults to "project".} 16 | 17 | \item{output}{The format of the output: \verb{data.frame`` or }vector``. Defaults to \code{data.frame}.} 18 | 19 | \item{quiet}{A \code{logical} value indicating whether to suppress messages. Can be \code{TRUE} or \code{FALSE}.} 20 | 21 | \item{target_dir}{The cache directory to list. Defaults to the user-specific data directory for "distrib" and "installed", and the current working directory for "project".} 22 | } 23 | \value{ 24 | A \code{dataframe} or \code{character} \code{vector} with the contents of the specified cache or project directory. 25 | } 26 | \description{ 27 | This function lists one of the following: 28 | \itemize{ 29 | \item \code{project} - list the contents of the Java symlinked/copied in the current project or directory specified by \code{target_dir} 30 | \item \code{distrib} - list the contents of the downloaded Java distributions cache in default location or specified by \code{target_dir} 31 | \item \code{installed} - list the contents of the Java installations cache (unpacked distributions) in default location or specified by \code{target_dir} 32 | } 33 | } 34 | \examples{ 35 | \dontrun{ 36 | java_list("project") 37 | java_list("installed") 38 | java_list("distrib") 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /man/java_valid_versions.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/java_valid_versions.R 3 | \name{java_valid_versions} 4 | \alias{java_valid_versions} 5 | \title{Retrieve Valid Java Versions} 6 | \usage{ 7 | java_valid_versions( 8 | distribution = "Corretto", 9 | platform = platform_detect()$os, 10 | arch = platform_detect()$arch, 11 | force = FALSE 12 | ) 13 | } 14 | \arguments{ 15 | \item{distribution}{The Java distribution to download. If not specified, defaults to "Amazon Corretto". Currently only \href{https://aws.amazon.com/corretto/}{"Amazon Corretto"} is supported.} 16 | 17 | \item{platform}{The platform for which to download the Java distribution. Defaults to the current platform.} 18 | 19 | \item{arch}{The architecture for which to download the Java distribution. Defaults to the current architecture.} 20 | 21 | \item{force}{Logical. If TRUE, forces a fresh API call even if a cached value exists. Defaults to FALSE.} 22 | } 23 | \value{ 24 | A character vector of valid Java versions. 25 | } 26 | \description{ 27 | This function retrieves a list of valid Java versions by querying an appropriate API endpoint based on the chosen distribution. 28 | The result is cached for 8 hours to avoid repeated API calls. If the API call fails (for example, due to a lack of internet connectivity), 29 | the function falls back to a pre-defined list of Java versions. 30 | } 31 | \examples{ 32 | \dontrun{ 33 | # Retrieve valid Java versions (cached if available) using Amazon Corretto endpoint 34 | versions <- java_valid_versions() 35 | 36 | # Force refresh the list of Java versions using the Oracle endpoint 37 | versions <- java_valid_versions(distribution = "Corretto", force = TRUE) 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /tests/testthat/test-java_valid_versions.R: -------------------------------------------------------------------------------- 1 | test_that("java_valid_versions returns a character vector with required versions", { 2 | skip_on_cran() 3 | # Clear any cached values 4 | options( 5 | rJavaEnv.valid_versions_cache = NULL, 6 | rJavaEnv.valid_versions_timestamp = NULL 7 | ) 8 | 9 | # Retrieve Java versions 10 | versions <- java_valid_versions() 11 | 12 | # Verify the result is a character vector and contains "8" and "11" 13 | expect_type(versions, "character") 14 | expect_true("8" %in% versions) 15 | expect_true("11" %in% versions) 16 | expect_true("24" %in% versions) 17 | }) 18 | 19 | test_that("force parameter bypasses the cache", { 20 | # Set a fake cache in the options 21 | fake_cache <- c("8", "11") 22 | options( 23 | rJavaEnv.valid_versions_cache = fake_cache, 24 | rJavaEnv.valid_versions_timestamp = Sys.time() 25 | ) 26 | 27 | # Force a refresh by setting force = TRUE. 28 | versions_force <- java_valid_versions(force = TRUE) 29 | 30 | # The returned value should not equal the fake cache. 31 | expect_false(identical(versions_force, fake_cache)) 32 | }) 33 | 34 | test_that("fallback is used when the API call fails", { 35 | # Clear the cache to force an API call. 36 | options( 37 | rJavaEnv.valid_versions_cache = NULL, 38 | rJavaEnv.valid_versions_timestamp = NULL 39 | ) 40 | 41 | local_mocked_bindings( 42 | read_json = function(...) stop("Simulated API failure"), 43 | .package = "jsonlite" 44 | ) 45 | 46 | fallback <- getOption("rJavaEnv.fallback_valid_versions_current_platform") 47 | versions <- java_valid_versions(force = TRUE) 48 | 49 | ## When the API call fails, the fallback list should be returned. 50 | expect_equal(versions, fallback) 51 | }) 52 | -------------------------------------------------------------------------------- /man/java_install.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/java_install.R 3 | \name{java_install} 4 | \alias{java_install} 5 | \title{Install Java from a distribution file} 6 | \usage{ 7 | java_install( 8 | java_distrib_path, 9 | project_path = NULL, 10 | autoset_java_env = TRUE, 11 | quiet = FALSE, 12 | force = FALSE 13 | ) 14 | } 15 | \arguments{ 16 | \item{java_distrib_path}{A \code{character} vector of length 1 containing the path to the Java distribution file.} 17 | 18 | \item{project_path}{A \code{character} vector of length 1 containing the project directory where Java should be installed. If not specified or \code{NULL}, defaults to the current working directory.} 19 | 20 | \item{autoset_java_env}{A \code{logical} indicating whether to set the \code{JAVA_HOME} and \code{PATH} environment variables to the installed Java directory. Defaults to \code{TRUE}.} 21 | 22 | \item{quiet}{A \code{logical} value indicating whether to suppress messages. Can be \code{TRUE} or \code{FALSE}.} 23 | 24 | \item{force}{A logical. Whether to overwrite an existing installation. Defaults to \code{FALSE}.} 25 | } 26 | \value{ 27 | The path to the installed Java directory. 28 | } 29 | \description{ 30 | Unpack Java distribution file into cache directory and link the installation into a project directory, optionally setting the \code{JAVA_HOME} and \code{PATH} environment variables to the Java version that was just installed. 31 | } 32 | \examples{ 33 | \dontrun{ 34 | 35 | # set cache dir to temporary directory 36 | options(rJavaEnv.cache_path = tempdir()) 37 | # download, install and autoset environmnet variables for Java 17 38 | java_17_distrib <- java_download(version = "17") 39 | java_install(java_distrib_path = java_17_distrib, project_path = tempdir()) 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /.github/workflows/update-citation-cff.yaml: -------------------------------------------------------------------------------- 1 | # Workflow derived from https://github.com/r-lib/actions/tree/master/examples 2 | # The action runs when: 3 | # - A new release is published 4 | # - The DESCRIPTION or inst/CITATION are modified 5 | # - Can be run manually 6 | # For customizing the triggers, visit https://docs.github.com/en/actions/learn-github-actions/events-that-trigger-workflows 7 | on: 8 | release: 9 | types: [published] 10 | push: 11 | branches: [master, main] 12 | paths: 13 | - DESCRIPTION 14 | - inst/CITATION 15 | workflow_dispatch: 16 | 17 | name: Update CITATION.cff 18 | 19 | jobs: 20 | update-citation-cff: 21 | runs-on: macos-latest 22 | env: 23 | GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} 24 | steps: 25 | - uses: actions/checkout@v3 26 | - uses: r-lib/actions/setup-r@v2 27 | - uses: r-lib/actions/setup-r-dependencies@v2 28 | with: 29 | extra-packages: | 30 | any::cffr 31 | any::V8 32 | 33 | - name: Update CITATION.cff 34 | run: | 35 | 36 | library(cffr) 37 | 38 | # Customize with your own code 39 | # See https://docs.ropensci.org/cffr/articles/cffr.html 40 | 41 | # Write your own keys 42 | mykeys <- list() 43 | 44 | # Create your CITATION.cff file 45 | cff_write(keys = mykeys) 46 | 47 | shell: Rscript {0} 48 | 49 | - name: Commit results 50 | run: | 51 | git config --local user.name "github-actions[bot]" 52 | git config --local user.email "41898282+github-actions[bot]@users.noreply.github.com" 53 | git add CITATION.cff 54 | git commit -m 'Update CITATION.cff' || echo "No changes to commit" 55 | git push origin || echo "No changes to commit" 56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /R/java_quick_install.R: -------------------------------------------------------------------------------- 1 | #' Download and install and set Java in current working/project directory 2 | #' 3 | #' @inheritParams java_download 4 | #' @inheritParams java_install 5 | #' @inheritParams global_quiet_param 6 | #' @return Invisibly returns the path to the Java home directory. If quiet is set to `FALSE`, also prints a message indicating that Java was installed and set in the current working/project directory. 7 | #' @export 8 | #' 9 | #' @examples 10 | #' \dontrun{ 11 | #' 12 | #' # quick download, unpack, install and set in current working directory default Java version (21) 13 | #' java_quick_install(17, temp_dir = TRUE) 14 | #' } 15 | java_quick_install <- function( 16 | version = 21, 17 | distribution = "Corretto", 18 | project_path = NULL, 19 | platform = platform_detect()$os, 20 | arch = platform_detect()$arch, 21 | quiet = FALSE, 22 | temp_dir = FALSE 23 | ) { 24 | rje_consent_check() 25 | 26 | if (temp_dir) { 27 | temp_dir <- tempdir() 28 | setwd(temp_dir) 29 | if (!dir.exists("rJavaEnv_cache")) { 30 | dir.create("rJavaEnv_cache", recursive = TRUE) 31 | } 32 | cache_path <- file.path(temp_dir, "rJavaEnv_cache") 33 | if (!dir.exists("rJavaEnv_project")) { 34 | dir.create("rJavaEnv_project", recursive = TRUE) 35 | } 36 | project_path <- file.path(temp_dir, "rJavaEnv_project") 37 | } else { 38 | cache_path <- getOption("rJavaEnv.cache_path") 39 | } 40 | 41 | java_distrib_path <- java_download( 42 | version = version, 43 | distribution = distribution, 44 | cache_path = cache_path, 45 | platform = platform, 46 | arch = arch, 47 | quiet = quiet 48 | ) 49 | 50 | java_home <- java_install( 51 | java_distrib_path, 52 | project_path = project_path, 53 | autoset_java_env = TRUE, 54 | quiet = quiet 55 | ) 56 | return(invisible(java_home)) 57 | } 58 | -------------------------------------------------------------------------------- /.github/workflows/java-live-tests.yml: -------------------------------------------------------------------------------- 1 | # GitHub Actions workflow to run the long-running live Java download tests. 2 | # This test downloads, installs, checks, and clears every supported Java version. 3 | # It is run on a schedule to avoid slowing down pull request checks. 4 | 5 | name: R Java Live Integration Tests 6 | 7 | on: 8 | # Allows you to run this workflow manually from the Actions tab 9 | workflow_dispatch: 10 | 11 | schedule: 12 | # Runs at 00:00 UTC on Saturday. 13 | # This corresponds to 1:00 AM in Berlin (CET, UTC+1) during standard time, 14 | # and 2:00 AM (CEST, UTC+2) during daylight saving time. 15 | - cron: '0 0 * * 6' 16 | 17 | 18 | jobs: 19 | R-CMD-check: 20 | runs-on: ${{ matrix.config.os }} 21 | 22 | name: ${{ matrix.config.os }} (${{ matrix.config.r }}) 23 | 24 | strategy: 25 | fail-fast: false 26 | matrix: 27 | config: 28 | - {os: macos-latest, r: 'release'} 29 | - {os: windows-latest, r: 'release'} 30 | - {os: ubuntu-latest, r: 'release'} 31 | 32 | env: 33 | GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} 34 | R_KEEP_PKG_SOURCE: yes 35 | RUN_JAVA_DOWNLOAD_TESTS: "TRUE" 36 | RUN_JAVA_DOWNLOAD_TESTS_QUIET: "FALSE" 37 | RUN_JAVA_DOWNLOAD_TESTS_QUIET_DOWNLOAD: "TRUE" 38 | 39 | steps: 40 | - uses: actions/checkout@v4 41 | 42 | - uses: r-lib/actions/setup-pandoc@v2 43 | 44 | - uses: r-lib/actions/setup-r@v2 45 | with: 46 | r-version: ${{ matrix.config.r }} 47 | http-user-agent: ${{ matrix.config.http-user-agent }} 48 | use-public-rspm: true 49 | 50 | - uses: r-lib/actions/setup-r-dependencies@v2 51 | with: 52 | extra-packages: any::rcmdcheck 53 | needs: check 54 | 55 | - uses: r-lib/actions/check-r-package@v2 56 | with: 57 | upload-snapshots: true 58 | build_args: 'c("--no-manual","--compact-vignettes=gs+qpdf")' 59 | -------------------------------------------------------------------------------- /man/java_build_env_set.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/java_build_env.R 3 | \name{java_build_env_set} 4 | \alias{java_build_env_set} 5 | \title{Set up the environment for building R packages with Java dependencies from source} 6 | \usage{ 7 | java_build_env_set( 8 | java_home = Sys.getenv("JAVA_HOME"), 9 | where = c("session", "project", "both"), 10 | project_path = NULL, 11 | quiet = FALSE 12 | ) 13 | } 14 | \arguments{ 15 | \item{java_home}{The path to the desired \code{JAVA_HOME}. Defaults to the value of the \code{JAVA_HOME} environment variable.} 16 | 17 | \item{where}{Where to set the build environment: "session", "project", or "both". Defaults to "session". When "both" or "project" is selected, the function updates the .Rprofile file in the project directory.} 18 | 19 | \item{project_path}{The path to the project directory, required when \code{where} is "project" or "both". Defaults to the current working directory.} 20 | 21 | \item{quiet}{A \code{logical} value indicating whether to suppress messages. Can be \code{TRUE} or \code{FALSE}.} 22 | } 23 | \value{ 24 | Invisibly returns \code{NULL} after setting the environment variables. 25 | } 26 | \description{ 27 | This function configures the current R session with the necessary environment 28 | variables to compile Java-dependent packages like 'rJava' from source. \strong{Note: this function is still experimental.} 29 | } 30 | \examples{ 31 | \dontrun{ 32 | # Download and install Java 17 33 | java_17_distrib <- java_download(version = "17", temp_dir = TRUE) 34 | java_home_path <- java_install( 35 | java_distrib_path = java_17_distrib, 36 | project_path = tempdir(), 37 | autoset_java_env = FALSE # Manually set env 38 | ) 39 | 40 | # Set up the build environment in the current session 41 | java_build_env_set(java_home = java_home_path) 42 | 43 | # Now, install rJava from source 44 | install.packages("rJava", type = "source", repos = "https://cloud.r-project.org") 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /man/java_env_set.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/java_env.R 3 | \name{java_env_set} 4 | \alias{java_env_set} 5 | \title{Set the \code{JAVA_HOME} and \code{PATH} environment variables to a given path} 6 | \usage{ 7 | java_env_set( 8 | where = c("session", "both", "project"), 9 | java_home, 10 | project_path = NULL, 11 | quiet = FALSE 12 | ) 13 | } 14 | \arguments{ 15 | \item{where}{Where to set the \code{JAVA_HOME}: "session", "project", or "both". Defaults to "session" and only updates the paths in the current R session. When "both" or "project" is selected, the function updates the .Rprofile file in the project directory to set the JAVA_HOME and PATH environment variables at the start of the R session.} 16 | 17 | \item{java_home}{The path to the desired \code{JAVA_HOME}.} 18 | 19 | \item{project_path}{A \code{character} vector of length 1 containing the project directory where Java should be installed. If not specified or \code{NULL}, defaults to the current working directory.} 20 | 21 | \item{quiet}{A \code{logical} value indicating whether to suppress messages. Can be \code{TRUE} or \code{FALSE}.} 22 | } 23 | \value{ 24 | Nothing. Sets the JAVA_HOME and PATH environment variables. 25 | } 26 | \description{ 27 | Set the \code{JAVA_HOME} and \code{PATH} environment variables to a given path 28 | } 29 | \examples{ 30 | \dontrun{ 31 | # download, install Java 17 32 | java_17_distrib <- java_download(version = "17", temp_dir = TRUE) 33 | java_home <- java_install( 34 | java_distrib_path = java_17_distrib, 35 | project_path = tempdir(), 36 | autoset_java_env = FALSE 37 | ) 38 | 39 | # now manually set the JAVA_HOME and PATH environment variables in current session 40 | java_env_set( 41 | where = "session", 42 | java_home = java_home 43 | ) 44 | 45 | # or set JAVA_HOME and PATH in the spefific projects' .Rprofile 46 | java_env_set( 47 | where = "project", 48 | java_home = java_home, 49 | project_path = tempdir() 50 | ) 51 | 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /tests/testthat/test-java_wrappers.R: -------------------------------------------------------------------------------- 1 | # Tests for java_quick_install() and use_java() 2 | 3 | test_that("java_quick_install executes flow correctly", { 4 | # Setup temp directories 5 | local_cache <- withr::local_tempdir() 6 | local_proj <- withr::local_tempdir() 7 | 8 | # Mock dependencies to prevent actual download/install 9 | local_mocked_bindings( 10 | java_download = function(...) file.path("mock", "distrib.tar.gz"), 11 | java_install = function(...) file.path("mock", "java_home"), 12 | rje_consent_check = function(...) TRUE, 13 | .package = "rJavaEnv" 14 | ) 15 | 16 | # Test 1: Standard Execution 17 | expect_invisible( 18 | result <- java_quick_install( 19 | version = 17, 20 | project_path = local_proj, 21 | quiet = TRUE 22 | ) 23 | ) 24 | expect_equal(result, file.path("mock", "java_home")) 25 | 26 | # Test 2: Temp Directory execution 27 | # We can't easily check internal variables, but we ensure it runs without error 28 | # and returns the mocked path, implying logic held up. 29 | 30 | expect_invisible( 31 | res_temp <- java_quick_install(version = 17, temp_dir = TRUE, quiet = TRUE) 32 | ) 33 | expect_equal(res_temp, file.path("mock", "java_home")) 34 | }) 35 | 36 | test_that("use_java executes flow correctly", { 37 | # Mock dependencies 38 | local_mocked_bindings( 39 | java_download = function(...) "mock_distrib_path", 40 | java_unpack = function(...) "mock_install_path", 41 | # Capture the arguments passed to java_env_set to verify logic 42 | java_env_set = function(where, java_home, quiet) { 43 | if (where != "session") stop("Wrong 'where' argument") 44 | if (java_home != "mock_install_path") stop("Wrong 'java_home' argument") 45 | invisible(NULL) 46 | }, 47 | java_valid_versions = function(...) c("8", "11", "17", "21"), 48 | .package = "rJavaEnv" 49 | ) 50 | 51 | # Should run silently and pass verification inside the mock 52 | expect_silent(use_java(version = 17, quiet = TRUE)) 53 | 54 | # Test message output when not quiet 55 | expect_message(use_java(version = 17, quiet = FALSE), "Java version 17 was set") 56 | }) 57 | -------------------------------------------------------------------------------- /man/java_download.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/java_download.R 3 | \name{java_download} 4 | \alias{java_download} 5 | \title{Download a Java distribution} 6 | \usage{ 7 | java_download( 8 | version = 21, 9 | distribution = "Corretto", 10 | cache_path = getOption("rJavaEnv.cache_path"), 11 | platform = platform_detect()$os, 12 | arch = platform_detect()$arch, 13 | quiet = FALSE, 14 | force = FALSE, 15 | temp_dir = FALSE 16 | ) 17 | } 18 | \arguments{ 19 | \item{version}{\code{Integer} or \code{character} vector of length 1 for major version of Java to download or install. If not specified, defaults to the latest LTS version. Can be "8", and "11" to "24" (or the same version numbers in \code{integer}) or any newer version if it is available for the selected distribution. For \code{macOS} on \code{aarch64} architecture (Apple Silicon) certain \code{Java} versions are not available.} 20 | 21 | \item{distribution}{The Java distribution to download. If not specified, defaults to "Amazon Corretto". Currently only \href{https://aws.amazon.com/corretto/}{"Amazon Corretto"} is supported.} 22 | 23 | \item{cache_path}{The destination directory to download the Java distribution to. Defaults to a user-specific data directory.} 24 | 25 | \item{platform}{The platform for which to download the Java distribution. Defaults to the current platform.} 26 | 27 | \item{arch}{The architecture for which to download the Java distribution. Defaults to the current architecture.} 28 | 29 | \item{quiet}{A \code{logical} value indicating whether to suppress messages. Can be \code{TRUE} or \code{FALSE}.} 30 | 31 | \item{force}{A logical. Whether the distribution file should be overwritten or not. Defaults to \code{FALSE}.} 32 | 33 | \item{temp_dir}{A logical. Whether the file should be saved in a temporary directory. Defaults to \code{FALSE}.} 34 | } 35 | \value{ 36 | The path to the downloaded Java distribution file. 37 | } 38 | \description{ 39 | Download a Java distribution 40 | } 41 | \examples{ 42 | \dontrun{ 43 | 44 | # download distribution of Java version 17 45 | java_download(version = "17", temp_dir = TRUE) 46 | 47 | # download default Java distribution (version 21) 48 | java_download(temp_dir = TRUE) 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /.github/workflows/test-coverage.yaml: -------------------------------------------------------------------------------- 1 | # Workflow derived from https://github.com/r-lib/actions/tree/v2/examples 2 | # Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help 3 | on: 4 | push: 5 | branches: [main] 6 | pull_request: 7 | workflow_dispatch: 8 | 9 | name: test-coverage.yaml 10 | 11 | permissions: read-all 12 | 13 | jobs: 14 | test-coverage: 15 | runs-on: ubuntu-latest 16 | env: 17 | GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} 18 | RUN_JAVA_DOWNLOAD_TESTS: "TRUE" 19 | RUN_JAVA_DOWNLOAD_TESTS_QUIET: "FALSE" 20 | RUN_JAVA_DOWNLOAD_TESTS_QUIET_DOWNLOAD: "TRUE" 21 | 22 | steps: 23 | - uses: actions/checkout@v4 24 | 25 | - uses: r-lib/actions/setup-r@v2 26 | with: 27 | use-public-rspm: true 28 | 29 | - uses: r-lib/actions/setup-r-dependencies@v2 30 | with: 31 | extra-packages: any::covr, any::xml2 32 | needs: coverage 33 | 34 | - name: Test coverage 35 | run: | 36 | cov <- covr::package_coverage( 37 | quiet = FALSE, 38 | clean = FALSE, 39 | install_path = file.path(normalizePath(Sys.getenv("RUNNER_TEMP"), winslash = "/"), "package") 40 | ) 41 | print(cov) 42 | covr::to_cobertura(cov) 43 | shell: Rscript {0} 44 | 45 | - uses: codecov/codecov-action@v5 46 | with: 47 | # Fail if error if not on PR, or if on PR and token is given 48 | fail_ci_if_error: ${{ github.event_name != 'pull_request' || secrets.CODECOV_TOKEN }} 49 | files: ./cobertura.xml 50 | plugins: noop 51 | disable_search: true 52 | token: ${{ secrets.CODECOV_TOKEN }} 53 | 54 | - name: Show testthat output 55 | if: always() 56 | run: | 57 | ## -------------------------------------------------------------------- 58 | find '${{ runner.temp }}/package' -name 'testthat.Rout*' -exec cat '{}' \; || true 59 | shell: bash 60 | 61 | - name: Upload test results 62 | if: failure() 63 | uses: actions/upload-artifact@v4 64 | with: 65 | name: coverage-test-failures 66 | path: ${{ runner.temp }}/package 67 | -------------------------------------------------------------------------------- /inst/resources/consent-info: -------------------------------------------------------------------------------- 1 | `rJavaEnv`: Manage Java Environments for R Projects 2 | 3 | Welcome to `rJavaEnv`! It looks like this is your first time using `rJavaEnv`. 4 | This message will guide you through some of the key features and how `rJavaEnv` works. 5 | 6 | `rJavaEnv` will manage Java Development Kits (JDKs) specifically for your R projects, 7 | ensuring that each project uses the appropriate Java version 8 | without affecting other projects or your system-wide Java installation. 9 | 10 | Here's what `rJavaEnv` will do: 11 | 12 | - Create a 'rjavaenv' folder in your project/current working directory. 13 | - Generate necessary configuration files in the project/current working directory. 14 | - Update your $JAVA_HOME and $PATH variables within the current R session. 15 | 16 | `rJavaEnv` will also update some existing files in your project/current working directory, such as: 17 | 18 | - .Rprofile 19 | 20 | Additionally, `rJavaEnv` maintains a cache of Java distributions and installations at: 21 | 22 | - ${rJavaEnv_CACHE} 23 | 24 | You can customize this path by setting the option `options(rJavaEnv.cache_path = 'path/to/your/java/cache')`. 25 | Alternatively, you can set the cache folder as argument `cache_path` package functions that have option. 26 | The same cache folder is used for both zipped java distributions and extracted distribution files. 27 | 28 | For more information, read the introductory vignette with `vignette("rJavaEnv")` and browse the package documentation online at https://www.ekotov.pro/rJavaEnv/. 29 | 30 | Whenever you install any `Java` JDK, kindly read the respective software license and agree to it before use. 31 | For the current default JDK installed with rJavaEnv, which is Amazon Corretto, please find the license for the version 32 | you are installing at https://github.com/corretto/. 33 | 34 | Finally, if you are on a Linux system that did not have any 'Java' version previoulsy installed and you are not using pre-build 'R' package binaries (for example from 'Posit Package Manager') and instead install all 'R' packages from source, after this step you may have to quit R, follow these steps: https://solutions.posit.co/envs-pkgs/using-rjava/#reconfigure-r to set configure 'Java' for 'R', and only then install 'rJava', as otherwise 'rJava' cannot be built from source. 35 | -------------------------------------------------------------------------------- /man/java_quick_install.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/java_quick_install.R 3 | \name{java_quick_install} 4 | \alias{java_quick_install} 5 | \title{Download and install and set Java in current working/project directory} 6 | \usage{ 7 | java_quick_install( 8 | version = 21, 9 | distribution = "Corretto", 10 | project_path = NULL, 11 | platform = platform_detect()$os, 12 | arch = platform_detect()$arch, 13 | quiet = FALSE, 14 | temp_dir = FALSE 15 | ) 16 | } 17 | \arguments{ 18 | \item{version}{\code{Integer} or \code{character} vector of length 1 for major version of Java to download or install. If not specified, defaults to the latest LTS version. Can be "8", and "11" to "24" (or the same version numbers in \code{integer}) or any newer version if it is available for the selected distribution. For \code{macOS} on \code{aarch64} architecture (Apple Silicon) certain \code{Java} versions are not available.} 19 | 20 | \item{distribution}{The Java distribution to download. If not specified, defaults to "Amazon Corretto". Currently only \href{https://aws.amazon.com/corretto/}{"Amazon Corretto"} is supported.} 21 | 22 | \item{project_path}{A \code{character} vector of length 1 containing the project directory where Java should be installed. If not specified or \code{NULL}, defaults to the current working directory.} 23 | 24 | \item{platform}{The platform for which to download the Java distribution. Defaults to the current platform.} 25 | 26 | \item{arch}{The architecture for which to download the Java distribution. Defaults to the current architecture.} 27 | 28 | \item{quiet}{A \code{logical} value indicating whether to suppress messages. Can be \code{TRUE} or \code{FALSE}.} 29 | 30 | \item{temp_dir}{A logical. Whether the file should be saved in a temporary directory. Defaults to \code{FALSE}.} 31 | } 32 | \value{ 33 | Invisibly returns the path to the Java home directory. If quiet is set to \code{FALSE}, also prints a message indicating that Java was installed and set in the current working/project directory. 34 | } 35 | \description{ 36 | Download and install and set Java in current working/project directory 37 | } 38 | \examples{ 39 | \dontrun{ 40 | 41 | # quick download, unpack, install and set in current working directory default Java version (21) 42 | java_quick_install(17, temp_dir = TRUE) 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /vignettes/bibliography.bib: -------------------------------------------------------------------------------- 1 | @article{pereira_r5r_2021, 2 | title = {r5r: Rapid Realistic Routing on Multimodal Transport Networks with {R}$^{\textrm{5}}$ in R}, 3 | shorttitle = {r5r}, 4 | url = {https://findingspress.org/article/21262-r5r-rapid-realistic-routing-on-multimodal-transport-networks-with-r-5-in-r}, 5 | doi = {10.32866/001c.21262}, 6 | language = {en}, 7 | urldate = {2021-03-04}, 8 | journal = {Findings}, 9 | author = {Pereira, Rafael H. M. and Saraiva, Marcus and Herszenhut, Daniel and Braga, Carlos Kaue Vieira and Conway, Matthew Wigginton}, 10 | month = mar, 11 | year = {2021}, 12 | note = {Publisher: Network Design Lab} 13 | } 14 | 15 | , 16 | 17 | @Manual{rjdbc, 18 | title = {RJDBC: Provides Access to Databases Through the JDBC Interface}, 19 | author = {Simon Urbanek}, 20 | year = {2022}, 21 | note = {R package version 0.2-10}, 22 | url = {https://CRAN.R-project.org/package=RJDBC}, 23 | } 24 | , 25 | 26 | @Manual{mailr, 27 | title = {mailR: A Utility to Send Emails from R}, 28 | author = {Rahul Premraj}, 29 | year = {2021}, 30 | note = {R package version 0.8}, 31 | url = {https://CRAN.R-project.org/package=mailR}, 32 | } 33 | 34 | , 35 | 36 | 37 | @Article{rweka, 38 | title = {Open-Source Machine Learning: {R} Meets {Weka}}, 39 | author = {Kurt Hornik and Christian Buchta and Achim Zeileis}, 40 | journal = {Computational Statistics}, 41 | year = {2009}, 42 | volume = {24}, 43 | number = {2}, 44 | pages = {225--232}, 45 | doi = {10.1007/s00180-008-0119-7}, 46 | } 47 | 48 | , 49 | 50 | @Manual{opennlp, 51 | title = {openNLP: Apache OpenNLP Tools Interface}, 52 | author = {Kurt Hornik}, 53 | year = {2019}, 54 | note = {R package version 0.2-7}, 55 | url = {https://CRAN.R-project.org/package=openNLP}, 56 | } 57 | 58 | , 59 | 60 | @Manual{xlsx, 61 | title = {xlsx: Read, Write, Format Excel 2007 and Excel 97/2000/XP/2003 Files}, 62 | author = {Adrian Dragulescu and Cole Arendt}, 63 | year = {2020}, 64 | note = {R package version 0.6.5}, 65 | url = {https://CRAN.R-project.org/package=xlsx}, 66 | } 67 | 68 | @Manual{rjava, 69 | title = {rJava: Low-Level R to Java Interface}, 70 | author = {Simon Urbanek}, 71 | year = {2024}, 72 | note = {R package version 1.0-11}, 73 | url = {https://CRAN.R-project.org/package=rJava}, 74 | } 75 | -------------------------------------------------------------------------------- /R/use_java.R: -------------------------------------------------------------------------------- 1 | #' Install specified Java version and set the `JAVA_HOME` and `PATH` environment variables in current R session 2 | #' 3 | #' @description 4 | #' Using specified Java version, set the `JAVA_HOME` and `PATH` environment variables in the current R session. If Java distribtuion has not been downloaded yet, download it. If it was not installed into cache directory yet, install it there and then set the environment variables. This is intended as a quick and easy way to use different Java versions in R scripts that are in the same project, but require different Java versions. For example, one could use this in scripts that are called by `targets` package or `callr` package. 5 | #' @inheritParams java_download 6 | #' @inheritParams java_install 7 | #' @inheritParams global_quiet_param 8 | #' @return `NULL`. Prints the message that Java was set in the current R session if `quiet` is set to `FALSE`. 9 | #' 10 | #' @export 11 | #' 12 | #' @examples 13 | #' \dontrun{ 14 | #' 15 | #' # set cache directory for Java to be in temporary directory 16 | #' options(rJavaEnv.cache_path = tempdir()) 17 | #' 18 | #' # install and set Java 8 in current R session 19 | #' use_java(8) 20 | #' # check Java version 21 | #' "8" == java_check_version_cmd(quiet = TRUE) 22 | #' "8" == java_check_version_rjava(quiet = TRUE) 23 | #' 24 | #' # install and set Java 17 in current R session 25 | #' use_java(17) 26 | #' # check Java version 27 | #' "17" == java_check_version_cmd(quiet = TRUE) 28 | #' "17" == java_check_version_rjava(quiet = TRUE) 29 | #' 30 | #' } 31 | #' 32 | use_java <- function( 33 | version = NULL, 34 | distribution = "Corretto", 35 | cache_path = getOption("rJavaEnv.cache_path"), 36 | platform = platform_detect()$os, 37 | arch = platform_detect()$arch, 38 | quiet = TRUE 39 | ) { 40 | checkmate::check_vector(version, len = 1) 41 | version <- as.character(version) 42 | checkmate::assert_choice(version, java_valid_versions()) 43 | 44 | java_distrib_path <- java_download( 45 | version = version, 46 | distribution = distribution, 47 | cache_path = cache_path, 48 | platform = platform, 49 | arch = arch, 50 | quiet = quiet 51 | ) 52 | 53 | java_cached_install_path <- java_unpack( 54 | java_distrib_path = java_distrib_path, 55 | quiet = quiet 56 | ) 57 | 58 | java_env_set( 59 | where = "session", 60 | java_home = java_cached_install_path, 61 | quiet = quiet 62 | ) 63 | 64 | if (!quiet) { 65 | cli::cli_alert_success( 66 | "Java version {version} was set in the current R session" 67 | ) 68 | } 69 | invisible() 70 | } 71 | -------------------------------------------------------------------------------- /tests/testthat/helper-mocks.R: -------------------------------------------------------------------------------- 1 | # Helper function to mock global dependencies for java_install tests 2 | mock_java_globals <- function(env = parent.frame()) { 3 | # We use assignInNamespace because local_mocked_bindings was failing to mock 4 | # the functions in the package namespace reliably in this context. 5 | 6 | # Mock java_valid_versions 7 | # It is internal, but assignInNamespace handles it. 8 | if (exists("java_valid_versions", envir = asNamespace("rJavaEnv"))) { 9 | original_java_valid_versions <- get( 10 | "java_valid_versions", 11 | envir = asNamespace("rJavaEnv") 12 | ) 13 | assignInNamespace( 14 | "java_valid_versions", 15 | function(...) c("8", "11", "17", "21"), 16 | ns = "rJavaEnv" 17 | ) 18 | withr::defer( 19 | assignInNamespace( 20 | "java_valid_versions", 21 | original_java_valid_versions, 22 | ns = "rJavaEnv" 23 | ), 24 | envir = env 25 | ) 26 | } 27 | 28 | # Mock rje_consent_check 29 | if (exists("rje_consent_check", envir = asNamespace("rJavaEnv"))) { 30 | original_rje_consent_check <- get( 31 | "rje_consent_check", 32 | envir = asNamespace("rJavaEnv") 33 | ) 34 | assignInNamespace("rje_consent_check", function() TRUE, ns = "rJavaEnv") 35 | withr::defer( 36 | assignInNamespace( 37 | "rje_consent_check", 38 | original_rje_consent_check, 39 | ns = "rJavaEnv" 40 | ), 41 | envir = env 42 | ) 43 | } 44 | 45 | # Mock java_unpack 46 | if (exists("java_unpack", envir = asNamespace("rJavaEnv"))) { 47 | original_java_unpack <- get("java_unpack", envir = asNamespace("rJavaEnv")) 48 | 49 | mock_unpack <- function(java_distrib_path, ...) { 50 | filename <- basename(java_distrib_path) 51 | parts <- strsplit(gsub("\\.tar\\.gz|\\.zip", "", filename), "-")[[1]] 52 | version <- parts[parts %in% c("8", "11", "17", "21")][1] 53 | arch <- parts[parts %in% c("x64", "aarch64")][1] 54 | platform <- parts[parts %in% c("linux", "windows", "macos")][1] 55 | 56 | # Use a generic, hardcoded root path instead of calling getOption(). 57 | # This makes the mock independent of the state being tested. 58 | file.path( 59 | "/mock/cache/path", 60 | "installed", 61 | platform, 62 | arch, 63 | version 64 | ) 65 | } 66 | 67 | assignInNamespace("java_unpack", mock_unpack, ns = "rJavaEnv") 68 | withr::defer( 69 | assignInNamespace("java_unpack", original_java_unpack, ns = "rJavaEnv"), 70 | envir = env 71 | ) 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /R/onLoad.R: -------------------------------------------------------------------------------- 1 | .onLoad <- function(libname, pkgname) { 2 | op <- options() 3 | op.rJavaEnv <- list( 4 | # Default folder choice (in line with renv package) 5 | rJavaEnv.cache_path = tools::R_user_dir("rJavaEnv", which = "cache"), 6 | rJavaEnv.valid_versions_cache = NULL, 7 | rJavaEnv.valid_versions_timestamp = NULL, 8 | # Fallback lists for various platforms 9 | rJavaEnv.fallback_valid_versions_macos_aarch64 = c( 10 | "8", 11 | "11", 12 | "17", 13 | "18", 14 | "19", 15 | "20", 16 | "21", 17 | "22", 18 | "23", 19 | "24", 20 | "25" 21 | ), 22 | rJavaEnv.fallback_valid_versions_macos_x64 = c( 23 | "8", 24 | "11", 25 | "15", 26 | "16", 27 | "17", 28 | "18", 29 | "19", 30 | "20", 31 | "21", 32 | "22", 33 | "23", 34 | "24", 35 | "25" 36 | ), 37 | rJavaEnv.fallback_valid_versions_linux_aarch64 = c( 38 | "8", 39 | "11", 40 | "15", 41 | "16", 42 | "17", 43 | "18", 44 | "19", 45 | "20", 46 | "21", 47 | "22", 48 | "23", 49 | "24", 50 | "25" 51 | ), 52 | rJavaEnv.fallback_valid_versions_linux_x64 = c( 53 | "8", 54 | "11", 55 | "15", 56 | "16", 57 | "17", 58 | "18", 59 | "19", 60 | "20", 61 | "21", 62 | "22", 63 | "23", 64 | "24", 65 | "25" 66 | ), 67 | rJavaEnv.fallback_valid_versions_windows_x64 = c( 68 | "8", 69 | "11", 70 | "15", 71 | "16", 72 | "17", 73 | "18", 74 | "19", 75 | "20", 76 | "21", 77 | "22", 78 | "23", 79 | "24", 80 | "25" 81 | ), 82 | rJavaEnv.fallback_valid_versions_windows_x86 = c( 83 | "8", 84 | "11" 85 | ) 86 | ) 87 | 88 | # Only set the options that haven't been defined yet 89 | toset <- !(names(op.rJavaEnv) %in% names(op)) 90 | if (any(toset)) { 91 | options(op.rJavaEnv[toset]) 92 | } 93 | 94 | # Now, detect the current platform (OS and architecture) 95 | platform <- platform_detect(quiet = TRUE) 96 | 97 | # Build the option name dynamically based on platform$os and platform$arch. 98 | # For example, for macOS on x64, this results in "rJavaEnv.fallback_valid_versions_macos_x64" 99 | fallback_option_name <- paste0( 100 | "rJavaEnv.fallback_valid_versions_", 101 | platform$os, 102 | "_", 103 | platform$arch 104 | ) 105 | 106 | # Retrieve the corresponding fallback list using getOption() 107 | fallback_current <- getOption(fallback_option_name) 108 | 109 | # Set the current platform valid versions option 110 | options(rJavaEnv.fallback_valid_versions_current_platform = fallback_current) 111 | 112 | invisible() 113 | } 114 | -------------------------------------------------------------------------------- /man/use_java.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/use_java.R 3 | \name{use_java} 4 | \alias{use_java} 5 | \title{Install specified Java version and set the \code{JAVA_HOME} and \code{PATH} environment variables in current R session} 6 | \usage{ 7 | use_java( 8 | version = NULL, 9 | distribution = "Corretto", 10 | cache_path = getOption("rJavaEnv.cache_path"), 11 | platform = platform_detect()$os, 12 | arch = platform_detect()$arch, 13 | quiet = TRUE 14 | ) 15 | } 16 | \arguments{ 17 | \item{version}{\code{Integer} or \code{character} vector of length 1 for major version of Java to download or install. If not specified, defaults to the latest LTS version. Can be "8", and "11" to "24" (or the same version numbers in \code{integer}) or any newer version if it is available for the selected distribution. For \code{macOS} on \code{aarch64} architecture (Apple Silicon) certain \code{Java} versions are not available.} 18 | 19 | \item{distribution}{The Java distribution to download. If not specified, defaults to "Amazon Corretto". Currently only \href{https://aws.amazon.com/corretto/}{"Amazon Corretto"} is supported.} 20 | 21 | \item{cache_path}{The destination directory to download the Java distribution to. Defaults to a user-specific data directory.} 22 | 23 | \item{platform}{The platform for which to download the Java distribution. Defaults to the current platform.} 24 | 25 | \item{arch}{The architecture for which to download the Java distribution. Defaults to the current architecture.} 26 | 27 | \item{quiet}{A \code{logical} value indicating whether to suppress messages. Can be \code{TRUE} or \code{FALSE}.} 28 | } 29 | \value{ 30 | \code{NULL}. Prints the message that Java was set in the current R session if \code{quiet} is set to \code{FALSE}. 31 | } 32 | \description{ 33 | Using specified Java version, set the \code{JAVA_HOME} and \code{PATH} environment variables in the current R session. If Java distribtuion has not been downloaded yet, download it. If it was not installed into cache directory yet, install it there and then set the environment variables. This is intended as a quick and easy way to use different Java versions in R scripts that are in the same project, but require different Java versions. For example, one could use this in scripts that are called by \code{targets} package or \code{callr} package. 34 | } 35 | \examples{ 36 | \dontrun{ 37 | 38 | # set cache directory for Java to be in temporary directory 39 | options(rJavaEnv.cache_path = tempdir()) 40 | 41 | # install and set Java 8 in current R session 42 | use_java(8) 43 | # check Java version 44 | "8" == java_check_version_cmd(quiet = TRUE) 45 | "8" == java_check_version_rjava(quiet = TRUE) 46 | 47 | # install and set Java 17 in current R session 48 | use_java(17) 49 | # check Java version 50 | "17" == java_check_version_cmd(quiet = TRUE) 51 | "17" == java_check_version_rjava(quiet = TRUE) 52 | 53 | } 54 | 55 | } 56 | -------------------------------------------------------------------------------- /_pkgdown.yml: -------------------------------------------------------------------------------- 1 | url: https://www.ekotov.pro/rJavaEnv/ 2 | template: 3 | bootstrap: 5 4 | bootswatch: flatly 5 | includes: 6 | in_header: | 7 | 8 | 9 | 10 | 11 | 21 | opengraph: 22 | image: 23 | src: man/figures/card.png 24 | alt: "rJavaEnv: Java Environments for R Projects. Install and manage Java environments using R" 25 | twitter: 26 | creator: "@EgorKotov" 27 | card: summary_large_image 28 | 29 | authors: 30 | Egor Kotov: 31 | href: "https://www.ekotov.pro" 32 | 33 | navbar: 34 | structure: 35 | left: [intro, reference, articles, tutorials, news] 36 | right: [search, github, lightswitch] 37 | 38 | home: 39 | title: 'rJavaEnv: `Java` Environments for R Projects' 40 | description: 'Install and manage `Java` environments using R' 41 | 42 | 43 | reference: 44 | - title: "Quick Install" 45 | desc: > 46 | Just quickly install `Java` in the current project 47 | contents: 48 | - java_quick_install 49 | - title: "Quick Set" 50 | desc: > 51 | Just quickly set `Java` in the current project (for use with `targets`/`callr`) 52 | contents: 53 | - use_java 54 | - title: "Check `Java` version" 55 | desc: > 56 | Check `Java` version with currently set environment 57 | contents: 58 | - java_check_version_cmd 59 | - java_check_version_rjava 60 | - java_get_home 61 | - title: "Fine-grained Control" 62 | desc: > 63 | Control every step of `Java` download, unpacking and installation 64 | contents: 65 | - java_download 66 | - java_unpack 67 | - java_install 68 | - java_env_set 69 | - java_env_unset 70 | - java_build_env_set 71 | - java_build_env_unset 72 | - title: "Manage files" 73 | desc: > 74 | Manage downloads, installs, and project-linked `Java` versions 75 | contents: 76 | - java_list 77 | - java_clear 78 | - title: "Other commands" 79 | contents: 80 | - java_valid_versions 81 | - rje_consent 82 | 83 | 84 | 85 | articles: 86 | - title: Documentation 87 | navbar: ~ 88 | contents: 89 | - rJavaEnv-step-by-step 90 | - multiple-java-with-targets-callr 91 | - why-rJavaEnv 92 | - install-rjava-from-source 93 | -------------------------------------------------------------------------------- /man/rJavaEnv-package.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/rJavaEnv-package.R 3 | \docType{package} 4 | \name{rJavaEnv-package} 5 | \alias{rJavaEnv} 6 | \alias{rJavaEnv-package} 7 | \title{rJavaEnv: 'Java' Environments for R Projects} 8 | \description{ 9 | \if{html}{\figure{logo.png}{options: style='float: right' alt='logo' width='120'}} 10 | 11 | Quickly install 'Java Development Kit (JDK)' without administrative privileges and set environment variables in current R session or project to solve common issues with 'Java' environment management in 'R'. Recommended to users of 'Java'/'rJava'-dependent 'R' packages such as 'r5r', 'opentripplanner', 'xlsx', 'openNLP', 'rWeka', 'RJDBC', 'tabulapdf', and many more. 'rJavaEnv' prevents common problems like 'Java' not found, 'Java' version conflicts, missing 'Java' installations, and the inability to install 'Java' due to lack of administrative privileges. 'rJavaEnv' automates the download, installation, and setup of the 'Java' on a per-project basis by setting the relevant 'JAVA_HOME' in the current 'R' session or the current working directory (via '.Rprofile', with the user's consent). Similar to what 'renv' does for 'R' packages, 'rJavaEnv' allows different 'Java' versions to be used across different projects, but can also be configured to allow multiple versions within the same project (e.g. with the help of 'targets' package). For users who need to install 'rJava' or other 'Java'-dependent packages from source, 'rJavaEnv' will display a message with instructions on how to run 'R CMD javareconf' to make the 'Java' configuration permanent, but also provides a function 'java_build_env_set' that sets the environment variables in the current R session temporarily to allow installation of 'rJava' from source without 'R CMD javareconf'. On 'Linux', in addition to setting environment variables, 'rJavaEnv' also dynamically loads 'libjvm.so' to ensure 'rJava' works correctly. See documentation for more details. 12 | } 13 | \seealso{ 14 | Useful links: 15 | \itemize{ 16 | \item \url{https://github.com/e-kotov/rJavaEnv} 17 | \item \url{https://www.ekotov.pro/rJavaEnv/} 18 | \item Report bugs at \url{https://github.com/e-kotov/rJavaEnv/issues} 19 | } 20 | 21 | } 22 | \author{ 23 | \strong{Maintainer}: Egor Kotov \email{kotov.egor@gmail.com} (\href{https://orcid.org/0000-0001-6690-5345}{ORCID}) [copyright holder] 24 | 25 | Authors: 26 | \itemize{ 27 | \item Chung-hong Chan \email{chainsawtiney@gmail.com} (\href{https://orcid.org/0000-0002-6232-7530}{ORCID}) 28 | } 29 | 30 | Other contributors: 31 | \itemize{ 32 | \item Mauricio Vargas \email{mavargas11@uc.cl} (\href{https://orcid.org/0000-0003-1017-7574}{ORCID}) [contributor] 33 | \item Hadley Wickham \email{hadley@posit.co} (use_java feature suggestion and PR review) [contributor] 34 | \item Enrique Mondragon-Estrada \email{enriquemondragon@proton.me} (\href{https://orcid.org/0009-0004-5592-1728}{ORCID}) [contributor] 35 | \item Jonas Lieth \email{jonas.lieth@gesis.org} (\href{https://orcid.org/0000-0002-3451-3176}{ORCID}) [contributor] 36 | } 37 | 38 | } 39 | \keyword{internal} 40 | -------------------------------------------------------------------------------- /.github/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to rJavaEnv 2 | 3 | This outlines how to propose a change to rJavaEnv. 4 | For a detailed discussion on contributing to this and other tidyverse packages, please see the [development contributing guide](https://rstd.io/tidy-contrib) and [code review principles](https://code-review.tidyverse.org/). 5 | 6 | ## Fixing typos 7 | 8 | You can fix typos, spelling mistakes, or grammatical errors in the documentation directly using the GitHub web interface, as long as the changes are made in the _source_ file. 9 | This generally means you'll need to edit [roxygen2 comments](https://roxygen2.r-lib.org/articles/roxygen2.html) in an `.R`, not a `.Rd` file. 10 | You can find the `.R` file that generates the `.Rd` by reading the comment in the first line. 11 | 12 | ## Bigger changes 13 | 14 | If you want to make a bigger change, it's a good idea to first file an issue and make sure someone from the team agrees that it’s needed. 15 | If you’ve found a bug, please file an issue that illustrates the bug with a minimal 16 | [reprex](https://www.tidyverse.org/help/#reprex) (this will also help you write a unit test, if needed). 17 | See the guide on [how to create a great issue](https://code-review.tidyverse.org/issues/) for more advice. 18 | 19 | ### Pull request process 20 | 21 | * Fork the package and clone onto your computer. If you haven't done this before, we recommend using `usethis::create_from_github("e-kotov/rJavaEnv", fork = TRUE)`. 22 | 23 | * Install all development dependencies with `devtools::install_dev_deps()`, and then make sure the package passes R CMD check by running `devtools::check()`. 24 | If R CMD check doesn't pass cleanly, it's a good idea to ask for help before continuing. 25 | * Create a Git branch for your pull request (PR). We recommend using `usethis::pr_init("brief-description-of-change")`. 26 | 27 | * Make your changes, commit to git, and then create a PR by running `usethis::pr_push()`, and following the prompts in your browser. 28 | The title of your PR should briefly describe the change. 29 | The body of your PR should contain `Fixes #issue-number`. 30 | 31 | * For user-facing changes, add a bullet to the top of `NEWS.md` (i.e. just below the first header). Follow the style described in . 32 | 33 | ### Code style 34 | 35 | * New code should follow the tidyverse [style guide](https://style.tidyverse.org). 36 | You can use the [styler](https://CRAN.R-project.org/package=styler) package to apply these styles, but please don't restyle code that has nothing to do with your PR. 37 | 38 | * We use [roxygen2](https://cran.r-project.org/package=roxygen2), with [Markdown syntax](https://cran.r-project.org/web/packages/roxygen2/vignettes/rd-formatting.html), for documentation. 39 | 40 | * We use [testthat](https://cran.r-project.org/package=testthat) for unit tests. 41 | Contributions with test cases included are easier to accept. 42 | 43 | ## Code of Conduct 44 | 45 | Please note that the rJavaEnv project is released with a 46 | [Contributor Code of Conduct](.github/CODE_OF_CONDUCT.md). By contributing to this 47 | project you agree to abide by its terms. 48 | -------------------------------------------------------------------------------- /.github/workflows/rhub.yaml: -------------------------------------------------------------------------------- 1 | # R-hub's generic GitHub Actions workflow file. It's canonical location is at 2 | # https://github.com/r-hub/actions/blob/v1/workflows/rhub.yaml 3 | # You can update this file to a newer version using the rhub2 package: 4 | # 5 | # rhub::rhub_setup() 6 | # 7 | # It is unlikely that you need to modify this file manually. 8 | 9 | name: R-hub 10 | run-name: "${{ github.event.inputs.id }}: ${{ github.event.inputs.name || format('Manually run by {0}', github.triggering_actor) }}" 11 | 12 | on: 13 | workflow_dispatch: 14 | inputs: 15 | config: 16 | description: 'A comma separated list of R-hub platforms to use.' 17 | type: string 18 | default: 'linux,windows,macos' 19 | name: 20 | description: 'Run name. You can leave this empty now.' 21 | type: string 22 | id: 23 | description: 'Unique ID. You can leave this empty now.' 24 | type: string 25 | 26 | jobs: 27 | 28 | setup: 29 | runs-on: ubuntu-latest 30 | outputs: 31 | containers: ${{ steps.rhub-setup.outputs.containers }} 32 | platforms: ${{ steps.rhub-setup.outputs.platforms }} 33 | 34 | steps: 35 | # NO NEED TO CHECKOUT HERE 36 | - uses: r-hub/actions/setup@v1 37 | with: 38 | config: ${{ github.event.inputs.config }} 39 | id: rhub-setup 40 | 41 | linux-containers: 42 | needs: setup 43 | if: ${{ needs.setup.outputs.containers != '[]' }} 44 | runs-on: ubuntu-latest 45 | name: ${{ matrix.config.label }} 46 | strategy: 47 | fail-fast: false 48 | matrix: 49 | config: ${{ fromJson(needs.setup.outputs.containers) }} 50 | container: 51 | image: ${{ matrix.config.container }} 52 | 53 | steps: 54 | - uses: r-hub/actions/checkout@v1 55 | - uses: r-hub/actions/platform-info@v1 56 | with: 57 | token: ${{ secrets.RHUB_TOKEN }} 58 | job-config: ${{ matrix.config.job-config }} 59 | - uses: r-hub/actions/setup-deps@v1 60 | with: 61 | token: ${{ secrets.RHUB_TOKEN }} 62 | job-config: ${{ matrix.config.job-config }} 63 | - uses: r-hub/actions/run-check@v1 64 | with: 65 | token: ${{ secrets.RHUB_TOKEN }} 66 | job-config: ${{ matrix.config.job-config }} 67 | 68 | other-platforms: 69 | needs: setup 70 | if: ${{ needs.setup.outputs.platforms != '[]' }} 71 | runs-on: ${{ matrix.config.os }} 72 | name: ${{ matrix.config.label }} 73 | strategy: 74 | fail-fast: false 75 | matrix: 76 | config: ${{ fromJson(needs.setup.outputs.platforms) }} 77 | 78 | steps: 79 | - uses: r-hub/actions/checkout@v1 80 | - uses: r-hub/actions/setup-r@v1 81 | with: 82 | job-config: ${{ matrix.config.job-config }} 83 | token: ${{ secrets.RHUB_TOKEN }} 84 | - uses: r-hub/actions/platform-info@v1 85 | with: 86 | token: ${{ secrets.RHUB_TOKEN }} 87 | job-config: ${{ matrix.config.job-config }} 88 | - uses: r-hub/actions/setup-deps@v1 89 | with: 90 | job-config: ${{ matrix.config.job-config }} 91 | token: ${{ secrets.RHUB_TOKEN }} 92 | - uses: r-hub/actions/run-check@v1 93 | with: 94 | job-config: ${{ matrix.config.job-config }} 95 | token: ${{ secrets.RHUB_TOKEN }} 96 | -------------------------------------------------------------------------------- /DESCRIPTION: -------------------------------------------------------------------------------- 1 | Package: rJavaEnv 2 | Title: 'Java' Environments for R Projects 3 | Version: 0.3.0.9000 4 | Authors@R: c( 5 | person("Egor", "Kotov", , "kotov.egor@gmail.com", role = c("aut", "cre", "cph"), 6 | comment = c(ORCID = "0000-0001-6690-5345")), 7 | person("Chung-hong", "Chan", , "chainsawtiney@gmail.com", role = "aut", 8 | comment = c(ORCID = "0000-0002-6232-7530")), 9 | person("Mauricio", "Vargas", , "mavargas11@uc.cl", role = "ctb", 10 | comment = c(ORCID = "0000-0003-1017-7574")), 11 | person("Hadley", "Wickham", , "hadley@posit.co", role = "ctb", 12 | comment = "use_java feature suggestion and PR review"), 13 | person("Enrique", "Mondragon-Estrada", , "enriquemondragon@proton.me", role = "ctb", 14 | comment = c(ORCID = "0009-0004-5592-1728")), 15 | person("Jonas", "Lieth", , "jonas.lieth@gesis.org", role = "ctb", 16 | comment = c(ORCID = "0000-0002-3451-3176")) 17 | ) 18 | Description: Quickly install 'Java Development Kit (JDK)' without 19 | administrative privileges and set environment variables in current R 20 | session or project to solve common issues with 'Java' environment 21 | management in 'R'. Recommended to users of 'Java'/'rJava'-dependent 22 | 'R' packages such as 'r5r', 'opentripplanner', 'xlsx', 'openNLP', 23 | 'rWeka', 'RJDBC', 'tabulapdf', and many more. 'rJavaEnv' prevents 24 | common problems like 'Java' not found, 'Java' version conflicts, 25 | missing 'Java' installations, and the inability to install 'Java' due 26 | to lack of administrative privileges. 'rJavaEnv' automates the 27 | download, installation, and setup of the 'Java' on a per-project basis 28 | by setting the relevant 'JAVA_HOME' in the current 'R' session or the 29 | current working directory (via '.Rprofile', with the user's consent). 30 | Similar to what 'renv' does for 'R' packages, 'rJavaEnv' allows 31 | different 'Java' versions to be used across different projects, but 32 | can also be configured to allow multiple versions within the same 33 | project (e.g. with the help of 'targets' package). For users who need 34 | to install 'rJava' or other 'Java'-dependent packages from source, 35 | 'rJavaEnv' will display a message with instructions on how to run 'R 36 | CMD javareconf' to make the 'Java' configuration permanent, but also 37 | provides a function 'java_build_env_set' that sets the environment 38 | variables in the current R session temporarily to allow installation 39 | of 'rJava' from source without 'R CMD javareconf'. On 'Linux', in 40 | addition to setting environment variables, 'rJavaEnv' also dynamically 41 | loads 'libjvm.so' to ensure 'rJava' works correctly. See 42 | documentation for more details. 43 | License: MIT + file LICENSE 44 | URL: https://github.com/e-kotov/rJavaEnv, https://www.ekotov.pro/rJavaEnv/ 45 | BugReports: https://github.com/e-kotov/rJavaEnv/issues 46 | Depends: 47 | R (>= 4.0) 48 | Imports: 49 | checkmate, 50 | cli, 51 | curl, 52 | jsonlite, 53 | rlang, 54 | utils 55 | Suggests: 56 | quarto, 57 | rJava, 58 | testthat (>= 3.0.0), 59 | withr 60 | VignetteBuilder: 61 | quarto 62 | Config/testthat/edition: 3 63 | Encoding: UTF-8 64 | Language: en-US 65 | Roxygen: list(markdown = TRUE) 66 | RoxygenNote: 7.3.3 67 | -------------------------------------------------------------------------------- /R/java_manage.R: -------------------------------------------------------------------------------- 1 | #' List the contents of the Java versions installed or cached 2 | #' 3 | #' @description 4 | #' This function lists one of the following: 5 | #' 6 | #' * `project` - list the contents of the Java symlinked/copied in the current project or directory specified by `target_dir` 7 | #' 8 | #' * `distrib` - list the contents of the downloaded Java distributions cache in default location or specified by `target_dir` 9 | #' 10 | #' * `installed` - list the contents of the Java installations cache (unpacked distributions) in default location or specified by `target_dir` 11 | #' 12 | #' @param type The type of cache to list: "distrib", "installed", or "project". Defaults to "project". 13 | #' @param output The format of the output: `data.frame`` or `vector``. Defaults to `data.frame`. 14 | #' @inheritParams global_quiet_param 15 | #' @param target_dir The cache directory to list. Defaults to the user-specific data directory for "distrib" and "installed", and the current working directory for "project". 16 | #' @return A `dataframe` or `character` `vector` with the contents of the specified cache or project directory. 17 | #' @export 18 | #' 19 | #' @examples 20 | #' \dontrun{ 21 | #' java_list("project") 22 | #' java_list("installed") 23 | #' java_list("distrib") 24 | #'} 25 | #' 26 | java_list <- function( 27 | type = c("project", "installed", "distrib"), 28 | output = c("data.frame", "vector"), 29 | quiet = TRUE, 30 | target_dir = NULL) { 31 | type <- match.arg(type) 32 | output <- match.arg(output) 33 | 34 | if (is.null(target_dir)) { 35 | if (type == "project") { 36 | target_dir <- getwd() 37 | } else { 38 | target_dir <- getOption("rJavaEnv.cache_path") 39 | } 40 | } 41 | 42 | if (type == "distrib") { 43 | return(java_list_distrib_cache(output = output, quiet = quiet, cache_path = target_dir)) 44 | } else if (type == "installed") { 45 | return(java_list_installed_cache(output = output, quiet = quiet, cache_path = target_dir)) 46 | } else if (type == "project") { 47 | return(java_list_in_project(output = output, quiet = quiet, project_path = target_dir)) 48 | } 49 | } 50 | 51 | #' Manage Java installations and distributions caches 52 | #' 53 | #' Wrapper function to clear the Java symlinked in the current project, installed, or distributions caches. 54 | #' 55 | #' @param type What to clear: "project" - remove symlinks to install cache in the current project, "installed" - remove installed Java versions, "distrib" - remove downloaded Java distributions. 56 | #' @param check Whether to list the contents of the cache directory before clearing it. Defaults to TRUE. 57 | #' @param delete_all Whether to delete all items without prompting. Defaults to FALSE. 58 | #' @param target_dir The directory to clear. Defaults to current working directory for "project" and user-specific data directory for "installed" and "distrib". Not recommended to change. 59 | #' @return A message indicating whether the cache was cleared or not. 60 | #' @export 61 | #' 62 | #' @examples 63 | #' \dontrun{ 64 | #' java_clear("project", target_dir = tempdir()) 65 | #' java_clear("installed", target_dir = tempdir()) 66 | #' java_clear("distrib", target_dir = tempdir()) 67 | #' } 68 | #' 69 | java_clear <- function( 70 | type = c("project", "installed", "distrib"), 71 | target_dir = NULL, 72 | check = TRUE, 73 | delete_all = FALSE) { 74 | rje_consent_check() 75 | 76 | type <- match.arg(type) 77 | 78 | if (is.null(target_dir)) { 79 | if (type == "project") { 80 | target_dir <- getwd() 81 | } else { 82 | target_dir <- getOption("rJavaEnv.cache_path") 83 | } 84 | } 85 | 86 | if (type == "distrib") { 87 | java_clear_distrib_cache(cache_path = target_dir, check = check, delete_all = delete_all) 88 | } else if (type == "installed") { 89 | java_clear_installed_cache(cache_path = target_dir, check = check, delete_all = delete_all) 90 | } else if (type == "project") { 91 | java_clear_in_project(project_path = target_dir, check = check, delete_all = delete_all) 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /R/java_manage_distrib_cache.R: -------------------------------------------------------------------------------- 1 | #' List the contents of the Java distributions cache folder 2 | #' 3 | #' @param output The format of the output: "data.frame" or "vector". Defaults to "data.frame". 4 | #' @inheritParams java_list 5 | #' @inheritParams java_download 6 | #' @inheritParams global_quiet_param 7 | #' @return A character vector with the contents of the cache directory. 8 | #' 9 | #' @keywords internal 10 | java_list_distrib_cache <- function( 11 | cache_path = getOption("rJavaEnv.cache_path"), 12 | output = c("data.frame", "vector"), 13 | quiet = TRUE 14 | ) { 15 | output <- match.arg(output) 16 | 17 | cache_path <- file.path(cache_path, "distrib") 18 | 19 | if (!dir.exists(cache_path)) { 20 | cli::cli_alert_danger("No Java distributions have been downloaded.") 21 | return(character(0)) 22 | } 23 | if (!quiet) cli::cli_inform("Contents of the Java distributions cache folder:") 24 | 25 | java_distrs <- grep( 26 | "md5$", 27 | list.files(cache_path, full.names = TRUE), 28 | invert = TRUE, 29 | value = TRUE 30 | ) 31 | 32 | if (output == "vector") { 33 | return(java_distrs) 34 | } else if (output == "data.frame") { 35 | java_distrs <- data.frame(java_distr_path = java_distrs) 36 | return(java_distrs) 37 | } 38 | } 39 | 40 | #' Clear the Java distributions cache folder 41 | #' 42 | #' @param cache_path The cache directory to clear. Defaults to the user-specific data directory. 43 | #' @inheritParams java_clear 44 | #' @inheritParams java_download 45 | #' @return A message indicating whether the cache was cleared or not. 46 | #' 47 | #' @keywords internal 48 | java_clear_distrib_cache <- function( 49 | cache_path = getOption("rJavaEnv.cache_path"), 50 | check = TRUE, 51 | delete_all = FALSE 52 | ) { 53 | rje_consent_check() 54 | 55 | distrib_cache_path <- file.path(cache_path, "distrib") 56 | 57 | if (!dir.exists(distrib_cache_path)) { 58 | if (length(list.files(distrib_cache_path)) == 0) { 59 | cli::cli_inform("Java distributions cache is already empty.") 60 | return(invisible(NULL)) 61 | } 62 | } 63 | 64 | if (delete_all) { 65 | unlink(file.path(distrib_cache_path, "*"), recursive = TRUE) 66 | cli::cli_inform("Java distributions cache cleared.") 67 | return(invisible(NULL)) 68 | } 69 | 70 | if (check) { 71 | distributions <- java_list_distrib_cache(output = "vector", cache_path = cache_path) 72 | if (length(distributions) == 0) { 73 | cli::cli_inform("No Java distributions found to clear.") 74 | return(invisible(NULL)) 75 | } 76 | 77 | cli::cli_alert_info("Existing Java distributions:") 78 | for (i in seq_along(distributions)) { 79 | cli::cli_inform("{i}: {distributions[i]}") 80 | } 81 | 82 | cli::cli_alert_info("Enter the number of the distribution to delete, 'all' to delete all, or '0' or any other character to cancel:") 83 | response <- readline() 84 | 85 | if (tolower(response) == "all") { 86 | unlink(file.path(distrib_cache_path, "*"), recursive = TRUE) 87 | cli::cli_inform("All Java distributions have been cleared.") 88 | } else { 89 | choice <- suppressWarnings(as.integer(response)) 90 | if (is.na(choice) || choice == 0 || choice > length(distributions)) { 91 | cli::cli_inform("No distributions were cleared.") 92 | } else { 93 | unlink(distributions[choice], recursive = TRUE) 94 | md5_file <- paste0(distributions[choice], "md5") 95 | if(file.exists(md5_file)) unlink(md5_file) 96 | cli::cli_inform("Java distribution {choice} has been cleared.") 97 | } 98 | } 99 | } else { 100 | cli::cli_alert_info("Are you sure you want to clear the Java distributions cache? (yes/no)") 101 | response <- readline() 102 | if (tolower(response) == "yes") { 103 | unlink(file.path(distrib_cache_path, "*"), recursive = TRUE) 104 | cli::cli_inform("Java distributions cache cleared.") 105 | } else { 106 | cli::cli_inform("Java distributions cache was not cleared.") 107 | } 108 | } 109 | 110 | return(invisible(NULL)) 111 | } 112 | -------------------------------------------------------------------------------- /vignettes/multiple-java-with-targets-callr.qmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Multiple `Java` environments in one project with `targets` and `callr`" 3 | vignette: > 4 | %\VignetteIndexEntry{Multiple `Java` environments in one project with `targets` and `callr`} 5 | %\VignetteEngine{quarto::html} 6 | %\VignetteEncoding{UTF-8} 7 | execute: 8 | eval: false 9 | format: 10 | html: 11 | toc: true 12 | toc-depth: 2 13 | code-overflow: wrap 14 | --- 15 | 16 | If you need to use multiple `Java` distribution versions in a single project, you can use a handy shortcut function `use_java()` kindly [suggested by Hadley Wickham](https://github.com/e-kotov/rJavaEnv/issues/44){target='_blank'}. 17 | 18 | Essentialy, `use_java()` does the same thing as `java_quick_install()`, but in a less intrusive way. It downloads the distribution of the user requested major version of `Java`, unpacks it, also to the cache folder, but unlike `java_quick_install()`, it does not copy or link the `Java` installation folder from cache into the project directory and does not create or edit your `.Rprofile` file. Instead, it just sets the environment in the current R script to the requested `Java` binaries in the cache folder. The download and unpacking only happens once, so each next run is practically instant, as the function only needs to set the environment in the current R script. 19 | 20 | # How to use `use_java()` 21 | 22 | Let's illustrate this with a simple example. 23 | 24 | First, load the package and check the valid major versions of `Java`: 25 | 26 | ```{r} 27 | library(rJavaEnv) 28 | java_valid_versions() 29 | ``` 30 | 31 | 32 | ``` 33 | [1] "8" "11" "15" "16" "17" "18" "19" "20" "21" "22" "23" "24" 34 | ``` 35 | 36 | ::: {.callout-note} 37 | The available versions of `Java` depend on your OS and architecture, so you might see a shorter list on your system. 38 | ::: 39 | 40 | Now select any two or three versions and run `use_java()`, checking every time that correct java was set in the current environment. 41 | 42 | ```{r} 43 | use_java("8") 44 | "8" == java_check_version_cmd(quiet = TRUE) 45 | "8" == java_check_version_rjava(quiet = TRUE) 46 | ``` 47 | 48 | ``` 49 | [1] TRUE 50 | [1] TRUE 51 | ``` 52 | 53 | ```{r} 54 | use_java(17) 55 | "17" == java_check_version_cmd(quiet = TRUE) 56 | "17" == java_check_version_rjava(quiet = TRUE) 57 | ``` 58 | 59 | ``` 60 | [1] TRUE 61 | [1] TRUE 62 | ``` 63 | 64 | ```{r} 65 | use_java(21) 66 | "21" == java_check_version_cmd(quiet = TRUE) 67 | "21" == java_check_version_rjava(quiet = TRUE) 68 | ``` 69 | 70 | 71 | ``` 72 | [1] TRUE 73 | [1] TRUE 74 | ``` 75 | 76 | You probably had to wait for a bit for the Java distribution to be downloaded and unpacked. 77 | 78 | However, now if you repeat the same commands, you will see that the correct `Java` version is set instantly, as downloading and unpacking are skipped. 79 | 80 | # How to use with `targets` and `callr` 81 | 82 | Both [`{targets}`](https://docs.ropensci.org/targets/){target="_blank"} and [`{callr}`](https://callr.r-lib.org/){target="_blank"} packages allow the user to run any R scripts in clean separate R sessions. This essentially allows the user to run multiple versions of `Java` in one project with `targets` and `callr`, mostly overcoming the issue of manually switching between `Java` versions in one project. 83 | 84 | One simple thing you can do if one of the scripts needs Java 8, and another one needs Java 17, is to insert `use_java()` in beginning of the scripts that you run through `targets` or `callr` like so: 85 | 86 | ```{r} 87 | library(rJavaEnv) 88 | use_java("17") 89 | ``` 90 | 91 | Or: 92 | 93 | ```{r} 94 | rJavaEnv::use_java("17") 95 | ``` 96 | 97 | 98 | The first run of such script will have to go through the the process of downloading and unpacking the `Java` distribution. The second run will not need to download and unpacking and will be instant. 99 | 100 | If you need the runs to be instant from the first attempt, you can pre-download and pre-install `Java` into cache folders using: 101 | 102 | ```{r} 103 | java_17_distrib <- java_download("17") 104 | java_unpack(java_17_distrib) 105 | ``` 106 | -------------------------------------------------------------------------------- /vignettes/install-rjava-from-source.qmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Install `rJava` from source" 3 | vignette: > 4 | %\VignetteIndexEntry{Install `rJava` from source} 5 | %\VignetteEngine{quarto::html} 6 | %\VignetteEncoding{UTF-8} 7 | execute: 8 | eval: false 9 | format: 10 | html: 11 | toc: true 12 | toc-depth: 2 13 | code-overflow: wrap 14 | --- 15 | 16 | The basics of using `rJavaEnv` are covered in the [Quick Start Guide](rJavaEnv.qmd), which demonstrates how to install Java in one line of code. This tutorial will show you how to install `rJava` packag from source if you want to or have to. 17 | 18 | ```{r} 19 | library(rJavaEnv) 20 | ``` 21 | 22 | Assume your project directory is currently in a temporary directory. Feel free to skip that, if you are already working in a desired project directory where you would like to install `Java`. In the example outputs below you will see paths that point to a temporary directory, but in a real project you would see your project directory instead. 23 | 24 | ```{r} 25 | project_dir <- tempdir() 26 | setwd(project_dir) 27 | ``` 28 | 29 | 30 | # 1. Install Java 31 | 32 | You can use detailed step-by-step process from the [step-by-step vignette](rJavaEnv-step-by-step.qmd) to download, unpack, install and link `Java` JDK of your desired version, but for simplicity, let's use shortcut functions 33 | 34 | Either quick install Java into current project directory: 35 | 36 | ```{r} 37 | java_quick_install(version = 21) 38 | ``` 39 | 40 | ::: callout-note 41 | You might also do `java_home <- java_quick_install(version = 21)`, as this will save the path to the installed Java home directory into `java_home` variable for later use, but the function to set the build environment actually uses the `JAVA_HOME` environment variable set by `java_quick_install()` by default, so it's not necessary. 42 | ::: 43 | 44 | 45 | Or you can simply do: 46 | 47 | ```{r} 48 | use_java(21) 49 | ``` 50 | 51 | This will essentially do the same as `java_quick_install()`, but only sets the `JAVA_HOME` and `PATH` environment variables in the current R session, without modifying your `.Rprofile` file or copying/linking the installation folder into your project directory. 52 | 53 | # 2. Set the environment for building `rJava` 54 | 55 | 56 | Now simply use: 57 | 58 | 59 | ```{r} 60 | java_build_env_set() 61 | ``` 62 | 63 | That is it, `java_build_env_set` will detect your platform and architecture and set the correct environment variables. If you want advanced control, you can use `java_home` to set custom `JAVA_HOME` path, or use `where='project'` to set the environment variables in your `.Rprofile` file in the current project directory. See `?java_build_env_set` for details. 64 | 65 | Once `java_build_env_set()` completes, it will print out OS-specific notes. In summary, 66 | 67 | - **On Linux**, you may need to install several system dependencies. For Debian/Ubuntu, this can be done with: 68 | ```bash 69 | sudo apt-get update && sudo apt-get install -y --no-install-recommends libpcre2-dev libdeflate-dev libzstd-dev liblzma-dev libbz2-dev zlib1g-dev libicu-dev && sudo rm -rf /var/lib/apt/lists/* 70 | ``` 71 | 72 | - **On Windows**, `Rtools` is required. You can download it from [https://cran.r-project.org/bin/windows/Rtools/](https://cran.r-project.org/bin/windows/Rtools/){target="_blank"}. 73 | 74 | - **On macOS**, you'll need the Xcode Command Line Tools. Install them by running: 75 | ```bash 76 | xcode-select --install 77 | ``` 78 | 79 | # 3. Install `rJava` from source 80 | 81 | Now you are ready to install `rJava` from source: 82 | 83 | ```{r} 84 | install.packages("rJava", type = "source") 85 | ``` 86 | 87 | If you are on a Linux distribution with pre-configured [`Posit Package Manager` (PPM)](https://packagemanager.posit.co/) repository that serves pre-compiled binaries even if `type="source"` (or in a similar situation on `Windows` or `macOS`), you can use `repos = "https://cloud.r-project.org"` to force installation from source: 88 | 89 | ```{r} 90 | install.packages("rJava", type = "source", repos = "https://cloud.r-project.org") 91 | ``` 92 | 93 | And that is it. You have successfully installed `rJava` from source. If you restart the R session, the build-related environment variables will be reset. To use your newly installed `rJava` package just do: 94 | 95 | ```{r} 96 | library(rJavaEnv) 97 | use_java(21) # or whatever version you installed 98 | library(rJava) 99 | ``` 100 | -------------------------------------------------------------------------------- /R/consent.R: -------------------------------------------------------------------------------- 1 | #' Obtain User Consent for rJavaEnv 2 | #' 3 | #' Get user consent for rJavaEnv to write and update files on the file system. 4 | #' rJavaEnv needs permission to manage files in your project and cache directories 5 | #' to function correctly. 6 | #' 7 | #' In line with [CRAN policies](https://cran.r-project.org/web/packages/policies.html), explicit user consent is required before making these changes. 8 | #' Please call `rJavaEnv::consent()` to provide consent. 9 | #' 10 | #' Alternatively, you can set the following \R option 11 | #' (especially useful for non-interactive R sessions): 12 | #' 13 | #' ``` 14 | #' options(rJavaEnv.consent = TRUE) 15 | #' ``` 16 | #' The function is based on the code of the `renv` package. 17 | #' Copyright 2023 Posit Software, PBC 18 | #' License: https://github.com/rstudio/renv/blob/main/LICENSE 19 | #' 20 | #' @param provided Logical indicating if consent is already provided. 21 | #' To provide consent in non-interactive \R sessions 22 | #' use `rJavaEnv::rje_consent(provided = TRUE)`. Default is `FALSE`. 23 | #' 24 | #' @return `TRUE` if consent is given, otherwise an error is raised. 25 | #' 26 | #' @export 27 | #' @examples 28 | #' \dontrun{ 29 | #' 30 | #' # to provide consent and prevent other functions from interrupting to get the consent 31 | #' rje_consent(provided = TRUE) 32 | #' } 33 | #' 34 | rje_consent <- function(provided = FALSE) { 35 | 36 | # Check if consent is already given via environment variable 37 | if (getOption("rJavaEnv.consent", default = FALSE)) { 38 | cli::cli_inform("Consent for using rJavaEnv has already been provided.") 39 | return(invisible(TRUE)) 40 | } 41 | 42 | # Check if consent is already given via cache directory 43 | user_package_cache_path <- getOption("rJavaEnv.cache_path") 44 | user_package_cache_path <- normalizePath(user_package_cache_path, winslash = "/", mustWork = FALSE) 45 | if (dir.exists(user_package_cache_path)) { 46 | cli::cli_inform("Consent for using rJavaEnv has already been provided.") 47 | return(invisible(TRUE)) 48 | } 49 | 50 | # write welcome message 51 | template <- system.file("resources/consent-info", package = "rJavaEnv") 52 | contents <- readLines(template) 53 | contents <- gsub("\\$\\{rJavaEnv_CACHE\\}", user_package_cache_path, contents) 54 | cli::cli_inform(contents) 55 | 56 | # Request user consent if not already provided 57 | if (!provided) { 58 | response <- readline(prompt = "Your response: (yes/no) ") 59 | provided <- tolower(response) %in% c("y", "yes", "yes.") 60 | } 61 | 62 | if (!provided) { 63 | cli::cli_abort("Consent was not provided; operation aborted.") 64 | } 65 | 66 | # Save user consent 67 | options(rJavaEnv.consent = TRUE) 68 | dir.create(user_package_cache_path, recursive = TRUE, showWarnings = FALSE) 69 | cli::cli_inform("Consent has been granted and recorded.") 70 | 71 | invisible(TRUE) 72 | } 73 | 74 | #' Verify User Consent for rJavaEnv 75 | #' 76 | #' Ensure that the user has granted permission for rJavaEnv to manage files on their file system. 77 | #' 78 | #' The function is based on the code of the `renv` package. 79 | #' Copyright 2023 Posit Software, PBC 80 | #' License: https://github.com/rstudio/renv/blob/main/LICENSE 81 | #' 82 | #' @return `TRUE` if consent is verified, otherwise an error is raised. 83 | #' @keywords internal 84 | rje_consent_check <- function() { 85 | 86 | # Check if explicit consent is given 87 | if (getOption("rJavaEnv.consent", FALSE)) { 88 | return(TRUE) 89 | } 90 | if (dir.exists(getOption("rJavaEnv.cache_path"))) { 91 | return(TRUE) 92 | } 93 | 94 | # Check for implicit consent 95 | consented <- 96 | !interactive() || 97 | rje_envvar_exists("CI") || 98 | rje_envvar_exists("GITHUB_ACTION") || 99 | rje_envvar_exists("RENV_PATHS_ROOT") || 100 | file.exists("/.singularity.d") 101 | 102 | if (consented) { 103 | options(rJavaEnv.consent = TRUE) 104 | return(TRUE) 105 | } 106 | 107 | # Prompt for explicit consent 108 | rje_consent() 109 | } 110 | 111 | 112 | #' Helper for clean env var check 113 | #' 114 | #' #' The function is based on the code of the `renv` package. 115 | #' Copyright 2023 Posit Software, PBC 116 | #' License: https://github.com/rstudio/renv/blob/main/LICENSE 117 | #' @param key The environment variable key to check. 118 | #' @keywords internal 119 | rje_envvar_exists <- function(key) { 120 | !is.na(Sys.getenv(key, unset = NA)) 121 | } 122 | -------------------------------------------------------------------------------- /R/java_unpack.R: -------------------------------------------------------------------------------- 1 | #' Unpack a Java distribution file into cache directory 2 | #' 3 | #' @description 4 | #' Unpack the Java distribution file into cache directory and return the path to the unpacked Java directory with Java binaries. 5 | #' 6 | #' 7 | #' @inheritParams java_install 8 | #' @param force A logical. Whether to overwrite an existing installation. Defaults to `FALSE`. 9 | #' @inheritParams global_quiet_param 10 | #' @return A `character` vector containing of length 1 containing the path to the unpacked Java directory. 11 | #' @export 12 | #' @examples 13 | #' \dontrun{ 14 | #' 15 | #' # set cache dir to temporary directory 16 | #' options(rJavaEnv.cache_path = tempdir()) 17 | #' 18 | #' # download Java 17 distrib and unpack it into cache dir 19 | #' java_17_distrib <- java_download(version = "17") 20 | #' java_home <- java_unpack(java_distrib_path = java_17_distrib) 21 | #' 22 | #' # set the JAVA_HOME environment variable in the current session 23 | #' # to the cache dir without touching any files in the current project directory 24 | #' java_env_set(where = "session", java_home = java_home) 25 | #' } 26 | #' 27 | java_unpack <- function( 28 | java_distrib_path, 29 | quiet = FALSE, 30 | force = FALSE 31 | ) { 32 | platforms <- c("windows", "linux", "macos") 33 | architectures <- c("x64", "aarch64", "arm64") 34 | java_versions <- java_valid_versions() 35 | 36 | # Extract information from the file name 37 | filename <- basename(java_distrib_path) 38 | parts <- strsplit(gsub("\\.tar\\.gz|\\.zip", "", filename), "-")[[1]] 39 | 40 | # Guess the version, architecture, and platform 41 | version <- parts[parts %in% java_versions][1] 42 | arch <- parts[parts %in% architectures][1] 43 | platform <- parts[parts %in% platforms][1] 44 | 45 | if (is.na(version)) { 46 | cli::cli_abort("Unable to detect Java version from filename.") 47 | } 48 | if (is.na(arch)) { 49 | cli::cli_abort("Unable to detect architecture from filename.") 50 | } 51 | if (is.na(platform)) { 52 | cli::cli_abort("Unable to detect platform from filename.") 53 | } 54 | 55 | # Create the installation path in the package cache 56 | cache_path <- getOption("rJavaEnv.cache_path") 57 | installed_path <- file.path(cache_path, "installed", platform, arch, version) 58 | 59 | if (dir.exists(installed_path) && force) { 60 | if (!quiet) { 61 | cli::cli_inform( 62 | "Forced re-installation. Removing existing installation at {.path {installed_path}}" 63 | ) 64 | } 65 | unlink(installed_path, recursive = TRUE) 66 | } 67 | 68 | # Check if the distribution has already been unpacked 69 | if (!dir.exists(installed_path) || length(list.files(installed_path)) == 0) { 70 | # Create the directories if they don't exist 71 | if (!dir.exists(installed_path)) { 72 | dir.create(installed_path, recursive = TRUE) 73 | } 74 | 75 | # Determine extraction path based on platform 76 | if (platform == "macos") { 77 | extract_subdir <- "Contents/Home" 78 | } else { 79 | extract_subdir <- "." 80 | } 81 | 82 | # Extract the files 83 | temp_dir <- file.path(tempdir(), "java_temp") 84 | if (dir.exists(temp_dir)) { 85 | unlink(temp_dir, recursive = TRUE) 86 | } 87 | 88 | dir.create(temp_dir, recursive = TRUE) 89 | 90 | if (grepl("\\.tar\\.gz$", java_distrib_path)) { 91 | utils::untar(java_distrib_path, exdir = temp_dir) 92 | } else if (grepl("\\.zip$", java_distrib_path)) { 93 | utils::unzip(java_distrib_path, exdir = temp_dir) 94 | } else { 95 | stop(cli::cli_abort("Unsupported file format", .envir = environment())) 96 | } 97 | 98 | # Safely find the extracted directory 99 | extracted_root_dir <- list.files(temp_dir, full.names = TRUE)[1] 100 | if (platform == "macos") { 101 | extracted_dir <- file.path(extracted_root_dir, "Contents", "Home") 102 | } else { 103 | extracted_dir <- extracted_root_dir 104 | } 105 | 106 | # Move the extracted files to the installation path 107 | file.copy( 108 | list.files(extracted_dir, full.names = TRUE), 109 | installed_path, 110 | recursive = TRUE 111 | ) 112 | 113 | # Clean up temporary directory 114 | unlink(temp_dir, recursive = TRUE) 115 | } else { 116 | if (!quiet) { 117 | cli::cli_inform( 118 | "Java distribution {filename} already unpacked at {.path {installed_path}}" 119 | ) 120 | } 121 | } 122 | return(installed_path) 123 | } 124 | -------------------------------------------------------------------------------- /inst/schemaorg.json: -------------------------------------------------------------------------------- 1 | { 2 | "@context": "https://schema.org", 3 | "@graph": [ 4 | { 5 | "type": "SoftwareSourceCode", 6 | "author": [ 7 | { 8 | "id": "https://orcid.org/0000-0002-6232-7530", 9 | "type": "Person", 10 | "email": "chainsawtiney@gmail.com", 11 | "familyName": "Chan", 12 | "givenName": "Chung-hong" 13 | }, 14 | { 15 | "id": "https://orcid.org/0000-0001-6690-5345" 16 | } 17 | ], 18 | "codeRepository": "https://github.com/e-kotov/rJavaEnv", 19 | "contributor": [ 20 | { 21 | "id": "https://orcid.org/0000-0003-1017-7574", 22 | "type": "Person", 23 | "email": "mavargas11@uc.cl", 24 | "familyName": "Vargas", 25 | "givenName": "Mauricio" 26 | }, 27 | { 28 | "type": "Person", 29 | "email": "hadley@posit.co", 30 | "familyName": "Wickham", 31 | "givenName": "Hadley" 32 | }, 33 | { 34 | "id": "https://orcid.org/0009-0004-5592-1728", 35 | "type": "Person", 36 | "email": "enriquemondragon@proton.me", 37 | "familyName": "Mondragon-Estrada", 38 | "givenName": "Enrique" 39 | }, 40 | { 41 | "id": "https://orcid.org/0000-0002-3451-3176", 42 | "type": "Person", 43 | "email": "jonas.lieth@gesis.org", 44 | "familyName": "Lieth", 45 | "givenName": "Jonas" 46 | } 47 | ], 48 | "copyrightHolder": { 49 | "id": "https://orcid.org/0000-0001-6690-5345", 50 | "type": "Person", 51 | "email": "kotov.egor@gmail.com", 52 | "familyName": "Kotov", 53 | "givenName": "Egor" 54 | }, 55 | "description": "Quickly install 'Java Development Kit (JDK)' without administrative privileges and set environment variables in current R session or project to solve common issues with 'Java' environment management in 'R'. Recommended to users of 'Java'/'rJava'-dependent 'R' packages such as 'r5r', 'opentripplanner', 'xlsx', 'openNLP', 'rWeka', 'RJDBC', 'tabulapdf', and many more. 'rJavaEnv' prevents common problems like 'Java' not found, 'Java' version conflicts, missing 'Java' installations, and the inability to install 'Java' due to lack of administrative privileges. 'rJavaEnv' automates the download, installation, and setup of the 'Java' on a per-project basis by setting the relevant 'JAVA_HOME' in the current 'R' session or the current working directory (via '.Rprofile', with the user's consent). Similar to what 'renv' does for 'R' packages, 'rJavaEnv' allows different 'Java' versions to be used across different projects, but can also be configured to allow multiple versions within the same project (e.g. with the help of 'targets' package). For users who need to install 'rJava' or other 'Java'-dependent packages from source, 'rJavaEnv' will display a message with instructions on how to run 'R CMD javareconf' to make the 'Java' configuration permanent, but also provides a function 'java_build_env_set' that sets the environment variables in the current R session temporarily to allow installation of 'rJava' from source without 'R CMD javareconf'. On 'Linux', in addition to setting environment variables, 'rJavaEnv' also dynamically loads 'libjvm.so' to ensure 'rJava' works correctly. See documentation for more details.", 56 | "license": "https://spdx.org/licenses/MIT", 57 | "name": "rJavaEnv: 'Java' Environments for R Projects", 58 | "programmingLanguage": { 59 | "type": "ComputerLanguage", 60 | "name": "R", 61 | "url": "https://r-project.org" 62 | }, 63 | "provider": { 64 | "id": "https://cran.r-project.org", 65 | "type": "Organization", 66 | "name": "Comprehensive R Archive Network (CRAN)", 67 | "url": "https://cran.r-project.org" 68 | }, 69 | "runtimePlatform": "R version 4.5.1 (2025-06-13)", 70 | "version": "0.3.0.9000" 71 | }, 72 | { 73 | "id": "https://doi.org/10.32614/CRAN.package.rJavaEnv", 74 | "type": "SoftwareSourceCode", 75 | "author": [ 76 | { 77 | "id": "https://orcid.org/0000-0001-6690-5345", 78 | "type": "Person", 79 | "email": "kotov.egor@gmail.com", 80 | "familyName": "Kotov", 81 | "givenName": "Egor" 82 | }, 83 | { 84 | "id": "https://orcid.org/0000-0002-6232-7530", 85 | "type": "Person", 86 | "email": "chainsawtiney@gmail.com", 87 | "familyName": "Chan", 88 | "givenName": "Chung-hong" 89 | } 90 | ], 91 | "name": "rJavaEnv: Java Environments for R Projects" 92 | } 93 | ] 94 | } 95 | -------------------------------------------------------------------------------- /NEWS.md: -------------------------------------------------------------------------------- 1 | # rJavaEnv (development version) 2 | 3 | ## New features 4 | 5 | - Linux support. On Linux, `libjvm.so` location is automatically detected and force-loaded via `dyn.load()`. Thanks to that, `rJava` and any depenent R packages can be installed and loaded, if repositories with pre-built packages, such as `Posit Package Manager`, is used or if you build `rJava` from source, see the `java_build_env_set()` function. 6 | 7 | - New function `java_build_env_set()` that sets the environment (either temporarily in the current session or in `./.Rprofile` file of the current working directory) to build `rJava` from source on `macOS`, `Linux` and `Windows` platforms. It uses the current value of `JAVA_HOME` environment variable by default, so that it is more convenient to use after `java_quick_install()` or `use_java()` commands. After running `java_build_env_set()`, users can install `rJava` from source with `install.packages("rJava", type = "source")` without any additional configuration. However, users will still need some system dependencies, e.g. on Linux they will need: libpcre2-dev, libdeflate-dev, libzstd-dev, liblzma-dev, libbz2-dev, zlib1g-dev, libicu-dev. A system message with a suggested `apt-get` command is printed. On Windows, `Rtools` must be installed. On `macOS`, `Xcode Command Line Tools` must be installed. See the new vignette `Install 'rJava' from source` for more details. 8 | 9 | - New function `java_get_home()` to get currently set `JAVA_HOME`. This is just a shortcut to `Sys.getenv("JAVA_HOME")`, as it is faster to type and can be even faster then used with autocomplete. 10 | 11 | ## Improvements 12 | 13 | - Download progress printing in `java_download()` respects the `quiet` argument now (internally passing the value to `curl::curl_download()`). 14 | 15 | - More robust Java version detection in `java_check_version_cmd()`. 16 | 17 | - `java_quick_install()` now also invisibly returns the path to `JAVA_HOME`. 18 | 19 | - Added `{rlang}` as a dependency, as `{cli}` uses it anyway for the functions that we use in `{rJavaEnv}`, but does not declare it as a dependency. Therefore this previously might have caused annoyances to the users, as after installing `{rJavaEnv}` they could not use any of the functions until they installed `{rlang}` manually. 20 | 21 | # rJavaEnv 0.3.0 22 | 23 | ## New features 24 | 25 | - `Java` version (currently still only for `Amazon Corretto`) is now determined dynamically using the official GitHub `json` with releases, so when new `Java` version becomes available, you will not be depenent on `rJavaEnv` to be updated. As a fallback, versions up to 24 are hardcoded. 26 | 27 | - Added `force` argument to `java_download()`. When set to `TRUE`, allows to overwrite the distribution file if it already exist in the cache. This save the trouble of deleting the cached file with `java_clear()` before re-downloading. 28 | 29 | - Added a new function `java_valid_versions()` allows to retrieve a list of all available `Java` versions for the current automatically detected OS and CPU architecture, or user-specified platform and architecture. 30 | 31 | ## Improvements 32 | 33 | - Better command line `Java` detection (thanks to Jonas Lieth) 34 | 35 | - Test coverage is now 7.2% 36 | 37 | # rJavaEnv 0.2.2 (2024-09-13) 38 | 39 | * Hot fix: improve robustness of setting `Java` environment in the current session with either `use_java()` or `java_quick_install()`. See bug fix below. 40 | 41 | * Bug fix: Setting Java environment via `rJava::.jniInitialized()` rendered impossible changing Java version for `rJava`-dependent packages, because it somehow pre-initialised `rJava` 42 | 43 | # rJavaEnv 0.2.1 (2024-09-03) 44 | 45 | * Documentation and description clean-up 46 | 47 | # rJavaEnv 0.2.0 (2024-08-28) 48 | 49 | * Breaking change: `java_check_version_cmd()` and `java_check_version_rjava()` now return detected `Java` version instead of `TRUE`/`FALSE` 50 | 51 | * New function `use_java()` to download, install and set `Java` from cache for the current sesssion, without touching the current project/working directory. This is intended for use with `targets` and `callr`. 52 | 53 | * New vignette on using the package with `targets' and 'callr` 54 | 55 | * Updated documentation with clearer instructions on cache folder cleanup before removing the package 56 | 57 | * Depends on `R` > 4.0 to be able to write to the package cache directory without extra user warning. Cache cleanup and management functions are provided, as well as the documentation in both README and vignettes. 58 | 59 | # rJavaEnv 0.1.2 60 | 61 | * Fixed broken links in README.md 62 | 63 | # rJavaEnv 0.1.1 64 | 65 | * Improved documentation 66 | 67 | * Better handling of cache directory 68 | 69 | * Bug fixes and changes to address CRAN reviewer's comments to the first submission 70 | 71 | # rJavaEnv 0.1.0 72 | 73 | * Initial release 74 | -------------------------------------------------------------------------------- /tests/testthat/test-java_download-mocked.R: -------------------------------------------------------------------------------- 1 | # Mocked unit tests for java_download() 2 | test_that("java_download handles successful download and checksum", { 3 | local_cache_path <- withr::local_tempdir() 4 | 5 | # MOCK THE SLOW NETWORK CALL 6 | local_mocked_bindings( 7 | java_valid_versions = function(...) c("8", "11", "17", "21") 8 | ) 9 | 10 | local_mocked_bindings( 11 | curl_download = function(url, destfile, ...) { 12 | if (grepl("\\.md5$", destfile)) { 13 | writeLines("dummymd5checksum", destfile) 14 | } else { 15 | writeLines("dummy content", destfile) 16 | } 17 | }, 18 | .package = "curl" 19 | ) 20 | 21 | local_mocked_bindings( 22 | md5sum = function(files) setNames("dummymd5checksum", files), 23 | .package = "tools" 24 | ) 25 | 26 | expect_silent( 27 | result_path <- java_download( 28 | version = "21", 29 | cache_path = local_cache_path, 30 | quiet = TRUE 31 | ) 32 | ) 33 | expect_true(file.exists(result_path)) 34 | }) 35 | 36 | test_that("java_download aborts on MD5 checksum mismatch", { 37 | local_cache_path <- withr::local_tempdir() 38 | 39 | # MOCK THE SLOW NETWORK CALL 40 | local_mocked_bindings( 41 | java_valid_versions = function(...) c("8", "11", "17", "21") 42 | ) 43 | 44 | local_mocked_bindings( 45 | curl_download = function(url, destfile, ...) { 46 | if (grepl("\\.md5$", destfile)) { 47 | writeLines("expected_checksum", destfile) 48 | } else { 49 | writeLines("some content", destfile) 50 | } 51 | }, 52 | .package = "curl" 53 | ) 54 | 55 | local_mocked_bindings( 56 | md5sum = function(files) setNames("actual_checksum_mismatch", files), 57 | .package = "tools" 58 | ) 59 | 60 | expect_error( 61 | java_download(version = "21", cache_path = local_cache_path, quiet = TRUE), 62 | "MD5 checksum mismatch" 63 | ) 64 | }) 65 | 66 | test_that("java_download skips download if file exists and force is FALSE", { 67 | local_cache_path <- withr::local_tempdir() 68 | dest_dir <- file.path(local_cache_path, "distrib") 69 | dir.create(dest_dir, recursive = TRUE) 70 | 71 | # MOCK THE SLOW NETWORK CALL 72 | local_mocked_bindings( 73 | java_valid_versions = function(...) c("8", "11", "17", "21") 74 | ) 75 | 76 | platform <- platform_detect()$os 77 | arch <- platform_detect()$arch 78 | java_urls <- java_urls_load() 79 | url_template <- java_urls[["Corretto"]][[platform]][[arch]] 80 | url <- gsub("\\{version\\}", "21", url_template) 81 | expected_file_path <- file.path(dest_dir, basename(url)) 82 | file.create(expected_file_path) 83 | 84 | local_mocked_bindings( 85 | curl_download = function(...) { 86 | stop("curl_download should not have been called!") 87 | }, 88 | .package = "curl" 89 | ) 90 | 91 | result <- java_download( 92 | version = "21", 93 | cache_path = local_cache_path, 94 | platform = platform, 95 | arch = arch, 96 | quiet = TRUE, 97 | force = FALSE 98 | ) 99 | 100 | expect_equal(normalizePath(result), normalizePath(expected_file_path)) 101 | }) 102 | 103 | 104 | test_that("java_download overwrites if file exists and force is TRUE", { 105 | local_cache_path <- withr::local_tempdir() 106 | dest_dir <- file.path(local_cache_path, "distrib") 107 | dir.create(dest_dir, recursive = TRUE) 108 | 109 | # MOCK THE SLOW NETWORK CALL 110 | local_mocked_bindings( 111 | java_valid_versions = function(...) c("8", "11", "17", "21") 112 | ) 113 | 114 | platform <- platform_detect()$os 115 | arch <- platform_detect()$arch 116 | java_urls <- java_urls_load() 117 | url_template <- java_urls[["Corretto"]][[platform]][[arch]] 118 | url <- gsub("\\{version\\}", "21", url_template) 119 | expected_file_path <- file.path(dest_dir, basename(url)) 120 | writeLines("old content", expected_file_path) 121 | 122 | curl_call_count <- 0 123 | local_mocked_bindings( 124 | curl_download = function(url, destfile, ...) { 125 | curl_call_count <<- curl_call_count + 1 126 | if (grepl("\\.md5$", destfile)) { 127 | writeLines("new_checksum", destfile) 128 | } else { 129 | writeLines("new content", destfile) 130 | } 131 | }, 132 | .package = "curl" 133 | ) 134 | 135 | local_mocked_bindings( 136 | md5sum = function(files) setNames("new_checksum", files), 137 | .package = "tools" 138 | ) 139 | 140 | java_download( 141 | version = "21", 142 | cache_path = local_cache_path, 143 | platform = platform, 144 | arch = arch, 145 | quiet = TRUE, 146 | force = TRUE 147 | ) 148 | 149 | expect_equal(curl_call_count, 2) 150 | expect_equal(readLines(expected_file_path), "new content") 151 | }) 152 | -------------------------------------------------------------------------------- /tests/testthat/test-internal_utilities_version.R: -------------------------------------------------------------------------------- 1 | # Unit tests for parsing Java version output 2 | # These tests focus on verifying that Java version strings are parsed correctly 3 | 4 | test_that("java_check_version_system regex extracts OpenJDK 17 version correctly", { 5 | # We test the regex parsing logic that java_check_version_system uses 6 | # by simulating what it does with the java version output 7 | 8 | java_ver_string <- 'openjdk version "17.0.1" 2021-10-19' 9 | matches <- regexec( 10 | '(openjdk|java) (version )?(\\\")?([0-9]{1,2})', 11 | java_ver_string 12 | ) 13 | major_java_ver <- regmatches(java_ver_string, matches)[[1]][5] 14 | 15 | expect_equal(major_java_ver, "17") 16 | }) 17 | 18 | test_that("java_check_version_system regex extracts Java 11 version correctly", { 19 | java_ver_string <- 'openjdk version "11.0.13" 2021-10-19' 20 | matches <- regexec( 21 | '(openjdk|java) (version )?(\\\")?([0-9]{1,2})', 22 | java_ver_string 23 | ) 24 | major_java_ver <- regmatches(java_ver_string, matches)[[1]][5] 25 | 26 | expect_equal(major_java_ver, "11") 27 | }) 28 | 29 | test_that("java_check_version_system regex extracts Java 8 version correctly", { 30 | java_ver_string <- 'java version "1.8.0_292"' 31 | matches <- regexec( 32 | '(openjdk|java) (version )?(\\\")?([0-9]{1,2})', 33 | java_ver_string 34 | ) 35 | major_java_ver <- regmatches(java_ver_string, matches)[[1]][5] 36 | 37 | # Java 8 returns "1", which should be converted to "8" 38 | expect_equal(major_java_ver, "1") 39 | 40 | # The function then converts "1" to "8" 41 | if (major_java_ver == "1") { 42 | major_java_ver <- "8" 43 | } 44 | expect_equal(major_java_ver, "8") 45 | }) 46 | 47 | test_that("java_check_version_system regex extracts Java 21 version correctly", { 48 | java_ver_string <- 'openjdk version "21.0.1" 2023-10-17' 49 | matches <- regexec( 50 | '(openjdk|java) (version )?(\\\")?([0-9]{1,2})', 51 | java_ver_string 52 | ) 53 | major_java_ver <- regmatches(java_ver_string, matches)[[1]][5] 54 | 55 | expect_equal(major_java_ver, "21") 56 | }) 57 | 58 | test_that("java_version_check_rscript output parsing for version 17", { 59 | # Test the parsing of output from java_version_check_rscript 60 | output <- c("rJava and other rJava/Java-based packages will use Java version: \"17.0.1\"") 61 | cleaned_output <- cli::ansi_strip(output[1]) 62 | major_java_ver <- sub('.*version: \\"([0-9]+).*', '\\1', cleaned_output) 63 | 64 | if (major_java_ver == "1") { 65 | major_java_ver <- "8" 66 | } 67 | 68 | expect_equal(major_java_ver, "17") 69 | }) 70 | 71 | test_that("java_version_check_rscript output parsing for version 1.8", { 72 | output <- c("rJava and other rJava/Java-based packages will use Java version: \"1.8.0\"") 73 | cleaned_output <- cli::ansi_strip(output[1]) 74 | major_java_ver <- sub('.*version: \\"([0-9]+).*', '\\1', cleaned_output) 75 | 76 | # For Java 8, version string starts with "1" 77 | expect_equal(major_java_ver, "1") 78 | 79 | if (major_java_ver == "1") { 80 | major_java_ver <- "8" 81 | } 82 | expect_equal(major_java_ver, "8") 83 | }) 84 | 85 | test_that("java_check_version_rjava silent behavior", { 86 | # This test verifies that when rJava is not installed, the function returns FALSE 87 | local_mocked_bindings( 88 | find.package = function(package, quiet = TRUE) { 89 | # Simulate rJava not being found 90 | character(0) 91 | }, 92 | .package = "base" 93 | ) 94 | 95 | result <- java_check_version_rjava(java_home = "/mock/java", quiet = TRUE) 96 | expect_false(result) 97 | }) 98 | 99 | test_that("java_check_version_cmd with quiet = TRUE doesn't throw", { 100 | # When JAVA_HOME is not set and we don't provide a java_home 101 | withr::local_envvar(c("JAVA_HOME" = NA)) 102 | 103 | result <- java_check_version_cmd(java_home = NULL, quiet = TRUE) 104 | # Should return FALSE gracefully without errors 105 | expect_false(result) 106 | }) 107 | 108 | test_that("Sys.which mock works correctly", { 109 | # Verify our mocking approach works 110 | local_mocked_bindings( 111 | Sys.which = function(x) { 112 | if (x == "java") "/usr/bin/java" else "" 113 | }, 114 | .package = "base" 115 | ) 116 | 117 | expect_equal(Sys.which("java"), "/usr/bin/java") 118 | expect_equal(Sys.which("nonexistent"), "") 119 | }) 120 | 121 | test_that("system2 mock can return version output", { 122 | # Verify our mocking approach works for system2 123 | local_mocked_bindings( 124 | system2 = function(cmd, args = NULL, ...) { 125 | c('openjdk version "11.0.1"') 126 | }, 127 | .package = "base" 128 | ) 129 | 130 | result <- system2("java", args = "-version") 131 | expect_equal(result[1], 'openjdk version "11.0.1"') 132 | }) 133 | -------------------------------------------------------------------------------- /R/java_manage_installed_cache.R: -------------------------------------------------------------------------------- 1 | #' List the contents of the Java installations cache folder 2 | #' 3 | #' @param output The format of the output: "data.frame" or "vector". Defaults to "data.frame". 4 | #' @param cache_path The cache directory to list. Defaults to the user-specific data directory. Not recommended to change. 5 | #' @inheritParams global_quiet_param 6 | #' @return A data frame or character vector with the contents of the cache directory. 7 | #' @keywords internal 8 | java_list_installed_cache <- function( 9 | output = c("data.frame", "vector"), 10 | quiet = TRUE, 11 | cache_path = getOption("rJavaEnv.cache_path") 12 | ) { 13 | output <- match.arg(output) 14 | installed_cache_path <- file.path(cache_path, "installed") 15 | 16 | if (!dir.exists(installed_cache_path)) { 17 | cli::cli_alert_danger("No Java distributions have been installed yet.") 18 | return(character(0)) 19 | } 20 | 21 | if (!quiet) cli::cli_inform("Contents of the Java installations cache folder:") 22 | 23 | # List directories up to the specified depth 24 | java_paths <- list.dirs(installed_cache_path, recursive = TRUE, full.names = TRUE) 25 | 26 | java_paths <- java_paths[vapply(java_paths, function(x) { 27 | length(strsplit(x, .Platform$file.sep)[[1]]) == length(strsplit(installed_cache_path, .Platform$file.sep)[[1]]) + 3 28 | }, logical(1))] 29 | 30 | if (length(java_paths) == 0) { 31 | return(character(0)) 32 | } 33 | 34 | if (output == "vector") { 35 | return(unname(java_paths)) 36 | } else if (output == "data.frame") { 37 | java_info <- lapply(java_paths, function(path) { 38 | parts <- strsplit(path, .Platform$file.sep)[[1]] 39 | parts <- parts[(length(parts) - 2):length(parts)] 40 | names(parts) <- c("platform", "arch", "version") 41 | parts <- c(path = path, parts) 42 | return(parts) 43 | }) 44 | java_info_df <- do.call(rbind, lapply(java_info, function(info) as.data.frame(t(info), stringsAsFactors = FALSE))) 45 | rownames(java_info_df) <- NULL 46 | return(java_info_df) 47 | } 48 | } 49 | 50 | #' Clear the Java installations cache folder 51 | #' 52 | #' @param cache_path The cache directory to clear. Defaults to the user-specific data directory. 53 | #' @param check Whether to list the contents of the cache directory before clearing it. Defaults to TRUE. 54 | #' @param delete_all Whether to delete all installations without prompting. Defaults to FALSE. 55 | #' @return A message indicating whether the cache was cleared or not. 56 | #' 57 | #' @keywords internal 58 | java_clear_installed_cache <- function( 59 | check = TRUE, 60 | delete_all = FALSE, 61 | cache_path = getOption("rJavaEnv.cache_path") 62 | ) { 63 | rje_consent_check() 64 | 65 | installed_cache_path <- file.path(cache_path, "installed") 66 | 67 | if (!dir.exists(installed_cache_path)) { 68 | cli::cli_inform("Java installations cache is already empty.") 69 | return(invisible(NULL)) 70 | } 71 | 72 | if (delete_all) { 73 | unlink(file.path(installed_cache_path, "*"), recursive = TRUE) 74 | cli::cli_inform("Java installations cache cleared.") 75 | return(invisible(NULL)) 76 | } 77 | 78 | if (check) { 79 | installations <- java_list_installed_cache(cache_path, quiet = FALSE, output = "vector") 80 | if (length(installations) == 0) { 81 | cli::cli_inform("No Java installations found to clear.") 82 | return(invisible(NULL)) 83 | } 84 | 85 | cli::cli_alert_info("Existing Java installations:") 86 | for (i in seq_along(installations)) { 87 | cli::cli_inform("{i}: {installations[i]}") 88 | } 89 | 90 | cli::cli_alert_info("Enter the number of the installation to delete, 'all' to delete all, or '0' or any other character to cancel:") 91 | response <- readline() 92 | 93 | if (tolower(response) == "all") { 94 | unlink(file.path(installed_cache_path, "*"), recursive = TRUE) 95 | cli::cli_inform("All Java installations have been cleared.") 96 | } else { 97 | choice <- suppressWarnings(as.integer(response)) 98 | if (is.na(choice) || choice == 0 || choice > length(installations)) { 99 | cli::cli_inform("No installations were cleared.") 100 | } else { 101 | unlink(installations[choice], recursive = TRUE) 102 | cli::cli_inform("Java installation {choice} has been cleared.") 103 | } 104 | } 105 | } else { 106 | cli::cli_alert_info("Are you sure you want to clear the Java installations cache? (yes/no)") 107 | response <- readline() 108 | if (tolower(response) == "yes") { 109 | unlink(file.path(installed_cache_path, "*"), recursive = TRUE) 110 | cli::cli_inform("Java installations cache cleared.") 111 | } else { 112 | cli::cli_inform("Java installations cache was not cleared.") 113 | } 114 | } 115 | 116 | return(invisible(NULL)) 117 | } 118 | -------------------------------------------------------------------------------- /vignettes/data-for-vignettes/rJava_dlstats.csv: -------------------------------------------------------------------------------- 1 | start;end;downloads;package 2 | 2014-01-01;2014-01-31;21206;rJava 3 | 2014-02-01;2014-02-28;20698;rJava 4 | 2014-03-01;2014-03-31;22972;rJava 5 | 2014-04-01;2014-04-30;30754;rJava 6 | 2014-05-01;2014-05-31;27456;rJava 7 | 2014-06-01;2014-06-30;79683;rJava 8 | 2014-07-01;2014-07-31;68628;rJava 9 | 2014-08-01;2014-08-31;53476;rJava 10 | 2014-09-01;2014-09-30;43039;rJava 11 | 2014-10-01;2014-10-31;42962;rJava 12 | 2014-11-01;2014-11-30;44860;rJava 13 | 2014-12-01;2014-12-31;43873;rJava 14 | 2015-01-01;2015-01-31;47579;rJava 15 | 2015-02-01;2015-02-28;45369;rJava 16 | 2015-03-01;2015-03-31;55592;rJava 17 | 2015-04-01;2015-04-30;59371;rJava 18 | 2015-05-01;2015-05-31;58762;rJava 19 | 2015-06-01;2015-06-30;70761;rJava 20 | 2015-07-01;2015-07-31;77745;rJava 21 | 2015-08-01;2015-08-31;93620;rJava 22 | 2015-09-01;2015-09-30;98996;rJava 23 | 2015-10-01;2015-10-31;105546;rJava 24 | 2015-11-01;2015-11-30;113165;rJava 25 | 2015-12-01;2015-12-31;92368;rJava 26 | 2016-01-01;2016-01-31;116670;rJava 27 | 2016-02-01;2016-02-29;105817;rJava 28 | 2016-03-01;2016-03-31;104942;rJava 29 | 2016-04-01;2016-04-30;91556;rJava 30 | 2016-05-01;2016-05-31;118943;rJava 31 | 2016-06-01;2016-06-30;117215;rJava 32 | 2016-07-01;2016-07-31;106574;rJava 33 | 2016-08-01;2016-08-31;108471;rJava 34 | 2016-09-01;2016-09-30;120946;rJava 35 | 2016-10-01;2016-10-31;134884;rJava 36 | 2016-11-01;2016-11-30;147999;rJava 37 | 2016-12-01;2016-12-31;118118;rJava 38 | 2017-01-01;2017-01-31;123550;rJava 39 | 2017-02-01;2017-02-28;138221;rJava 40 | 2017-03-01;2017-03-31;162562;rJava 41 | 2017-04-01;2017-04-30;153474;rJava 42 | 2017-05-01;2017-05-31;164487;rJava 43 | 2017-06-01;2017-06-30;153560;rJava 44 | 2017-07-01;2017-07-31;143023;rJava 45 | 2017-08-01;2017-08-31;128602;rJava 46 | 2017-09-01;2017-09-30;140409;rJava 47 | 2017-10-01;2017-10-31;177898;rJava 48 | 2017-11-01;2017-11-30;193822;rJava 49 | 2017-12-01;2017-12-31;155733;rJava 50 | 2018-01-01;2018-01-31;165852;rJava 51 | 2018-02-01;2018-02-28;147561;rJava 52 | 2018-03-01;2018-03-31;159540;rJava 53 | 2018-04-01;2018-04-30;159216;rJava 54 | 2018-05-01;2018-05-31;162024;rJava 55 | 2018-06-01;2018-06-30;177379;rJava 56 | 2018-07-01;2018-07-31;158981;rJava 57 | 2018-08-01;2018-08-31;146357;rJava 58 | 2018-09-01;2018-09-30;178890;rJava 59 | 2018-10-01;2018-10-31;222617;rJava 60 | 2018-11-01;2018-11-30;185174;rJava 61 | 2018-12-01;2018-12-31;140504;rJava 62 | 2019-01-01;2019-01-31;171958;rJava 63 | 2019-02-01;2019-02-28;157729;rJava 64 | 2019-03-01;2019-03-31;180216;rJava 65 | 2019-04-01;2019-04-30;226195;rJava 66 | 2019-05-01;2019-05-31;234531;rJava 67 | 2019-06-01;2019-06-30;187438;rJava 68 | 2019-07-01;2019-07-31;193139;rJava 69 | 2019-08-01;2019-08-31;181692;rJava 70 | 2019-09-01;2019-09-30;218554;rJava 71 | 2019-10-01;2019-10-31;224568;rJava 72 | 2019-11-01;2019-11-30;211361;rJava 73 | 2019-12-01;2019-12-31;191373;rJava 74 | 2020-01-01;2020-01-31;188198;rJava 75 | 2020-02-01;2020-02-29;177194;rJava 76 | 2020-03-01;2020-03-31;278531;rJava 77 | 2020-04-01;2020-04-30;235117;rJava 78 | 2020-05-01;2020-05-31;216240;rJava 79 | 2020-06-01;2020-06-30;209888;rJava 80 | 2020-07-01;2020-07-31;234058;rJava 81 | 2020-08-01;2020-08-31;194163;rJava 82 | 2020-09-01;2020-09-30;222106;rJava 83 | 2020-10-01;2020-10-31;241788;rJava 84 | 2020-11-01;2020-11-30;215793;rJava 85 | 2020-12-01;2020-12-31;180348;rJava 86 | 2021-01-01;2021-01-31;168354;rJava 87 | 2021-02-01;2021-02-28;155617;rJava 88 | 2021-03-01;2021-03-31;183883;rJava 89 | 2021-04-01;2021-04-30;178903;rJava 90 | 2021-05-01;2021-05-31;178902;rJava 91 | 2021-06-01;2021-06-30;173072;rJava 92 | 2021-07-01;2021-07-31;141658;rJava 93 | 2021-08-01;2021-08-31;170959;rJava 94 | 2021-09-01;2021-09-30;254287;rJava 95 | 2021-10-01;2021-10-31;274728;rJava 96 | 2021-11-01;2021-11-30;223077;rJava 97 | 2021-12-01;2021-12-31;210562;rJava 98 | 2022-01-01;2022-01-31;192186;rJava 99 | 2022-02-01;2022-02-28;154710;rJava 100 | 2022-03-01;2022-03-31;255524;rJava 101 | 2022-04-01;2022-04-30;571935;rJava 102 | 2022-05-01;2022-05-31;852808;rJava 103 | 2022-06-01;2022-06-30;725289;rJava 104 | 2022-07-01;2022-07-31;639130;rJava 105 | 2022-08-01;2022-08-31;712597;rJava 106 | 2022-09-01;2022-09-30;633770;rJava 107 | 2022-10-01;2022-10-31;433795;rJava 108 | 2022-11-01;2022-11-30;337744;rJava 109 | 2022-12-01;2022-12-31;319878;rJava 110 | 2023-01-01;2023-01-31;403060;rJava 111 | 2023-02-01;2023-02-28;361259;rJava 112 | 2023-03-01;2023-03-31;475392;rJava 113 | 2023-04-01;2023-04-30;442267;rJava 114 | 2023-05-01;2023-05-31;400598;rJava 115 | 2023-06-01;2023-06-30;318804;rJava 116 | 2023-07-01;2023-07-31;176955;rJava 117 | 2023-08-01;2023-08-31;139944;rJava 118 | 2023-09-01;2023-09-30;137718;rJava 119 | 2023-10-01;2023-10-31;280514;rJava 120 | 2023-11-01;2023-11-30;285721;rJava 121 | 2023-12-01;2023-12-31;302552;rJava 122 | 2024-01-01;2024-01-31;328002;rJava 123 | 2024-02-01;2024-02-29;228557;rJava 124 | 2024-03-01;2024-03-31;194654;rJava 125 | 2024-04-01;2024-04-30;187262;rJava 126 | 2024-05-01;2024-05-31;198761;rJava 127 | 2024-06-01;2024-06-30;169666;rJava 128 | 2024-07-01;2024-07-31;148789;rJava 129 | 2024-08-01;2024-08-31;135307;rJava 130 | 2024-09-01;2024-09-26;107725;rJava 131 | -------------------------------------------------------------------------------- /R/java_manage_project.R: -------------------------------------------------------------------------------- 1 | #' List the Java versions symlinked in the current project 2 | #' 3 | #' @param project_path The project directory to list. Defaults to the current working directory. 4 | #' @param output The format of the output: "data.frame" or "vector". Defaults to "data.frame". 5 | #' @inheritParams global_quiet_param 6 | #' @return A data frame or character vector with the symlinked Java versions in the project directory. 7 | #' @keywords internal 8 | java_list_in_project <- function( 9 | project_path = NULL, 10 | output = c("data.frame", "vector"), 11 | quiet = TRUE 12 | ) { 13 | 14 | # Resolve the project path 15 | # consistent with renv behavior 16 | # https://github.com/rstudio/renv/blob/d6bced36afa0ad56719ca78be6773e9b4bbb078f/R/init.R#L69-L86 17 | project_path <- ifelse(is.null(project_path), getwd(), project_path) 18 | 19 | output <- match.arg(output) 20 | java_symlink_dir <- file.path(project_path, "rjavaenv") 21 | 22 | if (!dir.exists(java_symlink_dir)) { 23 | cli::cli_alert_danger("No Java has been installed in the project.") 24 | return(invisible(NULL)) 25 | } 26 | 27 | 28 | # List directories up to the specified depth 29 | java_paths <- list.dirs(java_symlink_dir, recursive = TRUE, full.names = TRUE) 30 | 31 | java_paths <- java_paths[vapply(java_paths, function(x) { 32 | length(strsplit(x, .Platform$file.sep)[[1]]) == length(strsplit(java_symlink_dir, .Platform$file.sep)[[1]]) + 3 33 | }, logical(1))] 34 | 35 | if (length(java_paths) == 0) { 36 | cli::cli_alert_danger("No Java has been installed in the project.") 37 | return(invisible(NULL)) 38 | } 39 | 40 | if (!quiet) cli::cli_inform("Contents of the Java symlinks in the project folder:") 41 | 42 | if (output == "vector") { 43 | return(unname(java_paths)) 44 | } else if (output == "data.frame") { 45 | java_info <- lapply(java_paths, function(path) { 46 | parts <- strsplit(path, .Platform$file.sep)[[1]] 47 | parts <- parts[(length(parts) - 2):length(parts)] 48 | names(parts) <- c("platform", "arch", "version") 49 | parts <- c(path = path, parts) 50 | return(parts) 51 | }) 52 | java_info_df <- do.call(rbind, lapply(java_info, function(info) as.data.frame(t(info), stringsAsFactors = FALSE))) 53 | rownames(java_info_df) <- NULL 54 | return(java_info_df) 55 | } 56 | } 57 | 58 | #' Clear the Java versions symlinked in the current project 59 | #' 60 | #' @param project_path The project directory to clear. Defaults to the current working directory. 61 | #' @param check Whether to list the symlinked Java versions before clearing them. Defaults to TRUE. 62 | #' @param delete_all Whether to delete all symlinks without prompting. Defaults to FALSE. 63 | #' @return A message indicating whether the symlinks were cleared or not. 64 | #' 65 | #' @keywords internal 66 | java_clear_in_project <- function( 67 | project_path = NULL, 68 | check = TRUE, 69 | delete_all = FALSE 70 | ) { 71 | rje_consent_check() 72 | 73 | # Resolve the project path 74 | # consistent with renv behavior 75 | # https://github.com/rstudio/renv/blob/d6bced36afa0ad56719ca78be6773e9b4bbb078f/R/init.R#L69-L86 76 | project_path <- ifelse(is.null(project_path), getwd(), project_path) 77 | 78 | java_symlink_dir <- file.path(project_path, "rjavaenv") 79 | 80 | if (!dir.exists(java_symlink_dir)) { 81 | cli::cli_inform("Java symlink directory does not exist in the project.") 82 | return(invisible(NULL)) 83 | } 84 | 85 | if (delete_all) { 86 | unlink(file.path(java_symlink_dir), recursive = TRUE) 87 | cli::cli_inform("All Java symlinks in the project have been cleared.") 88 | return(invisible(NULL)) 89 | } 90 | 91 | if (check) { 92 | symlinks <- java_list_in_project(project_path = project_path, output = "vector") 93 | if (length(symlinks) == 0) { 94 | cli::cli_inform("No Java symlinks found to clear.") 95 | return(invisible(NULL)) 96 | } 97 | 98 | cli::cli_alert_info("Existing Java symlinks:") 99 | for (i in seq_along(symlinks)) { 100 | cli::cli_inform("{i}: {symlinks[i]}") 101 | } 102 | 103 | cli::cli_alert_info("Enter the number of the symlink to delete, 'all' to delete all, or '0' or any other character to cancel:") 104 | response <- readline() 105 | 106 | if (tolower(response) == "all") { 107 | unlink(file.path(java_symlink_dir, "*"), recursive = TRUE) 108 | cli::cli_inform("All Java symlinks in the project have been cleared.") 109 | } else { 110 | choice <- suppressWarnings(as.integer(response)) 111 | if (is.na(choice) || choice == 0 || choice > length(symlinks)) { 112 | cli::cli_inform("No symlinks were cleared.") 113 | } else { 114 | unlink(symlinks[choice], recursive = TRUE) 115 | cli::cli_inform("Java symlink {choice} has been cleared.") 116 | } 117 | } 118 | } else { 119 | cli::cli_alert_info("Are you sure you want to clear all Java symlinks in the project? (yes/no)") 120 | response <- readline() 121 | if (tolower(response) == "yes") { 122 | unlink(file.path(java_symlink_dir, "*"), recursive = TRUE) 123 | cli::cli_inform("All Java symlinks in the project have been cleared.") 124 | } else { 125 | cli::cli_inform("No Java symlinks were cleared.") 126 | } 127 | } 128 | 129 | return(invisible(NULL)) 130 | } 131 | -------------------------------------------------------------------------------- /vignettes/data-for-vignettes/ggplot2_dlstats.csv: -------------------------------------------------------------------------------- 1 | start;end;downloads;package 2 | 2014-01-01;2014-01-31;33457;ggplot2 3 | 2014-02-01;2014-02-28;36817;ggplot2 4 | 2014-03-01;2014-03-31;47652;ggplot2 5 | 2014-04-01;2014-04-30;55404;ggplot2 6 | 2014-05-01;2014-05-31;54371;ggplot2 7 | 2014-06-01;2014-06-30;201761;ggplot2 8 | 2014-07-01;2014-07-31;92133;ggplot2 9 | 2014-08-01;2014-08-31;56890;ggplot2 10 | 2014-09-01;2014-09-30;70136;ggplot2 11 | 2014-10-01;2014-10-31;82817;ggplot2 12 | 2014-11-01;2014-11-30;79063;ggplot2 13 | 2014-12-01;2014-12-31;65079;ggplot2 14 | 2015-01-01;2015-01-31;85349;ggplot2 15 | 2015-02-01;2015-02-28;95591;ggplot2 16 | 2015-03-01;2015-03-31;140066;ggplot2 17 | 2015-04-01;2015-04-30;146008;ggplot2 18 | 2015-05-01;2015-05-31;142558;ggplot2 19 | 2015-06-01;2015-06-30;134730;ggplot2 20 | 2015-07-01;2015-07-31;126061;ggplot2 21 | 2015-08-01;2015-08-31;136617;ggplot2 22 | 2015-09-01;2015-09-30;176111;ggplot2 23 | 2015-10-01;2015-10-31;195243;ggplot2 24 | 2015-11-01;2015-11-30;198381;ggplot2 25 | 2015-12-01;2015-12-31;181234;ggplot2 26 | 2016-01-01;2016-01-31;228779;ggplot2 27 | 2016-02-01;2016-02-29;247028;ggplot2 28 | 2016-03-01;2016-03-31;262481;ggplot2 29 | 2016-04-01;2016-04-30;219765;ggplot2 30 | 2016-05-01;2016-05-31;249214;ggplot2 31 | 2016-06-01;2016-06-30;236981;ggplot2 32 | 2016-07-01;2016-07-31;210707;ggplot2 33 | 2016-08-01;2016-08-31;226941;ggplot2 34 | 2016-09-01;2016-09-30;294401;ggplot2 35 | 2016-10-01;2016-10-31;326941;ggplot2 36 | 2016-11-01;2016-11-30;435630;ggplot2 37 | 2016-12-01;2016-12-31;335209;ggplot2 38 | 2017-01-01;2017-01-31;411301;ggplot2 39 | 2017-02-01;2017-02-28;407285;ggplot2 40 | 2017-03-01;2017-03-31;464633;ggplot2 41 | 2017-04-01;2017-04-30;433774;ggplot2 42 | 2017-05-01;2017-05-31;420708;ggplot2 43 | 2017-06-01;2017-06-30;359623;ggplot2 44 | 2017-07-01;2017-07-31;318111;ggplot2 45 | 2017-08-01;2017-08-31;311367;ggplot2 46 | 2017-09-01;2017-09-30;389654;ggplot2 47 | 2017-10-01;2017-10-31;450465;ggplot2 48 | 2017-11-01;2017-11-30;454752;ggplot2 49 | 2017-12-01;2017-12-31;351634;ggplot2 50 | 2018-01-01;2018-01-31;419372;ggplot2 51 | 2018-02-01;2018-02-28;415838;ggplot2 52 | 2018-03-01;2018-03-31;495357;ggplot2 53 | 2018-04-01;2018-04-30;511879;ggplot2 54 | 2018-05-01;2018-05-31;507604;ggplot2 55 | 2018-06-01;2018-06-30;439156;ggplot2 56 | 2018-07-01;2018-07-31;552553;ggplot2 57 | 2018-08-01;2018-08-31;497218;ggplot2 58 | 2018-09-01;2018-09-30;647281;ggplot2 59 | 2018-10-01;2018-10-31;822873;ggplot2 60 | 2018-11-01;2018-11-30;809889;ggplot2 61 | 2018-12-01;2018-12-31;585313;ggplot2 62 | 2019-01-01;2019-01-31;726400;ggplot2 63 | 2019-02-01;2019-02-28;720326;ggplot2 64 | 2019-03-01;2019-03-31;771832;ggplot2 65 | 2019-04-01;2019-04-30;830500;ggplot2 66 | 2019-05-01;2019-05-31;830059;ggplot2 67 | 2019-06-01;2019-06-30;702976;ggplot2 68 | 2019-07-01;2019-07-31;712857;ggplot2 69 | 2019-08-01;2019-08-31;719862;ggplot2 70 | 2019-09-01;2019-09-30;988740;ggplot2 71 | 2019-10-01;2019-10-31;1058606;ggplot2 72 | 2019-11-01;2019-11-30;958562;ggplot2 73 | 2019-12-01;2019-12-31;869022;ggplot2 74 | 2020-01-01;2020-01-31;990079;ggplot2 75 | 2020-02-01;2020-02-29;1021046;ggplot2 76 | 2020-03-01;2020-03-31;1743064;ggplot2 77 | 2020-04-01;2020-04-30;1788712;ggplot2 78 | 2020-05-01;2020-05-31;1688318;ggplot2 79 | 2020-06-01;2020-06-30;1653368;ggplot2 80 | 2020-07-01;2020-07-31;1455078;ggplot2 81 | 2020-08-01;2020-08-31;1400458;ggplot2 82 | 2020-09-01;2020-09-30;1585801;ggplot2 83 | 2020-10-01;2020-10-31;1696668;ggplot2 84 | 2020-11-01;2020-11-30;1801691;ggplot2 85 | 2020-12-01;2020-12-31;905064;ggplot2 86 | 2021-01-01;2021-01-31;1128155;ggplot2 87 | 2021-02-01;2021-02-28;946051;ggplot2 88 | 2021-03-01;2021-03-31;1851241;ggplot2 89 | 2021-04-01;2021-04-30;1900989;ggplot2 90 | 2021-05-01;2021-05-31;1983929;ggplot2 91 | 2021-06-01;2021-06-30;1957952;ggplot2 92 | 2021-07-01;2021-07-31;1948565;ggplot2 93 | 2021-08-01;2021-08-31;2072506;ggplot2 94 | 2021-09-01;2021-09-30;2971064;ggplot2 95 | 2021-10-01;2021-10-31;3298060;ggplot2 96 | 2021-11-01;2021-11-30;3162372;ggplot2 97 | 2021-12-01;2021-12-31;2376174;ggplot2 98 | 2022-01-01;2022-01-31;2091880;ggplot2 99 | 2022-02-01;2022-02-28;2077216;ggplot2 100 | 2022-03-01;2022-03-31;2422703;ggplot2 101 | 2022-04-01;2022-04-30;2689183;ggplot2 102 | 2022-05-01;2022-05-31;3113536;ggplot2 103 | 2022-06-01;2022-06-30;2849346;ggplot2 104 | 2022-07-01;2022-07-31;2676911;ggplot2 105 | 2022-08-01;2022-08-31;2594350;ggplot2 106 | 2022-09-01;2022-09-30;2754884;ggplot2 107 | 2022-10-01;2022-10-31;2905716;ggplot2 108 | 2022-11-01;2022-11-30;2930801;ggplot2 109 | 2022-12-01;2022-12-31;2351346;ggplot2 110 | 2023-01-01;2023-01-31;2356847;ggplot2 111 | 2023-02-01;2023-02-28;2307038;ggplot2 112 | 2023-03-01;2023-03-31;2484066;ggplot2 113 | 2023-04-01;2023-04-30;1966351;ggplot2 114 | 2023-05-01;2023-05-31;2502717;ggplot2 115 | 2023-06-01;2023-06-30;2507430;ggplot2 116 | 2023-07-01;2023-07-31;2430173;ggplot2 117 | 2023-08-01;2023-08-31;2534005;ggplot2 118 | 2023-09-01;2023-09-30;2655965;ggplot2 119 | 2023-10-01;2023-10-31;2917801;ggplot2 120 | 2023-11-01;2023-11-30;3000819;ggplot2 121 | 2023-12-01;2023-12-31;2225776;ggplot2 122 | 2024-01-01;2024-01-31;2248917;ggplot2 123 | 2024-02-01;2024-02-29;2289545;ggplot2 124 | 2024-03-01;2024-03-31;2469492;ggplot2 125 | 2024-04-01;2024-04-30;1932736;ggplot2 126 | 2024-05-01;2024-05-31;1891742;ggplot2 127 | 2024-06-01;2024-06-30;1599144;ggplot2 128 | 2024-07-01;2024-07-31;1536478;ggplot2 129 | 2024-08-01;2024-08-31;1458005;ggplot2 130 | 2024-09-01;2024-09-26;1329676;ggplot2 131 | -------------------------------------------------------------------------------- /R/java_valid_versions.R: -------------------------------------------------------------------------------- 1 | #' Retrieve Valid Java Versions 2 | #' 3 | #' This function retrieves a list of valid Java versions by querying an appropriate API endpoint based on the chosen distribution. 4 | #' The result is cached for 8 hours to avoid repeated API calls. If the API call fails (for example, due to a lack of internet connectivity), 5 | #' the function falls back to a pre-defined list of Java versions. 6 | #' 7 | #' @inheritParams java_download 8 | #' 9 | #' @param force Logical. If TRUE, forces a fresh API call even if a cached value exists. Defaults to FALSE. 10 | #' 11 | #' @return A character vector of valid Java versions. 12 | #' 13 | #' @examples 14 | #' \dontrun{ 15 | #' # Retrieve valid Java versions (cached if available) using Amazon Corretto endpoint 16 | #' versions <- java_valid_versions() 17 | #' 18 | #' # Force refresh the list of Java versions using the Oracle endpoint 19 | #' versions <- java_valid_versions(distribution = "Corretto", force = TRUE) 20 | #' } 21 | #' 22 | #' @export 23 | #' 24 | java_valid_versions <- function( 25 | distribution = "Corretto", 26 | platform = platform_detect()$os, 27 | arch = platform_detect()$arch, 28 | force = FALSE 29 | ) { 30 | # Define cache expiry time (in hours) 31 | expiry_hours <- 8 32 | 33 | # Retrieve cached values from options 34 | valid_versions_cache <- getOption("rJavaEnv.valid_versions_cache") 35 | valid_versions_timestamp <- getOption("rJavaEnv.valid_versions_timestamp") 36 | 37 | # Return cached value if available and not expired, unless force is TRUE. 38 | if ( 39 | !force && 40 | !is.null(valid_versions_cache) && 41 | !is.null(valid_versions_timestamp) && 42 | as.numeric(difftime( 43 | Sys.time(), 44 | valid_versions_timestamp, 45 | units = "hours" 46 | )) < 47 | expiry_hours 48 | ) { 49 | return(valid_versions_cache) 50 | } 51 | 52 | # Select helper based on distribution value. 53 | new_versions <- switch( 54 | distribution, 55 | # "Oracle" = java_valid_versions_oracle(), 56 | "Corretto" = java_valid_major_versions_corretto( 57 | platform = platform, 58 | arch = arch 59 | ), 60 | stop("Unsupported distribution") 61 | ) 62 | 63 | # Update the cache options with the new values and current timestamp. 64 | options( 65 | rJavaEnv.valid_versions_cache = new_versions, 66 | rJavaEnv.valid_versions_timestamp = Sys.time() 67 | ) 68 | 69 | return(new_versions) 70 | } 71 | 72 | #' Get Available Online Versions of Amazon Corretto 73 | #' 74 | #' This function downloads the latest Amazon Corretto version information from the 75 | #' Corretto GitHub endpoint and returns a data frame with details for all eligible releases. 76 | #' 77 | #' It leverages the existing \code{platform_detect()} function to infer the current operating 78 | #' system and architecture if these are not provided. 79 | #' 80 | #' @param arch Optional character string for the target architecture (e.g., "x64"). 81 | #' If \code{NULL}, it is inferred using \code{platform_detect()}. 82 | #' @param platform Optional character string for the operating system (e.g., "windows", "macos", "linux"). 83 | #' If \code{NULL}, it is inferred using \code{platform_detect()}. 84 | #' @param imageType Optional character string to filter on; defaults to \code{"jdk"}. Can be set to \code{"jre"} for Windows Java Runtime Environment. 85 | #' 86 | #' @return A `character` vector of available major Corretto versions. 87 | #' 88 | #' @keywords internal 89 | #' 90 | java_valid_major_versions_corretto <- function( 91 | arch = NULL, 92 | platform = NULL, 93 | imageType = "jdk" 94 | ) { 95 | # If platform or arch are not provided, detect them using the existing function. 96 | if (is.null(platform) || is.null(arch)) { 97 | plat <- platform_detect(quiet = TRUE) 98 | if (is.null(platform)) platform <- plat$os 99 | if (is.null(arch)) arch <- plat$arch 100 | } 101 | 102 | # URL for the Corretto version information. 103 | availableVersionsUrl <- "https://corretto.github.io/corretto-downloads/latest_links/indexmap_with_checksum.json" 104 | 105 | # Fetch and parse the JSON using httr. 106 | corretto_versions <- tryCatch( 107 | { 108 | json_data <- jsonlite::read_json(availableVersionsUrl) 109 | eligible <- json_data[[platform]][[arch]][[imageType]] 110 | if (is.null(eligible)) { 111 | stop( 112 | "No eligible versions found for the specified platform, architecture, and image type." 113 | ) 114 | } 115 | names(eligible) 116 | }, 117 | error = function(e) { 118 | platform_arch <- paste(platform, arch, sep = "_") 119 | getOption(paste0("rJavaEnv.fallback_valid_versions_", platform_arch)) 120 | } 121 | ) 122 | 123 | corretto_versions <- as.character(sort(as.numeric(corretto_versions))) 124 | return(corretto_versions) 125 | } 126 | 127 | # Helper function for Oracle distribution 128 | # java_valid_versions_oracle <- function() { 129 | # oracle_api_url <- "https://java.oraclecloud.com/javaVersions" 130 | # tryCatch( 131 | # { 132 | # oracle_java_versions <- jsonlite::fromJSON( 133 | # oracle_api_url, 134 | # simplifyDataFrame = TRUE 135 | # ) 136 | # # Combine "8" and "11" with the sorted versions from the API 137 | # c("8", "11", sort(as.character(oracle_java_versions$items$jdkVersion))) 138 | # }, 139 | # error = function(e) { 140 | # # If the API call fails, use the fallback list stored in options. 141 | # getOption("rJavaEnv.fallback_valid_versions_current_platform") 142 | # } 143 | # ) 144 | # } 145 | -------------------------------------------------------------------------------- /tests/testthat/test-java_env_unit.R: -------------------------------------------------------------------------------- 1 | # Unit tests for java_env.R functions 2 | # Tests java_env_set and java_env_unset with mocked system calls 3 | 4 | test_that("java_env_set (session) sets JAVA_HOME in the environment", { 5 | # Mock rje_consent_check to avoid interactive prompts 6 | local_mocked_bindings( 7 | rje_consent_check = function() TRUE, 8 | .package = "rJavaEnv" 9 | ) 10 | 11 | # Mock installed.packages to avoid rJava check 12 | local_mocked_bindings( 13 | installed.packages = function(...) matrix(character(0), nrow = 0, ncol = 2), 14 | .package = "utils" 15 | ) 16 | 17 | # Mock loadedNamespaces to say rJava is not loaded 18 | local_mocked_bindings( 19 | loadedNamespaces = function() character(0), 20 | .package = "base" 21 | ) 22 | 23 | # Mock Sys.info to return non-Linux system 24 | local_mocked_bindings( 25 | Sys.info = function() c(sysname = "Darwin"), 26 | .package = "base" 27 | ) 28 | 29 | java_home_mock <- "/mock/java/home" 30 | 31 | # Use withr to temporarily capture original PATH 32 | withr::with_envvar(c("PATH" = "/usr/bin:/bin"), { 33 | java_env_set(where = "session", java_home = java_home_mock, quiet = TRUE) 34 | 35 | # Check that JAVA_HOME was set 36 | expect_equal(Sys.getenv("JAVA_HOME"), java_home_mock) 37 | # Check that PATH was modified to include java bin dir 38 | expect_true(grepl("/mock/java/home/bin", Sys.getenv("PATH"))) 39 | }) 40 | }) 41 | 42 | test_that("java_env_set (project) writes to .Rprofile", { 43 | proj_dir <- withr::local_tempdir() 44 | 45 | local_mocked_bindings( 46 | rje_consent_check = function() TRUE, 47 | .package = "rJavaEnv" 48 | ) 49 | 50 | local_mocked_bindings( 51 | installed.packages = function(...) matrix(character(0), nrow = 0, ncol = 2), 52 | .package = "utils" 53 | ) 54 | 55 | local_mocked_bindings( 56 | loadedNamespaces = function() character(0), 57 | .package = "base" 58 | ) 59 | 60 | local_mocked_bindings( 61 | Sys.info = function() c(sysname = "Darwin"), 62 | .package = "base" 63 | ) 64 | 65 | java_env_set(where = "project", java_home = "/mock/java", project_path = proj_dir, quiet = TRUE) 66 | 67 | rprof <- file.path(proj_dir, ".Rprofile") 68 | expect_true(file.exists(rprof)) 69 | 70 | content <- readLines(rprof) 71 | # Check that .Rprofile contains the rJavaEnv markers 72 | expect_true(any(grepl("# rJavaEnv begin", content))) 73 | expect_true(any(grepl("# rJavaEnv end", content))) 74 | # Check that it sets JAVA_HOME 75 | expect_true(any(grepl("Sys.setenv\\(JAVA_HOME", content))) 76 | }) 77 | 78 | test_that("java_env_set (both) sets session and project", { 79 | proj_dir <- withr::local_tempdir() 80 | 81 | local_mocked_bindings( 82 | rje_consent_check = function() TRUE, 83 | .package = "rJavaEnv" 84 | ) 85 | 86 | local_mocked_bindings( 87 | installed.packages = function(...) matrix(character(0), nrow = 0, ncol = 2), 88 | .package = "utils" 89 | ) 90 | 91 | local_mocked_bindings( 92 | loadedNamespaces = function() character(0), 93 | .package = "base" 94 | ) 95 | 96 | local_mocked_bindings( 97 | Sys.info = function() c(sysname = "Darwin"), 98 | .package = "base" 99 | ) 100 | 101 | java_home_mock <- "/mock/java" 102 | withr::with_envvar(c("PATH" = "/usr/bin"), { 103 | java_env_set(where = "both", java_home = java_home_mock, project_path = proj_dir, quiet = TRUE) 104 | 105 | # Check .Rprofile was created 106 | rprof <- file.path(proj_dir, ".Rprofile") 107 | expect_true(file.exists(rprof)) 108 | 109 | # Check that session env was set 110 | expect_equal(Sys.getenv("JAVA_HOME"), java_home_mock) 111 | }) 112 | }) 113 | 114 | test_that("java_env_unset removes settings from .Rprofile", { 115 | proj_dir <- withr::local_tempdir() 116 | rprof <- file.path(proj_dir, ".Rprofile") 117 | 118 | # Create a .Rprofile with rJavaEnv markers 119 | writeLines( 120 | c( 121 | "# Some other config", 122 | "# rJavaEnv begin: Manage JAVA_HOME", 123 | "Sys.setenv(JAVA_HOME = '/path/to/java')", 124 | "# rJavaEnv end: Manage JAVA_HOME", 125 | "# More config" 126 | ), 127 | rprof 128 | ) 129 | 130 | local_mocked_bindings( 131 | rje_consent_check = function() TRUE, 132 | .package = "rJavaEnv" 133 | ) 134 | 135 | java_env_unset(project_path = proj_dir, quiet = TRUE) 136 | 137 | content <- readLines(rprof) 138 | # rJavaEnv lines should be removed 139 | expect_false(any(grepl("# rJavaEnv", content))) 140 | # Other content should remain 141 | expect_true(any(grepl("Some other config", content))) 142 | expect_true(any(grepl("More config", content))) 143 | }) 144 | 145 | test_that("java_env_unset handles missing .Rprofile gracefully", { 146 | proj_dir <- withr::local_tempdir() 147 | 148 | local_mocked_bindings( 149 | rje_consent_check = function() TRUE, 150 | .package = "rJavaEnv" 151 | ) 152 | 153 | # Should not error when .Rprofile doesn't exist 154 | expect_silent( 155 | java_env_unset(project_path = proj_dir, quiet = TRUE) 156 | ) 157 | }) 158 | 159 | test_that("java_env_set validates input", { 160 | local_mocked_bindings( 161 | rje_consent_check = function() TRUE, 162 | .package = "rJavaEnv" 163 | ) 164 | 165 | # Should error on invalid 'where' argument 166 | expect_error( 167 | java_env_set(where = "invalid", java_home = "/mock/java"), 168 | "should be one of" 169 | ) 170 | 171 | # Should error on non-string java_home 172 | expect_error( 173 | java_env_set(where = "session", java_home = 123), 174 | "Assertion on 'java_home' failed" 175 | ) 176 | }) 177 | -------------------------------------------------------------------------------- /tests/testthat/test-java_full-cycle-live.R: -------------------------------------------------------------------------------- 1 | test_that("full download, install, check, and clear cycle works for all versions", { 2 | # --- Test Configuration --- 3 | testthat::skip_on_cran() 4 | # Sys.setenv("RUN_JAVA_DOWNLOAD_TESTS" = "TRUE") 5 | # Sys.setenv("RUN_JAVA_DOWNLOAD_TESTS_QUIET" = "FALSE") 6 | # Sys.setenv("RUN_JAVA_DOWNLOAD_TESTS_QUIET" = "TRUE") 7 | # Sys.setenv("RUN_JAVA_DOWNLOAD_TESTS_QUIET_DOWNLOAD" = "FALSE") 8 | # Sys.setenv("RUN_JAVA_DOWNLOAD_TESTS_QUIET_DOWNLOAD" = "TRUE") 9 | skip_if_not( 10 | Sys.getenv("RUN_JAVA_DOWNLOAD_TESTS") == "TRUE", 11 | "Skipping real download test. Set RUN_JAVA_DOWNLOAD_TESTS='TRUE' to run." 12 | ) 13 | if (Sys.getenv("RUN_JAVA_DOWNLOAD_TESTS_QUIET") == "TRUE") { 14 | rj_quiet <- TRUE 15 | } else { 16 | rj_quiet <- FALSE 17 | } 18 | if (Sys.getenv("RUN_JAVA_DOWNLOAD_TESTS_QUIET_DOWNLOAD") == "TRUE") { 19 | rj_dl_quiet <- TRUE 20 | } else { 21 | rj_dl_quiet <- FALSE 22 | } 23 | 24 | # --- 1. Setup a Self-Cleaning Temporary Environment --- 25 | main_temp_dir <- tempfile(pattern = "rJavaEnv-full-test-") 26 | dir.create(main_temp_dir, recursive = TRUE) 27 | 28 | # The on.exit() call is the final safety net, ensuring everything is deleted 29 | # at the end, even if the test or the in-loop java_clear() fails. 30 | on.exit(unlink(main_temp_dir, recursive = TRUE, force = TRUE), add = TRUE) 31 | 32 | temp_cache_dir <- file.path(main_temp_dir, "cache") 33 | temp_project_dir <- file.path(main_temp_dir, "project") 34 | dir.create(temp_cache_dir, recursive = TRUE) 35 | dir.create(temp_project_dir, recursive = TRUE) 36 | 37 | withr::local_options(list( 38 | rJavaEnv.cache_path = temp_cache_dir, 39 | rJavaEnv.consent = TRUE 40 | )) 41 | 42 | # --- 2. Get the list of Java versions to test --- 43 | java_versions <- tryCatch( 44 | { 45 | java_valid_versions(force = TRUE) 46 | }, 47 | error = function(e) { 48 | getOption("rJavaEnv.fallback_valid_versions_current_platform") 49 | } 50 | ) 51 | cli::cli_inform( 52 | "Found {length(java_versions)} Java versions to test: {java_versions}" 53 | ) 54 | 55 | # --- 3. Loop through each version and perform the full workflow --- 56 | for (java_version in java_versions) { 57 | context_info <- paste("Testing Java version:", java_version) 58 | cli::cli_h2(context_info) 59 | 60 | # --- Step A: Download --- 61 | cli::cli_inform("-> Step 1: Downloading Java {java_version}...") 62 | downloaded_file <- java_download( 63 | version = java_version, 64 | quiet = rj_dl_quiet, 65 | force = FALSE, 66 | ) 67 | testthat::expect_true(file.exists(downloaded_file), info = context_info) 68 | 69 | # --- Step B: Install --- 70 | cli::cli_inform("-> Step 2: Installing Java {java_version}...") 71 | java_home_path <- java_install( 72 | java_distrib_path = downloaded_file, 73 | project_path = temp_project_dir, 74 | autoset_java_env = TRUE, 75 | quiet = rj_quiet, 76 | force = FALSE 77 | ) 78 | testthat::expect_true(dir.exists(java_home_path), info = context_info) 79 | 80 | # --- Step C: Check and Verify --- 81 | cli::cli_inform("-> Step 3: Verifying with java_check_version_cmd()...") 82 | cmd_version_result <- java_check_version_cmd( 83 | java_home = java_home_path, 84 | quiet = rj_quiet 85 | ) 86 | testthat::expect_equal( 87 | cmd_version_result, 88 | java_version, 89 | info = context_info 90 | ) 91 | if (cmd_version_result == java_version) { 92 | cli::cli_inform( 93 | "Successfully verified Java {java_version} with command line." 94 | ) 95 | } else { 96 | cli::cli_alert_danger( 97 | "Command line verification failed for Java {java_version}." 98 | ) 99 | } 100 | 101 | cli::cli_inform("-> Step 4: Verifying with java_check_version_rjava()...") 102 | rjava_version_result <- java_check_version_rjava( 103 | java_home = java_home_path, 104 | quiet = rj_quiet 105 | ) 106 | testthat::expect_equal( 107 | rjava_version_result, 108 | java_version, 109 | info = context_info 110 | ) 111 | if (rjava_version_result == java_version) { 112 | cli::cli_inform("Successfully verified Java {java_version} with rJava.") 113 | } else { 114 | cli::cli_alert_danger( 115 | "rJava verification failed for Java {java_version}." 116 | ) 117 | } 118 | 119 | # --- Step D: Clean up within the loop to test java_clear() --- 120 | cli::cli_inform("-> Step 5: Clearing caches with java_clear()...") 121 | 122 | # Clear the downloaded distribution files 123 | java_clear( 124 | type = "distrib", 125 | target_dir = temp_cache_dir, 126 | check = FALSE, # Must be FALSE for non-interactive use 127 | delete_all = TRUE # Must be TRUE for non-interactive use 128 | ) 129 | 130 | # Clear the unpacked installation files 131 | java_clear( 132 | type = "installed", 133 | target_dir = temp_cache_dir, 134 | check = FALSE, 135 | delete_all = TRUE 136 | ) 137 | 138 | # Verify that the cleanup was successful 139 | distrib_dir <- file.path(temp_cache_dir, "distrib") 140 | installed_dir <- file.path(temp_cache_dir, "installed") 141 | 142 | testthat::expect_equal( 143 | length(list.files(distrib_dir)), 144 | 0, 145 | info = context_info 146 | ) 147 | testthat::expect_equal( 148 | length(list.files(installed_dir)), 149 | 0, 150 | info = context_info 151 | ) 152 | 153 | cli::cli_alert_success( 154 | "Successfully processed and cleared Java version: {java_version}" 155 | ) 156 | } 157 | }) 158 | -------------------------------------------------------------------------------- /tests/testthat/test-internal_utilities.R: -------------------------------------------------------------------------------- 1 | # Tests for platform_detect() and rje_consent() 2 | 3 | test_that("platform_detect returns correct structure", { 4 | res <- platform_detect(quiet = TRUE) 5 | 6 | expect_type(res, "list") 7 | expect_named(res, c("os", "arch")) 8 | expect_true(res$os %in% c("linux", "windows", "macos")) 9 | expect_true(res$arch %in% c("x64", "x86", "aarch64")) 10 | }) 11 | 12 | test_that("platform_detect returns correct OS for current platform", { 13 | res <- platform_detect(quiet = TRUE) 14 | sys_info <- Sys.info() 15 | 16 | expected_os <- switch( 17 | tolower(sys_info["sysname"]), 18 | "windows" = "windows", 19 | "linux" = "linux", 20 | "darwin" = "macos" 21 | ) 22 | 23 | expect_equal(res$os, expected_os) 24 | }) 25 | 26 | test_that("platform_detect respects R_ARCH for Windows architecture", { 27 | skip_on_os("mac") 28 | skip_on_os("linux") 29 | 30 | # Test x64 architecture via R_ARCH 31 | withr::local_envvar(R_ARCH = "/x64") 32 | res <- platform_detect(quiet = TRUE) 33 | expect_equal(res$arch, "x64") 34 | 35 | # Test x86 architecture via R_ARCH 36 | withr::local_envvar(R_ARCH = "/i386") 37 | res <- platform_detect(quiet = TRUE) 38 | expect_equal(res$arch, "x86") 39 | }) 40 | 41 | test_that("platform_detect prints messages when not quiet", { 42 | expect_message( 43 | platform_detect(quiet = FALSE), 44 | "Detected platform" 45 | ) 46 | }) 47 | 48 | test_that("rje_consent returns TRUE when option is already set", { 49 | withr::local_options(list(rJavaEnv.consent = TRUE)) 50 | 51 | expect_message( 52 | result <- rje_consent(), 53 | "already been provided" 54 | ) 55 | expect_true(result) 56 | }) 57 | 58 | test_that("rje_consent returns TRUE when cache directory exists", { 59 | cache_dir <- withr::local_tempdir() 60 | withr::local_options(list( 61 | rJavaEnv.consent = FALSE, 62 | rJavaEnv.cache_path = cache_dir 63 | )) 64 | 65 | expect_message( 66 | result <- rje_consent(), 67 | "already been provided" 68 | ) 69 | expect_true(result) 70 | }) 71 | 72 | test_that("rje_consent handles user typing 'yes'", { 73 | cache_dir <- file.path(withr::local_tempdir(), "nonexistent") 74 | withr::local_options(list( 75 | rJavaEnv.consent = FALSE, 76 | rJavaEnv.cache_path = cache_dir 77 | )) 78 | 79 | # Mock readline to return "yes" 80 | local_mocked_bindings(readline = function(...) "yes", .package = "base") 81 | 82 | expect_message( 83 | result <- rje_consent(), 84 | "Consent has been granted" 85 | ) 86 | expect_true(getOption("rJavaEnv.consent")) 87 | }) 88 | 89 | test_that("rje_consent handles user typing 'no'", { 90 | cache_dir <- file.path(withr::local_tempdir(), "nonexistent") 91 | withr::local_options(list( 92 | rJavaEnv.consent = FALSE, 93 | rJavaEnv.cache_path = cache_dir 94 | )) 95 | 96 | # Mock readline to return "no" 97 | local_mocked_bindings(readline = function(...) "no", .package = "base") 98 | 99 | expect_error( 100 | rje_consent(), 101 | "Consent was not provided" 102 | ) 103 | }) 104 | 105 | test_that("rje_consent accepts 'provided = TRUE' argument", { 106 | cache_dir <- file.path(withr::local_tempdir(), "nonexistent") 107 | withr::local_options(list( 108 | rJavaEnv.consent = FALSE, 109 | rJavaEnv.cache_path = cache_dir 110 | )) 111 | 112 | expect_message( 113 | result <- rje_consent(provided = TRUE), 114 | "Consent has been granted" 115 | ) 116 | expect_true(getOption("rJavaEnv.consent")) 117 | }) 118 | 119 | test_that("rje_consent_check returns TRUE when consent option is set", { 120 | withr::local_options(list(rJavaEnv.consent = TRUE)) 121 | 122 | expect_true(rje_consent_check()) 123 | }) 124 | 125 | test_that("rje_consent_check returns TRUE when cache directory exists", { 126 | cache_dir <- withr::local_tempdir() 127 | withr::local_options(list( 128 | rJavaEnv.consent = FALSE, 129 | rJavaEnv.cache_path = cache_dir 130 | )) 131 | 132 | expect_true(rje_consent_check()) 133 | }) 134 | 135 | test_that("rje_consent_check grants implicit consent in CI environments", { 136 | cache_dir <- file.path(withr::local_tempdir(), "nonexistent") 137 | withr::local_options(list( 138 | rJavaEnv.consent = FALSE, 139 | rJavaEnv.cache_path = cache_dir 140 | )) 141 | withr::local_envvar(CI = "true") 142 | 143 | expect_true(rje_consent_check()) 144 | expect_true(getOption("rJavaEnv.consent")) 145 | }) 146 | 147 | test_that("rje_consent_check grants implicit consent in GitHub Actions", { 148 | cache_dir <- file.path(withr::local_tempdir(), "nonexistent") 149 | withr::local_options(list( 150 | rJavaEnv.consent = FALSE, 151 | rJavaEnv.cache_path = cache_dir 152 | )) 153 | withr::local_envvar(GITHUB_ACTION = "test-action") 154 | 155 | expect_true(rje_consent_check()) 156 | expect_true(getOption("rJavaEnv.consent")) 157 | }) 158 | 159 | test_that("rje_envvar_exists correctly detects environment variables", { 160 | withr::local_envvar(TEST_VAR_EXISTS = "value") 161 | 162 | expect_true(rje_envvar_exists("TEST_VAR_EXISTS")) 163 | expect_false(rje_envvar_exists("TEST_VAR_DOES_NOT_EXIST_12345")) 164 | }) 165 | 166 | test_that("java_urls_load returns correct structure", { 167 | urls <- java_urls_load() 168 | 169 | expect_type(urls, "list") 170 | expect_true("Corretto" %in% names(urls)) 171 | }) 172 | 173 | test_that("platform_detect handles common architectures", { 174 | # This test verifies the current platform returns one of the known architectures 175 | res <- platform_detect(quiet = TRUE) 176 | 177 | # The function should not error on the current machine 178 | 179 | expect_true(length(res$arch) == 1) 180 | expect_true(nchar(res$arch) > 0) 181 | }) 182 | -------------------------------------------------------------------------------- /vignettes/data-for-vignettes/data_table_dlstats.csv: -------------------------------------------------------------------------------- 1 | start;end;downloads;package 2 | 2014-01-01;2014-01-31;5308;data.table 3 | 2014-02-01;2014-02-28;6363;data.table 4 | 2014-03-01;2014-03-31;9784;data.table 5 | 2014-04-01;2014-04-30;12796;data.table 6 | 2014-05-01;2014-05-31;12312;data.table 7 | 2014-06-01;2014-06-30;13502;data.table 8 | 2014-07-01;2014-07-31;14397;data.table 9 | 2014-08-01;2014-08-31;14224;data.table 10 | 2014-09-01;2014-09-30;14193;data.table 11 | 2014-10-01;2014-10-31;21691;data.table 12 | 2014-11-01;2014-11-30;19681;data.table 13 | 2014-12-01;2014-12-31;17256;data.table 14 | 2015-01-01;2015-01-31;19970;data.table 15 | 2015-02-01;2015-02-28;21808;data.table 16 | 2015-03-01;2015-03-31;26032;data.table 17 | 2015-04-01;2015-04-30;31241;data.table 18 | 2015-05-01;2015-05-31;32581;data.table 19 | 2015-06-01;2015-06-30;35062;data.table 20 | 2015-07-01;2015-07-31;36540;data.table 21 | 2015-08-01;2015-08-31;50404;data.table 22 | 2015-09-01;2015-09-30;61375;data.table 23 | 2015-10-01;2015-10-31;64900;data.table 24 | 2015-11-01;2015-11-30;67938;data.table 25 | 2015-12-01;2015-12-31;61084;data.table 26 | 2016-01-01;2016-01-31;66463;data.table 27 | 2016-02-01;2016-02-29;65813;data.table 28 | 2016-03-01;2016-03-31;63233;data.table 29 | 2016-04-01;2016-04-30;59395;data.table 30 | 2016-05-01;2016-05-31;117233;data.table 31 | 2016-06-01;2016-06-30;110241;data.table 32 | 2016-07-01;2016-07-31;104528;data.table 33 | 2016-08-01;2016-08-31;108044;data.table 34 | 2016-09-01;2016-09-30;127614;data.table 35 | 2016-10-01;2016-10-31;146051;data.table 36 | 2016-11-01;2016-11-30;183043;data.table 37 | 2016-12-01;2016-12-31;181973;data.table 38 | 2017-01-01;2017-01-31;168188;data.table 39 | 2017-02-01;2017-02-28;265672;data.table 40 | 2017-03-01;2017-03-31;236241;data.table 41 | 2017-04-01;2017-04-30;199142;data.table 42 | 2017-05-01;2017-05-31;192961;data.table 43 | 2017-06-01;2017-06-30;185656;data.table 44 | 2017-07-01;2017-07-31;161976;data.table 45 | 2017-08-01;2017-08-31;156174;data.table 46 | 2017-09-01;2017-09-30;188326;data.table 47 | 2017-10-01;2017-10-31;325890;data.table 48 | 2017-11-01;2017-11-30;289248;data.table 49 | 2017-12-01;2017-12-31;212365;data.table 50 | 2018-01-01;2018-01-31;214533;data.table 51 | 2018-02-01;2018-02-28;219905;data.table 52 | 2018-03-01;2018-03-31;244143;data.table 53 | 2018-04-01;2018-04-30;297276;data.table 54 | 2018-05-01;2018-05-31;412734;data.table 55 | 2018-06-01;2018-06-30;304389;data.table 56 | 2018-07-01;2018-07-31;297191;data.table 57 | 2018-08-01;2018-08-31;273482;data.table 58 | 2018-09-01;2018-09-30;403235;data.table 59 | 2018-10-01;2018-10-31;491636;data.table 60 | 2018-11-01;2018-11-30;424741;data.table 61 | 2018-12-01;2018-12-31;330548;data.table 62 | 2019-01-01;2019-01-31;668709;data.table 63 | 2019-02-01;2019-02-28;666770;data.table 64 | 2019-03-01;2019-03-31;668349;data.table 65 | 2019-04-01;2019-04-30;729934;data.table 66 | 2019-05-01;2019-05-31;618185;data.table 67 | 2019-06-01;2019-06-30;444470;data.table 68 | 2019-07-01;2019-07-31;495586;data.table 69 | 2019-08-01;2019-08-31;454263;data.table 70 | 2019-09-01;2019-09-30;515846;data.table 71 | 2019-10-01;2019-10-31;715833;data.table 72 | 2019-11-01;2019-11-30;566063;data.table 73 | 2019-12-01;2019-12-31;500906;data.table 74 | 2020-01-01;2020-01-31;525533;data.table 75 | 2020-02-01;2020-02-29;502941;data.table 76 | 2020-03-01;2020-03-31;571181;data.table 77 | 2020-04-01;2020-04-30;596472;data.table 78 | 2020-05-01;2020-05-31;594441;data.table 79 | 2020-06-01;2020-06-30;562159;data.table 80 | 2020-07-01;2020-07-31;548913;data.table 81 | 2020-08-01;2020-08-31;584097;data.table 82 | 2020-09-01;2020-09-30;660371;data.table 83 | 2020-10-01;2020-10-31;745488;data.table 84 | 2020-11-01;2020-11-30;711626;data.table 85 | 2020-12-01;2020-12-31;667454;data.table 86 | 2021-01-01;2021-01-31;684310;data.table 87 | 2021-02-01;2021-02-28;696210;data.table 88 | 2021-03-01;2021-03-31;814729;data.table 89 | 2021-04-01;2021-04-30;743535;data.table 90 | 2021-05-01;2021-05-31;719963;data.table 91 | 2021-06-01;2021-06-30;730959;data.table 92 | 2021-07-01;2021-07-31;636526;data.table 93 | 2021-08-01;2021-08-31;661484;data.table 94 | 2021-09-01;2021-09-30;835160;data.table 95 | 2021-10-01;2021-10-31;943031;data.table 96 | 2021-11-01;2021-11-30;850174;data.table 97 | 2021-12-01;2021-12-31;763067;data.table 98 | 2022-01-01;2022-01-31;799994;data.table 99 | 2022-02-01;2022-02-28;800786;data.table 100 | 2022-03-01;2022-03-31;911517;data.table 101 | 2022-04-01;2022-04-30;909134;data.table 102 | 2022-05-01;2022-05-31;958481;data.table 103 | 2022-06-01;2022-06-30;891046;data.table 104 | 2022-07-01;2022-07-31;816538;data.table 105 | 2022-08-01;2022-08-31;848647;data.table 106 | 2022-09-01;2022-09-30;855167;data.table 107 | 2022-10-01;2022-10-31;962825;data.table 108 | 2022-11-01;2022-11-30;1117776;data.table 109 | 2022-12-01;2022-12-31;821153;data.table 110 | 2023-01-01;2023-01-31;748596;data.table 111 | 2023-02-01;2023-02-28;789184;data.table 112 | 2023-03-01;2023-03-31;913025;data.table 113 | 2023-04-01;2023-04-30;775531;data.table 114 | 2023-05-01;2023-05-31;779533;data.table 115 | 2023-06-01;2023-06-30;676283;data.table 116 | 2023-07-01;2023-07-31;570552;data.table 117 | 2023-08-01;2023-08-31;586248;data.table 118 | 2023-09-01;2023-09-30;694988;data.table 119 | 2023-10-01;2023-10-31;696944;data.table 120 | 2023-11-01;2023-11-30;965821;data.table 121 | 2023-12-01;2023-12-31;638954;data.table 122 | 2024-01-01;2024-01-31;739831;data.table 123 | 2024-02-01;2024-02-29;821539;data.table 124 | 2024-03-01;2024-03-31;845520;data.table 125 | 2024-04-01;2024-04-30;886330;data.table 126 | 2024-05-01;2024-05-31;846726;data.table 127 | 2024-06-01;2024-06-30;677560;data.table 128 | 2024-07-01;2024-07-31;698441;data.table 129 | 2024-08-01;2024-08-31;749291;data.table 130 | 2024-09-01;2024-09-26;729796;data.table 131 | -------------------------------------------------------------------------------- /.github/CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | We as members, contributors, and leaders pledge to make participation in our 6 | community a harassment-free experience for everyone, regardless of age, body 7 | size, visible or invisible disability, ethnicity, sex characteristics, gender 8 | identity and expression, level of experience, education, socio-economic status, 9 | nationality, personal appearance, race, caste, color, religion, or sexual 10 | identity and orientation. 11 | 12 | We pledge to act and interact in ways that contribute to an open, welcoming, 13 | diverse, inclusive, and healthy community. 14 | 15 | ## Our Standards 16 | 17 | Examples of behavior that contributes to a positive environment for our 18 | community include: 19 | 20 | * Demonstrating empathy and kindness toward other people 21 | * Being respectful of differing opinions, viewpoints, and experiences 22 | * Giving and gracefully accepting constructive feedback 23 | * Accepting responsibility and apologizing to those affected by our mistakes, 24 | and learning from the experience 25 | * Focusing on what is best not just for us as individuals, but for the overall 26 | community 27 | 28 | Examples of unacceptable behavior include: 29 | 30 | * The use of sexualized language or imagery, and sexual attention or advances of 31 | any kind 32 | * Trolling, insulting or derogatory comments, and personal or political attacks 33 | * Public or private harassment 34 | * Publishing others' private information, such as a physical or email address, 35 | without their explicit permission 36 | * Other conduct which could reasonably be considered inappropriate in a 37 | professional setting 38 | 39 | ## Enforcement Responsibilities 40 | 41 | Community leaders are responsible for clarifying and enforcing our standards of 42 | acceptable behavior and will take appropriate and fair corrective action in 43 | response to any behavior that they deem inappropriate, threatening, offensive, 44 | or harmful. 45 | 46 | Community leaders have the right and responsibility to remove, edit, or reject 47 | comments, commits, code, wiki edits, issues, and other contributions that are 48 | not aligned to this Code of Conduct, and will communicate reasons for moderation 49 | decisions when appropriate. 50 | 51 | ## Scope 52 | 53 | This Code of Conduct applies within all community spaces, and also applies when 54 | an individual is officially representing the community in public spaces. 55 | Examples of representing our community include using an official e-mail address, 56 | posting via an official social media account, or acting as an appointed 57 | representative at an online or offline event. 58 | 59 | ## Enforcement 60 | 61 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 62 | reported to the community leaders responsible for enforcement at kotov.egor@gmail.com. 63 | All complaints will be reviewed and investigated promptly and fairly. 64 | 65 | All community leaders are obligated to respect the privacy and security of the 66 | reporter of any incident. 67 | 68 | ## Enforcement Guidelines 69 | 70 | Community leaders will follow these Community Impact Guidelines in determining 71 | the consequences for any action they deem in violation of this Code of Conduct: 72 | 73 | ### 1. Correction 74 | 75 | **Community Impact**: Use of inappropriate language or other behavior deemed 76 | unprofessional or unwelcome in the community. 77 | 78 | **Consequence**: A private, written warning from community leaders, providing 79 | clarity around the nature of the violation and an explanation of why the 80 | behavior was inappropriate. A public apology may be requested. 81 | 82 | ### 2. Warning 83 | 84 | **Community Impact**: A violation through a single incident or series of 85 | actions. 86 | 87 | **Consequence**: A warning with consequences for continued behavior. No 88 | interaction with the people involved, including unsolicited interaction with 89 | those enforcing the Code of Conduct, for a specified period of time. This 90 | includes avoiding interactions in community spaces as well as external channels 91 | like social media. Violating these terms may lead to a temporary or permanent 92 | ban. 93 | 94 | ### 3. Temporary Ban 95 | 96 | **Community Impact**: A serious violation of community standards, including 97 | sustained inappropriate behavior. 98 | 99 | **Consequence**: A temporary ban from any sort of interaction or public 100 | communication with the community for a specified period of time. No public or 101 | private interaction with the people involved, including unsolicited interaction 102 | with those enforcing the Code of Conduct, is allowed during this period. 103 | Violating these terms may lead to a permanent ban. 104 | 105 | ### 4. Permanent Ban 106 | 107 | **Community Impact**: Demonstrating a pattern of violation of community 108 | standards, including sustained inappropriate behavior, harassment of an 109 | individual, or aggression toward or disparagement of classes of individuals. 110 | 111 | **Consequence**: A permanent ban from any sort of public interaction within the 112 | community. 113 | 114 | ## Attribution 115 | 116 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], 117 | version 2.1, available at 118 | . 119 | 120 | Community Impact Guidelines were inspired by 121 | [Mozilla's code of conduct enforcement ladder][https://github.com/mozilla/inclusion]. 122 | 123 | For answers to common questions about this code of conduct, see the FAQ at 124 | . Translations are available at . 125 | 126 | [homepage]: https://www.contributor-covenant.org 127 | -------------------------------------------------------------------------------- /tests/testthat/test-java_manage.R: -------------------------------------------------------------------------------- 1 | # Tests for java_list() and java_clear() 2 | 3 | test_that("java_list dispatches correctly", { 4 | # Mock the specific list functions 5 | local_mocked_bindings( 6 | java_list_distrib_cache = function(...) "listed_distrib", 7 | java_list_installed_cache = function(...) "listed_installed", 8 | java_list_in_project = function(...) "listed_project", 9 | .package = "rJavaEnv" 10 | ) 11 | 12 | expect_equal(java_list("distrib"), "listed_distrib") 13 | expect_equal(java_list("installed"), "listed_installed") 14 | expect_equal(java_list("project"), "listed_project") 15 | }) 16 | 17 | test_that("java_clear (project) handles user input correctly", { 18 | # Setup fake project structure with proper depth 19 | proj_dir <- withr::local_tempdir() 20 | rjava_dir <- file.path(proj_dir, "rjavaenv", "linux", "x64", "17") 21 | dir.create(rjava_dir, recursive = TRUE) 22 | file.create(file.path(rjava_dir, "dummy_file")) 23 | 24 | # Mock consent 25 | local_mocked_bindings(rje_consent_check = function() TRUE, .package = "rJavaEnv") 26 | 27 | # Case 1: User says "no" (check=FALSE triggers yes/no prompt) 28 | local_mocked_bindings(readline = function(...) "no", .package = "base") 29 | 30 | expect_message( 31 | java_clear("project", target_dir = proj_dir, check = FALSE), 32 | "No Java symlinks were cleared" 33 | ) 34 | # The directory should still exist 35 | expect_true(dir.exists(rjava_dir)) 36 | 37 | # Case 2: User says "yes" 38 | local_mocked_bindings(readline = function(...) "yes", .package = "base") 39 | expect_message( 40 | java_clear("project", target_dir = proj_dir, check = FALSE), 41 | "cleared" 42 | ) 43 | # Contents should be cleared 44 | rjava_base <- file.path(proj_dir, "rjavaenv") 45 | expect_length(list.files(rjava_base, recursive = TRUE), 0) 46 | }) 47 | 48 | test_that("java_clear (distrib) deletes specific files via menu", { 49 | cache_dir <- withr::local_tempdir() 50 | dist_dir <- file.path(cache_dir, "distrib") 51 | dir.create(dist_dir, recursive = TRUE) 52 | 53 | f1 <- file.path(dist_dir, "java1.tar.gz") 54 | f2 <- file.path(dist_dir, "java2.tar.gz") 55 | file.create(f1) 56 | file.create(f2) 57 | 58 | # Mock consent 59 | local_mocked_bindings(rje_consent_check = function() TRUE, .package = "rJavaEnv") 60 | 61 | # User selects item "1" (check=TRUE triggers numbered menu) 62 | local_mocked_bindings(readline = function(...) "1", .package = "base") 63 | 64 | # We must mock java_list_distrib_cache to return vector so the index works 65 | local_mocked_bindings( 66 | java_list_distrib_cache = function(...) c(f1, f2), 67 | .package = "rJavaEnv" 68 | ) 69 | 70 | java_clear("distrib", target_dir = cache_dir, check = TRUE) 71 | 72 | expect_false(file.exists(f1)) 73 | expect_true(file.exists(f2)) 74 | }) 75 | 76 | test_that("java_clear deletes all when requested", { 77 | cache_dir <- withr::local_tempdir() 78 | inst_dir <- file.path(cache_dir, "installed") 79 | dir.create(inst_dir, recursive = TRUE) 80 | file.create(file.path(inst_dir, "folder1")) 81 | 82 | local_mocked_bindings(rje_consent_check = function() TRUE, .package = "rJavaEnv") 83 | 84 | java_clear("installed", target_dir = cache_dir, delete_all = TRUE) 85 | expect_length(list.files(inst_dir), 0) 86 | }) 87 | 88 | test_that("java_clear (installed) handles numbered selection", { 89 | cache_dir <- withr::local_tempdir() 90 | inst_dir <- file.path(cache_dir, "installed", "linux", "x64", "17") 91 | dir.create(inst_dir, recursive = TRUE) 92 | inst_dir2 <- file.path(cache_dir, "installed", "linux", "x64", "21") 93 | dir.create(inst_dir2, recursive = TRUE) 94 | 95 | local_mocked_bindings(rje_consent_check = function() TRUE, .package = "rJavaEnv") 96 | 97 | # User selects item "1" 98 | local_mocked_bindings(readline = function(...) "1", .package = "base") 99 | 100 | # Mock java_list_installed_cache to return expected paths 101 | local_mocked_bindings( 102 | java_list_installed_cache = function(...) c(inst_dir, inst_dir2), 103 | .package = "rJavaEnv" 104 | ) 105 | 106 | java_clear("installed", target_dir = cache_dir, check = TRUE) 107 | 108 | expect_false(dir.exists(inst_dir)) 109 | expect_true(dir.exists(inst_dir2)) 110 | }) 111 | 112 | test_that("java_clear (project) handles 'all' option", { 113 | proj_dir <- withr::local_tempdir() 114 | rjava_dir1 <- file.path(proj_dir, "rjavaenv", "linux", "x64", "17") 115 | rjava_dir2 <- file.path(proj_dir, "rjavaenv", "linux", "x64", "21") 116 | dir.create(rjava_dir1, recursive = TRUE) 117 | dir.create(rjava_dir2, recursive = TRUE) 118 | 119 | local_mocked_bindings(rje_consent_check = function() TRUE, .package = "rJavaEnv") 120 | 121 | # User types "all" 122 | local_mocked_bindings(readline = function(...) "all", .package = "base") 123 | 124 | java_clear("project", target_dir = proj_dir, check = TRUE) 125 | 126 | # All should be cleared 127 | rjava_base <- file.path(proj_dir, "rjavaenv") 128 | expect_length(list.files(rjava_base, recursive = TRUE), 0) 129 | }) 130 | 131 | test_that("java_clear cancels on invalid input", 132 | { 133 | cache_dir <- withr::local_tempdir() 134 | dist_dir <- file.path(cache_dir, "distrib") 135 | dir.create(dist_dir, recursive = TRUE) 136 | 137 | f1 <- file.path(dist_dir, "java1.tar.gz") 138 | file.create(f1) 139 | 140 | local_mocked_bindings(rje_consent_check = function() TRUE, .package = "rJavaEnv") 141 | 142 | # User enters "0" to cancel 143 | local_mocked_bindings(readline = function(...) "0", .package = "base") 144 | 145 | local_mocked_bindings( 146 | java_list_distrib_cache = function(...) c(f1), 147 | .package = "rJavaEnv" 148 | ) 149 | 150 | expect_message( 151 | java_clear("distrib", target_dir = cache_dir, check = TRUE), 152 | "No distributions were cleared" 153 | ) 154 | 155 | # File should still exist 156 | expect_true(file.exists(f1)) 157 | }) 158 | -------------------------------------------------------------------------------- /R/internal_utilities.R: -------------------------------------------------------------------------------- 1 | #' Detect platform and architecture 2 | #' 3 | #' @inheritParams global_quiet_param 4 | #' @keywords internal 5 | #' @return A list of length 2 with the detected platform and architecture. 6 | #' 7 | platform_detect <- function(quiet = TRUE) { 8 | sys_info <- tolower(Sys.info()) 9 | 10 | os <- switch( 11 | sys_info["sysname"], 12 | "windows" = "windows", 13 | "linux" = "linux", 14 | "darwin" = "macos", 15 | stop(cli::cli_abort("Unsupported platform")) 16 | ) 17 | 18 | # NEW: Check R_ARCH first, then fall back to Sys.info() 19 | r_arch_env <- Sys.getenv("R_ARCH") 20 | 21 | if (r_arch_env == "/i386") { 22 | arch <- "x86" 23 | } else if (r_arch_env == "/x64") { 24 | arch <- "x64" 25 | } else { 26 | # Fallback for non-Windows or when not in a build context 27 | arch <- switch( 28 | sys_info["machine"], 29 | "x86-64" = "x64", 30 | "x86_64" = "x64", 31 | "i386" = "x86", 32 | "i486" = "x86", 33 | "i586" = "x86", 34 | "i686" = "x86", 35 | "aarch64" = "aarch64", 36 | "arm64" = "aarch64", 37 | stop(cli::cli_abort("Unsupported architecture")) 38 | ) 39 | } 40 | 41 | if (isFALSE(quiet)) { 42 | cli::cli_inform("Detected platform: {os}") 43 | cli::cli_inform("Detected architecture: {arch}") 44 | } 45 | 46 | return(list(os = os, arch = arch)) 47 | } 48 | 49 | #' Load Java URLs from JSON file 50 | #' 51 | #' @keywords internal 52 | #' 53 | #' @return A list with the Java URLs structured as in the JSON file by distribution, platform, and architecture. 54 | #' 55 | java_urls_load <- function() { 56 | json_file <- system.file("extdata", "java_urls.json", package = "rJavaEnv") 57 | if (json_file == "") { 58 | cli::cli_abort("Configuration file not found") 59 | } 60 | jsonlite::fromJSON(json_file, simplifyVector = FALSE) 61 | } 62 | 63 | #' Test all Java URLs 64 | #' 65 | #' @keywords internal 66 | #' 67 | #' @return A list with the results of testing all Java URLs. 68 | #' 69 | urls_test_all <- function() { 70 | java_urls <- java_urls_load() 71 | results <- list() 72 | 73 | for (distribution in names(java_urls)) { 74 | for (platform in names(java_urls[[distribution]])) { 75 | for (arch in names(java_urls[[distribution]][[platform]])) { 76 | url_template <- java_urls[[distribution]][[platform]][[arch]] 77 | 78 | # Replace {version} with a placeholder version to test URL 79 | url <- gsub("\\{version\\}", "11", url_template) 80 | 81 | try( 82 | { 83 | response <- curl::curl_fetch_memory( 84 | url, 85 | handle = curl::new_handle(nobody = TRUE) 86 | ) 87 | status <- response$status_code 88 | }, 89 | silent = TRUE 90 | ) 91 | 92 | if (!exists("status")) { 93 | status <- NA 94 | } 95 | 96 | results[[paste(distribution, platform, arch, sep = "-")]] <- list( 97 | url = url, 98 | status = status 99 | ) 100 | 101 | # Clear status variable for next iteration 102 | rm(status) 103 | } 104 | } 105 | } 106 | 107 | return(results) 108 | } 109 | 110 | 111 | # Unexported function to initialize Java using rJava and check Java version 112 | # This is intended to be called from the exported function java_check_version_rjava 113 | # Updated java_version_check_rscript function with verbosity control 114 | #' Check Java version using rJava 115 | #' 116 | #' @keywords internal 117 | #' 118 | #' @param java_home 119 | #' 120 | #' @return A message with the Java version or an error message. 121 | #' 122 | java_version_check_rscript <- function(java_home) { 123 | result <- tryCatch( 124 | { 125 | Sys.setenv(JAVA_HOME = java_home) 126 | 127 | old_path <- Sys.getenv("PATH") 128 | new_path <- file.path(java_home, "bin") 129 | Sys.setenv(PATH = paste(new_path, old_path, sep = .Platform$path.sep)) 130 | 131 | # On Linux, find and dynamically load libjvm.so 132 | if (Sys.info()["sysname"] == "Linux") { 133 | all_files <- list.files( 134 | path = java_home, 135 | pattern = "libjvm.so$", 136 | recursive = TRUE, 137 | full.names = TRUE 138 | ) 139 | 140 | libjvm_path <- NULL 141 | if (length(all_files) > 0) { 142 | # Prefer the 'server' version if available 143 | server_files <- all_files[grepl("/server/libjvm.so$", all_files)] 144 | if (length(server_files) > 0) { 145 | libjvm_path <- server_files[1] 146 | } else { 147 | libjvm_path <- all_files[1] 148 | } 149 | } 150 | 151 | if (!is.null(libjvm_path) && file.exists(libjvm_path)) { 152 | tryCatch( 153 | dyn.load(libjvm_path), 154 | error = function(e) { 155 | # Use base message to avoid dependency issues in the isolated script 156 | message(sprintf( 157 | "Found libjvm.so at '%s' but failed to load it: %s", 158 | libjvm_path, 159 | e$message 160 | )) 161 | } 162 | ) 163 | } else { 164 | message(sprintf( 165 | "Could not find libjvm.so within the provided JAVA_HOME: %s", 166 | java_home 167 | )) 168 | } 169 | } 170 | 171 | suppressWarnings(rJava::.jinit()) 172 | suppressWarnings( 173 | java_version <- rJava::.jcall( 174 | "java.lang.System", 175 | "S", 176 | "getProperty", 177 | "java.version" 178 | ) 179 | ) 180 | 181 | message <- cli::format_message( 182 | "rJava and other rJava/Java-based packages will use Java version: {.val {java_version}}" 183 | ) 184 | 185 | message 186 | }, 187 | error = function(e) { 188 | cli::format_message("Error checking Java version: {e$message}") 189 | } 190 | ) 191 | 192 | return(result) 193 | } 194 | --------------------------------------------------------------------------------