| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent 9da45a6 commit 85783bd
3 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -10,6 +10,7 @@ | |||
| 10 | 10 | from pre_commit.languages import fail | |
| 11 | 11 | from pre_commit.languages import golang | |
| 12 | 12 | from pre_commit.languages import haskell | |
| 13 | + from pre_commit.languages import julia | ||
| 13 | 14 | from pre_commit.languages import lua | |
| 14 | 15 | from pre_commit.languages import node | |
| 15 | 16 | from pre_commit.languages import perl | |
@@ -33,6 +34,7 @@ | |||
| 33 | 34 | 'fail': fail, | |
| 34 | 35 | 'golang': golang, | |
| 35 | 36 | 'haskell': haskell, | |
| 37 | + 'julia': julia, | ||
| 36 | 38 | 'lua': lua, | |
| 37 | 39 | 'node': node, | |
| 38 | 40 | 'perl': perl, | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,132 @@ | |||
| 1 | + from __future__ import annotations | ||
| 2 | + | ||
| 3 | + import contextlib | ||
| 4 | + import os | ||
| 5 | + import shutil | ||
| 6 | + from collections.abc import Generator | ||
| 7 | + from collections.abc import Sequence | ||
| 8 | + | ||
| 9 | + from pre_commit import lang_base | ||
| 10 | + from pre_commit.envcontext import envcontext | ||
| 11 | + from pre_commit.envcontext import PatchesT | ||
| 12 | + from pre_commit.envcontext import UNSET | ||
| 13 | + from pre_commit.prefix import Prefix | ||
| 14 | + from pre_commit.util import cmd_output_b | ||
| 15 | + | ||
| 16 | + ENVIRONMENT_DIR = 'juliaenv' | ||
| 17 | + health_check = lang_base.basic_health_check | ||
| 18 | + get_default_version = lang_base.basic_get_default_version | ||
| 19 | + | ||
| 20 | + | ||
| 21 | + def run_hook( | ||
| 22 | + prefix: Prefix, | ||
| 23 | + entry: str, | ||
| 24 | + args: Sequence[str], | ||
| 25 | + file_args: Sequence[str], | ||
| 26 | + *, | ||
| 27 | + is_local: bool, | ||
| 28 | + require_serial: bool, | ||
| 29 | + color: bool, | ||
| 30 | + ) -> tuple[int, bytes]: | ||
| 31 | + # `entry` is a (hook-repo relative) file followed by (optional) args, e.g. | ||
| 32 | + # `bin/id.jl` or `bin/hook.jl --arg1 --arg2` so we | ||
| 33 | + # 1) shell parse it and join with args with hook_cmd | ||
| 34 | + # 2) prepend the hooks prefix path to the first argument (the file), unless | ||
| 35 | + # it is a local script | ||
| 36 | + # 3) prepend `julia` as the interpreter | ||
| 37 | + | ||
| 38 | + cmd = lang_base.hook_cmd(entry, args) | ||
| 39 | + script = cmd[0] if is_local else prefix.path(cmd[0]) | ||
| 40 | + cmd = ('julia', script, *cmd[1:]) | ||
| 41 | + return lang_base.run_xargs( | ||
| 42 | + cmd, | ||
| 43 | + file_args, | ||
| 44 | + require_serial=require_serial, | ||
| 45 | + color=color, | ||
| 46 | + ) | ||
| 47 | + | ||
| 48 | + | ||
| 49 | + def get_env_patch(target_dir: str, version: str) -> PatchesT: | ||
| 50 | + return ( | ||
| 51 | + ('JULIA_LOAD_PATH', target_dir), | ||
| 52 | + # May be set, remove it to not interfer with LOAD_PATH | ||
| 53 | + ('JULIA_PROJECT', UNSET), | ||
| 54 | + ) | ||
| 55 | + | ||
| 56 | + | ||
| 57 | + @contextlib.contextmanager | ||
| 58 | + def in_env(prefix: Prefix, version: str) -> Generator[None]: | ||
| 59 | + envdir = lang_base.environment_dir(prefix, ENVIRONMENT_DIR, version) | ||
| 60 | + with envcontext(get_env_patch(envdir, version)): | ||
| 61 | + yield | ||
| 62 | + | ||
| 63 | + | ||
| 64 | + def install_environment( | ||
| 65 | + prefix: Prefix, | ||
| 66 | + version: str, | ||
| 67 | + additional_dependencies: Sequence[str], | ||
| 68 | + ) -> None: | ||
| 69 | + envdir = lang_base.environment_dir(prefix, ENVIRONMENT_DIR, version) | ||
| 70 | + with in_env(prefix, version): | ||
| 71 | + # TODO: Support language_version with juliaup similar to rust via | ||
| 72 | + # rustup | ||
| 73 | + # if version != 'system': | ||
| 74 | + # ... | ||
| 75 | + | ||
| 76 | + # Copy Project.toml to hook env if it exist | ||
| 77 | + os.makedirs(envdir, exist_ok=True) | ||
| 78 | + project_names = ('JuliaProject.toml', 'Project.toml') | ||
| 79 | + project_found = False | ||
| 80 | + for project_name in project_names: | ||
| 81 | + project_file = prefix.path(project_name) | ||
| 82 | + if not os.path.isfile(project_file): | ||
| 83 | + continue | ||
| 84 | + shutil.copy(project_file, envdir) | ||
| 85 | + project_found = True | ||
| 86 | + break | ||
| 87 | + | ||
| 88 | + # If no project file was found we create an empty one so that the | ||
| 89 | + # package manager doesn't error | ||
| 90 | + if not project_found: | ||
| 91 | + open(os.path.join(envdir, 'Project.toml'), 'a').close() | ||
| 92 | + | ||
| 93 | + # Copy Manifest.toml to hook env if it exists | ||
| 94 | + manifest_names = ('JuliaManifest.toml', 'Manifest.toml') | ||
| 95 | + for manifest_name in manifest_names: | ||
| 96 | + manifest_file = prefix.path(manifest_name) | ||
| 97 | + if not os.path.isfile(manifest_file): | ||
| 98 | + continue | ||
| 99 | + shutil.copy(manifest_file, envdir) | ||
| 100 | + break | ||
| 101 | + | ||
| 102 | + # Julia code to instantiate the hook environment | ||
| 103 | + julia_code = """ | ||
| 104 | + @assert length(ARGS) > 0 | ||
| 105 | + hook_env = ARGS[1] | ||
| 106 | + deps = join(ARGS[2:end], " ") | ||
| 107 | + | ||
| 108 | + # We prepend @stdlib here so that we can load the package manager even | ||
| 109 | + # though `get_env_patch` limits `JULIA_LOAD_PATH` to just the hook env. | ||
| 110 | + pushfirst!(LOAD_PATH, "@stdlib") | ||
| 111 | + using Pkg | ||
| 112 | + popfirst!(LOAD_PATH) | ||
| 113 | + | ||
| 114 | + # Instantiate the environment shipped with the hook repo. If we have | ||
| 115 | + # additional dependencies we disable precompilation in this step to | ||
| 116 | + # avoid double work. | ||
| 117 | + precompile = isempty(deps) ? "1" : "0" | ||
| 118 | + withenv("JULIA_PKG_PRECOMPILE_AUTO" => precompile) do | ||
| 119 | + Pkg.instantiate() | ||
| 120 | + end | ||
| 121 | + | ||
| 122 | + # Add additional dependencies (with precompilation) | ||
| 123 | + if !isempty(deps) | ||
| 124 | + withenv("JULIA_PKG_PRECOMPILE_AUTO" => "1") do | ||
| 125 | + Pkg.REPLMode.pkgstr("add " * deps) | ||
| 126 | + end | ||
| 127 | + end | ||
| 128 | + """ | ||
| 129 | + cmd_output_b( | ||
| 130 | + 'julia', '-e', julia_code, '--', envdir, *additional_dependencies, | ||
| 131 | + cwd=prefix.prefix_dir, | ||
| 132 | + ) | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,97 @@ | |||
| 1 | + from __future__ import annotations | ||
| 2 | + | ||
| 3 | + from pre_commit.languages import julia | ||
| 4 | + from testing.language_helpers import run_language | ||
| 5 | + from testing.util import cwd | ||
| 6 | + | ||
| 7 | + | ||
| 8 | + def _make_hook(tmp_path, julia_code): | ||
| 9 | + src_dir = tmp_path.joinpath('src') | ||
| 10 | + src_dir.mkdir() | ||
| 11 | + src_dir.joinpath('main.jl').write_text(julia_code) | ||
| 12 | + tmp_path.joinpath('Project.toml').write_text( | ||
| 13 | + '[deps]\n' | ||
| 14 | + 'Example = "7876af07-990d-54b4-ab0e-23690620f79a"\n', | ||
| 15 | + ) | ||
| 16 | + | ||
| 17 | + | ||
| 18 | + def test_julia_hook(tmp_path): | ||
| 19 | + code = """ | ||
| 20 | + using Example | ||
| 21 | + function main() | ||
| 22 | + println("Hello, world!") | ||
| 23 | + end | ||
| 24 | + main() | ||
| 25 | + """ | ||
| 26 | + _make_hook(tmp_path, code) | ||
| 27 | + expected = (0, b'Hello, world!\n') | ||
| 28 | + assert run_language(tmp_path, julia, 'src/main.jl') == expected | ||
| 29 | + | ||
| 30 | + | ||
| 31 | + def test_julia_hook_manifest(tmp_path): | ||
| 32 | + code = """ | ||
| 33 | + using Example | ||
| 34 | + println(pkgversion(Example)) | ||
| 35 | + """ | ||
| 36 | + _make_hook(tmp_path, code) | ||
| 37 | + | ||
| 38 | + tmp_path.joinpath('Manifest.toml').write_text( | ||
| 39 | + 'manifest_format = "2.0"\n\n' | ||
| 40 | + '[[deps.Example]]\n' | ||
| 41 | + 'git-tree-sha1 = "11820aa9c229fd3833d4bd69e5e75ef4e7273bf1"\n' | ||
| 42 | + 'uuid = "7876af07-990d-54b4-ab0e-23690620f79a"\n' | ||
| 43 | + 'version = "0.5.4"\n', | ||
| 44 | + ) | ||
| 45 | + expected = (0, b'0.5.4\n') | ||
| 46 | + assert run_language(tmp_path, julia, 'src/main.jl') == expected | ||
| 47 | + | ||
| 48 | + | ||
| 49 | + def test_julia_hook_args(tmp_path): | ||
| 50 | + code = """ | ||
| 51 | + function main(argv) | ||
| 52 | + foreach(println, argv) | ||
| 53 | + end | ||
| 54 | + main(ARGS) | ||
| 55 | + """ | ||
| 56 | + _make_hook(tmp_path, code) | ||
| 57 | + expected = (0, b'--arg1\n--arg2\n') | ||
| 58 | + assert run_language( | ||
| 59 | + tmp_path, julia, 'src/main.jl --arg1 --arg2', | ||
| 60 | + ) == expected | ||
| 61 | + | ||
| 62 | + | ||
| 63 | + def test_julia_hook_additional_deps(tmp_path): | ||
| 64 | + code = """ | ||
| 65 | + using TOML | ||
| 66 | + function main() | ||
| 67 | + project_file = Base.active_project() | ||
| 68 | + dict = TOML.parsefile(project_file) | ||
| 69 | + for (k, v) in dict["deps"] | ||
| 70 | + println(k, " = ", v) | ||
| 71 | + end | ||
| 72 | + end | ||
| 73 | + main() | ||
| 74 | + """ | ||
| 75 | + _make_hook(tmp_path, code) | ||
| 76 | + deps = ('TOML=fa267f1f-6049-4f14-aa54-33bafae1ed76',) | ||
| 77 | + ret, out = run_language(tmp_path, julia, 'src/main.jl', deps=deps) | ||
| 78 | + assert ret == 0 | ||
| 79 | + assert b'Example = 7876af07-990d-54b4-ab0e-23690620f79a' in out | ||
| 80 | + assert b'TOML = fa267f1f-6049-4f14-aa54-33bafae1ed76' in out | ||
| 81 | + | ||
| 82 | + | ||
| 83 | + def test_julia_repo_local(tmp_path): | ||
| 84 | + env_dir = tmp_path.joinpath('envdir') | ||
| 85 | + env_dir.mkdir() | ||
| 86 | + local_dir = tmp_path.joinpath('local') | ||
| 87 | + local_dir.mkdir() | ||
| 88 | + local_dir.joinpath('local.jl').write_text( | ||
| 89 | + 'using TOML; foreach(println, ARGS)', | ||
| 90 | + ) | ||
| 91 | + with cwd(local_dir): | ||
| 92 | + deps = ('TOML=fa267f1f-6049-4f14-aa54-33bafae1ed76',) | ||
| 93 | + expected = (0, b'--local-arg1\n--local-arg2\n') | ||
| 94 | + assert run_language( | ||
| 95 | + env_dir, julia, 'local.jl --local-arg1 --local-arg2', | ||
| 96 | + deps=deps, is_local=True, | ||
| 97 | + ) == expected | ||
| Back | FazBrowse Home | New Git URL |
0 commit comments