cran4linux / rspm

RStudio Package Manager
https://cran4linux.github.io/rspm
Other
46 stars 4 forks source link

Difficulty with rspm when working with renv #24

Open IanVermes opened 6 months ago

IanVermes commented 6 months ago

I've been having a little trouble trying to get your package to work for me in a Docker context, and suspect it's my own misunderstanding.

Without renv I know that working without renv works well, as this minimal Dockerfile works perfectly:

FROM rocker/r-base:4.2.2

RUN apt-get update -yq \
    && apt-get install -yq \
    apt-file

WORKDIR /opt/example

RUN Rscript -e 'install.packages("rspm"); rspm::enable(); install.packages("units")'

With renv

But with renv I'm doing something wrong but can't see what.

I have a small reproducible example where I try to install the units package with rspm and renv.

## Dockerfile
FROM rocker/r-base:4.2.2

RUN apt-get update -yq \
    && apt-get install -yq \
    apt-file

WORKDIR /opt/example

RUN Rscript -e 'install.packages("renv"); renv::init(); renv::install("rspm"); rspm::install_sysreqs()'

RUN Rscript -e 'rspm::renv_init(); renv::install("units")'

Then I run it as follows (Docker version 24.0.5) but fails to build:

docker build --progress plain --no-cache . > build.log 2>&1

And the logs yield the following (complete build.log attached)

...
#8 [5/5] RUN Rscript -e 'rspm::renv_init(); renv::install("units")'
#8 1.484 # Downloading packages -------------------------------------------------------
#8 1.487 - Downloading units from CRAN ...               OK [242.2 Kb]
#8 1.668 - Downloading Rcpp from CRAN ...                OK [3.3 Mb]
#8 1.865 Successfully downloaded 2 packages in 0.57 seconds.
#8 1.865 
#8 1.866 The following package(s) will be installed:
#8 1.866 - Rcpp  [1.0.12]
#8 1.866 - units [0.8-5]
#8 1.866 These packages will be installed into "/opt/example/renv/library/R-4.2/x86_64-pc-linux-gnu".
#8 1.866 
#8 1.866 # Installing packages --------------------------------------------------------
#8 1.931 - Installing Rcpp ...                           OK [built from source and cached in 32s]
#8 34.16 - Installing units ...                          FAILED
#8 35.94 Error: Error installing package 'units':
#8 35.94 =================================
#8 35.94 
#8 35.94 * installing *source* package ‘units’ ...
#8 35.94 ** package ‘units’ successfully unpacked and MD5 sums checked
#8 35.94 ** using staged installation
#8 35.94 configure: units: 0.8-5
#8 35.94 checking whether the C++ compiler works... yes
#8 35.94 checking for C++ compiler default output file name... a.out
#8 35.94 checking for suffix of executables... 
#8 35.94 checking whether we are cross compiling... no
#8 35.94 checking for suffix of object files... o
#8 35.94 checking whether the compiler supports GNU C++... yes
#8 35.94 checking whether g++ -std=gnu++14 accepts -g... yes
#8 35.94 checking for g++ -std=gnu++14 option to enable C++11 features... none needed
#8 35.94 checking for stdio.h... yes
#8 35.94 checking for stdlib.h... yes
#8 35.94 checking for string.h... yes
#8 35.94 checking for inttypes.h... yes
#8 35.94 checking for stdint.h... yes
#8 35.94 checking for strings.h... yes
#8 35.94 checking for sys/stat.h... yes
#8 35.94 checking for sys/types.h... yes
#8 35.94 checking for unistd.h... yes
#8 35.94 checking for _Bool... no
#8 35.94 checking for stdbool.h that conforms to C99... yes
#8 35.94 checking for error_at_line... yes
#8 35.94 checking for gcc... gcc
#8 35.94 checking whether the compiler supports GNU C... yes
#8 35.94 checking whether gcc accepts -g... yes
#8 35.94 checking for gcc option to enable C11 features... none needed
#8 35.94 checking for XML_ParserCreate in -lexpat... no
#8 35.94 checking for udunits2.h... no
#8 35.94 checking for udunits2/udunits2.h... no
#8 35.94 checking for ut_read_xml in -ludunits2... no
#8 35.94 configure: error: in `/tmp/Rtmpt7NwwG/R.INSTALLcbdc56a2a/units':
#8 35.94 configure: error: 
#8 35.94 --------------------------------------------------------------------------------
#8 35.94   Configuration failed because libudunits2.so was not found. Try installing:
#8 35.94     * deb: libudunits2-dev (Debian, Ubuntu, ...)
#8 35.94     * rpm: udunits2-devel (Fedora, EPEL, ...)
#8 35.94     * brew: udunits (OSX)
#8 35.94   If udunits2 is already installed in a non-standard location, use:
#8 35.94     --configure-args='--with-udunits2-lib=/usr/local/lib'
#8 35.94   if the library was not found, and/or:
#8 35.94     --configure-args='--with-udunits2-include=/usr/include/udunits2'
#8 35.94   if the header was not found, replacing paths with appropriate values.
#8 35.94   You can alternatively set UDUNITS2_INCLUDE and UDUNITS2_LIBS manually.
#8 35.94 --------------------------------------------------------------------------------
#8 35.94 
#8 35.94 See `config.log' for more details
#8 35.94 ERROR: configuration failed for package ‘units’
#8 35.94 * removing ‘/opt/example/renv/staging/1/units’
#8 35.94 install of package 'units' failed [error code 1]
...

While it is a very helpful error message and I could resolve the installation manually, but was hoping from the documentation that renv::install("units@0.8-0") followed by rspm::install_sysreqs() would work.

Please let me know what I've missed.

Our workflow revolves around renv and renv::install - so moving back to install.packages wouldn't be desirable.

Enchufa2 commented 6 months ago

rspm::renv_init() is meant to be run instead of renv::init().

IanVermes commented 6 months ago

Thanks @Enchufa2 for the help.

I tried that, but unfortunately an error appears during the build, as before. The error message is identical next build.log

## Dockerfile
FROM rocker/r-base:4.2.2

RUN apt-get update -yq \
    && apt-get install -yq \
    apt-file

WORKDIR /opt/example

RUN Rscript -e 'install.packages("renv"); install.packages("rspm"); rspm::renv_init(); rspm::install_sysreqs(); renv::install("units")'

Just incase there is something session based that I might be missing, I've tried to reproduce the docs https://rdrr.io/cran/rspm/man/renv_init.html, and its not possible for me.

## Dockerfile
FROM rocker/r-base:4.2.2

RUN apt-get update -yq \
    && apt-get install -yq \
    apt-file

WORKDIR /opt/example

RUN Rscript -e 'install.packages("renv"); install.packages("rspm")'
docker build --progress plain -t minimal:example .
docker run --rm -it minimal:example R

Within the same R session:

rspm::renv_init()
renv::install("units@0.8-0")      # <--- fails here again (same error as log)
rspm::install_sysreqs()           ## never run, as previous step fails
install.packages("units")         # <--- runs perfectly, rspm shims working as expected
IanVermes commented 6 months ago

Also, just for reference

> packageVersion("rspm")
[1] ‘0.5.2’
> packageVersion("renv")
[1] ‘1.0.7’
Enchufa2 commented 6 months ago

Mmmh... this is supposed to work:

## Dockerfile
FROM rocker/r-base:4.2.2

RUN apt-get update -yq \
    && apt-get install -yq \
    apt-file

WORKDIR /opt/example

RUN Rscript -e 'install.packages(c("renv", "rspm")); rspm::renv_init()'
RUN Rscript -e 'install.packages("units")'

At least it worked at some point. But it seems that now renv is trying to load the package after installing it? So it fails and rspm has no chance of installing the library. I don't see any option in renv to avoid this behavior. Maybe you could ask there?

IanVermes commented 6 months ago

Thank you for taking a look. This does work.

...
RUN Rscript -e 'install.packages(c("renv", "rspm")); rspm::renv_init()'
RUN Rscript -e 'install.packages("units")'

But tragically for long running scientific projects or for deterministically building docker images, version pinning of dependencies is crucial.

Pinning is not possible with install.packages -- the use case of specifying dplyr@1.1.2, bioc::rtracklayer@1.58.0 or from github VanLoo-lab/ascat/ASCAT@v3.1.2 is very strong and why renv::install is preferred to install.packages.

rspm is such a good package and renv is good toolkit.

Enchufa2 commented 6 months ago

That is why rspm::install_sysreqs() is exported. You can call this function manually after any package installation. BTW, normally in a docker workflow with renv one would call restore with a lockfile, instead of calling install for individual packages. See this thread for reference: https://github.com/cran4linux/rspm/issues/17

IanVermes commented 6 months ago

Thanks @Enchufa2 - I'll test it going via the restore route first. I'm on leave but will let you know in about 10 days.