[MRG] Add support for installing different versions of R (#772)

[MRG] Add support for installing different versions of R
pull/797/head
Tim Head 2019-09-18 08:15:11 +02:00 zatwierdzone przez GitHub
commit bfbec349c2
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: 4AEE18F83AFDEB23
4 zmienionych plików z 238 dodań i 40 usunięć

Wyświetl plik

@ -212,7 +212,7 @@ If you only need to run things once during the build phase use :ref:`postBuild`.
Sometimes you want to specify the version of the runtime
(e.g. the version of Python or R),
but the environment specification format don't let you specify this information
but the environment specification format will not let you specify this information
(e.g. requirements.txt or install.R).
For these cases, we have a special file, ``runtime.txt``.
@ -220,7 +220,7 @@ For these cases, we have a special file, ``runtime.txt``.
``runtime.txt`` is only supported when used with environment specifications
that do not already support specifying the runtime
(e.g. when using ``environment.yml`` for conda or ``Project.toml`` for Julia,
(when using ``environment.yml`` for conda or ``Project.toml`` for Julia,
``runtime.txt`` will be ignored).
To use python-2.7: add ``python-2.7`` in runtime.txt file.
@ -231,8 +231,11 @@ Python 2 installed. To see a full example repository, visit our
repo2docker uses R libraries pinned to a specific snapshot on
`MRAN <https://mran.microsoft.com/documents/rro/reproducibility>`_.
You need to have a ``runtime.txt`` file that is formatted as
``r-<YYYY>-<MM>-<DD>``, where YYYY-MM-DD is a snapshot at MRAN that will be
used for installing libraries.
``r-<RVERSION>-<YYYY>-<MM>-<DD>``, where YYYY-MM-DD is a snapshot at MRAN that will be
used for installing libraries. You can set RVERSION to 3.4, 3.5 or 3.6 to select
the version of R you want to use. If you do not specify a R version the latest
released version will be used (currently R 3.6). You can also specify the exact
patch release you want to use for the 3.5 and 3.6 series.
To see an example R repository, visit our `R
example in binder-examples <https://github.com/binder-examples/r/blob/master/runtime.txt>`_.

Wyświetl plik

@ -49,10 +49,11 @@ Julia versions 0.6.x and earlier are supported via a :ref:`REQUIRE <REQUIRE>` fi
R
~
Only R 3.4.4 is currently supported, which is installed via ``apt`` from the
`ubuntu bionic repository <https://packages.ubuntu.com/bionic/r-base>`_.
The default version of R is currently R 3.6.1. You can select the version of
R you want to use by specifying it in the :ref:`runtime.txt <runtime.txt>`
file.
We support R versions 3.4, 3.5 and 3.6.
Why is my repository is failing to build with ``ResolvePackageNotFound`` ?
@ -149,17 +150,17 @@ notebooks (among others).
the container, use the ``--volumes`` option instead. Similarly,
for a fully customized user Dockerfile, this option is not
guaranteed to work.
Why is my R shiny app not launching?
----------------------------------------------------------------------------------
If you are trying to run an R shiny app using the ``/shiny/folder_containing_shiny``
url option, but the launch returns "The application exited during initialization.",
there might be something wrong with the specification of the app. One way of debugging
the app in the container is by running the ``rstudio`` url, open either the ui or
server file for the app, and run the app in the container rstudio. This way you can
see the rstudio logs as it tries to initialise the shiny app. If you a missing a
the app in the container is by running the ``rstudio`` url, open either the ui or
server file for the app, and run the app in the container rstudio. This way you can
see the rstudio logs as it tries to initialise the shiny app. If you a missing a
package or other dependency for the container, this will be obvious at this stage.

Wyświetl plik

@ -2,6 +2,8 @@ import re
import os
import datetime
from distutils.version import LooseVersion as V
from .python import PythonBuildPack
@ -55,6 +57,41 @@ class RBuildPack(PythonBuildPack):
return self._runtime
@property
def r_version(self):
"""Detect the R version for a given `runtime.txt`
Will return the version specified by the user or the current default
version.
"""
version_map = {
"3.4": "3.4",
"3.5": "3.5.3-1bionic",
"3.5.0": "3.5.0-1bionic",
"3.5.1": "3.5.1-2bionic",
"3.5.2": "3.5.2-1bionic",
"3.5.3": "3.5.3-1bionic",
"3.6": "3.6.1-3bionic",
"3.6.0": "3.6.0-2bionic",
"3.6.1": "3.6.1-3bionic",
}
# the default if nothing is specified
r_version = "3.6"
if not hasattr(self, "_r_version"):
parts = self.runtime.split("-")
if len(parts) == 5:
r_version = parts[1]
if r_version not in version_map:
raise ValueError(
"Version '{}' of R is not supported.".format(r_version)
)
# translate to the full version string
self._r_version = version_map.get(r_version)
return self._r_version
@property
def checkpoint_date(self):
"""
@ -63,11 +100,14 @@ class RBuildPack(PythonBuildPack):
Returns '' if no date is specified
"""
if not hasattr(self, "_checkpoint_date"):
match = re.match(r"r-(\d\d\d\d)-(\d\d)-(\d\d)", self.runtime)
match = re.match(r"r-(\d.\d(.\d)?-)?(\d\d\d\d)-(\d\d)-(\d\d)", self.runtime)
if not match:
self._checkpoint_date = False
else:
self._checkpoint_date = datetime.date(*[int(s) for s in match.groups()])
# turn the last three groups of the match into a date
self._checkpoint_date = datetime.date(
*[int(s) for s in match.groups()[-3:]]
)
return self._checkpoint_date
@ -127,20 +167,19 @@ class RBuildPack(PythonBuildPack):
We install a base version of R, and packages required for RStudio to
be installed.
"""
return (
super()
.get_packages()
.union(
[
"r-base",
# For rstudio
"psmisc",
"libapparmor1",
"sudo",
"lsb-release",
]
)
)
packages = [
# For rstudio
"psmisc",
"libapparmor1",
"sudo",
"lsb-release",
]
# For R 3.4 we use the default Ubuntu package, for other versions we
# install from a different PPA
if V(self.r_version) < V("3.5"):
packages.append("r-base")
return super().get_packages().union(packages)
def get_build_scripts(self):
"""
@ -180,7 +219,38 @@ class RBuildPack(PythonBuildPack):
self.checkpoint_date.isoformat()
)
scripts = [
scripts = []
# For R 3.4 we want to use the default Ubuntu package but otherwise
# we use the packages from a PPA
if V(self.r_version) >= V("3.5"):
scripts += [
(
"root",
r"""
echo "deb https://cloud.r-project.org/bin/linux/ubuntu bionic-cran35/" > /etc/apt/sources.list.d/r3.6-ubuntu.list
""",
),
(
"root",
r"""
apt-key adv --keyserver keyserver.ubuntu.com --recv-keys E298A3A825C0D65DFD57CBB651716619E084DAB9
""",
),
(
"root",
r"""
apt-get update && \
apt-get install --yes r-base={} && \
apt-get -qq purge && \
apt-get -qq clean && \
rm -rf /var/lib/apt/lists/*
""".format(
self.r_version
),
),
]
scripts += [
(
"root",
r"""
@ -277,17 +347,32 @@ class RBuildPack(PythonBuildPack):
]
if "r" in self.stencila_contexts:
scripts += [
(
"${NB_USER}",
# Install and register stencila library
r"""
R --quiet -e "source('https://bioconductor.org/biocLite.R'); biocLite('graph')" && \
R --quiet -e "devtools::install_github('stencila/r', ref = '361bbf560f3f0561a8612349bca66cd8978f4f24')" && \
R --quiet -e "stencila::register()"
""",
)
]
# new versions of R require a different way of installing bioconductor
if V(self.r_version) <= V("3.5"):
scripts += [
(
"${NB_USER}",
# Install and register stencila library
r"""
R --quiet -e "source('https://bioconductor.org/biocLite.R'); biocLite('graph')" && \
R --quiet -e "devtools::install_github('stencila/r', ref = '361bbf560f3f0561a8612349bca66cd8978f4f24')" && \
R --quiet -e "stencila::register()"
""",
)
]
else:
scripts += [
(
"${NB_USER}",
# Install and register stencila library
r"""
R --quiet -e "install.packages('BiocManager'); BiocManager::install(); BiocManager::install(c('graph'))" && \
R --quiet -e "devtools::install_github('stencila/r', ref = '361bbf560f3f0561a8612349bca66cd8978f4f24')" && \
R --quiet -e "stencila::register()"
""",
)
]
return super().get_build_scripts() + scripts

Wyświetl plik

@ -0,0 +1,109 @@
from datetime import date
import pytest
from repo2docker import buildpacks
def test_unsupported_version(tmpdir):
tmpdir.chdir()
with open("runtime.txt", "w") as f:
f.write("r-3.8-2019-01-01")
r = buildpacks.RBuildPack()
with pytest.raises(ValueError) as excinfo:
# access the property to trigger the exception
_ = r.r_version
# check the version is mentioned in the exception
assert "'3.8'" in str(excinfo.value)
@pytest.mark.parametrize(
"runtime_version, expected", [("", "3.6"), ("3.6", "3.6"), ("3.5.1", "3.5")]
)
def test_version_specification(tmpdir, runtime_version, expected):
tmpdir.chdir()
with open("runtime.txt", "w") as f:
if runtime_version:
runtime_version += "-"
f.write(f"r-{runtime_version}2019-01-01")
r = buildpacks.RBuildPack()
assert r.r_version.startswith(expected)
def test_version_completion(tmpdir):
tmpdir.chdir()
with open("runtime.txt", "w") as f:
f.write(f"r-3.6-2019-01-01")
r = buildpacks.RBuildPack()
assert r.r_version == "3.6.1-3bionic"
@pytest.mark.parametrize(
"runtime, expected",
[
("r-2019-01-01", (2019, 1, 1)),
("r-3.6.1-2019-01-01", (2019, 1, 1)),
("r-3.5-2019-01-01", (2019, 1, 1)),
],
)
def test_mran_date(tmpdir, runtime, expected):
tmpdir.chdir()
with open("runtime.txt", "w") as f:
f.write(runtime)
r = buildpacks.RBuildPack()
assert r.checkpoint_date == date(*expected)
def test_install_from_base(tmpdir):
# check that for R==3.4 we install from ubuntu
tmpdir.chdir()
with open("runtime.txt", "w") as f:
f.write("r-3.4-2019-01-02")
r = buildpacks.RBuildPack()
assert "r-base" in r.get_packages()
def test_install_from_ppa(tmpdir):
# check that for R>3.4 we don't install r-base from Ubuntu
tmpdir.chdir()
with open("runtime.txt", "w") as f:
f.write("r-3.5-2019-01-02")
r = buildpacks.RBuildPack()
assert "r-base" not in r.get_packages()
def test_custom_ppa(tmpdir):
tmpdir.chdir()
with open("runtime.txt", "w") as f:
f.write("r-3.5-2019-01-02")
r = buildpacks.RBuildPack()
scripts = r.get_build_scripts()
# check that at least one of the build scripts adds this new PPA
for user, script in scripts:
if "https://cloud.r-project.org/bin/linux/ubuntu bionic-cran35/" in script:
break
else:
assert False, "Should have added a new PPA"
# check that we install the right package
for user, script in scripts:
if "r-base=3.5" in script:
break
else:
assert False, "Should have installed base R"