From bb5aeca97ba05dc0a0c54173e5640d408723ac38 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 13 Apr 2026 19:11:04 +0000 Subject: [PATCH 1/7] Bump Vampire/setup-wsl from 6 to 7 Bumps [Vampire/setup-wsl](https://github.com/vampire/setup-wsl) from 6 to 7. - [Release notes](https://github.com/vampire/setup-wsl/releases) - [Commits](https://github.com/vampire/setup-wsl/compare/v6...v7) --- updated-dependencies: - dependency-name: Vampire/setup-wsl dependency-version: '7' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/R-CMD-check-wsl.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/R-CMD-check-wsl.yaml b/.github/workflows/R-CMD-check-wsl.yaml index 2d6475c3..7e77a422 100644 --- a/.github/workflows/R-CMD-check-wsl.yaml +++ b/.github/workflows/R-CMD-check-wsl.yaml @@ -44,7 +44,7 @@ jobs: with: extra-packages: any::rcmdcheck, local::. - - uses: Vampire/setup-wsl@v6 + - uses: Vampire/setup-wsl@v7 with: distribution: Ubuntu-22.04 wsl-version: 2 From 33f435ca716fc5a65c22872ceeedc4864847eed4 Mon Sep 17 00:00:00 2001 From: jgabry Date: Mon, 13 Apr 2026 20:21:06 -0600 Subject: [PATCH 2/7] try fixing WSL CI --- .github/workflows/R-CMD-check-wsl.yaml | 7 ++++++- .github/workflows/R-CMD-check.yaml | 2 +- .github/workflows/Test-coverage.yaml | 2 +- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/.github/workflows/R-CMD-check-wsl.yaml b/.github/workflows/R-CMD-check-wsl.yaml index 7e77a422..a753680b 100644 --- a/.github/workflows/R-CMD-check-wsl.yaml +++ b/.github/workflows/R-CMD-check-wsl.yaml @@ -32,7 +32,7 @@ jobs: steps: - name: cmdstan env vars run: | - echo "CMDSTAN_PATH=${HOME}/.cmdstan" >> $GITHUB_ENV + echo "CMDSTAN=${HOME}/.cmdstan" >> $GITHUB_ENV shell: bash - uses: actions/checkout@v6 @@ -61,6 +61,11 @@ jobs: run: | cmdstanr::check_cmdstan_toolchain() cmdstanr::install_cmdstan(cores = 2, wsl = TRUE, overwrite = TRUE) + cat( + paste0("CMDSTAN=", cmdstanr::cmdstan_path(), "\n"), + file = Sys.getenv("GITHUB_ENV"), + append = TRUE + ) shell: Rscript {0} - name: Session info diff --git a/.github/workflows/R-CMD-check.yaml b/.github/workflows/R-CMD-check.yaml index be322ea4..a0df178b 100644 --- a/.github/workflows/R-CMD-check.yaml +++ b/.github/workflows/R-CMD-check.yaml @@ -55,7 +55,7 @@ jobs: steps: - name: cmdstan env vars run: | - echo "CMDSTAN_PATH=${HOME}/.cmdstan" >> $GITHUB_ENV + echo "CMDSTAN=${HOME}/.cmdstan" >> $GITHUB_ENV shell: bash - uses: actions/checkout@v6 diff --git a/.github/workflows/Test-coverage.yaml b/.github/workflows/Test-coverage.yaml index 5598d53b..65a2b4e4 100644 --- a/.github/workflows/Test-coverage.yaml +++ b/.github/workflows/Test-coverage.yaml @@ -34,7 +34,7 @@ jobs: steps: - name: cmdstan env vars run: | - echo "CMDSTAN_PATH=${HOME}/.cmdstan" >> $GITHUB_ENV + echo "CMDSTAN=${HOME}/.cmdstan" >> $GITHUB_ENV shell: bash - uses: n1hility/cancel-previous-runs@v3 From 6d7187cc694154993b098fa4054ae4d2b6480f35 Mon Sep 17 00:00:00 2001 From: jgabry Date: Tue, 14 Apr 2026 08:20:45 -0600 Subject: [PATCH 3/7] Remove unnecessary cmdstan env vars step in all workflows --- .github/workflows/R-CMD-check-wsl.yaml | 5 ----- .github/workflows/R-CMD-check.yaml | 5 ----- .github/workflows/Test-coverage.yaml | 5 ----- 3 files changed, 15 deletions(-) diff --git a/.github/workflows/R-CMD-check-wsl.yaml b/.github/workflows/R-CMD-check-wsl.yaml index a753680b..6b564d1d 100644 --- a/.github/workflows/R-CMD-check-wsl.yaml +++ b/.github/workflows/R-CMD-check-wsl.yaml @@ -30,11 +30,6 @@ jobs: CMDSTANR_OPENCL_TESTS: true steps: - - name: cmdstan env vars - run: | - echo "CMDSTAN=${HOME}/.cmdstan" >> $GITHUB_ENV - shell: bash - - uses: actions/checkout@v6 - uses: r-lib/actions/setup-r@v2 diff --git a/.github/workflows/R-CMD-check.yaml b/.github/workflows/R-CMD-check.yaml index a0df178b..85293dab 100644 --- a/.github/workflows/R-CMD-check.yaml +++ b/.github/workflows/R-CMD-check.yaml @@ -53,11 +53,6 @@ jobs: PKG_SYSREQS_DB_UPDATE_TIMEOUT: 30s steps: - - name: cmdstan env vars - run: | - echo "CMDSTAN=${HOME}/.cmdstan" >> $GITHUB_ENV - shell: bash - - uses: actions/checkout@v6 - uses: r-lib/actions/setup-r@v2 diff --git a/.github/workflows/Test-coverage.yaml b/.github/workflows/Test-coverage.yaml index 65a2b4e4..166ad66c 100644 --- a/.github/workflows/Test-coverage.yaml +++ b/.github/workflows/Test-coverage.yaml @@ -32,11 +32,6 @@ jobs: NOT_CRAN: true steps: - - name: cmdstan env vars - run: | - echo "CMDSTAN=${HOME}/.cmdstan" >> $GITHUB_ENV - shell: bash - - uses: n1hility/cancel-previous-runs@v3 with: token: ${{ secrets.GITHUB_TOKEN }} From 11d90f355525743addcf2fd745d4ac021b3f5f16 Mon Sep 17 00:00:00 2001 From: Visruth Srimath Kandali Date: Tue, 14 Apr 2026 09:55:38 -0700 Subject: [PATCH 4/7] Update R-CMD-check-wsl.yaml Trying what copilot suggested--user perms changed with v7 --- .github/workflows/R-CMD-check-wsl.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/R-CMD-check-wsl.yaml b/.github/workflows/R-CMD-check-wsl.yaml index 6b564d1d..699958a9 100644 --- a/.github/workflows/R-CMD-check-wsl.yaml +++ b/.github/workflows/R-CMD-check-wsl.yaml @@ -50,6 +50,7 @@ jobs: run: | sudo apt-get update sudo apt-get install -y build-essential libopenmpi-dev ocl-icd-opencl-dev pocl-opencl-icd + sudo chmod 755 /root shell: wsl-bash {0} - name: Install cmdstan From c7621839938bd81ad8d4376cff84c0e2abe9911e Mon Sep 17 00:00:00 2001 From: jgabry Date: Tue, 14 Apr 2026 12:31:51 -0600 Subject: [PATCH 5/7] Honor CMDSTAN in set_cmdstan_path() --- R/path.R | 108 +++++++++++++++++++++++++------------ R/zzz.R | 41 +------------- man/set_cmdstan_path.Rd | 3 +- tests/testthat/test-path.R | 27 +++++++++- 4 files changed, 102 insertions(+), 77 deletions(-) diff --git a/R/path.R b/R/path.R index 3e4fecc1..a8af3565 100644 --- a/R/path.R +++ b/R/path.R @@ -9,7 +9,8 @@ #' @export #' #' @param path (string) The full file path to the CmdStan installation. If -#' `NULL` (the default) then the path is set to the default path used by +#' `NULL` (the default) then the path is set using the `"CMDSTAN"` +#' environment variable when available, otherwise the default path used by #' [install_cmdstan()] if it exists. #' @return A string. Either the file path to the CmdStan installation or the #' CmdStan version number. @@ -39,7 +40,20 @@ #' set_cmdstan_path <- function(path = NULL) { if (is.null(path)) { - path <- cmdstan_default_path() + env_path <- resolve_cmdstan_path_from_env() + if (isTRUE(is.na(env_path))) { + unset_cmdstan_path() + return(invisible(NULL)) + } + if (!is.null(env_path)) { + path <- env_path + } else { + path <- cmdstan_default_path() + if (is.null(path)) { + unset_cmdstan_path() + return(invisible(NULL)) + } + } } if (dir.exists(path)) { path <- absolute_path(path) @@ -50,9 +64,7 @@ set_cmdstan_path <- function(path = NULL) { "cmdstanr now requires CmdStan v", cmdstan_min_version(), " or newer.", call. = FALSE ) - .cmdstanr$PATH <- NULL - .cmdstanr$VERSION <- NULL - .cmdstanr$WSL <- FALSE + unset_cmdstan_path() return(invisible(path)) } .cmdstanr$PATH <- path @@ -60,7 +72,7 @@ set_cmdstan_path <- function(path = NULL) { .cmdstanr$WSL <- grepl("//wsl$", path, fixed = TRUE) message("CmdStan path set to: ", path) } else { - warning("Path not set. Can't find directory: ", path, call. = FALSE) + warning("CmdStan path not set. Can't find directory: ", path, call. = FALSE) } invisible(path) } @@ -102,6 +114,12 @@ cmdstan_version <- function(error_on_NA = TRUE) { .cmdstanr$TEMP_DIR <- NULL .cmdstanr$WSL <- FALSE +unset_cmdstan_path <- function() { + .cmdstanr$PATH <- NULL + .cmdstanr$VERSION <- NULL + .cmdstanr$WSL <- FALSE +} + # path to temp directory cmdstan_tempdir <- function() { .cmdstanr$TEMP_DIR @@ -128,8 +146,36 @@ is_supported_cmdstan_version <- function(version) { isTRUE(cmp >= 0) } -#' cmdstan_default_install_path -#' +resolve_cmdstan_path_from_env <- function() { + path <- Sys.getenv("CMDSTAN") + if (!nzchar(path)) { + return(NULL) + } + if (!dir.exists(path)) { + warning( + "CmdStan path not set. Can't find directory specified by environment ", + "variable 'CMDSTAN'.", + call. = FALSE + ) + return(NA_character_) + } + path <- absolute_path(path) + version <- suppressWarnings(read_cmdstan_version(path)) + if (!is.null(version)) { + return(path) + } + path <- cmdstan_default_path(dir = path) + if (is.null(path)) { + warning( + "CmdStan path not set. No CmdStan installation found in the path ", + "specified by the environment variable 'CMDSTAN'.", + call. = FALSE + ) + return(NA_character_) + } + path +} + #' Path to where [install_cmdstan()] with default settings installs CmdStan. #' #' @keywords internal @@ -140,14 +186,24 @@ cmdstan_default_install_path <- function(wsl = FALSE) { if (wsl) { file.path(paste0(wsl_dir_prefix(wsl = TRUE), wsl_home_dir()), ".cmdstan") } else { - file.path(.home_path(), ".cmdstan") + file.path(home_path(), ".cmdstan") } } -#' cmdstan_default_path -#' -#' Returns the path to the installation of CmdStan with the most recent release -#' version. +home_path <- function() { + home <- Sys.getenv("HOME") + if (os_is_windows()) { + userprofile <- Sys.getenv("USERPROFILE") + h_drivepath <- file.path(Sys.getenv("HOMEDRIVE"), Sys.getenv("HOMEPATH")) + win_home <- ifelse(userprofile == "", h_drivepath, userprofile) + if (win_home != "") { + home <- win_home + } + } + home +} + +#' Path to the installation of CmdStan with the most recent release version #' #' For Windows systems with WSL CmdStan installs, if there are side-by-side WSL #' and native installs with the same version then the WSL is preferred. @@ -180,9 +236,9 @@ cmdstan_default_path <- function(dir = NULL) { } if (dir.exists(installs_path) || wsl_path_exists) { latest_cmdstan <- ifelse(dir.exists(installs_path), - .latest_cmdstan_installed(installs_path), "") + latest_cmdstan_installed(installs_path), "") latest_wsl_cmdstan <- ifelse(wsl_path_exists, - .latest_cmdstan_installed(wsl_installs_path), "") + latest_cmdstan_installed(wsl_installs_path), "") if (!nzchar(latest_cmdstan) && !nzchar(latest_wsl_cmdstan)) { return(NULL) } @@ -195,7 +251,7 @@ cmdstan_default_path <- function(dir = NULL) { NULL } -.latest_cmdstan_installed <- function(installs_path) { +latest_cmdstan_installed <- function(installs_path) { cmdstan_installs <- list.dirs(path = installs_path, recursive = FALSE, full.names = FALSE) # if installed in cmdstan folder with no version move to cmdstan-version folder if ("cmdstan" %in% cmdstan_installs) { @@ -242,6 +298,7 @@ read_cmdstan_version <- function(path) { sub("CMDSTAN_VERSION := ", "", version_line) } + #' Returns whether the supplied installation is a release candidate #' @noRd #' @param path Path to installation. @@ -253,12 +310,6 @@ is_release_candidate <- function(path) { grepl(pattern = "-rc[0-9]*$", x = path) } -# unset the path (only used in tests) -unset_cmdstan_path <- function() { - .cmdstanr$PATH <- NULL - .cmdstanr$VERSION <- NULL - .cmdstanr$WSL <- FALSE -} # fake a cmdstan version (only used in tests) fake_cmdstan_version <- function(version, mod = NULL) { @@ -275,16 +326,3 @@ fake_cmdstan_version <- function(version, mod = NULL) { reset_cmdstan_version <- function(mod = NULL) { fake_cmdstan_version(read_cmdstan_version(cmdstan_path()), mod = mod) } - -.home_path <- function() { - home <- Sys.getenv("HOME") - if (os_is_windows()) { - userprofile <- Sys.getenv("USERPROFILE") - h_drivepath <- file.path(Sys.getenv("HOMEDRIVE"), Sys.getenv("HOMEPATH")) - win_home <- ifelse(userprofile == "", h_drivepath, userprofile) - if (win_home != "") { - home <- win_home - } - } - home -} diff --git a/R/zzz.R b/R/zzz.R index 68d59245..bea367db 100644 --- a/R/zzz.R +++ b/R/zzz.R @@ -35,46 +35,7 @@ startup_messages <- function() { } cmdstanr_initialize <- function() { - # First check for environment variable CMDSTAN, but if not found - # then see if default - path <- Sys.getenv("CMDSTAN") - if (isTRUE(nzchar(path))) { # CMDSTAN environment variable found - if (dir.exists(path)) { - path <- absolute_path(path) - suppressWarnings(suppressMessages(set_cmdstan_path(path))) - if (is.null(cmdstan_version(error_on_NA = FALSE))) { - path <- cmdstan_default_path(dir = path) - if (is.null(path)) { - warning( - "No CmdStan installation found in the path specified ", - "by the environment variable 'CMDSTAN'.", - call. = FALSE - ) - .cmdstanr$PATH <- NULL - .cmdstanr$VERSION <- NULL - .cmdstanr$WSL <- FALSE - } else { - set_cmdstan_path(path) - } - } - } else { - warning( - "Can't find directory specified by environment variable 'CMDSTAN'. ", - "Path not set.", - call. = FALSE - ) - .cmdstanr$PATH <- NULL - .cmdstanr$VERSION <- NULL - .cmdstanr$WSL <- FALSE - } - - } else { # environment variable not found - path <- cmdstan_default_path() - if (!is.null(path)) { - suppressMessages(set_cmdstan_path(path)) - } - } - + suppressMessages(set_cmdstan_path()) .cmdstanr$TEMP_DIR <- tempdir(check = TRUE) invisible(TRUE) } diff --git a/man/set_cmdstan_path.Rd b/man/set_cmdstan_path.Rd index b803cdd8..fe77e09c 100644 --- a/man/set_cmdstan_path.Rd +++ b/man/set_cmdstan_path.Rd @@ -14,7 +14,8 @@ cmdstan_version(error_on_NA = TRUE) } \arguments{ \item{path}{(string) The full file path to the CmdStan installation. If -\code{NULL} (the default) then the path is set to the default path used by +\code{NULL} (the default) then the path is set using the \code{"CMDSTAN"} +environment variable when available, otherwise the default path used by \code{\link[=install_cmdstan]{install_cmdstan()}} if it exists.} \item{error_on_NA}{(logical) Should an error be thrown if CmdStan is not diff --git a/tests/testthat/test-path.R b/tests/testthat/test-path.R index 5bc25819..d2c7d9d7 100644 --- a/tests/testthat/test-path.R +++ b/tests/testthat/test-path.R @@ -45,6 +45,31 @@ test_that("Setting path from env var is detected", { expect_false(is.null(.cmdstanr$VERSION)) }) +test_that("set_cmdstan_path() uses CMDSTAN env var when path is omitted", { + unset_cmdstan_path() + withr::local_envvar(c(CMDSTAN = PATH)) + expect_message( + set_cmdstan_path(), + paste("CmdStan path set to:", PATH), + fixed = TRUE + ) + expect_equal(cmdstan_path(), PATH) +}) + +test_that("set_cmdstan_path() clears cached state when no path is detected", { + .cmdstanr$PATH <- PATH + .cmdstanr$VERSION <- VERSION + .cmdstanr$WSL <- TRUE + local_mocked_bindings( + resolve_cmdstan_path_from_env = function() NULL, + cmdstan_default_path = function(dir = NULL) NULL + ) + expect_silent(set_cmdstan_path()) + expect_null(.cmdstanr$PATH) + expect_null(.cmdstanr$VERSION) + expect_false(isTRUE(.cmdstanr$WSL)) +}) + test_that("Unsupported CmdStan path from env var is rejected", { unset_cmdstan_path() .cmdstanr$WSL <- TRUE @@ -73,7 +98,7 @@ test_that("Existing CMDSTAN env path with no install resets cached state", { withr::local_envvar(c(CMDSTAN = empty_parent)) expect_warning( cmdstanr_initialize(), - "No CmdStan installation found in the path specified by the environment variable 'CMDSTAN'.", + "CmdStan path not set. No CmdStan installation found in the path specified by the environment variable 'CMDSTAN'.", fixed = TRUE ) expect_null(.cmdstanr$PATH) From f5c8c2425688613a4979c02b8743ac3bbd203bde Mon Sep 17 00:00:00 2001 From: jgabry Date: Tue, 14 Apr 2026 12:32:19 -0600 Subject: [PATCH 6/7] update Rd files --- man/cmdstan_default_install_path.Rd | 2 +- man/cmdstan_default_path.Rd | 6 +----- man/cmdstanr-package.Rd | 21 +++++++++++---------- 3 files changed, 13 insertions(+), 16 deletions(-) diff --git a/man/cmdstan_default_install_path.Rd b/man/cmdstan_default_install_path.Rd index b5ebd9b7..5faaa03e 100644 --- a/man/cmdstan_default_install_path.Rd +++ b/man/cmdstan_default_install_path.Rd @@ -2,7 +2,7 @@ % Please edit documentation in R/path.R \name{cmdstan_default_install_path} \alias{cmdstan_default_install_path} -\title{cmdstan_default_install_path} +\title{Path to where \code{\link[=install_cmdstan]{install_cmdstan()}} with default settings installs CmdStan.} \usage{ cmdstan_default_install_path(wsl = FALSE) } diff --git a/man/cmdstan_default_path.Rd b/man/cmdstan_default_path.Rd index 2d4ffe9b..c4b8f3fb 100644 --- a/man/cmdstan_default_path.Rd +++ b/man/cmdstan_default_path.Rd @@ -2,7 +2,7 @@ % Please edit documentation in R/path.R \name{cmdstan_default_path} \alias{cmdstan_default_path} -\title{cmdstan_default_path} +\title{Path to the installation of CmdStan with the most recent release version} \usage{ cmdstan_default_path(dir = NULL) } @@ -14,10 +14,6 @@ Path to the CmdStan installation with the most recent release version, or \code{NULL} if no installation found. } \description{ -Returns the path to the installation of CmdStan with the most recent release -version. -} -\details{ For Windows systems with WSL CmdStan installs, if there are side-by-side WSL and native installs with the same version then the WSL is preferred. Otherwise, the most recent release is chosen, regardless of whether it is diff --git a/man/cmdstanr-package.Rd b/man/cmdstanr-package.Rd index e6479f57..be303bac 100644 --- a/man/cmdstanr-package.Rd +++ b/man/cmdstanr-package.Rd @@ -34,22 +34,22 @@ algorithms, and writing results to output files. \subsection{Advantages of RStan}{ \itemize{ \item Allows other developers to distribute R packages with \emph{pre-compiled} -Stan programs (like \strong{rstanarm}) on CRAN. (Note: As of 2023, this -can mostly be achieved with CmdStanR as well. See \href{https://mc-stan.org/cmdstanr/articles/cmdstanr-internals.html#developing-using-cmdstanr}{Developing using CmdStanR}.) -\item Avoids use of R6 classes, which may result in more familiar syntax -for many R users. +Stan programs (like \strong{rstanarm}) on CRAN. (Note: As of 2023, this can +mostly be achieved with CmdStanR as well. See \href{https://mc-stan.org/cmdstanr/articles/cmdstanr-internals.html#developing-using-cmdstanr}{Developing using CmdStanR}.) +\item Avoids use of R6 classes, which may result in more familiar syntax for +many R users. \item CRAN binaries available for Mac and Windows. } } \subsection{Advantages of CmdStanR}{ \itemize{ -\item Compatible with latest versions of Stan. Keeping up with Stan -releases is complicated for RStan, often requiring non-trivial -changes to the \strong{rstan} package and new CRAN releases of both -\strong{rstan} and \strong{StanHeaders}. With CmdStanR the latest improvements -in Stan will be available from R immediately after updating CmdStan -using \code{cmdstanr::install_cmdstan()}. +\item Compatible with latest versions of Stan. Keeping up with Stan releases +is complicated for RStan, often requiring non-trivial changes to the +\strong{rstan} package and new CRAN releases of both \strong{rstan} and +\strong{StanHeaders}. With CmdStanR the latest improvements in Stan will be +available from R immediately after updating CmdStan using +\code{cmdstanr::install_cmdstan()}. \item Running Stan via external processes results in fewer unexpected crashes, especially in RStudio. \item Less memory overhead. @@ -229,6 +229,7 @@ Other contributors: \item Martin ModrĂ¡k [contributor] \item Ven Popov [contributor] \item Visruth Srimath Kandali [contributor] + \item Aki Vehtari [contributor] } } From 5b9717f7dcbb81d7ad3eaa04e6f17bdf8e50779e Mon Sep 17 00:00:00 2001 From: jgabry Date: Tue, 14 Apr 2026 16:22:25 -0600 Subject: [PATCH 7/7] Avoid fragile file checks on WSL CmdStan paths --- R/install.R | 12 +++++++++--- R/path.R | 15 +++++---------- tests/testthat/test-path.R | 12 ++++++++++++ tests/testthat/test-utils.R | 8 ++++++++ 4 files changed, 34 insertions(+), 13 deletions(-) diff --git a/R/install.R b/R/install.R index 2aa5453c..ee91fd1c 100644 --- a/R/install.R +++ b/R/install.R @@ -327,11 +327,17 @@ cmdstan_make_local <- function(dir = cmdstan_path(), } write(built_flags, file = make_local_path, append = append) } - if (file.exists(make_local_path)) { - return(trimws(strsplit(trimws(readChar(make_local_path, file.info(make_local_path)$size)), "\n")[[1]])) - } else { + make_local_contents <- tryCatch( + suppressWarnings(readLines(make_local_path, warn = FALSE)), + error = function(e) NULL + ) + if (is.null(make_local_contents)) { return(NULL) } + if (length(make_local_contents) == 0) { + return("") + } + trimws(strsplit(trimws(paste(make_local_contents, collapse = "\n")), "\n", fixed = TRUE)[[1]]) } #' @rdname install_cmdstan diff --git a/R/path.R b/R/path.R index a8af3565..6df8e65b 100644 --- a/R/path.R +++ b/R/path.R @@ -253,14 +253,6 @@ cmdstan_default_path <- function(dir = NULL) { latest_cmdstan_installed <- function(installs_path) { cmdstan_installs <- list.dirs(path = installs_path, recursive = FALSE, full.names = FALSE) - # if installed in cmdstan folder with no version move to cmdstan-version folder - if ("cmdstan" %in% cmdstan_installs) { - ver <- read_cmdstan_version(file.path(installs_path, "cmdstan")) - old_path <- file.path(installs_path, "cmdstan") - new_path <- file.path(installs_path, paste0("cmdstan-", ver)) - file.rename(old_path, new_path) - cmdstan_installs <- list.dirs(path = installs_path, recursive = FALSE, full.names = FALSE) - } latest_cmdstan <- "" if (length(cmdstan_installs) > 0) { cmdstan_installs <- grep("^cmdstan-", cmdstan_installs, value = TRUE) @@ -282,7 +274,11 @@ latest_cmdstan_installed <- function(installs_path) { #' @return Version number as a string. read_cmdstan_version <- function(path) { makefile_path <- file.path(path, "makefile") - if (!file.exists(makefile_path)) { + makefile <- tryCatch( + suppressWarnings(readLines(makefile_path, warn = FALSE)), + error = function(e) NULL + ) + if (is.null(makefile)) { warning( "Can't find CmdStan makefile to detect version number. ", "Path may not point to valid installation.", @@ -290,7 +286,6 @@ read_cmdstan_version <- function(path) { ) return(NULL) } - makefile <- readLines(makefile_path) version_line <- grep("^CMDSTAN_VERSION :=", makefile, value = TRUE) if (length(version_line) == 0) { stop("CmdStan makefile is missing a version number.", call. = FALSE) diff --git a/tests/testthat/test-path.R b/tests/testthat/test-path.R index d2c7d9d7..aff71d08 100644 --- a/tests/testthat/test-path.R +++ b/tests/testthat/test-path.R @@ -203,6 +203,18 @@ test_that("cmdstan_default_path() returns NULL for empty custom install director expect_null(cmdstan_default_path(dir = installs)) }) +test_that("cmdstan_default_path() ignores unversioned cmdstan directory", { + installs <- withr::local_tempdir(pattern = "cmdstan-legacy-installs") + dir.create(file.path(installs, "cmdstan"), recursive = TRUE, showWarnings = FALSE) + dir.create(file.path(installs, "cmdstan-2.36.0"), recursive = TRUE, showWarnings = FALSE) + + expect_equal( + cmdstan_default_path(dir = installs), + file.path(installs, "cmdstan-2.36.0") + ) + expect_true(dir.exists(file.path(installs, "cmdstan"))) +}) + test_that("CmdStan version helpers handle invalid inputs", { expect_identical(cmdstan_min_version(), "2.35.0") expect_false(is_supported_cmdstan_version(NULL)) diff --git a/tests/testthat/test-utils.R b/tests/testthat/test-utils.R index b27628c5..2aaf0aba 100644 --- a/tests/testthat/test-utils.R +++ b/tests/testthat/test-utils.R @@ -196,6 +196,14 @@ test_that("cmdstan_make_local() works", { cmdstan_make_local(cpp_options = as.list(exisiting_make_local), append = FALSE) }) +test_that("cmdstan_make_local() preserves empty make/local behavior", { + dir <- withr::local_tempdir() + dir.create(file.path(dir, "make"), recursive = TRUE, showWarnings = FALSE) + file.create(file.path(dir, "make", "local")) + + expect_identical(cmdstan_make_local(dir = dir), "") +}) + test_that("matching_variables() works", { ret <- matching_variables(c("beta"), c("alpha", "beta[1]", "beta[2]", "beta[3]")) expect_equal(