Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

renv::activate() and renv::status() fail to recognize installed packages when library is on dual protocol drive #2058

Open
MalteSteinDE opened this issue Dec 11, 2024 · 3 comments

Comments

@MalteSteinDE
Copy link

We are using a dual protocol drive (SMB+NFS), and security is controlled in Unix style. But we are facing issues with using Windows R. I raised a similar issue #1625. This was solving in new renv version. Now renv installation is detected correctly, but not the installation of any other R package.

The renv project library path will be assumed as not executable. Therefore the installed R package in the renv project library will not be considers as available/installed, which is causing renv::activate() and renv::status() raising an error of "The following package(s) are used in this project, but are not installed:"

Package can be installed in renv project library and be used (e.g. with library() or in the code itself) and renv::snapshot() is working as expected.

Note: Using same R project with Linux R is causing no issues and renv is working as expected.

Main issue

I did a root cause analysis on it:

It is coming from the winAccessW functions of base R version:
https://github.com/SurajGupta/r-source/blob/a28e609e72ed7c47f6ddfbb86c85279a0750f0b7/src/gnuwin32/extra.c#L654
It is using the GetFileSecurityW function from windows.h.

On the dual drive folders R is not able to check the security descriptor. Therefore, R assuming every file on dual drive as not executable, which is causing issues (e.g. in detecting installed R packages in library). Files or folder will get from file.access(path="XX", mode=1) the result -1 (= no execution access), even if the detected mode bit is 777 from file.info()

> file.access("Z:/testing/renv/library/R-4.2/x86_64-w64-mingw32", 1)
-1

> file.info("Z:/testing/renv/library/R-4.2/x86_64-w64-mingw32")
size isdir mode  exe
0 TRUE 777  no

I'm in contact with POSIT on the root issue, but was asked to raise this issue here as well.

@kevinushey
Copy link
Collaborator

Thanks for the bug report. It is interesting that renv::snapshot() works, since that uses much of the same machinery as renv::status() in figuring out what packages are currently installed.

Some more diagnostics information that might be useful:


Can you confirm that your installed packages are being loaded from the renv project library? For example, what do you see with:

find.package("rlang")
install.packages("rlang")
library(rlang)
find.package("rlang")
getNamespaceInfo("rlang", "path")
> find.package("rlang")
Error in find.package("rlang") : there is no package calledrlang> install.packages("rlang")
The following package(s) will be installed:
- rlang [1.1.4]
These packages will be installed into "~/scratch/example/renv/library/linux-ubuntu-noble/R-4.4/x86_64-pc-linux-gnu".

Do you want to proceed? [Y/n]: y

# Installing packages --------------------------------------------------------
- Installing rlang ...                          OK [linked from cache]
Successfully installed 1 package in 29 milliseconds.
> library(rlang)
> find.package("rlang")
[1] "/home/kevin/.cache/R/renv/cache/v5/linux-ubuntu-noble/R-4.4/x86_64-pc-linux-gnu/rlang/1.1.4/3eec01f8b1dee337674b2e34ab1f9bc1/rlang"
> getNamespaceInfo("rlang", "path")
[1] "/home/kevin/.cache/R/renv/cache/v5/linux-ubuntu-noble/R-4.4/x86_64-pc-linux-gnu/rlang/1.1.4/3eec01f8b1dee337674b2e34ab1f9bc1/rlang"

Can we also check if renv is successfully enumerating the package dependencies in your project? For example:

renv::install("dplyr", prompt = FALSE)
str(renv:::renv_package_dependencies("dplyr"))

I see:

> renv::install("dplyr", prompt = FALSE)
The following package(s) will be installed:
- dplyr [1.1.4]
These packages will be installed into "~/scratch/example/renv/library/linux-ubuntu-noble/R-4.4/x86_64-pc-linux-gnu".

# Installing packages --------------------------------------------------------
- Installing dplyr ...                          OK [linked from cache]
Successfully installed 1 package in 25 milliseconds.
> str(renv:::renv_package_dependencies("dplyr"))
List of 21
 $ tidyselect: chr "/home/kevin/scratch/example/renv/library/linux-ubuntu-noble/R-4.4/x86_64-pc-linux-gnu/tidyselect"
 $ R6        : chr "/home/kevin/scratch/example/renv/library/linux-ubuntu-noble/R-4.4/x86_64-pc-linux-gnu/R6"
 $ magrittr  : chr "/home/kevin/scratch/example/renv/library/linux-ubuntu-noble/R-4.4/x86_64-pc-linux-gnu/magrittr"
 $ generics  : chr "/home/kevin/scratch/example/renv/library/linux-ubuntu-noble/R-4.4/x86_64-pc-linux-gnu/generics"
 $ cli       : chr "/home/kevin/scratch/example/renv/library/linux-ubuntu-noble/R-4.4/x86_64-pc-linux-gnu/cli"
 $ graphics  : chr "/home/kevin/.cache/R/renv/sandbox/linux-ubuntu-noble/R-4.4/x86_64-pc-linux-gnu/db5e602d/graphics"
 $ withr     : chr "/home/kevin/scratch/example/renv/library/linux-ubuntu-noble/R-4.4/x86_64-pc-linux-gnu/withr"
 $ pillar    : chr "/home/kevin/scratch/example/renv/library/linux-ubuntu-noble/R-4.4/x86_64-pc-linux-gnu/pillar"
 $ glue      : chr "/home/kevin/scratch/example/renv/library/linux-ubuntu-noble/R-4.4/x86_64-pc-linux-gnu/glue"
 $ utils     : chr "/home/kevin/.cache/R/renv/sandbox/linux-ubuntu-noble/R-4.4/x86_64-pc-linux-gnu/db5e602d/utils"
 $ dplyr     : chr "/home/kevin/scratch/example/renv/library/linux-ubuntu-noble/R-4.4/x86_64-pc-linux-gnu/dplyr"
 $ tibble    : chr "/home/kevin/scratch/example/renv/library/linux-ubuntu-noble/R-4.4/x86_64-pc-linux-gnu/tibble"
 $ grDevices : chr "/home/kevin/.cache/R/renv/sandbox/linux-ubuntu-noble/R-4.4/x86_64-pc-linux-gnu/db5e602d/grDevices"
 $ stats     : chr "/home/kevin/.cache/R/renv/sandbox/linux-ubuntu-noble/R-4.4/x86_64-pc-linux-gnu/db5e602d/stats"
 $ utf8      : chr "/home/kevin/scratch/example/renv/library/linux-ubuntu-noble/R-4.4/x86_64-pc-linux-gnu/utf8"
 $ fansi     : chr "/home/kevin/scratch/example/renv/library/linux-ubuntu-noble/R-4.4/x86_64-pc-linux-gnu/fansi"
 $ vctrs     : chr "/home/kevin/scratch/example/renv/library/linux-ubuntu-noble/R-4.4/x86_64-pc-linux-gnu/vctrs"
 $ methods   : chr "/home/kevin/.cache/R/renv/sandbox/linux-ubuntu-noble/R-4.4/x86_64-pc-linux-gnu/db5e602d/methods"
 $ lifecycle : chr "/home/kevin/scratch/example/renv/library/linux-ubuntu-noble/R-4.4/x86_64-pc-linux-gnu/lifecycle"
 $ pkgconfig : chr "/home/kevin/scratch/example/renv/library/linux-ubuntu-noble/R-4.4/x86_64-pc-linux-gnu/pkgconfig"
 $ rlang     : chr "/home/kevin/scratch/example/renv/library/linux-ubuntu-noble/R-4.4/x86_64-pc-linux-gnu/rlang"

Finally, let's also try running renv::status() with some tracers active.

trace(
  renv:::renv_snapshot_packages,
  tracer = quote({ print(utils::ls.str()) }),
  exit = quote({ utils::str(paths) })
)

trace(
  renv:::renv_snapshot_dependencies,
  tracer = quote({ print(utils::ls.str()) }),
  exit = quote({ utils::str(packages) })
)

renv::status()

I see:

> renv::status()
Tracing renv_snapshot_dependencies(project, dev = dev) on entry 
dev :  logi FALSE
project :  chr "/home/kevin/scratch/example"
type :  NULL
Tracing renv_snapshot_dependencies(project, dev = dev) on exit 
 chr [1:2] "renv" "utils"
Tracing renv_snapshot_dependencies(project = project, type = type, dev = dev) on entry 
dev :  logi FALSE
project :  chr "/home/kevin/scratch/example"
type :  chr "all"
Tracing renv_snapshot_dependencies(project = project, type = type, dev = dev) on exit 
 chr [1:32] "cli" "dplyr" "fansi" "generics" "glue" "lifecycle" "magrittr" "pillar" "pkgconfig" "R6" "renv" "rlang" "tibble" "tidyselect" "utf8" "vctrs" "withr" "boot" "class" ...
Tracing renv_snapshot_packages(packages = setdiff(packages, exclude),  .... on entry 
libpaths :  chr [1:2] "/home/kevin/scratch/example/renv/library/linux-ubuntu-noble/R-4.4/x86_64-pc-linux-gnu" ...
packages :  chr [1:32] "cli" "dplyr" "fansi" "generics" "glue" "lifecycle" "magrittr" "pillar" "pkgconfig" "R6" "renv" "rlang" "tibble" "tidyselect" "utf8" "vctrs" "withr" "boot" "class" ...
project :  chr "/home/kevin/scratch/example"
Tracing renv_snapshot_packages(packages = setdiff(packages, exclude),  .... on exit 
 Named chr [1:32] "/home/kevin/scratch/example/renv/library/linux-ubuntu-noble/R-4.4/x86_64-pc-linux-gnu/vctrs" ...
 - attr(*, "names")= chr [1:32] "vctrs" "nlme" "cli" "rlang" ...
No issues found -- the project is in a consistent state.

@kevinushey
Copy link
Collaborator

All that said, this would likely need to be fixed in R Core itself; I'm not totally confident that renv will be able to work around these issues on this filesystem.

@kevinushey
Copy link
Collaborator

The other thing you could try would be to forcefully overwrite the file.access() function, e.g. with something like:

file.access <- function(names, mode = 0) {
  
  res <- if (mode == 1) {
    # assume that files / folders are executable
    rep.int(0L, length(names))
  } else {
    .Internal(file.access(names, mode))
  }
  
  names(res) <- names
  res
  
}

environment(file.access) <- .BaseNamespaceEnv
unlockBinding("file.access", env = .BaseNamespaceEnv)
assign("file.access", file.access, env = .BaseNamespaceEnv)
lockBinding("file.access", env = .BaseNamespaceEnv)
rm("file.access")

You could place this in, for example, your R installation's etc/Rprofile.site, and use this (or some version of this) to work around the undesired behavior of file.access() in this scenario.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants