@@ -38,11 +38,7 @@ class RBuildPack(PythonBuildPack):
3838
3939 - are needed by a specific tool
4040
41- The `r-base-core` package from Ubuntu or "Ubuntu packages for R"
42- apt repositories is used to install R itself,
43- rather than any of the methods from https://cran.r-project.org/.
44-
45- The `r-base-dev` package is installed as advised in RStudio instructions.
41+ R is installed from https://docs.rstudio.com/resources/install-r/
4642 """
4743
4844 @property
@@ -68,33 +64,32 @@ def r_version(self):
6864 version.
6965 """
7066 version_map = {
71- "3.4" : "3.4" ,
72- "3.5" : "3.5.3-1bionic" ,
73- "3.5.0" : "3.5.0-1bionic" ,
74- "3.5.1" : "3.5.1-2bionic" ,
75- "3.5.2" : "3.5.2-1bionic" ,
76- "3.5.3" : "3.5.3-1bionic" ,
77- "3.6" : "3.6.3-1bionic" ,
78- "3.6.0" : "3.6.0-2bionic" ,
79- "3.6.1" : "3.6.1-3bionic" ,
80- "4.0" : "4.0.5-1.1804.0" ,
81- "4.0.2" : "4.0.2-1.1804.0" ,
82- "4.1" : "4.1.2-1.1804.0" ,
67+ "4.2" : "4.2.0" ,
68+ "4.1" : "4.1.3" ,
69+ "4.0" : "4.0.5" ,
70+ "3.6" : "3.6.3" ,
71+ "3.5" : "3.5.3" ,
72+ "3.4" : "3.4.0" ,
73+ "3.3" : "3.3.3" ,
8374 }
75+
8476 # the default if nothing is specified
85- r_version = "4.1"
77+ # Use full version is needed here, so it a valid semver
78+ r_version = version_map ["4.1" ]
8679
8780 if not hasattr (self , "_r_version" ):
8881 parts = self .runtime .split ("-" )
82+ # If runtime.txt is not set, or if it isn't of the form r-<version>-<yyyy>-<mm>-<dd>,
83+ # we don't use any of it in determining r version and just use the default
8984 if len (parts ) == 5 :
9085 r_version = parts [1 ]
91- if r_version not in version_map :
92- raise ValueError (
93- "Version '{}' of R is not supported." . format ( r_version )
94- )
86+ # For versions of form x.y, we want to explicitly provide x.y.z - latest patchlevel
87+ # available. Users can however explicitly specify the full version to get something specific
88+ if r_version in version_map :
89+ r_version = version_map [ r_version ]
9590
9691 # translate to the full version string
97- self ._r_version = version_map . get ( r_version )
92+ self ._r_version = r_version
9893
9994 return self ._r_version
10095
@@ -141,6 +136,20 @@ def detect(self):
141136 self ._runtime = "r-{}" .format (str (self ._checkpoint_date ))
142137 return True
143138
139+ def get_env (self ):
140+ """
141+ Set custom env vars needed for RStudio to load
142+ """
143+ return super ().get_env () + [
144+ # rstudio (rsession) can't seem to find R unless we explicitly tell it where
145+ # it is - just $PATH isn't enough. I discovered these are the env vars it
146+ # looks for by digging through RStudio source and finding
147+ # https://github.com/rstudio/rstudio/blob/v2022.02.3+492/src/cpp/r/session/RDiscovery.cpp
148+ ("R_HOME" , f"/opt/R/{ self .r_version } /lib/R" ),
149+ ("R_DOC_DIR" , "${R_HOME}/doc" ),
150+ ("LD_LIBRARY_PATH" , "${R_HOME}/lib:${LD_LIBRARY_PATH}" ),
151+ ]
152+
144153 def get_path (self ):
145154 """
146155 Return paths to be added to the PATH environment variable.
@@ -177,12 +186,6 @@ def get_packages(self):
177186 "sudo" ,
178187 "lsb-release" ,
179188 ]
180- # For R 3.4 we use the default Ubuntu package, for other versions we
181- # install from a different apt repository
182- if V (self .r_version ) < V ("3.5" ):
183- packages .append ("r-base" )
184- packages .append ("r-base-dev" )
185- packages .append ("libclang-dev" )
186189
187190 return super ().get_packages ().union (packages )
188191
@@ -268,46 +271,25 @@ def get_build_scripts(self):
268271
269272 cran_mirror_url = self .get_cran_mirror_url (self .checkpoint_date )
270273
271- # Determine which R apt repository should be enabled
272- if V (self .r_version ) >= V ("3.5" ):
273- if V (self .r_version ) >= V ("4" ):
274- vs = "40"
275- else :
276- vs = "35"
277-
278274 scripts = [
279275 (
280276 "root" ,
281277 rf"""
282- echo "deb https://cloud.r-project.org/bin/linux/ubuntu bionic-cran{ vs } /" > /etc/apt/sources.list.d/r-ubuntu.list
283- """ ,
284- ),
285- # Dont use apt-key directly, as gpg does not always respect *_proxy vars. This increase the chances
286- # of being able to reach it from behind a firewall
287- (
288- "root" ,
289- r"""
290- wget --quiet -O - 'https://keyserver.ubuntu.com/pks/lookup?op=get&search=0xe298a3a825c0d65dfd57cbb651716619e084dab9' | apt-key add -
291- """ ,
292- ),
293- (
294- "root" ,
295- # we should have --no-install-recommends on all our apt-get install commands,
296- # but here it's important because it will pull in CRAN packages
297- # via r-recommends, which is only guaranteed to be compatible with the latest r-base-core
298- r"""
299278 apt-get update > /dev/null && \
300279 apt-get install --yes --no-install-recommends \
301- r-base-core={R_version} \
302- r-base-dev={R_version} \
303280 libclang-dev \
304281 libzmq3-dev > /dev/null && \
282+ wget --quiet -O /tmp/r-{ self .r_version } .deb \
283+ https://cdn.rstudio.com/r/ubuntu-$(. /etc/os-release && echo $VERSION_ID | sed 's/\.//')/pkgs/r-{ self .r_version } _1_amd64.deb && \
284+ apt install --yes --no-install-recommends /tmp/r-{ self .r_version } .deb > /dev/null && \
285+ rm /tmp/r-{ self .r_version } .deb && \
305286 apt-get -qq purge && \
306287 apt-get -qq clean && \
307- rm -rf /var/lib/apt/lists/*
308- """ .format (
309- R_version = self .r_version
310- ),
288+ rm -rf /var/lib/apt/lists/* && \
289+ ln -s /opt/R/{ self .r_version } /bin/R /usr/local/bin/R && \
290+ ln -s /opt/R/{ self .r_version } /bin/Rscript /usr/local/bin/Rscript && \
291+ R --version
292+ """ ,
311293 ),
312294 ]
313295
@@ -326,9 +308,9 @@ def get_build_scripts(self):
326308 # Set paths so that RStudio shares libraries with base R
327309 # install. This first comments out any R_LIBS_USER that
328310 # might be set in /etc/R/Renviron and then sets it.
329- r """
330- sed -i -e '/^R_LIBS_USER=/s/^/#/' /etc/R /Renviron && \
331- echo "R_LIBS_USER=${R_LIBS_USER}" >> /etc/R /Renviron
311+ rf """
312+ sed -i -e '/^R_LIBS_USER=/s/^/#/' /opt/R/ { self . r_version } /lib/R/etc /Renviron && \
313+ echo "R_LIBS_USER=${{ R_LIBS_USER}} " >> /opt/R/ { self . r_version } /lib/R/etc /Renviron
332314 """ ,
333315 ),
334316 (
@@ -338,15 +320,12 @@ def get_build_scripts(self):
338320 # Quite hilarious, IMO.
339321 # See https://docs.rstudio.com/rspm/1.0.12/admin/binaries.html
340322 # Set mirror for RStudio too, by modifying rsession.conf
341- r """
323+ rf """
342324 R RHOME && \
343- mkdir -p /usr/lib/R/etc /etc/rstudio && \
344- echo 'options(repos = c(CRAN = "{cran_mirror_url}"))' > /usr/lib/R/etc/Rprofile.site && \
345- echo 'options(HTTPUserAgent = sprintf("R/%s R (%s)", getRversion(), paste(getRversion(), R.version$platform, R.version$arch, R.version$os)))' >> /usr/lib/R/etc/Rprofile.site && \
325+ mkdir -p /etc/rstudio && \
326+ echo 'options(repos = c(CRAN = "{ cran_mirror_url } "))' > /opt/R/{ self .r_version } /lib/R/etc/Rprofile.site && \
346327 echo 'r-cran-repos={ cran_mirror_url } ' > /etc/rstudio/rsession.conf
347- """ .format (
348- cran_mirror_url = cran_mirror_url
349- ),
328+ """ ,
350329 ),
351330 (
352331 "${NB_USER}" ,
0 commit comments