Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion DESCRIPTION
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ Description: Sets up the macOS Rtools compiled code toolchain.
License: AGPL (>= 3)
Encoding: UTF-8
Roxygen: list(markdown = TRUE)
RoxygenNote: 7.3.3
OS_type: unix
SystemRequirements: macOS
Imports:
Expand All @@ -34,3 +33,4 @@ Suggests:
mockery,
testthat (>= 3.0.0)
Config/testthat/edition: 3
Config/roxygen2/version: 8.0.0
4 changes: 2 additions & 2 deletions R/assertions.R
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ assert <- function(condition, message = NULL, call = caller_env()) {
#' @export
assert_mac <- function(call = caller_env()) {
if (!is_macos()) {
current_os <- base::tolower(base::Sys.info()[['sysname']])
current_os <- system_os()
cli::cli_abort(c(
"{.pkg macrtools}: This function requires macOS.",
"{.pkg macrtools}: The current operating system is {.val {current_os}}."
Expand Down Expand Up @@ -80,7 +80,7 @@ assert_x86_64 <- function(call = caller_env()) {
#' @export
assert_r_version_supported <- function(call = caller_env()) {
if (!is_r_version_supported()) {
version_number <- base::paste(base::R.version$major, base::R.version$minor, sep = ".")
version_number <- r_version_full()
supported_min <- minimum_supported_r_version()
supported_max <- maximum_supported_r_version()
cli::cli_abort(c(
Expand Down
2 changes: 1 addition & 1 deletion R/blocks.R
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ block_replace = function(desc, value, path,

if (base::is.null(block_lines)) {
base::message("Copy and paste the following lines into ", path, ":")
base::paste0(base::c(block_start, value, block_end), collapse = "\n")
base::message(base::paste0(base::c(block_start, value, block_end), collapse = "\n"))
return(base::invisible(FALSE))
}

Expand Down
120 changes: 63 additions & 57 deletions R/gfortran.R
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@ gfortran_install <- function(password = base::getOption("macrtools.password"), v
if (verbose) {
# Get system info
arch_info <- system_arch()
r_version <- base::paste(base::R.version$major, base::R.version$minor, sep='.')
r_version <- r_version_full()

cli::cli_alert_info("{.pkg macrtools}: Preparing to download and install gfortran.")
cli::cli_bullets(c(
Expand Down Expand Up @@ -243,60 +243,15 @@ gfortran_install <- function(password = base::getOption("macrtools.password"), v
password = entered_password_gfortran,
verbose = verbose)
} else if(is_r_version_at_least("4.0")) {
if (is_x86_64()) {
gfortran_status <- install_gfortran_82_mojave(
password = entered_password_gfortran,
verbose = verbose)
} else if (is_aarch64()) {
if (is_r_version("4.2")) {
if (verbose) {
install_path <- install_location()
cli::cli_alert_info("{.pkg macrtools}: Installing gfortran 12 for Apple Silicon with R 4.2")
cli::cli_bullets(c(
"Source: {.url https://mac.r-project.org/tools/}",
"Target installation: {.path {install_path}}"
))
cli::cli_text("") # Add spacing
}
gfortran_status <- install_gfortran_12_arm(
password = entered_password_gfortran,
verbose = verbose)
} else if(is_r_version("4.1")) {
if (verbose) {
install_path <- install_location()
cli::cli_alert_info("{.pkg macrtools}: Installing gfortran 11 for Apple Silicon with R 4.1")
cli::cli_bullets(c(
"Source: {.url https://mac.r-project.org/libs-arm64/}",
"Target installation: {.path {install_path}}"
))
cli::cli_text("") # Add spacing
}
gfortran_status <- install_gfortran_11_arm(
password = entered_password_gfortran,
verbose = verbose)
} else {
cli::cli_abort(c(
"{.pkg macrtools}: Unable to install gfortran for Apple Silicon (arm64/aarch64).",
"i" = "Official R support for Apple Silicon began in R 4.1.",
"i" = "Please upgrade R to version 4.1 or higher.",
"i" = "Visit https://cran.r-project.org/bin/macosx/ to download a compatible R version for Apple Silicon."
))
return(base::invisible(FALSE))
}
} else {
arch <- system_arch()
cli::cli_abort(c(
"{.pkg macrtools}: Unsupported macOS architecture: {.val {arch}}",
"i" = "Only Intel (x86_64) and Apple Silicon (arm64/aarch64) architectures are supported."
))
return(base::invisible(FALSE))
}
gfortran_status <- install_gfortran_legacy(
password = entered_password_gfortran,
verbose = verbose)
}

if(base::isFALSE(gfortran_status)) {
install_path <- gfortran_install_location()
arch_info <- system_arch()
r_version <- base::paste(base::R.version$major, base::R.version$minor, sep='.')
r_version <- r_version_full()

cli::cli_abort(c(
"{.pkg macrtools}: Failed to install gfortran.",
Expand All @@ -305,7 +260,6 @@ gfortran_install <- function(password = base::getOption("macrtools.password"), v
"i" = "R version: {.val {r_version}}",
"i" = "Please try to manually install following the instructions at: https://mac.thecoatlessprofessor.com/macrtools/reference/gfortran.html#installing-gfortran"
))
return(base::invisible(FALSE))
}

renviron_gfortran_path(path_variable)
Expand Down Expand Up @@ -392,7 +346,6 @@ gfortran_uninstall <- function(password = base::getOption("macrtools.password"),
"{.pkg macrtools}: We were not able to uninstall gfortran.",
"i" = "Please try to manually uninstall using: https://mac.thecoatlessprofessor.com/macrtools/reference/gfortran.html#uninstalling-gfortran"
))
return(base::invisible(FALSE))
}

if (verbose) {
Expand Down Expand Up @@ -434,15 +387,14 @@ gfortran_update <- function(password = base::getOption("macrtools.password"), ve
# Verify that the tool exists
if (!base::file.exists(path_gfortran_update)) {
cli::cli_abort("{.pkg macrtools}: Could not find gfortran-update-sdk at {.path {path_gfortran_update}}")
return(base::invisible(FALSE))
}

if (verbose) {
cli::cli_alert_info("{.pkg macrtools}: Updating gfortran.")
cli::cli_bullets(c(
"Update tool: {.path {path_gfortran_update}}",
"Architecture: {.val {system_arch()}}",
"R version: {.val {base::paste(base::R.version$major, base::R.version$minor, sep='.')}}"
"R version: {.val {r_version_full()}}"
))
cli::cli_text("") # Add spacing
}
Expand All @@ -458,7 +410,6 @@ gfortran_update <- function(password = base::getOption("macrtools.password"), ve
"{.pkg macrtools}: We were not able to update gfortran.",
"i" = "Please try to manually update using: https://mac.thecoatlessprofessor.com/macrtools/reference/gfortran.html#updating-gfortran"
))
return(base::invisible(FALSE))
}

if (verbose) {
Expand All @@ -474,7 +425,7 @@ gfortran <- function(args) {
sys::exec_internal("gfortran", args = args, error = FALSE),
error = function(e) {
base::list(
output = e,
stdout = base::charToRaw(base::paste0(base::conditionMessage(e), "\n")),
status = -127L
)
}
Expand All @@ -489,6 +440,62 @@ gfortran <- function(args) {
)
}

#' Install gfortran for the legacy R 4.0-4.2 toolchain
#'
#' @details
#' Intel Macs use the gfortran 8.2 Mojave DMG; Apple Silicon uses the gfortran 12
#' (R 4.2) or gfortran 11 (R 4.1) arm64 tarball. Apple Silicon on R 4.0 and any
#' other architecture are unsupported and abort.
#'
#' @noRd
install_gfortran_legacy <- function(password = base::getOption("macrtools.password"),
verbose = TRUE) {
if (is_x86_64()) {
return(install_gfortran_82_mojave(password = password, verbose = verbose))
}

if (!is_aarch64()) {
arch <- system_arch()
cli::cli_abort(c(
"{.pkg macrtools}: Unsupported macOS architecture: {.val {arch}}",
"i" = "Only Intel (x86_64) and Apple Silicon (arm64/aarch64) architectures are supported."
))
}

if (is_r_version("4.2")) {
if (verbose) {
install_path <- install_location()
cli::cli_alert_info("{.pkg macrtools}: Installing gfortran 12 for Apple Silicon with R 4.2")
cli::cli_bullets(c(
"Source: {.url https://mac.r-project.org/tools/}",
"Target installation: {.path {install_path}}"
))
cli::cli_text("") # Add spacing
}
return(install_gfortran_12_arm(password = password, verbose = verbose))
}

if (is_r_version("4.1")) {
if (verbose) {
install_path <- install_location()
cli::cli_alert_info("{.pkg macrtools}: Installing gfortran 11 for Apple Silicon with R 4.1")
cli::cli_bullets(c(
"Source: {.url https://mac.r-project.org/libs-arm64/}",
"Target installation: {.path {install_path}}"
))
cli::cli_text("") # Add spacing
}
return(install_gfortran_11_arm(password = password, verbose = verbose))
}

cli::cli_abort(c(
"{.pkg macrtools}: Unable to install gfortran for Apple Silicon (arm64/aarch64).",
"i" = "Official R support for Apple Silicon began in R 4.1.",
"i" = "Please upgrade R to version 4.1 or higher.",
"i" = "Visit https://cran.r-project.org/bin/macosx/ to download a compatible R version for Apple Silicon."
))
}

#' Download and Install gfortran 8.2 for Intel Macs
#'
#' @noRd
Expand Down Expand Up @@ -520,7 +527,6 @@ install_gfortran_82_mojave <- function(password = base::getOption("macrtools.pas

if (!success) {
cli::cli_abort("{.pkg macrtools}: Error installing the gfortran package")
return(FALSE)
}

# Remove unused gfortran file
Expand Down
69 changes: 29 additions & 40 deletions R/installers.R
Original file line number Diff line number Diff line change
@@ -1,69 +1,59 @@
# Installation directories ----

install_strip_level <- function(arch = system_arch()) {
# Dispatch on architecture, mapping arm64/aarch64 to the same value, with a
# shared error for anything that is not Apple Silicon or Intel.
arch_switch <- function(arch, arm64, x86_64) {
base::switch(
arch,
"arm64" = 3,
"aarch64" = 3,
"x86_64" = 2,
"arm64" = arm64,
"aarch64" = arm64,
"x86_64" = x86_64,
cli::cli_abort("{.pkg macrtools}: Architecture {.val {arch}} not recognized. Please ensure you are on either an Apple Silicon (arm64) or Intel (x86_64) system.")
)
}

recipe_binary_install_strip_level <- function(arch = system_arch()) {
# Guard the recipe/gfortran installers against unsupported R versions, naming
# the component that is unavailable.
assert_supported_r_version_for <- function(component) {
if (!is_r_version_supported()) {
supported_min <- minimum_supported_r_version()
supported_max <- maximum_supported_r_version()
cli::cli_abort("{.pkg macrtools}: Unsupported R version. We only support recipe binary installation for R {supported_min}.x through R {supported_max}.x.")
cli::cli_abort("{.pkg macrtools}: Unsupported R version. We only support {component} for R {supported_min}.x through R {supported_max}.x.")
}
}

install_strip_level <- function(arch = system_arch()) {
arch_switch(arch, arm64 = 3, x86_64 = 2)
}

recipe_binary_install_strip_level <- function(arch = system_arch()) {
assert_supported_r_version_for("recipe binary installation")
if (is_r_version_at_least("4.3")) {
base::switch(
arch,
"arm64" = 3,
"aarch64" = 3,
"x86_64" = 3,
cli::cli_abort("{.pkg macrtools}: Architecture {.val {arch}} not recognized. Please ensure you are on either an Apple Silicon (arm64) or Intel (x86_64) system.")
)
arch_switch(arch, arm64 = 3, x86_64 = 3)
} else {
install_strip_level()
}
}

install_location <- function(arch = system_arch()) {
base::switch(
arch,
"arm64" = install_directory_arm64(),
"aarch64" = install_directory_arm64(),
"x86_64" = install_directory_x86_64(),
cli::cli_abort("{.pkg macrtools}: Architecture {.val {arch}} not recognized. Please ensure you are on either an Apple Silicon (arm64) or Intel (x86_64) system.")
)
arch_switch(arch, arm64 = install_directory_arm64(), x86_64 = install_directory_x86_64())
}

recipe_binary_install_location <- function(arch = system_arch()) {
if (!is_r_version_supported()) {
supported_min <- minimum_supported_r_version()
supported_max <- maximum_supported_r_version()
cli::cli_abort("{.pkg macrtools}: Unsupported R version. We only support recipe binary installation for R {supported_min}.x through R {supported_max}.x.")
}
assert_supported_r_version_for("recipe binary installation")
if (is_r_version_at_least("4.3")) {
base::switch(
arch_switch(
arch,
"arm64" = install_directory_arm64(),
"aarch64" = install_directory_arm64(),
"x86_64" = install_directory_x86_64_r_version_4_3(),
cli::cli_abort("{.pkg macrtools}: Architecture {.val {arch}} not recognized. Please ensure you are on either an Apple Silicon (arm64) or Intel (x86_64) system.")
arm64 = install_directory_arm64(),
x86_64 = install_directory_x86_64_r_version_4_3()
)
} else {
install_location()
}
}

gfortran_install_location <- function(arch = system_arch()) {
if (!is_r_version_supported()) {
supported_min <- minimum_supported_r_version()
supported_max <- maximum_supported_r_version()
cli::cli_abort("{.pkg macrtools}: Unsupported R version. We only support gfortran installation for R {supported_min}.x through R {supported_max}.x.")
}
assert_supported_r_version_for("gfortran installation")
if (is_r_version_at_least("4.3")) {
"/opt"
} else {
Expand Down Expand Up @@ -275,7 +265,7 @@ tar_package_install <- function(path_to_tar,
status <- shell_execute(cmd, sudo = sudo, password = password, verbose = verbose)

# Verify installation is okay:
if (status < 0) {
if (status != 0) {
cli::cli_abort("{.pkg macrtools}: Failed to install from {.path {path_to_tar}}")
}

Expand Down Expand Up @@ -347,15 +337,14 @@ dmg_package_install <- function(path_to_dmg,
install_status <- shell_execute(cmd, sudo = TRUE, password = password)

if (install_status != 0) {
# Unmount the volume before surfacing the failure so we do not leak it.
cmd <- base::paste("hdiutil", "detach", base::shQuote(base::file.path("/Volumes", bare_volume)))
shell_execute(cmd, sudo = FALSE)
cli::cli_abort(c(
"{.pkg macrtools}: Failed to install package from disk image.",
"Disk image: {.file {volume_with_extension}}",
"Status code: {.val {install_status}}"
))
# Attempt to unmount anyway
cmd <- base::paste("hdiutil", "detach", base::shQuote(base::file.path("/Volumes", bare_volume)))
shell_execute(cmd, sudo = FALSE)
return(FALSE)
}

if (verbose) {
Expand Down
Loading
Loading