avoid quoting and escaping while installing R hooks by writing code to tempfile instead of execute R code inline

This commit is contained in:
Lorenz Walthert 2023-05-15 09:26:55 +02:00 committed by Anthony Sottile
parent c389ac0ba8
commit cd09c3525e

View file

@ -4,6 +4,8 @@ import contextlib
import os import os
import shlex import shlex
import shutil import shutil
import tempfile
import textwrap
from typing import Generator from typing import Generator
from typing import Sequence from typing import Sequence
@ -21,6 +23,19 @@ get_default_version = lang_base.basic_get_default_version
health_check = lang_base.basic_health_check health_check = lang_base.basic_health_check
@contextlib.contextmanager
def _r_code_in_tempfile(code: str) -> Generator[str, None, None]:
"""
To avoid quoting and escaping issues, avoid `Rscript [options] -e {expr}`
but use `Rscript [options] path/to/file_with_expr.R`
"""
with tempfile.TemporaryDirectory() as tmpdir:
fname = os.path.join(tmpdir, 'script.R')
with open(fname, 'w') as f:
f.write(_inline_r_setup(textwrap.dedent(code)))
yield fname
def get_env_patch(venv: str) -> PatchesT: def get_env_patch(venv: str) -> PatchesT:
return ( return (
('R_PROFILE_USER', os.path.join(venv, 'activate.R')), ('R_PROFILE_USER', os.path.join(venv, 'activate.R')),
@ -129,20 +144,19 @@ def install_environment(
}} }}
""" """
cmd_output_b( with _r_code_in_tempfile(r_code_inst_environment) as f:
_rscript_exec(), '--vanilla', '-e', cmd_output_b(_rscript_exec(), '--vanilla', f, cwd=env_dir)
_inline_r_setup(r_code_inst_environment),
cwd=env_dir,
)
if additional_dependencies: if additional_dependencies:
r_code_inst_add = 'renv::install(commandArgs(trailingOnly = TRUE))' r_code_inst_add = 'renv::install(commandArgs(trailingOnly = TRUE))'
with in_env(prefix, version): with in_env(prefix, version):
cmd_output_b( with _r_code_in_tempfile(r_code_inst_add) as f:
_rscript_exec(), *RSCRIPT_OPTS, '-e', cmd_output_b(
_inline_r_setup(r_code_inst_add), _rscript_exec(), *RSCRIPT_OPTS,
*additional_dependencies, f,
cwd=env_dir, *additional_dependencies,
) cwd=env_dir,
)
def _inline_r_setup(code: str) -> str: def _inline_r_setup(code: str) -> str:
@ -150,11 +164,16 @@ def _inline_r_setup(code: str) -> str:
Some behaviour of R cannot be configured via env variables, but can Some behaviour of R cannot be configured via env variables, but can
only be configured via R options once R has started. These are set here. only be configured via R options once R has started. These are set here.
""" """
with_option = f"""\ with_option = [
options(install.packages.compile.from.source = "never", pkgType = "binary") textwrap.dedent("""\
{code} options(
""" install.packages.compile.from.source = "never",
return with_option pkgType = "binary"
)
"""),
code,
]
return '\n'.join(with_option)
def run_hook( def run_hook(