summaryrefslogtreecommitdiffstats
path: root/pre_commit/languages
diff options
context:
space:
mode:
Diffstat (limited to 'pre_commit/languages')
-rw-r--r--pre_commit/languages/golang.py2
-rw-r--r--pre_commit/languages/julia.py132
-rw-r--r--pre_commit/languages/r.py48
3 files changed, 170 insertions, 12 deletions
diff --git a/pre_commit/languages/golang.py b/pre_commit/languages/golang.py
index 6090879..678c04b 100644
--- a/pre_commit/languages/golang.py
+++ b/pre_commit/languages/golang.py
@@ -75,6 +75,7 @@ def get_env_patch(venv: str, version: str) -> PatchesT:
return (
('GOROOT', os.path.join(venv, '.go')),
+ ('GOTOOLCHAIN', 'local'),
(
'PATH', (
os.path.join(venv, 'bin'), os.pathsep,
@@ -145,6 +146,7 @@ def install_environment(
env = no_git_env(dict(os.environ, GOPATH=gopath))
env.pop('GOBIN', None)
if version != 'system':
+ env['GOTOOLCHAIN'] = 'local'
env['GOROOT'] = os.path.join(env_dir, '.go')
env['PATH'] = os.pathsep.join((
os.path.join(env_dir, '.go', 'bin'), os.environ['PATH'],
diff --git a/pre_commit/languages/julia.py b/pre_commit/languages/julia.py
new file mode 100644
index 0000000..df91c06
--- /dev/null
+++ b/pre_commit/languages/julia.py
@@ -0,0 +1,132 @@
+from __future__ import annotations
+
+import contextlib
+import os
+import shutil
+from collections.abc import Generator
+from collections.abc import Sequence
+
+from pre_commit import lang_base
+from pre_commit.envcontext import envcontext
+from pre_commit.envcontext import PatchesT
+from pre_commit.envcontext import UNSET
+from pre_commit.prefix import Prefix
+from pre_commit.util import cmd_output_b
+
+ENVIRONMENT_DIR = 'juliaenv'
+health_check = lang_base.basic_health_check
+get_default_version = lang_base.basic_get_default_version
+
+
+def run_hook(
+ prefix: Prefix,
+ entry: str,
+ args: Sequence[str],
+ file_args: Sequence[str],
+ *,
+ is_local: bool,
+ require_serial: bool,
+ color: bool,
+) -> tuple[int, bytes]:
+ # `entry` is a (hook-repo relative) file followed by (optional) args, e.g.
+ # `bin/id.jl` or `bin/hook.jl --arg1 --arg2` so we
+ # 1) shell parse it and join with args with hook_cmd
+ # 2) prepend the hooks prefix path to the first argument (the file), unless
+ # it is a local script
+ # 3) prepend `julia` as the interpreter
+
+ cmd = lang_base.hook_cmd(entry, args)
+ script = cmd[0] if is_local else prefix.path(cmd[0])
+ cmd = ('julia', script, *cmd[1:])
+ return lang_base.run_xargs(
+ cmd,
+ file_args,
+ require_serial=require_serial,
+ color=color,
+ )
+
+
+def get_env_patch(target_dir: str, version: str) -> PatchesT:
+ return (
+ ('JULIA_LOAD_PATH', target_dir),
+ # May be set, remove it to not interfer with LOAD_PATH
+ ('JULIA_PROJECT', UNSET),
+ )
+
+
+@contextlib.contextmanager
+def in_env(prefix: Prefix, version: str) -> Generator[None]:
+ envdir = lang_base.environment_dir(prefix, ENVIRONMENT_DIR, version)
+ with envcontext(get_env_patch(envdir, version)):
+ yield
+
+
+def install_environment(
+ prefix: Prefix,
+ version: str,
+ additional_dependencies: Sequence[str],
+) -> None:
+ envdir = lang_base.environment_dir(prefix, ENVIRONMENT_DIR, version)
+ with in_env(prefix, version):
+ # TODO: Support language_version with juliaup similar to rust via
+ # rustup
+ # if version != 'system':
+ # ...
+
+ # Copy Project.toml to hook env if it exist
+ os.makedirs(envdir, exist_ok=True)
+ project_names = ('JuliaProject.toml', 'Project.toml')
+ project_found = False
+ for project_name in project_names:
+ project_file = prefix.path(project_name)
+ if not os.path.isfile(project_file):
+ continue
+ shutil.copy(project_file, envdir)
+ project_found = True
+ break
+
+ # If no project file was found we create an empty one so that the
+ # package manager doesn't error
+ if not project_found:
+ open(os.path.join(envdir, 'Project.toml'), 'a').close()
+
+ # Copy Manifest.toml to hook env if it exists
+ manifest_names = ('JuliaManifest.toml', 'Manifest.toml')
+ for manifest_name in manifest_names:
+ manifest_file = prefix.path(manifest_name)
+ if not os.path.isfile(manifest_file):
+ continue
+ shutil.copy(manifest_file, envdir)
+ break
+
+ # Julia code to instantiate the hook environment
+ julia_code = """
+ @assert length(ARGS) > 0
+ hook_env = ARGS[1]
+ deps = join(ARGS[2:end], " ")
+
+ # We prepend @stdlib here so that we can load the package manager even
+ # though `get_env_patch` limits `JULIA_LOAD_PATH` to just the hook env.
+ pushfirst!(LOAD_PATH, "@stdlib")
+ using Pkg
+ popfirst!(LOAD_PATH)
+
+ # Instantiate the environment shipped with the hook repo. If we have
+ # additional dependencies we disable precompilation in this step to
+ # avoid double work.
+ precompile = isempty(deps) ? "1" : "0"
+ withenv("JULIA_PKG_PRECOMPILE_AUTO" => precompile) do
+ Pkg.instantiate()
+ end
+
+ # Add additional dependencies (with precompilation)
+ if !isempty(deps)
+ withenv("JULIA_PKG_PRECOMPILE_AUTO" => "1") do
+ Pkg.REPLMode.pkgstr("add " * deps)
+ end
+ end
+ """
+ cmd_output_b(
+ 'julia', '-e', julia_code, '--', envdir, *additional_dependencies,
+ cwd=prefix.prefix_dir,
+ )
diff --git a/pre_commit/languages/r.py b/pre_commit/languages/r.py
index c75a308..f70d2fd 100644
--- a/pre_commit/languages/r.py
+++ b/pre_commit/languages/r.py
@@ -15,27 +15,50 @@ from pre_commit.envcontext import PatchesT
from pre_commit.envcontext import UNSET
from pre_commit.prefix import Prefix
from pre_commit.util import cmd_output
-from pre_commit.util import cmd_output_b
from pre_commit.util import win_exe
ENVIRONMENT_DIR = 'renv'
-RSCRIPT_OPTS = ('--no-save', '--no-restore', '--no-site-file', '--no-environ')
get_default_version = lang_base.basic_get_default_version
+_RENV_ACTIVATED_OPTS = (
+ '--no-save', '--no-restore', '--no-site-file', '--no-environ',
+)
-def _execute_vanilla_r_code_as_script(
+
+def _execute_r(
code: str, *,
prefix: Prefix, version: str, args: Sequence[str] = (), cwd: str,
+ cli_opts: Sequence[str],
) -> str:
with in_env(prefix, version), _r_code_in_tempfile(code) as f:
_, out, _ = cmd_output(
- _rscript_exec(), *RSCRIPT_OPTS, f, *args, cwd=cwd,
+ _rscript_exec(), *cli_opts, f, *args, cwd=cwd,
)
return out.rstrip('\n')
+def _execute_r_in_renv(
+ code: str, *,
+ prefix: Prefix, version: str, args: Sequence[str] = (), cwd: str,
+) -> str:
+ return _execute_r(
+ code=code, prefix=prefix, version=version, args=args, cwd=cwd,
+ cli_opts=_RENV_ACTIVATED_OPTS,
+ )
+
+
+def _execute_vanilla_r(
+ code: str, *,
+ prefix: Prefix, version: str, args: Sequence[str] = (), cwd: str,
+) -> str:
+ return _execute_r(
+ code=code, prefix=prefix, version=version, args=args, cwd=cwd,
+ cli_opts=('--vanilla',),
+ )
+
+
def _read_installed_version(envdir: str, prefix: Prefix, version: str) -> str:
- return _execute_vanilla_r_code_as_script(
+ return _execute_r_in_renv(
'cat(renv::settings$r.version())',
prefix=prefix, version=version,
cwd=envdir,
@@ -43,7 +66,7 @@ def _read_installed_version(envdir: str, prefix: Prefix, version: str) -> str:
def _read_executable_version(envdir: str, prefix: Prefix, version: str) -> str:
- return _execute_vanilla_r_code_as_script(
+ return _execute_r_in_renv(
'cat(as.character(getRversion()))',
prefix=prefix, version=version,
cwd=envdir,
@@ -53,7 +76,7 @@ def _read_executable_version(envdir: str, prefix: Prefix, version: str) -> str:
def _write_current_r_version(
envdir: str, prefix: Prefix, version: str,
) -> None:
- _execute_vanilla_r_code_as_script(
+ _execute_r_in_renv(
'renv::settings$r.version(as.character(getRversion()))',
prefix=prefix, version=version,
cwd=envdir,
@@ -161,7 +184,7 @@ def _cmd_from_hook(
_entry_validate(cmd)
cmd_part = _prefix_if_file_entry(cmd, prefix, is_local=is_local)
- return (cmd[0], *RSCRIPT_OPTS, *cmd_part, *args)
+ return (cmd[0], *_RENV_ACTIVATED_OPTS, *cmd_part, *args)
def install_environment(
@@ -204,14 +227,15 @@ def install_environment(
renv::install(prefix_dir)
}}
"""
-
- with _r_code_in_tempfile(r_code_inst_environment) as f:
- cmd_output_b(_rscript_exec(), '--vanilla', f, cwd=env_dir)
+ _execute_vanilla_r(
+ r_code_inst_environment,
+ prefix=prefix, version=version, cwd=env_dir,
+ )
_write_current_r_version(envdir=env_dir, prefix=prefix, version=version)
if additional_dependencies:
r_code_inst_add = 'renv::install(commandArgs(trailingOnly = TRUE))'
- _execute_vanilla_r_code_as_script(
+ _execute_r_in_renv(
code=r_code_inst_add, prefix=prefix, version=version,
args=additional_dependencies,
cwd=env_dir,