kopia lustrzana https://github.com/jupyterhub/repo2docker
[MRG] Add support for installing different versions of R (#772)
[MRG] Add support for installing different versions of Rpull/797/head
commit
bfbec349c2
|
@ -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>`_.
|
||||
|
|
|
@ -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.
|
||||
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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"
|
Ładowanie…
Reference in New Issue