Last active
May 31, 2017 02:01
-
-
Save cmattoon/a78166721c6b38fbc0ec19014de27656 to your computer and use it in GitHub Desktop.
Install R packages on ShinyServerPro
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
""" | |
Install R Packages from the command line | |
Usage: (parse app.R) | |
./rpkg app.R | |
Usage: (install R packages) | |
./rpkg shiny V8 plyr | |
""" | |
import os | |
import pwd | |
import shlex | |
import subprocess | |
import sys | |
E_OK = 0 | |
E_BADARGS = 1 | |
# The name of the shiny user | |
SHINY_USER_NAME = 'shiny' | |
def loadfile(filename): | |
""" | |
:param filename: | |
:return: | |
""" | |
with open(filename, 'r') as fd: | |
return filter(lambda l: l.startswith('require('), | |
[line.strip() for line in fd.readlines()]) | |
def change_user(uid, gid): | |
""" | |
Returns a pre-exec function to pass to subprocess.Popen | |
This allows the script to run as the 'shiny' user | |
(defined in SHINY_USER_NAME) | |
:param uid: int | |
:param gid: int | |
:return: function | |
""" | |
def wrapper(): | |
os.setgid(gid) | |
os.setuid(uid) | |
return wrapper | |
def get_install_command(package): | |
return shlex.split("R -e \'install.packages(\"%s\", repos=\"http://cran.rstudio.com/\")\'".format(package) | |
def get_new_env(username): | |
""" | |
Build up an environment for the new user | |
:param username: | |
:return: | |
""" | |
info = pwd.getpwnam(username) | |
env = os.environ.copy() | |
env['HOME'] = info.pw_dir | |
env['LOGNAME'] = info.pw_name | |
env['PWD'] = os.getcwd() | |
env['USER'] = info.pw_name | |
cwd = os.getcwd() | |
preexec = change_user(info.pw_uid, info.pw_gid) | |
return env, cwd, preexec | |
def install_package(package): | |
""" | |
Installs an R package | |
:param package: The name of the package to install | |
:type package: str | |
:return: | |
""" | |
print(">> Installing '{}'".format(package)) | |
env, cwd, preexec = get_new_env(SHINY_USER_NAME) | |
ps = subprocess.Popen(get_install_command(package), | |
preexec_fn=preexec, | |
cwd=cwd, | |
env=env, | |
stdout=subprocess.PIPE, | |
stderr=subprocess.PIPE) | |
_out, _err = ps.communicate() | |
success_str = "* DONE ({})".format(package) | |
if success_str not in _err: | |
print("\033[31mERROR") | |
print(_err) | |
print("\033[0m") | |
return False | |
print(" [\033[32mOK\033[0m]") | |
return True | |
def install_packages(packages): | |
""" | |
Mostly unnecessary, unless you run into exceptions | |
Add the install_package call inside a try:except block | |
to install *most* packages | |
:param packages: | |
:return: | |
""" | |
for package in packages: | |
install_package(package) | |
def main(filename): | |
""" | |
:param filename: | |
:return: | |
""" | |
packages = [] | |
if os.path.exists(filename): | |
# Parse a file | |
lines = loadfile(filename) | |
for require in lines: | |
packages.append(require.replace('require(', '').replace(')', '')) | |
else: | |
# Install a list of packages | |
for arg in sys.argv[1:]: | |
packages.append(arg) | |
install_packages(packages) | |
if __name__ == '__main__': | |
try: | |
infile = sys.argv[1] | |
except IndexError: | |
print("Usage: {0} <path/to/app.R>\nOr: {1} list of packages".format(sys.argv[0], sys.argv[0])) | |
exit(E_BADARGS) | |
exit(main(infile)) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment