diff --git a/pre_commit/languages/rust.py b/pre_commit/languages/rust.py index 541a333c..41053f88 100644 --- a/pre_commit/languages/rust.py +++ b/pre_commit/languages/rust.py @@ -39,6 +39,7 @@ def in_env(prefix): def _add_dependencies(cargo_toml_path, additional_dependencies): with open(cargo_toml_path, 'r+') as f: cargo_toml = toml.load(f) + cargo_toml.setdefault('dependencies', {}) for dep in additional_dependencies: name, _, spec = dep.partition(':') cargo_toml['dependencies'][name] = spec or '*' @@ -47,7 +48,7 @@ def _add_dependencies(cargo_toml_path, additional_dependencies): f.truncate() -def install_environment(prefix, version, additional_deps): +def install_environment(prefix, version, additional_dependencies): helpers.assert_version_default('rust', version) directory = prefix.path( helpers.environment_dir(ENVIRONMENT_DIR, 'default'), @@ -63,14 +64,23 @@ def install_environment(prefix, version, additional_deps): # # Because of this, we allow specifying "cli" dependencies by prefixing # with 'cli:'. - cli_deps = {dep for dep in additional_deps if dep.startswith('cli:')} - lib_deps = set(additional_deps) - cli_deps + cli_deps = { + dep for dep in additional_dependencies if dep.startswith('cli:') + } + lib_deps = set(additional_dependencies) - cli_deps if len(lib_deps) > 0: _add_dependencies(prefix.path('Cargo.toml'), lib_deps) with clean_path_on_failure(directory): - packages_to_install = {()} | {(dep[len('cli:'):],) for dep in cli_deps} + packages_to_install = {()} + for cli_dep in cli_deps: + cli_dep = cli_dep[len('cli:'):] + package, _, version = cli_dep.partition(':') + if version != '': + packages_to_install.add((package, '--version', version)) + else: + packages_to_install.add((package,)) for package in packages_to_install: cmd_output( diff --git a/testing/resources/rust_hooks_repo/.pre-commit-hooks.yaml b/testing/resources/rust_hooks_repo/.pre-commit-hooks.yaml new file mode 100644 index 00000000..df1269ff --- /dev/null +++ b/testing/resources/rust_hooks_repo/.pre-commit-hooks.yaml @@ -0,0 +1,5 @@ +- id: rust-hook + name: rust example hook + entry: rust-hello-world + language: rust + files: '' diff --git a/testing/resources/rust_hooks_repo/Cargo.lock b/testing/resources/rust_hooks_repo/Cargo.lock new file mode 100644 index 00000000..36fbfda2 --- /dev/null +++ b/testing/resources/rust_hooks_repo/Cargo.lock @@ -0,0 +1,3 @@ +[[package]] +name = "rust-hello-world" +version = "0.1.0" diff --git a/testing/resources/rust_hooks_repo/Cargo.toml b/testing/resources/rust_hooks_repo/Cargo.toml new file mode 100644 index 00000000..cd83b435 --- /dev/null +++ b/testing/resources/rust_hooks_repo/Cargo.toml @@ -0,0 +1,3 @@ +[package] +name = "rust-hello-world" +version = "0.1.0" diff --git a/testing/resources/rust_hooks_repo/src/main.rs b/testing/resources/rust_hooks_repo/src/main.rs new file mode 100644 index 00000000..ad379d6e --- /dev/null +++ b/testing/resources/rust_hooks_repo/src/main.rs @@ -0,0 +1,3 @@ +fn main() { + println!("hello world"); +} diff --git a/tests/repository_test.py b/tests/repository_test.py index 67b8f3f6..6fece071 100644 --- a/tests/repository_test.py +++ b/tests/repository_test.py @@ -20,6 +20,7 @@ from pre_commit.languages import node from pre_commit.languages import pcre from pre_commit.languages import python from pre_commit.languages import ruby +from pre_commit.languages import rust from pre_commit.repository import Repository from pre_commit.util import cmd_output from testing.fixtures import config_with_local_hooks @@ -282,6 +283,51 @@ def test_golang_hook(tempdir_factory, store): ) +@pytest.mark.integration +def test_rust_hook(tempdir_factory, store): + _test_hook_repo( + tempdir_factory, store, 'rust_hooks_repo', + 'rust-hook', [], b'hello world\n', + ) + + +@pytest.mark.integration +@pytest.mark.parametrize('dep', ('cli:shellharden:3.1.0', 'cli:shellharden')) +def test_additional_rust_cli_dependencies_installed( + tempdir_factory, store, dep, +): + path = make_repo(tempdir_factory, 'rust_hooks_repo') + config = make_config_from_repo(path) + # A small rust package with no dependencies. + config['hooks'][0]['additional_dependencies'] = [dep] + repo = Repository.create(config, store) + repo.require_installed() + (prefix, _, _, _), = repo._venvs() + binaries = os.listdir(prefix.path( + helpers.environment_dir(rust.ENVIRONMENT_DIR, 'default'), 'bin', + )) + assert 'shellharden' in binaries + + +@pytest.mark.integration +def test_additional_rust_lib_dependencies_installed( + tempdir_factory, store, +): + path = make_repo(tempdir_factory, 'rust_hooks_repo') + config = make_config_from_repo(path) + # A small rust package with no dependencies. + deps = ['shellharden:3.1.0'] + config['hooks'][0]['additional_dependencies'] = deps + repo = Repository.create(config, store) + repo.require_installed() + (prefix, _, _, _), = repo._venvs() + binaries = os.listdir(prefix.path( + helpers.environment_dir(rust.ENVIRONMENT_DIR, 'default'), 'bin', + )) + assert 'rust-hello-world' in binaries + assert 'shellharden' not in binaries + + @pytest.mark.integration def test_missing_executable(tempdir_factory, store): _test_hook_repo(