Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Updates for Stencila #457

Merged
merged 26 commits into from
Nov 9, 2018
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
24def16
verify R installation for r-markdown with Stencila
nuest Oct 29, 2018
9624f0f
extract contexts from stencila document
nuest Oct 29, 2018
8342fbd
do not look for stencila if binder dir found
nuest Oct 30, 2018
3a479b6
install R for Stencila from R buildpack
nuest Oct 30, 2018
da41a90
update versions of stencila/r and stencila/py
nuest Oct 30, 2018
7e8450f
more detailed check for Stencila + Python test
nuest Oct 30, 2018
6d30417
add Stencila config files to docs
nuest Oct 30, 2018
3f4da20
reduce calls to stencila_manifest_contexts
nuest Oct 30, 2018
a57a443
Fix wording in config_files.rst
betatim Oct 30, 2018
8d9a487
add Stencila to user interface docs
nuest Oct 30, 2018
d6dc570
continue Stencila detection if /binder dir is present, improve
nuest Oct 30, 2018
12b4457
restructure R buildpack docs
nuest Oct 30, 2018
c843e25
simplify test for contexts (is now by default an empty list)
nuest Oct 30, 2018
9c81c3e
rename stencila_manifest_contexts to stencila_contexts
nuest Oct 30, 2018
b1bff5b
parse Stencila xml files instead of regex
nuest Oct 30, 2018
d12c4b5
increase timeout for stencila tests on travis
nuest Oct 31, 2018
b032a7c
safe one if clause (intersection is already false-y)
nuest Nov 5, 2018
df7c620
do not install Stencila Python context if only python-jupyter cells f…
nuest Nov 5, 2018
c2b17d5
add tests pyjp vs. py for Stencila, make Stencila tests more specific
nuest Nov 5, 2018
e576c03
describe more complex detection mechanism used for stencila in dev docs
nuest Nov 6, 2018
490962e
split up Stencila tests to not run into timeouts on Travis CI
nuest Nov 6, 2018
d849664
Update repo2docker/buildpacks/base.py
betatim Nov 7, 2018
c49694a
Update repo2docker/buildpacks/base.py
betatim Nov 7, 2018
0ccca49
Update docs in buildpacks/r.py
betatim Nov 7, 2018
58a5c8b
make loops more readable
nuest Nov 9, 2018
68194a0
reformat some long lines
nuest Nov 9, 2018
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions docs/source/config_files.rst
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,22 @@ You also need to have a ``runtime.txt`` file that is formatted as
``r-<YYYY>-<MM>-<DD>``, where YYYY-MM-DD is a snapshot of MRAN that will be
used for your R installation.

``manifest.xml`` - Install Stencila
===================================

`Stencila <https://stenci.la/>`_ is an open source office suite for reproducible research.
It is powered by the open file format `Dar <https://github.com/substance/dar>`_.

If your repository contains a Stencila document, repo2docker detects it based on the file ``manifest.xml``.
The required `execution contexts <https://stenci.la/learn/intro.html>` are extracted from a Dar article (i.e.
files named ``*.jats.xml``).

You may also have a ``runtime.txt`` and/or an ``install.R`` to manually configure the your R installation.
nuest marked this conversation as resolved.
Show resolved Hide resolved

To see example repositories, visit our
`Stencila with R <https://github.com/binder-examples/stencila-r/>`_ and
`Stencila with Python <https://github.com/binder-examples/stencila-py>`_ examples.

.. _postBuild:

``postBuild`` - Run code after installing the environment
Expand Down
57 changes: 54 additions & 3 deletions repo2docker/buildpacks/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -271,16 +271,54 @@ def stencila_manifest_dir(self):
# ${STENCILA_ARCHIVE_DIR}/${STENCILA_ARCHIVE}/manifest.xml

self._stencila_manifest_dir = None

if os.path.exists('binder'):
return self._stencila_manifest_dir

for root, dirs, files in os.walk("."):
if "manifest.xml" in files:
self.log.debug("Found a manifest.xml at %s", root)
self._stencila_manifest_dir = root.split(os.path.sep, 1)[1]
self.log.info(
"Found stencila manifest.xml in %s",
"Using stencila manifest.xml in %s",
self._stencila_manifest_dir,
)
break
return self._stencila_manifest_dir

@property
def stencila_manifest_contexts(self):
nuest marked this conversation as resolved.
Show resolved Hide resolved
"""Find the stencila manifest contexts if it exists"""
if hasattr(self, '_stencila_manifest_contexts'):
return self._stencila_manifest_contexts

# look at the content of the jats.xml file to extract the required execution contexts

self._stencila_manifest_contexts = None

if os.path.exists('binder'):
return self._stencila_manifest_contexts

for root, dirs, files in os.walk("."):
for filename in files:
if filename.endswith(".jats.xml"):
self.log.debug("Found a .jats.xml: %s", filename)
self._stencila_manifest_contexts = set()

# extract code languages from file
with open(os.path.join(root, filename)) as f:
for line in f:
match = re.match('.*language="(.+?)"', line)
nuest marked this conversation as resolved.
Show resolved Hide resolved
if match:
self._stencila_manifest_contexts.add(match.group(1))

self.log.info(
"Using stencila executions contexts %s",
self._stencila_manifest_contexts,
)
break
return self._stencila_manifest_contexts

def get_build_scripts(self):
"""
Ordered list of shell script snippets to build the base image.
Expand Down Expand Up @@ -518,14 +556,27 @@ def get_assemble_scripts(self):
))
except FileNotFoundError:
pass
if self.stencila_manifest_contexts:
if {'py', 'pyjp'}.intersection(self.stencila_manifest_contexts):
assemble_scripts.extend(
[
(
"${NB_USER}",
r"""
${KERNEL_PYTHON_PREFIX}/bin/pip install --no-cache https://github.com/stencila/py/archive/f1260796.tar.gz && \
${KERNEL_PYTHON_PREFIX}/bin/python -m stencila register
""",
)
]
)
#if {'r'}.intersection(self.stencila_manifest_contexts):
# handled in RBuildPack
nuest marked this conversation as resolved.
Show resolved Hide resolved
if self.stencila_manifest_dir:
assemble_scripts.extend(
[
(
"${NB_USER}",
r"""
${KERNEL_PYTHON_PREFIX}/bin/pip install --no-cache https://github.com/stencila/py/archive/f6a245fd.tar.gz && \
${KERNEL_PYTHON_PREFIX}/bin/python -m stencila register && \
${NB_PYTHON_PREFIX}/bin/pip install --no-cache nbstencilaproxy==0.1.1 && \
jupyter serverextension enable --sys-prefix --py nbstencilaproxy && \
jupyter nbextension install --sys-prefix --py nbstencilaproxy && \
Expand Down
47 changes: 36 additions & 11 deletions repo2docker/buildpacks/r.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,14 @@ class RBuildPack(PythonBuildPack):
date snapshot of https://mran.microsoft.com/timemachine
from which libraries are to be installed.

2. An optional `install.R` file that will be executed at build time,
2. A `DESCRIPTION` file signaling an R package, or
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we should split this discussion into two things: how we detect that R needs installing and how to specify which libraries should be installed.

A more eloquent version of:

Setup R + RStudio if runtime.txt or DESCRIPTION or jats thing

Libraries will be installed if specified in install.R or as dependencies in DESCRIPTION

a Stencila document (*.jats.xml) with R code chunks (i.e. language="r")
is found:

MRAN snapshot is set to latest date that is guaranteed to exist
across timezones.

3. (Optional) An `install.R` file that will be executed at build time,
and can be used for installing packages from both MRAN and GitHub.

The `r-base` package from Ubuntu apt repositories is used to install
Expand Down Expand Up @@ -64,21 +71,22 @@ def detect(self):
unless a `requirements.txt` is present and we do not want to require the
presence of a `requirements.txt` to use R.

Instead we just check if runtime.txt contains a string of the form
`r-<YYYY>-<MM>-<DD>`
Instead we check the options described in the class comment above.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd delete this line if we don't want to duplicate the contents of the doc string for the class. Ideally we'd be able to come up with a nice short summary about all the various ways to trigger the R buildpack but I currently can't think of one :-(

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Deleted. Your call, really. I guess the "nice short summary" means it can't be automated.

Do you think there should be a developer-facing variant of the config files docs?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some developer facing docs would be good. Maybe building on https://repo2docker.readthedocs.io/en/latest/architecture.html?

"""
# If no date is found, then self.checkpoint_date will be False
# Otherwise, it'll be a date object, which will evaluate to True
if self.checkpoint_date:
return True

description_R = 'DESCRIPTION'
if not os.path.exists('binder') and os.path.exists(description_R):
if not self.checkpoint_date:
# no R snapshot date set through runtime.txt
# set the R runtime to the latest date that is guaranteed to be on MRAN across timezones
self._checkpoint_date = datetime.date.today() - datetime.timedelta(days=2)
self._runtime = "r-{}".format(str(self._checkpoint_date))
return True
if not os.path.exists('binder'):
if os.path.exists(description_R) or (self.stencila_manifest_contexts and "r" in self.stencila_manifest_contexts):
nuest marked this conversation as resolved.
Show resolved Hide resolved
nuest marked this conversation as resolved.
Show resolved Hide resolved
if not self.checkpoint_date:
# no R snapshot date set through runtime.txt
# set the R runtime to the latest date that is guaranteed to be on MRAN across timezones
self._checkpoint_date = datetime.date.today() - datetime.timedelta(days=2)
self._runtime = "r-{}".format(str(self._checkpoint_date))
return True

def get_path(self):
"""
Expand Down Expand Up @@ -133,6 +141,7 @@ def get_build_scripts(self):
- R's devtools package, at a particular frozen version (determined by MRAN)
- IRKernel
- nbrsessionproxy (to access RStudio via Jupyter Notebook)
- stencila R package (if Stencila document with R code chunks detected)
"""
rstudio_url = 'https://download2.rstudio.org/rstudio-server-1.1.419-amd64.deb'
# This is MD5, because that is what RStudio download page provides!
Expand All @@ -148,7 +157,7 @@ def get_build_scripts(self):
# IRKernel version - specified as a tag in the IRKernel repository
irkernel_version = '0.8.11'

return super().get_build_scripts() + [
scripts = [
(
"root",
r"""
Expand Down Expand Up @@ -226,6 +235,22 @@ def get_build_scripts(self):
),
]

if self.stencila_manifest_contexts:
nuest marked this conversation as resolved.
Show resolved Hide resolved
if "r" in self.stencila_manifest_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()"
"""
),
]

return super().get_build_scripts() + scripts

def get_assemble_scripts(self):
"""
Return series of build-steps specific to this repository
Expand Down
5 changes: 5 additions & 0 deletions tests/stencila/pyjp/verify
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#!/bin/sh

jupyter serverextension list 2>&1 | grep nbstencilaproxy
jupyter nbextension list 2>&1 | grep nbstencilaproxy
python3 -c "import stencila"
1 change: 1 addition & 0 deletions tests/stencila/basic/verify → tests/stencila/r/verify
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@

jupyter serverextension list 2>&1 | grep nbstencilaproxy
jupyter nbextension list 2>&1 | grep nbstencilaproxy
R -e "library('stencila');"