Skip to content

Commit 78eb54b

Browse files
authored
Merge pull request #46 from e-kotov/44-interface-that-doesnt-affect-rprofile
44 interface that doesnt affect rprofile
2 parents 3ccf4ed + 5d3d1ac commit 78eb54b

27 files changed

+610
-137
lines changed

.Rbuildignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,3 +21,4 @@
2121
^vignettes/bibliography.bib$
2222
^vignettes/media$
2323
^CRAN-SUBMISSION$
24+
^vignettes/.quarto$

DESCRIPTION

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,3 +45,5 @@ Encoding: UTF-8
4545
Language: en-US
4646
Roxygen: list(markdown = TRUE)
4747
RoxygenNote: 7.3.2
48+
Depends:
49+
R (>= 4.0)

NAMESPACE

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,7 @@ export(java_env_unset)
99
export(java_install)
1010
export(java_list)
1111
export(java_quick_install)
12+
export(java_unpack)
1213
export(rje_consent)
14+
export(use_java)
1315
importFrom(utils,getFromNamespace)

R/java_download.R

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
#' Download a Java distribution
22
#'
3-
#' @param version The Java version to download. If not specified, defaults to the latest LTS version.
4-
#' @param distribution The Java distribution to download. If not specified, defaults to "Corretto".
3+
#' @param version `Integer` or `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", "11", "17", "21", "22", or 8, 11, 17, 21, or 22.
4+
#' @param 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.
55
#' @param cache_path The destination directory to download the Java distribution to. Defaults to a user-specific data directory.
66
#' @param platform The platform for which to download the Java distribution. Defaults to the current platform.
77
#' @param arch The architecture for which to download the Java distribution. Defaults to the current architecture.
@@ -40,18 +40,18 @@ java_download <- function(
4040
cache_path <- file.path(temp_dir, "rJavaEnv_cache")
4141
}
4242

43-
rje_consent_check()
43+
# rje_consent_check() # disabling consent check for now
4444
java_urls <- java_urls_load()
4545

4646
valid_distributions <- names(java_urls)
4747
valid_platforms <- names(java_urls[[distribution]])
4848
valid_architectures <- names(java_urls[[distribution]][[platform]])
4949

5050
# Checks for the parameters
51-
checkmate::assert(
52-
checkmate::check_integerish(version, lower = 1),
53-
checkmate::check_character(version, pattern = "^[0-9]+$")
54-
)
51+
checkmate::check_vector(version, len = 1)
52+
version <- as.character(version)
53+
checkmate::assert_choice(version, getOption("rJavaEnv.valid_major_java_versions"))
54+
5555
checkmate::assert_choice(distribution, valid_distributions)
5656

5757
# Create the distrib subfolder within the destination directory

R/java_env.R

Lines changed: 64 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -38,14 +38,13 @@ java_env_set <- function(
3838
project_path = NULL,
3939
quiet = FALSE
4040
) {
41-
rje_consent_check()
42-
41+
4342
where <- match.arg(where)
4443
checkmate::assertString(java_home)
4544
checkmate::assertFlag(quiet)
46-
47-
48-
45+
46+
47+
4948
if (where %in% c("session", "both")) {
5049
java_env_set_session(java_home)
5150
if (!quiet) {
@@ -55,7 +54,8 @@ java_env_set <- function(
5554
))
5655
}
5756
}
58-
57+
58+
rje_consent_check()
5959
if (where %in% c("project", "both")) {
6060
# consistent with renv behavior for using
6161
# the current working directory by default
@@ -82,6 +82,14 @@ java_env_set <- function(
8282
#' @keywords internal
8383
#'
8484
java_env_set_session <- function(java_home) {
85+
86+
# check if rJava is installed and alread initialized
87+
if (requireNamespace("rJava", quietly = TRUE)) {
88+
if( getFromNamespace(".jniInitialized", "rJava") == TRUE ) {
89+
cli::cli_inform(c("!" = "You have already initialised `rJava` directly or via your Java-dependent R package in the current session. `Java` version can only be set once per session for packages that rely on `rJava`. Unless you restart the R session or run your code in a new R subprocess using `targets` or `callr`, the new `JAVA_HOME` and `PATH` will not take effect."))
90+
}
91+
}
92+
8593
Sys.setenv(JAVA_HOME = java_home)
8694
old_path <- Sys.getenv("PATH")
8795
new_path <- file.path(java_home, "bin")
@@ -137,17 +145,15 @@ java_env_set_rprofile <- function(
137145

138146
#' Check Java Version with a Specified JAVA_HOME Using a Separate R Session
139147
#'
140-
#' This function sets the JAVA_HOME environment variable, initializes the JVM using rJava,
141-
#' and prints the Java version that would be used if the user sets the given JAVA_HOME
142-
#' in the current R session. This check is performed in a separate R session to avoid
143-
#' having to reload the current R session. The reason for this is that once Java is initialized in an R session,
144-
#' it cannot be uninitialized unless the current R session is restarted.
148+
#' 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.
145149
#'
146-
#' @param java_home The path to the desired JAVA_HOME. If NULL, uses the current JAVA_HOME environment variable.
147150
#' @inheritParams global_quiet_param
148-
#' @return TRUE if successful, otherwise FALSE.
151+
#' @inheritParams java_check_version_cmd
152+
#' @return A `character` vector of length 1 containing the major Java version.
149153
#' @examples
154+
#' \dontrun{
150155
#' java_check_version_rjava()
156+
#' }
151157
#'
152158
#' @export
153159
java_check_version_rjava <- function(
@@ -214,28 +220,37 @@ java_check_version_rjava <- function(
214220
} else {
215221
cli::cli_inform("With the user-specified JAVA_HOME {output}")
216222
}
217-
} else {
218-
cli::cli_inform(c("OK", paste("Java version:", java_version)))
219223
}
220-
return(TRUE)
221224
}
222225
} else {
223226
if (!quiet) cli::cli_alert_danger("Failed to retrieve Java version.")
224227
}
228+
229+
matches <- gregexpr('(?<=Java version: \\\")[0-9]{1,2}(?=\\.)', output, perl = TRUE)
230+
major_java_ver <- regmatches(output, matches)[[1]]
231+
major_java_ver
232+
233+
# fix 1 to 8, as Java 8 prints "1.8"
234+
if (major_java_ver == "1") {
235+
major_java_ver <- "8"
236+
}
237+
238+
return(major_java_ver)
225239
}
226240

227241
#' Check installed Java version using terminal commands
228242
#'
229243
#' @param java_home Path to Java home directory. If NULL, the function uses the JAVA_HOME environment variable.
230-
#'
231-
#' @return TRUE if successful, otherwise FALSE.
244+
#' @inheritParams global_quiet_param
245+
#' @return A `character` vector of length 1 containing the major Java version.
232246
#' @export
233247
#'
234248
#' @examples
235249
#' java_check_version_cmd()
236250
#'
237251
java_check_version_cmd <- function(
238-
java_home = NULL
252+
java_home = NULL,
253+
quiet = FALSE
239254
) {
240255
# Backup the current JAVA_HOME
241256
old_java_home <- Sys.getenv("JAVA_HOME")
@@ -248,13 +263,13 @@ java_check_version_cmd <- function(
248263
# Get JAVA_HOME again and check if it's set
249264
current_java_home <- Sys.getenv("JAVA_HOME")
250265
if (current_java_home == "") {
251-
cli::cli_alert_warning("JAVA_HOME is not set.")
266+
if (!quiet) cli::cli_inform(c("!" = "JAVA_HOME is not set."))
252267
if (!is.null(java_home)) {
253268
Sys.setenv(JAVA_HOME = old_java_home)
254269
}
255270
return(FALSE)
256271
} else {
257-
cli::cli_inform("JAVA_HOME: {.path {current_java_home}}")
272+
if (!quiet) cli::cli_inform("JAVA_HOME: {.path {current_java_home}}")
258273
}
259274

260275
# Check if java executable exists in the PATH
@@ -267,27 +282,29 @@ java_check_version_cmd <- function(
267282
}
268283

269284
# Check Java path and version using system commands
270-
success <- java_check_version_system()
285+
major_java_version <- java_check_version_system(quiet = quiet)
271286

272287
# restore original JAVA_HOME that was in the environment before the function was called
273288
if (!is.null(java_home)) {
274289
Sys.setenv(JAVA_HOME = old_java_home)
275290
}
276291

277-
return(success)
292+
return(major_java_version)
278293
}
279294

280-
#' Check and print Java path and version
295+
#' Check and print Java path and version using system commands
281296
#'
282297
#' This function checks the Java executable path and retrieves the Java version,
283298
#' then prints these details to the console.
284-
#'
299+
#' @inheritParams java_check_version_cmd
300+
#' @return A `character` vector of length 1 containing the major Java version.
285301
#' @keywords internal
286-
#'
287-
#' @return TRUE if successful, otherwise FALSE.
288-
java_check_version_system <- function() {
302+
#'
303+
java_check_version_system <- function(
304+
quiet
305+
) {
289306
which_java <- tryCatch(
290-
system2("which", args = "java", stdout = TRUE, stderr = TRUE),
307+
Sys.which("java"),
291308
error = function(e) NULL
292309
)
293310
if (is.null(which_java)) {
@@ -303,12 +320,24 @@ java_check_version_system <- function() {
303320
return(FALSE)
304321
}
305322

306-
cli::cli_inform(c(
307-
"Java path: {.path {which_java}}",
308-
"Java version:\n{.val {paste(java_ver, collapse = '\n')}}"
309-
))
323+
if (!quiet) {
324+
cli::cli_inform(c(
325+
"Java path: {.path {which_java}}",
326+
"Java version:\n{.val {paste(java_ver, collapse = '\n')}}"
327+
))
328+
}
329+
330+
# extract Java version
331+
java_ver_string <- java_ver[[1]]
332+
matches <- gregexpr('(?<=openjdk version \\\")[0-9]{1,2}(?=\\.)', java_ver_string, perl = TRUE)
333+
major_java_ver <- regmatches(java_ver_string, matches)[[1]]
334+
335+
# fix 1 to 8, as Java 8 prints "1.8"
336+
if (major_java_ver == "1") {
337+
major_java_ver <- "8"
338+
}
310339

311-
invisible(TRUE)
340+
return(major_java_ver)
312341
}
313342

314343

@@ -346,7 +375,7 @@ java_env_unset <- function(
346375
}
347376
} else {
348377
if (!quiet) {
349-
cli::cli_alert_warning("No .Rprofile found in the project directory: {.path project_path}")
378+
cli::cli_inform(c("!" = "No .Rprofile found in the project directory: {.path project_path}"))
350379
}
351380
}
352381
}

R/java_install.R

Lines changed: 15 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
#' Install Java from a distribution file
22
#'
3-
#' @param java_distrib_path The path to the Java distribution file.
4-
#' @param project_path The project directory where Java should be installed. If not specified or `NULL`, defaults to the current working directory.
5-
#' @param autoset_java_env Whether to set the `JAVA_HOME` and `PATH` environment variables to the installed Java directory. Defaults to `TRUE`.
3+
#' @description
4+
#' Unpack Java distribution file into cache directory and link the installation into a project directory, optionally setting the `JAVA_HOME` and `PATH` environment variables to the Java version that was just installed.
5+
#'
6+
#' @param java_distrib_path A `character` vector of length 1 containing the path to the Java distribution file.
7+
#' @param project_path A `character` vector of length 1 containing the project directory where Java should be installed. If not specified or `NULL`, defaults to the current working directory.
8+
#' @param autoset_java_env A `logical` indicating whether to set the `JAVA_HOME` and `PATH` environment variables to the installed Java directory. Defaults to `TRUE`.
69
#' @inheritParams java_download
710
#' @inheritParams global_quiet_param
811
#' @return The path to the installed Java directory.
@@ -24,16 +27,21 @@ java_install <- function(
2427
quiet = FALSE
2528
) {
2629
rje_consent_check()
27-
28-
platforms <- c("windows", "linux", "macos")
29-
architectures <- c("x64", "aarch64", "arm64")
30-
java_versions <- c("8", "11", "17", "21", "22")
3130

3231
# Resolve the project path
3332
# consistent with renv behavior
3433
# https://github.com/rstudio/renv/blob/d6bced36afa0ad56719ca78be6773e9b4bbb078f/R/init.R#L69-L86
3534
project_path <- ifelse(is.null(project_path), getwd(), project_path)
3635

36+
installed_path <- java_unpack(
37+
java_distrib_path = java_distrib_path,
38+
quiet = quiet
39+
)
40+
41+
platforms <- c("windows", "linux", "macos")
42+
architectures <- c("x64", "aarch64", "arm64")
43+
java_versions <- getOption("rJavaEnv.valid_major_java_versions")
44+
3745
# Extract information from the file name
3846
filename <- basename(java_distrib_path)
3947
parts <- strsplit(gsub("\\.tar\\.gz|\\.zip", "", filename), "-")[[1]]
@@ -43,61 +51,6 @@ java_install <- function(
4351
arch <- parts[vapply(parts, function(x) x %in% architectures, logical(1))][1]
4452
platform <- parts[vapply(parts, function(x) x %in% platforms, logical(1))][1]
4553

46-
if (is.na(version)) stop(cli::cli_abort("Unable to detect Java version from filename.", .envir = environment()))
47-
if (is.na(arch)) stop(cli::cli_abort("Unable to detect architecture from filename.", .envir = environment()))
48-
if (is.na(platform)) stop(cli::cli_abort("Unable to detect platform from filename.", .envir = environment()))
49-
50-
# Create the installation path in the package cache
51-
cache_path <- getOption("rJavaEnv.cache_path")
52-
installed_path <- file.path(cache_path, "installed", platform, arch, version)
53-
54-
# Check if the distribution has already been unpacked
55-
if (!dir.exists(installed_path) || length(list.files(installed_path)) == 0) {
56-
# Create the directories if they don't exist
57-
if (!dir.exists(installed_path)) {
58-
dir.create(installed_path, recursive = TRUE)
59-
}
60-
61-
# Determine extraction path based on platform
62-
if (platform == "macos") {
63-
extract_subdir <- "Contents/Home"
64-
} else {
65-
extract_subdir <- "."
66-
}
67-
68-
# Extract the files
69-
temp_dir <- file.path(tempdir(), "java_temp")
70-
if (dir.exists(temp_dir)) {
71-
unlink(temp_dir, recursive = TRUE)
72-
}
73-
74-
dir.create(temp_dir, recursive = TRUE)
75-
76-
if (grepl("\\.tar\\.gz$", java_distrib_path)) {
77-
utils::untar(java_distrib_path, exdir = temp_dir)
78-
} else if (grepl("\\.zip$", java_distrib_path)) {
79-
utils::unzip(java_distrib_path, exdir = temp_dir)
80-
} else {
81-
stop(cli::cli_abort("Unsupported file format", .envir = environment()))
82-
}
83-
84-
# Safely find the extracted directory
85-
extracted_root_dir <- list.files(temp_dir, full.names = TRUE)[1]
86-
if (platform == "macos") {
87-
extracted_dir <- file.path(extracted_root_dir, "Contents", "Home")
88-
} else {
89-
extracted_dir <- extracted_root_dir
90-
}
91-
92-
# Move the extracted files to the installation path
93-
file.copy(list.files(extracted_dir, full.names = TRUE), installed_path, recursive = TRUE)
94-
95-
# Clean up temporary directory
96-
unlink(temp_dir, recursive = TRUE)
97-
} else {
98-
if (!quiet) cli::cli_inform("Java distribution {filename} already unpacked at {.path {installed_path}}")
99-
}
100-
10154
# Create a symlink in the project directory
10255
project_version_path <- file.path(project_path, "rjavaenv", platform, arch, version)
10356
if (!dir.exists(dirname(project_version_path))) {

0 commit comments

Comments
 (0)