diff --git a/README.md b/README.md index 14581a1..fd064fa 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,9 @@ # jupyter-rsession-proxy -**jupyter-rsession-proxy** provides Jupyter server and notebook extensions to proxy RStudio. +[![PyPI](https://img.shields.io/pypi/v/jupyter-rsession-proxy?label=PyPI%20Version)](https://pypi.org/project/jupyter-rsession-proxy/) +[![PyPI - Wheel](https://img.shields.io/pypi/wheel/jupyter-rsession-proxy)](https://pypi.org/project/jupyter-rsession-proxy/) + +**jupyter-rsession-proxy** provides Jupyter server and notebook extensions to proxy RStudio Server (multi-user env.) or RStudio Session (single-user env.). ![Screenshot](screenshot.png) @@ -25,6 +28,20 @@ Install the library: pip install jupyter-rsession-proxy ``` +## Configuring using environment variables + +This extension can be configured using environment variables. +Below is a list with all supported environment variables. + +| Environment variable | Description | +| --------------------- |-------------| +| RSTUDIO_RSERVER_BIN | Prioritized location for searching binary file "rserver". Should be an absolute path to rserver or not set. | +| RSTUDIO_RSERVER_ARGS | Overrides all arguments (except --www-port) for "rserver" binary. | +| RSTUDIO_RSESSION_BIN | Prioritized location for searching binary file "rsession". Should be an absolute path to rserver or not set. | +| RSTUDIO_RSESSION_ARGS | Overrides all arguments (except --www-port and --user-identity) for "rsession" binary. | +| RSTUDIO_FOLDER | Prioritized folder for searching all RStudio related binary files. Should be an absolute path to folder or not set. | + + ## Example [rocker/binder](https://hub.docker.com/r/rocker/binder) contains an example installation which you can run on binder. diff --git a/jupyter_rsession_proxy/__init__.py b/jupyter_rsession_proxy/__init__.py index 55f1fbe..7c912e1 100644 --- a/jupyter_rsession_proxy/__init__.py +++ b/jupyter_rsession_proxy/__init__.py @@ -1,9 +1,44 @@ -import os -import subprocess +""" +This file contains logic that is required for "jupyter-server-proxy" to register additional launchers in Jupyter Notebook. +Docs: https://github.com/jupyterhub/jupyter-server-proxy/blob/master/docs/server-process.rst +""" import getpass +import os +import shlex import shutil +import subprocess + + +# RSTUDIO_RSERVER_BIN - Prioritized location for searching binary file "rserver". +# Should be an absolute path to rserver or not set. +RSTUDIO_RSERVER_BIN = os.getenv('RSTUDIO_RSERVER_BIN') + +# RSTUDIO_RSERVER_ARGS - Overrides all arguments (except --www-port) for "rserver" binary. +# Should be an absolute path to rserver or not set. +RSTUDIO_RSERVER_ARGS = os.getenv('RSTUDIO_RSERVER_ARGS', '') + +# RSTUDIO_RSESSION_BIN - Prioritized location for searching binary file "rsession". +RSTUDIO_RSESSION_BIN = os.getenv('RSTUDIO_RSESSION_BIN') + +# RSTUDIO_RSESSION_ARGS - Overrides all arguments (except --www-port and --user-identity) for "rsession" binary. +RSTUDIO_RSESSION_ARGS = os.getenv( + 'RSTUDIO_RSESSION_ARGS', + '--standalone=1 --program-mode=server --log-stderr=1 --session-timeout-minutes=0' +) + +# RSTUDIO_FOLDER - Prioritized folder for searching all RStudio related binary files. +# Should be an absolute path to folder or not set. +RSTUDIO_FOLDER = os.getenv('RSTUDIO_FOLDER') + def get_rstudio_executable(prog): + """Find location (absolute path) of RStudio program""" + # Try env. variable RSTUDIO_FOLDER to search prog in + if RSTUDIO_FOLDER: + bin_location = os.path.join(RSTUDIO_FOLDER, prog) + if os.path.exists(bin_location): + return bin_location + # Find prog in known locations other_paths = [ # When rstudio-server deb is installed @@ -11,6 +46,8 @@ def get_rstudio_executable(prog): # When just rstudio deb is installed os.path.join('/usr/lib/rstudio/bin', prog), ] + + # Try to find prog in PATH if shutil.which(prog): return prog @@ -18,33 +55,40 @@ def get_rstudio_executable(prog): if os.path.exists(op): return op - raise FileNotFoundError(f'Could not find {prog} in PATH') + raise FileNotFoundError(f'Could not find {prog} in PATH or well known locations') def get_icon_path(): + """Get path to icon for Jupyter web interface""" return os.path.join( os.path.dirname(os.path.abspath(__file__)), 'icons', 'rstudio.svg' ) def setup_rserver(): + """Get entry for RServer""" def _get_env(port): return dict(USER=getpass.getuser()) def _get_cmd(port): - return [ - get_rstudio_executable('rserver'), + bin_file = RSTUDIO_RSERVER_BIN if RSTUDIO_RSERVER_BIN else get_rstudio_executable('rserver') + cmd = [ + bin_file, '--www-port=' + str(port) ] + if RSTUDIO_RSERVER_ARGS: + cmd.extend(shlex.split(RSTUDIO_RSERVER_ARGS)) + return cmd return { 'command': _get_cmd, 'environment': _get_env, 'launcher_entry': { - 'title': 'RStudio', + 'title': 'RStudio Server', 'icon_path': get_icon_path() } } def setup_rsession(): + """Get entry for RSession""" def _get_env(port): # Detect various environment variables rsession requires to run # Via rstudio's src/cpp/core/r_util/REnvironmentPosix.cpp @@ -65,21 +109,21 @@ def _get_env(port): } def _get_cmd(port): - return [ - get_rstudio_executable('rsession'), - '--standalone=1', - '--program-mode=server', - '--log-stderr=1', - '--session-timeout-minutes=0', + bin_file = RSTUDIO_RSESSION_BIN if RSTUDIO_RSESSION_BIN else get_rstudio_executable('rsession') + cmd = [ + bin_file, '--user-identity=' + getpass.getuser(), '--www-port=' + str(port) ] + if RSTUDIO_RSESSION_ARGS: + cmd.extend(shlex.split(RSTUDIO_RSESSION_ARGS)) + return cmd return { 'command': _get_cmd, 'environment': _get_env, 'launcher_entry': { - 'title': 'RStudio', + 'title': 'RStudio Session', 'icon_path': get_icon_path() } } diff --git a/setup.py b/setup.py index 2846a31..2337c8a 100644 --- a/setup.py +++ b/setup.py @@ -1,20 +1,24 @@ import setuptools setuptools.setup( - name="jupyter-rsession-proxy", - version='1.1', - url="https://github.com/jupyterhub/jupyter-rsession-proxy", - author="Ryan Lovett & Yuvi Panda", - description="Jupyter extension to proxy RStudio", + name='jupyter-rsession-proxy', + version='1.2', + url='https://github.com/jupyterhub/jupyter-rsession-proxy', + author='Ryan Lovett & Yuvi Panda & Kirill Makhonin', + description='Jupyter extension to proxy RStudio', packages=setuptools.find_packages(), - keywords=['Jupyter'], - classifiers=['Framework :: Jupyter'], + keywords=['Jupyter'], + classifiers=[ + 'Framework :: Jupyter', + 'Programming Language :: Python :: 3' + ], install_requires=[ 'jupyter-server-proxy' ], entry_points={ 'jupyter_serverproxy_servers': [ - 'rstudio = jupyter_rsession_proxy:setup_rserver' + 'rstudio = jupyter_rsession_proxy:setup_rserver', + 'rsession = jupyter_rsession_proxy:setup_rsession' ] }, package_data={