r-lib / rig

The R Installation Manager
MIT License
661 stars 22 forks source link

Local (directory) default version #171

Open arnold-c opened 1 year ago

arnold-c commented 1 year ago

Apologies if I missed this being discussed previously (possibly related to #74, #132, #139, and #45), but is there any way to set a default R version per directory? I don't use RStudio, so I'm not sure if the method described in the other issues would apply here (please correct me if I'm wrong).

I was thinking that this could work a little like pyenv in python, which has the pyenv local 3.x command to set the version you'd like to use (https://github.com/pyenv/pyenv/blob/master/COMMANDS.md#pyenv-local). Obviously this could be tied to the renv.lock file if used, but I think manually specifying it would work well and might be easier to implement.

gaborcsardi commented 1 year ago

Thanks for the suggestion, this would make sense, but rig currently does not do this.

Maybe it will at some point, but not just yet. It is not entirely clear how this should work with rig, but the Python docs are useful.

If you really want to do this, you can change the PATH to point a specific R version, in your local shell, and then that version is used in all subprocesses, unless they change or ignore the PATH of course.

danielloader commented 11 months ago

Echoing this would be useful expecially when mounting projects in the rig container (be it via visual studio code and the devcontainer setup or manually via docker), so it auto-selects either the nearest or exact version depending on implementation logic.

Be nice to be able to have a .r-version file with 4.1 in and then get the latest supported rig build for that branch.

Alternatively or optionally, RIG_DEFAULT_VERSION environment variable being checked, and if set, used.

tomcardoso commented 11 months ago

Wanted to +1 this. I have enjoyed this kind of pattern (having a dotfile in a local directory and rig/terminal automatically switching versions if it finds a file) in the past through stuff like nvm (with its .nvmrc files) and chruby (with .ruby-version files).

gaborcsardi commented 11 months ago

One question that comes up early with this pattern is what should happen with user package libraries. Currently the libraries are shared between R patch versions, e.g. R 4.3.0, R 4.3.1 and R 4.3.2 use the same user package library, at ~/R/aarch64-unknown-linux-gnu-library/4.3 (on a typical Linux).

Is that a problem? Should 4.3.0 and 4.3.1 have a separate library? I would lean towards NO, implying that if you want more separation and (say) project-specific libraries, you'd need to use an additional tool, e.g. https://github.com/rstudio/renv.

Does this make sense? (Maybe we should have another option to use fully version-specific libraries, independently of the local .rigrc feature?)

gaborcsardi commented 11 months ago

Yet another question. Do I understand it correctly, that in order to set up a "project" with the correct R versions, users would need to run rig use within the directory first?

I.e. it is not expected that just changing the working directory and starting R (or equivalently, opening RStudio or VS code in that project/directory) is supposed to set up the correct R version (and possibly other setup)?

Isn't that a bit inconvenient? Ideally, opening the project in RStudio should already start up with the correct R version? How do other editors do this? Does VS Code recognize .nvmrc files, and does it set up the correct Node version?

danielloader commented 11 months ago

One question that comes up early with this pattern is what should happen with user package libraries. Currently the libraries are shared between R patch versions, e.g. R 4.3.0, R 4.3.1 and R 4.3.2 use the same user package library, at ~/R/aarch64-unknown-linux-gnu-library/4.3 (on a typical Linux).

Is that a problem? Should 4.3.0 and 4.3.1 have a separate library? I would lean towards NO, implying that if you want more separation and (say) project-specific libraries, you'd need to use an additional tool, e.g. https://github.com/rstudio/renv.

Does this make sense? (Maybe we should have another option to use fully version-specific libraries, independently of the local .rigrc feature?)

Slightly off topic but you've raised a question - if patch versions are considered the same, is it desirable for the following to happen:

image

As you can see rig isn't able to select a version by the major.minor even if it's installed already. Interestingly, it can if you do rig add 4.1 first, presumably setting up an alias internally?

Yet another question. Do I understand it correctly, that in order to set up a "project" with the correct R versions, users would need to run rig use within the directory first?

I.e. it is not expected that just changing the working directory and starting R (or equivalently, opening RStudio or VS code in that project/directory) is supposed to set up the correct R version (and possibly other setup)?

Isn't that a bit inconvenient? Ideally, opening the project in RStudio should already start up with the correct R version? How do other editors do this? Does VS Code recognize .nvmrc files, and does it set up the correct Node version?

As to this, you're right to question this, because it's definitely not intuitive - I guess personally I was asking in an exclusively docker framed context. I want to be able to use rig as a base container to build a project in a multistage build - right now I need to do RUN commands to add then default a version, if I could use an ENV/ARG to set the version, where it adds it if it's missing, and defaults to it after it would make this workflow easier to handle.

To be clear it's not a blocker, the RUN commands will do in a pinch.

gaborcsardi commented 11 months ago

if patch versions are considered the same

They are not the same (on Linux and Windows), but they share the same user package library, simply because that's the default setup by R.

danielloader commented 11 months ago

In that case would it be a good or bad design choice if rig being asked to default to a major.minor release just sets to the nearest major.minor.patch, maybe with an additional but non fatal warning in the terminal that an exact match has not been found?

if patch versions are considered the same

They are not the same (on Linux and Windows), but they share the same user package library, simply because that's the default setup by R.

gaborcsardi commented 11 months ago

In that case would it be a good or bad design choice if rig being asked to default to a major.minor release just sets to the nearest major.minor.patch, maybe with an additional but non fatal warning in the terminal that an exact match has not been found?

Possibly. I have wanted to have more explicit support for aliases (e.g. you can say rig default release already), so this would kind of fall into that category.

But yeah, mostly independent of the original issue.

arnold-c commented 11 months ago

I think to answer some of the questions that have come up, it might be good if rig has a fallback version that it defaults if it can't find a file/something that specifies a particular version be used. It might be reasonable to have this as the most recent version (e.g. rig default release, as @gaborcsardi suggested).

Regarding how it should work in practice, I would potentially lean towards having separate libraries for each minor version, where a project that specifies a particular R version should also require specific package versions, managed by renv. Upon setting a local R version, rig could run renv::init(), for example. I believe this might reduce the number of edge cases that have to be dealt with. However, I appreciate that there are some instances where renv isn't warranted, so this isn't a strong preference.

To initialize a project with an R version, I think forcing the user to be intentional is OK e.g. rig local 4.2.1. After this first time, possibly it could save and source the version information in a similar manner as renv i.e., using .Rprofile? Then when R/RStudio/other editors start up in that directory it switches to the local version, otherwise it stays in the default R version?

gaborcsardi commented 11 months ago

In general, I think renv users will need to have a different workflow, so for now, I would focus on use cases without renv.

The thing is, using .Rprofile is not great, because if there is an .Rprofile, then the ~/.Rprofile is not used, and people have setup code there. Unless of course they use renv, but that case is difficult as well, because we would need to merge renv and rig setup in a single .Rprofile.

So ideally, this would work without creating an .Rprofile file. Which means that the user needs to run rig use every time they "open" the project.

tomcardoso commented 11 months ago

Yet another question. Do I understand it correctly, that in order to set up a "project" with the correct R versions, users would need to run rig use within the directory first?

I.e. it is not expected that just changing the working directory and starting R (or equivalently, opening RStudio or VS code in that project/directory) is supposed to set up the correct R version (and possibly other setup)?

Isn't that a bit inconvenient? Ideally, opening the project in RStudio should already start up with the correct R version? How do other editors do this? Does VS Code recognize .nvmrc files, and does it set up the correct Node version?

Sorry, just seeing this now. You're right that running rig use every time would be very annoying. nvm and chruby solve for this by asking that users add hooks into their .zshrc or .bashrc (or whatever) files that automatically switch versions if the right dotfile is detected. This is explained in this nvm guide: https://github.com/nvm-sh/nvm?tab=readme-ov-file#calling-nvm-use-automatically-in-a-directory-with-a-nvmrc-file

I think something similar for rig would be great. cd into a folder, and rig automaticaly runs rig use X based on a version in a .rig or .r-version file. I'm not sure how this would work with RStudio, though. Can pre-launch hooks be added to RStudio, or is there any ability for version switching there? That's a bit beyond my comprehension.

gaborcsardi commented 11 months ago

@tomcardoso I suppose rig could set up an /usr/local/bin/R (+ Rscript) script that switches version to the one prescribed in a local .rigconfig (or .rconfig?) file.

But we can't really do much with RStudio, I am afraid. There is an RStudio hook to run R code at startup, but you'd need to set that up from an .Rprofile, which means that R has to be running already, which is too late to choose a version. So RStudio would need to support .rconfig files explicitly.

tomcardoso commented 11 months ago

@gaborcsardi Makes sense. FWIW, I think shell hooks would be a great start. And I wonder, too, if the RStudio folks would consider building this into the app.

R (and R package) version inconsistencies are one of the great pain points for me (and, I suspect, many others) in R. Sharing code, deploying to GitHub or Shiny, etc. are a huge pain because packages change, backwards compatibility gets broken, functions get deprecated, and so on – all of which makes the R development toolchain quite brittle. Deploying a GitHub Action-based R scraper is often an exercise in frustration. renv has helped somewhat, but the problem is that the libraries are still at the mercy of the local R version. So whatever can be done to integrate the shell, rig, renv and RStudio more tightly would be hugely appreciated. I'm happy to help with code, feature/design suggestions or as a guinea pig for an auto-switching feature, FWIW; just let me know.

jrosell commented 10 months ago

Thanks for the suggestion, this would make sense, but rig currently does not do this.

Maybe it will at some point, but not just yet. It is not entirely clear how this should work with rig, but the Python docs are useful.

If you really want to do this, you can change the PATH to point a specific R version, in your local shell, and then that version is used in all subprocesses, unless they change or ignore the PATH of course.

I think that the error of rig defaultcommand requiring sudo permsions could be improved by explaining the user how can they set the required variables theirself.

For example: $ export PATH=/opt/R/3.6.3/bin:$PATH or $ export PATH=/opt/R/4.3.2/bin:$PATH

(I assume other things should be changed too)

samhinshaw commented 6 months ago

Yet another question. Do I understand it correctly, that in order to set up a "project" with the correct R versions, users would need to run rig use within the directory first?

I.e. it is not expected that just changing the working directory and starting R (or equivalently, opening RStudio or VS code in that project/directory) is supposed to set up the correct R version (and possibly other setup)?

Isn't that a bit inconvenient? Ideally, opening the project in RStudio should already start up with the correct R version? How do other editors do this? Does VS Code recognize .nvmrc files, and does it set up the correct Node version?

AFAIK, it leaves it up to the user on how they'd like to hook in, but provides some examples. Though this is just shell integration, and not editor-specific.

I will add that using direnv is always a good workaround:

rig switch $(< .rigrc)
gaborcsardi commented 6 months ago
rig switch $(< .rigrc)

I think this is fine, as long as you are not running multiple versions in parallel, because rig switch is a global switch.

jrosell commented 6 months ago

This requires sudo:

rig switch $(< .rigrc)

I think this is fine, as long as you are not running multiple versions in parallel, because rig switch is a global switch.

For Ubuntu 22, I imagine something like this using an .env file with autoenv or another similar tool:

if [ -f .rigrc ]; then
  NEWPATH=$PATH
  NEWPATH=$(echo "$NEWPATH" | sed -e 's/:\/usr\/local\/bin\/R$//')
  NEWPATH=$(echo "$NEWPATH" | sed -e 's/:\/opt\/R\/3.6.3\/bin$//')
  NEWPATH=$(echo "$NEWPATH" | sed -e 's/:\/opt\/R\/4.3.2\/bin$//')
  NEWPATH=$(echo "$NEWPATH" | sed -e 's/:\/opt\/R\/4.4.0\/bin$//')
  RPATH=/opt/R/$(< .rigrc)/bin
  export PATH=$RPATH:$NEWPATH
  echo $PATH
fi
jrosell commented 3 months ago

Any updates regarding this? I think it could be easier to solve it using Positron, right?

arnold-c commented 1 week ago

For what it's worth, I like rig, but I've been trying out a combination of pixi and direnv with some success (see here, though be sure to add the direnv eval to your shell, which isn't included in the pixi instructions). This allows me to specify an R version for each project, and, assuming I have created the necessary .envrc file in the project root, the correct version is automatically loaded by pixi. A few extra steps and files that I would ideally like, but has been pretty smooth overall

gaborcsardi commented 1 week ago

@arnold-c Maybe we can close this issue then?

arnold-c commented 1 week ago

@gaborcsardi More than happy to - I didn't originally in case this was something that was being left as a future plan, but please feel free to close if that's not the case (at least, not imminently). Thanks for the discussion and openness to the thought!