Skip to content

Commit

Permalink
feat: hooks
Browse files Browse the repository at this point in the history
  • Loading branch information
jdx committed Nov 29, 2024
1 parent ef37b7c commit 99a2faa
Show file tree
Hide file tree
Showing 19 changed files with 645 additions and 91 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ fslock = "0.2.1"
git2 = "<1"
glob = "0.3"
globset = "0.4"
globwalk = "0.9"
heck = "0.5"
home = "0.5"
humantime = "2"
Expand Down
62 changes: 62 additions & 0 deletions docs/hooks.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
# Hooks

You can have mise automatically execute scripts when it runs. The configuration goes into `mise.toml`.

## CD hook

This hook is run anytimes the directory is changed.

```toml
[hooks]
cd = "echo 'I changed directories'"
```

## Enter hook

This hook is run when the project is entered. Changing directories while in the project will not trigger this hook again.

```toml
[hooks]
enter = "echo 'I entered the project'"
```

## Leave hook (not yet implemented)

This hook is run when the project is left. Changing directories while in the project will not trigger this hook.

```toml
[hooks]
leave = "echo 'I left the project'"
```

## Preinstall/postinstall hook

These hooks are run before tools are installed. Unlike other hooks, these hooks do not require `mise activate`.

```toml
[hooks]
preinstall = "echo 'I am about to install tools'"
postinstall = "echo 'I just installed tools'"
```

## Watch files hook

While using `mise activate` you can have mise watch files for changes and execute a script when a file changes.

```bash
[[watch_files]]
patterns = ["src/**/*.rs"]
script = "cargo fmt"
```

This hook will have the following environment variables set:

- `MISE_WATCH_FILES_MODIFIED`: A colon-separated list of the files that have been modified. Colons are escaped with a backslash.

## Hook execution

Hooks are executed with the following environment variables set:

- `MISE_ORIGINAL_CWD`: The directory that the user is in.
- `MISE_PROJECT_DIR`: The root directory of the project.
- `MISE_PREVIOUS_DIR`: The directory that the user was in before the directory change (only if a directory change occurred).
31 changes: 31 additions & 0 deletions e2e/config/test_hooks
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
#!/usr/bin/env bash

cat <<EOF >mise.toml
[tools]
dummy = 'latest'
[hooks]
enter = 'echo ENTER'
#leave = 'echo LEAVE'
cd = 'echo CD'
preinstall = 'echo PREINSTALL'
postinstall = 'echo POSTINSTALL'
EOF

assert_contains "mise i 2>&1" "PREINSTALL"
assert_contains "mise i dummy@1 2>&1" "POSTINSTALL"

eval "$(mise hook-env)"
assert_not_contains "mise hook-env 2>&1" "CD"
assert_not_contains "mise hook-env 2>&1" "ENTER"
pushd .. || exit 1
assert_not_contains "mise hook-env 2>&1" "CD"
assert_not_contains "mise hook-env 2>&1" "ENTER"
eval "$(mise hook-env)"
popd || exit 1
assert_contains "mise hook-env 2>&1" "CD"
assert_contains "mise hook-env 2>&1" "ENTER"
eval "$(mise hook-env)"
mkdir foo
cd foo || exit 1
assert_contains "mise hook-env 2>&1" "CD"
assert_not_contains "mise hook-env 2>&1" "ENTER"
69 changes: 53 additions & 16 deletions schema/mise.json
Original file line number Diff line number Diff line change
Expand Up @@ -590,6 +590,10 @@
}
}
},
"shell": {
"description": "Sets the shell across all mise commands like `mise run`, `mise en`, and watch files.",
"type": "string"
},
"shorthands_file": {
"description": "Path to a file containing custom tool shorthands.",
"type": "string"
Expand Down Expand Up @@ -660,20 +664,14 @@
}
},
"unix_default_file_shell_args": {
"default": ["sh"],
"default": "sh",
"description": "List of default shell arguments for unix to be used with `file`. For example `sh`.",
"type": "array",
"items": {
"type": "string"
}
"type": "string"
},
"unix_default_inline_shell_args": {
"default": ["sh", "-c", "-o", "errexit"],
"default": "sh -c -o errexit",
"description": "List of default shell arguments for unix to be used with inline commands. For example, `sh`, `-c` for sh.",
"type": "array",
"items": {
"type": "string"
}
"type": "string"
},
"use_file_shell_for_executable_tasks": {
"default": false,
Expand All @@ -695,20 +693,17 @@
"type": "boolean"
},
"windows_default_file_shell_args": {
"default": ["cmd", "/c"],
"default": "cmd /c",
"description": "List of default shell arguments for Windows to be used for file commands. For example, `cmd`, `/c` for cmd.exe.",
"type": "array",
"items": {
"type": "string"
}
},
"windows_default_inline_shell_args": {
"default": ["cmd", "/c"],
"default": "cmd /c",
"description": "List of default shell arguments for Windows to be used for inline commands. For example, `cmd`, `/c` for cmd.exe.",
"type": "array",
"items": {
"type": "string"
}
"type": "string"
},
"windows_executable_extensions": {
"default": ["exe", "bat", "cmd", "com", "ps1", "vbs"],
Expand Down Expand Up @@ -940,6 +935,39 @@
}
}
]
},
"hooks": {
"description": "hooks to run",
"type": "object",
"additionalProperties": {
"description": "script to run",
"type": "string"
}
},
"watch_files": {
"description": "files to watch for changes",
"type": "array",
"items": {
"type": "object",
"description": "file to watch for changes",
"additionalProperties": false,
"properties": {
"run": {
"type": "string",
"description": "script to run when file changes",
"items": {
"type": "string"
}
},
"patterns": {
"type": "array",
"description": "patterns to watch for",
"items": {
"type": "string"
}
}
}
}
}
},
"additionalProperties": false,
Expand Down Expand Up @@ -1024,6 +1052,15 @@
"description": "dev tools to use",
"type": "object"
},
"hooks": {
"$ref": "#/$defs/hooks"
},
"vars": {
"$ref": "#/$defs/vars"
},
"watch_files": {
"$ref": "#/$defs/watch_files"
},
"_": {
"additionalProperties": true
}
Expand Down
33 changes: 18 additions & 15 deletions settings.toml
Original file line number Diff line number Diff line change
Expand Up @@ -762,6 +762,16 @@ type = "Path"
optional = true
description = "Path to the rustup home directory. Defaults to ~/.rustup or %USERPROFILE%\\.rustup"

[shell]
env = "MISE_SHELL"
type = "String"
optional = true
description = "Sets the shell across all mise commands like `mise run`, `mise en`, and watch files."
docs = """
Sets the shell across all mise commands like `mise run`, `mise en`, and watch files.
This overrides MISE_UNIX_DEFAULT_INLINE_SHELL_ARGS and MISE_WINDOWS_DEFAULT_INLINE_SHELL_ARGS if set.
"""

[shorthands_file]
env = "MISE_SHORTHANDS_FILE"
type = "Path"
Expand Down Expand Up @@ -881,18 +891,14 @@ description = "This is a list of config paths that mise will automatically mark

[unix_default_file_shell_args]
env = "MISE_UNIX_DEFAULT_FILE_SHELL_ARGS"
type = "ListString"
rust_type = "Vec<String>"
default = ["sh"]
parse_env = "list_by_comma"
type = "String"
default = "sh"
description = "List of default shell arguments for unix to be used with `file`. For example `sh`."

[unix_default_inline_shell_args]
env = "MISE_UNIX_DEFAULT_INLINE_SHELL_ARGS"
type = "ListString"
rust_type = "Vec<String>"
default = ["sh", "-c", "-o", "errexit"]
parse_env = "list_by_comma"
type = "String"
default = "sh -c -o errexit"
description = "List of default shell arguments for unix to be used with inline commands. For example, `sh`, `-c` for sh."

[use_file_shell_for_executable_tasks]
Expand Down Expand Up @@ -935,17 +941,14 @@ default to using a vfox plugin for cmake.
[windows_default_file_shell_args]
env = "MISE_WINDOWS_DEFAULT_FILE_SHELL_ARGS"
type = "ListString"
rust_type = "Vec<String>"
default = ["cmd", "/c"]
parse_env = "list_by_comma"
rust_type = "String"
default = "cmd /c"
description = "List of default shell arguments for Windows to be used for file commands. For example, `cmd`, `/c` for cmd.exe."

[windows_default_inline_shell_args]
env = "MISE_WINDOWS_DEFAULT_INLINE_SHELL_ARGS"
type = "ListString"
rust_type = "Vec<String>"
default = ["cmd", "/c"]
parse_env = "list_by_comma"
type = "String"
default = "cmd /c"
description = "List of default shell arguments for Windows to be used for inline commands. For example, `cmd`, `/c` for cmd.exe."

[windows_executable_extensions]
Expand Down
13 changes: 8 additions & 5 deletions src/cli/hook_env.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use std::env::{join_paths, split_paths};
use std::ops::Deref;
use std::path::{Path, PathBuf};
use std::path::PathBuf;

use console::truncate_str;
use eyre::Result;
Expand All @@ -10,9 +10,10 @@ use crate::config::{Config, Settings};
use crate::direnv::DirenvDiff;
use crate::env::{PATH_KEY, TERM_WIDTH, __MISE_DIFF};
use crate::env_diff::{EnvDiff, EnvDiffOperation};
use crate::hook_env::WatchFilePattern;
use crate::shell::{get_shell, ShellType};
use crate::toolset::{Toolset, ToolsetBuilder};
use crate::{dirs, env, hook_env};
use crate::{dirs, env, hook_env, hooks, watch_files};

/// [internal] called by activate hook to update env vars directory change
#[derive(Debug, clap::Args)]
Expand All @@ -36,7 +37,7 @@ impl HookEnv {
let config = Config::try_get()?;
let watch_files = config.watch_files()?;
time!("hook-env");
if hook_env::should_exit_early(&watch_files) {
if hook_env::should_exit_early(watch_files.clone()) {
return Ok(());
}
time!("should_exit_early");
Expand All @@ -58,12 +59,14 @@ impl HookEnv {
let settings = Settings::try_get()?;
patches.extend(self.build_path_operations(&settings, &paths, &__MISE_DIFF.path)?);
patches.push(self.build_diff_operation(&diff)?);
patches.push(self.build_watch_operation(&watch_files)?);
patches.push(self.build_watch_operation(watch_files.clone())?);
patches.push(self.build_dir_operation()?);

let output = hook_env::build_env_commands(&*shell, &patches);
miseprint!("{output}")?;
self.display_status(&config, &ts)?;
hooks::run_all_hooks(&ts);
watch_files::execute_runs(&ts);

Ok(())
}
Expand Down Expand Up @@ -180,7 +183,7 @@ impl HookEnv {

fn build_watch_operation(
&self,
watch_files: impl IntoIterator<Item = impl AsRef<Path>>,
watch_files: impl IntoIterator<Item = WatchFilePattern>,
) -> Result<EnvDiffOperation> {
let watches = hook_env::build_watches(watch_files)?;
Ok(EnvDiffOperation::Add(
Expand Down
Loading

0 comments on commit 99a2faa

Please sign in to comment.