eddelbuettel / r2u

CRAN as Ubuntu Binaries
https://eddelbuettel.github.io/r2u
247 stars 17 forks source link

Install Different Versions of Packages in Different Libraries #67

Closed jaredlander closed 3 months ago

jaredlander commented 3 months ago

This is not so much an issue as it is a question, or perhaps even a feature request.

While working on different projects I often need to keep different versions of R and packages. Say R 4.2 with {zoo} 1.8-9 and R 4.4 with {zoo} 1.8-11. Or even different versions of a package with the same version of R.

Without {bspm} or r2u, {renv} mostly accomplishes this, though I understand from the FAQ that {renv} does not play nicely with {bspm} and I understand why. But I am wondering if it is possible to use {bspm}/r2u to install specific versions of packages into different libraries on my system? If I can install the packages into specific libraries, then I suppose it will even work with different versions of R.

I pulled rocker/r2u:jammy, setup a directory for a local library and started R.

docker pull rocker/r2u:jammy
docker run --rm -it rocker/r2u:jammy bash
mkdir -p /home/docker/p1/paks
cd /home/docker/p1
R

Then I added /home/docker/p1/paks too the library path.

.libPaths('/home/docker/p1/paks')

Just to be careful, I specifically set the lib argument in install.packages().

install.packages('zoo', lib='/home/docker/p1/paks')

This results in a successful install.

Get:1 http://security.ubuntu.com/ubuntu jammy-security InRelease [129 kB]
Get:2 http://archive.ubuntu.com/ubuntu jammy InRelease [270 kB]
Ign https://r2u.stat.illinois.edu/ubuntu jammy InRelease
Get:3 http://security.ubuntu.com/ubuntu jammy-security/restricted amd64 Packages [2944 kB]
Get:4 https://r2u.stat.illinois.edu/ubuntu jammy Release [5713 B]
Get:5 https://r2u.stat.illinois.edu/ubuntu jammy Release.gpg [793 B]
Get:6 http://security.ubuntu.com/ubuntu jammy-security/multiverse amd64 Packages [44.7 kB]
Get:7 http://security.ubuntu.com/ubuntu jammy-security/main amd64 Packages [2221 kB]
Get:8 http://security.ubuntu.com/ubuntu jammy-security/universe amd64 Packages [1135 kB]
Get:9 https://r2u.stat.illinois.edu/ubuntu jammy/main all Packages [8239 kB]
Get:10 https://cloud.r-project.org/bin/linux/ubuntu jammy-cran40/ InRelease [3626 B]
Get:11 https://cloud.r-project.org/bin/linux/ubuntu jammy-cran40/ Packages [55.6 kB]
Get:12 http://archive.ubuntu.com/ubuntu jammy-updates InRelease [128 kB]
Get:13 http://archive.ubuntu.com/ubuntu jammy-backports InRelease [127 kB]
Get:14 https://r2u.stat.illinois.edu/ubuntu jammy/main amd64 Packages [2560 kB]
Get:15 http://archive.ubuntu.com/ubuntu jammy/universe amd64 Packages [17.5 MB]
Get:16 http://archive.ubuntu.com/ubuntu jammy/multiverse amd64 Packages [266 kB]
Get:17 http://archive.ubuntu.com/ubuntu jammy/restricted amd64 Packages [164 kB]
Get:18 http://archive.ubuntu.com/ubuntu jammy/main amd64 Packages [1792 kB]
Get:19 http://archive.ubuntu.com/ubuntu jammy-updates/multiverse amd64 Packages [51.8 kB]
Get:20 http://archive.ubuntu.com/ubuntu jammy-updates/restricted amd64 Packages [3041 kB]
Get:21 http://archive.ubuntu.com/ubuntu jammy-updates/main amd64 Packages [2498 kB]
Get:22 http://archive.ubuntu.com/ubuntu jammy-updates/universe amd64 Packages [1425 kB]
Get:23 http://archive.ubuntu.com/ubuntu jammy-backports/main amd64 Packages [111 kB]
Get:24 http://archive.ubuntu.com/ubuntu jammy-backports/universe amd64 Packages [36.9 kB]
Fetched 44.7 MB in 0s (0 B/s)
Install system packages as root...
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
Get:1 https://r2u.stat.illinois.edu/ubuntu jammy/main amd64 r-cran-zoo amd64 1.8-12-1.ca2204.1 [984 kB]
Fetched 984 kB in 0s (0 B/s)
Selecting previously unselected package r-cran-zoo.
(Reading database ... 18555 files and directories currently installed.)
Preparing to unpack .../r-cran-zoo_1.8-12-1.ca2204.1_amd64.deb ...
Unpacking r-cran-zoo (1.8-12-1.ca2204.1) ...
Setting up r-cran-zoo (1.8-12-1.ca2204.1) ...

However, it is not installed where I intended.

installed.packages()[, c('Package', 'LibPath')]
           Package      LibPath
boot       "boot"       "/usr/lib/R/site-library"
bspm       "bspm"       "/usr/lib/R/site-library"
class      "class"      "/usr/lib/R/site-library"
cluster    "cluster"    "/usr/lib/R/site-library"
codetools  "codetools"  "/usr/lib/R/site-library"
docopt     "docopt"     "/usr/lib/R/site-library"
foreign    "foreign"    "/usr/lib/R/site-library"
KernSmooth "KernSmooth" "/usr/lib/R/site-library"
lattice    "lattice"    "/usr/lib/R/site-library"
littler    "littler"    "/usr/lib/R/site-library"
MASS       "MASS"       "/usr/lib/R/site-library"
Matrix     "Matrix"     "/usr/lib/R/site-library"
mgcv       "mgcv"       "/usr/lib/R/site-library"
nlme       "nlme"       "/usr/lib/R/site-library"
nnet       "nnet"       "/usr/lib/R/site-library"
remotes    "remotes"    "/usr/lib/R/site-library"
rpart      "rpart"      "/usr/lib/R/site-library"
spatial    "spatial"    "/usr/lib/R/site-library"
survival   "survival"   "/usr/lib/R/site-library"
zoo        "zoo"        "/usr/lib/R/site-library"
base       "base"       "/usr/lib/R/library"
compiler   "compiler"   "/usr/lib/R/library"
datasets   "datasets"   "/usr/lib/R/library"
graphics   "graphics"   "/usr/lib/R/library"
grDevices  "grDevices"  "/usr/lib/R/library"
grid       "grid"       "/usr/lib/R/library"
methods    "methods"    "/usr/lib/R/library"
parallel   "parallel"   "/usr/lib/R/library"
splines    "splines"    "/usr/lib/R/library"
stats      "stats"      "/usr/lib/R/library"
stats4     "stats4"     "/usr/lib/R/library"
tcltk      "tcltk"      "/usr/lib/R/library"
tools      "tools"      "/usr/lib/R/library"
utils      "utils"      "/usr/lib/R/library"

You can see it is installed at /usr/lib/R/site-library.

So, to the original question, can I specify where to install the package? And follow up, can I specify a specific version of the package?

And another follow up, I tried running the container as the docker user and I couldn't install anything because sudo was not found. Can a user without sudo privileges install packages with {bspm}? I thought they could but maybe I'm wrong?

eddelbuettel commented 3 months ago

[ Let's leave other packages like renv out of it for a second, you know where to get help for those. I do not use them and r2u neither promotes not discourages them. So what follows will just focus on r2u and bspm and your desired use case as I understand it. ]

r2u and bspm 'basics'

r2u is "just a repo", i.e. it simply contains (a lot of) precompiled (current) CRAN packages for you to download and install in a way we claim is "Fast. Easy. Reliable.". I hope we can agree so far.

Now recall what type of repo this is. An apt repo just like c2d4u that came before it, or an Ubuntu repo with its roughly 1000 or so r-cran-* packages. r2u is the first to finally bring all of CRAN (give or take: I skip some requiring proprietary libraries, or uber-complicated builds.) The genius of bspm is to trace() the install.packages("package") call and to convert into the correponding apt install r-cran-package call. No more, no less. And this is a lot, actually! And the apt installation goes exactly where the files are inside .deb it installs for you. So what install.packages("data.table") (to take no-dependency one for simplicity) does is described seconds later by dpkg -L r-cran-data.table.

Also note that r2u follows CRAN. You get one version. The current one. Base R does really have no provisions to give you other versions. So r2u never promises to be a time machine that undigs old version, or crazyness as they do over in other languages that let you install random combinations of packages under the so-called "pinning" approach ... which often enough results in headaches.

r2u does not do that. It combines one strength (of CRAN, the best repo out there for open source as "everything current is guaranteed to work with everything else current) with another strength, namely apt which is still the best package manager resolving each and every binary dependency. Unfaillingly.

The combination is potent, and our usage continues to increase steadily.

Your use case

You are of course entirely free to use the above as a base layer and compose on top as you please. The packages you installed with r2u are now present. Unless you tweak .libPaths() you get them by default. r2u also does not modify R: you can still add to / prepent to the .libPaths() as you please. We all often do so for, say, reverse dependency testing. Or to bring in an older version / cached version because we like a particular feature or aspect. (E.g. I often do docs for simple packages with an old roxygen2 6.0.1 which 'does what I need' more easily.)

So to me it seems one possible step forward for you is to rely on r2u to relieve you of the burden of the 'base layer' of packages you desire out of the 21k CRAN packages , and to complement it as you please with additional "well defined pockets" of other or versioned packages. But you will likely have to install those as p3m binaries, or via pak, and deal with whatever else they do not cover, manually. That should still work quite nicely. If you try it, let us know how it does. (And recall to set bspm::disable() before an install.packages() call without bspm.)

eddelbuettel commented 3 months ago

PS I have also wondered a few times about the feasibility of keeping apt repository index information 'by date' not unlike MRAN dit and p3m.dev does. That should be doable: the pool directy of an apt repo very much have different version of the same package. But someone for whom that is a bigger itch than it is for me needs to sit down and experiment / implement. I will not have the bandwidth to do so.

jaredlander commented 3 months ago

Thanks for the response. Here are some questions back at you.

Also note that r2u follows CRAN. You get one version. The current one. Base R does really have no provisions to give you other versions.

When installing from apt with the right PPAs, I can install a specific version like sudo apt install <package name>=<version> (and I'm realizing now that it is now quite so simple). Is something similar possible in this case, such as sudo apt install r-cran-zoo=1.8-9? I'm guessing that's what you alluded to in your second comment.?

So to me it seems one possible step forward for you is to rely on r2u to relieve you of the burden of the 'base layer' of packages you desire out of the 21k CRAN packages , and to complement it as you please with additional "well defined pockets" of other or versioned packages. But you will likely have to install those as p3m binaries, or via pak, and deal with whatever else they do not cover, manually. That should still work quite nicely. If you try it, let us know how it does. (And recall to set bspm::disable() before an install.packages() call without bspm.)

So it looks like the answer is that packages installed from r2u are system wide (meaning other users too?) and if I want to get specific versions for one library and other versions for other libraries, I stick with p3m or the such.

eddelbuettel commented 3 months ago

Re 1) apt can do that when the (pool of) repositories you have declared has several versions. But install.packages() does not not, and r2u / bspm hence do not offer a pass through. So this is a no in the context of your previous R-centered questions, and yes if you know what you are doing at the Ubuntu level.

Re 2) apt always installs system-wide. You could possibly invent a 'faking' mechanism and a) using it install a package, then b) copy it to a per-user dir you make accessible via .libPaths() and thereafter c) uninstall it. You of course lose the ability of apt to protect any dependencies your now per-user package may have (as apt no longer sees it / knowns about it) but you get a cheeky install if that floats your boat.