Skip to content

Commit bf273d9

Browse files
committed
refactor: central hook path and metadata handling
1 parent 29e0fff commit bf273d9

File tree

1 file changed

+28
-30
lines changed

1 file changed

+28
-30
lines changed

src/hook.rs

Lines changed: 28 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,9 @@ use anyhow::{anyhow, Context, Result};
99
use crate::wrap::Message;
1010

1111
/// Find path to hook script given a hook name.
12-
fn get_hook_path(repo: &gix::Repository, hook_name: &str) -> Result<PathBuf> {
12+
///
13+
/// Returns None if the hook script is not found or is not executable.
14+
fn get_hook_path(repo: &gix::Repository, hook_name: &str) -> Result<Option<PathBuf>> {
1315
let config = repo.config_snapshot();
1416
let hooks_path =
1517
if let Some(core_hooks_path) = config.trusted_path("core.hookspath").transpose()? {
@@ -27,7 +29,20 @@ fn get_hook_path(repo: &gix::Repository, hook_name: &str) -> Result<PathBuf> {
2729
// No core.hookspath, use default .git/hooks location
2830
Cow::Owned(repo.common_dir().join("hooks"))
2931
};
30-
Ok(hooks_path.join(hook_name))
32+
let hook_path = hooks_path.join(hook_name);
33+
34+
let hook_meta = match std::fs::metadata(&hook_path) {
35+
Ok(meta) => meta,
36+
Err(_) => return Ok(None), // ignore missing hook
37+
};
38+
39+
if !is_executable(&hook_meta) {
40+
return Ok(None);
41+
}
42+
43+
let hook_path = gix::path::realpath(hook_path)?;
44+
45+
Ok(Some(hook_path))
3146
}
3247

3348
/// Run the git `pre-commit` hook script.
@@ -40,25 +55,17 @@ fn get_hook_path(repo: &gix::Repository, hook_name: &str) -> Result<PathBuf> {
4055
/// existing, not being a file, or not being executable.
4156
pub(crate) fn run_pre_commit_hook(repo: &gix::Repository, use_editor: bool) -> Result<bool> {
4257
let hook_name = "pre-commit";
43-
let hook_path = get_hook_path(repo, hook_name)?;
44-
let hook_meta = match std::fs::metadata(&hook_path) {
45-
Ok(meta) => meta,
46-
Err(_) => return Ok(false), // ignore missing hook
47-
};
48-
49-
if !hook_meta.is_file() {
50-
return Ok(false);
51-
}
52-
53-
// Ignore non-executable hooks
54-
if !is_executable(&hook_meta) {
58+
let hook_path = if let Some(hook_path) = get_hook_path(repo, hook_name)? {
59+
hook_path
60+
} else {
5561
return Ok(false);
56-
}
62+
};
5763

58-
let mut hook_command = std::process::Command::new(gix::path::realpath(hook_path)?);
5964
let workdir = repo
6065
.work_dir()
6166
.expect("should not get this far with a bare repo");
67+
68+
let mut hook_command = std::process::Command::new(hook_path);
6269
if !use_editor {
6370
hook_command.env("GIT_EDITOR", ":");
6471
}
@@ -95,20 +102,11 @@ pub(crate) fn run_commit_msg_hook<'repo>(
95102
use_editor: bool,
96103
) -> Result<Message<'repo>> {
97104
let hook_name = "commit-msg";
98-
let hook_path = get_hook_path(repo, hook_name)?;
99-
let hook_meta = match std::fs::metadata(&hook_path) {
100-
Ok(meta) => meta,
101-
Err(_) => return Ok(message), // ignore missing hook
102-
};
103-
104-
if !hook_meta.is_file() {
105-
return Ok(message);
106-
}
107-
108-
// Ignore non-executable hooks
109-
if !is_executable(&hook_meta) {
105+
let hook_path = if let Some(hook_path) = get_hook_path(repo, hook_name)? {
106+
hook_path
107+
} else {
110108
return Ok(message);
111-
}
109+
};
112110

113111
let mut msg_file = tempfile::NamedTempFile::new()?;
114112
msg_file.write_all(message.raw_bytes())?;
@@ -118,7 +116,7 @@ pub(crate) fn run_commit_msg_hook<'repo>(
118116

119117
// TODO: when git runs this hook, it only sets GIT_INDEX_FILE and sometimes
120118
// GIT_EDITOR. So author and committer vars are not clearly required.
121-
let mut hook_command = std::process::Command::new(gix::path::realpath(hook_path)?);
119+
let mut hook_command = std::process::Command::new(hook_path);
122120
hook_command.env("GIT_INDEX_FILE", &index_path);
123121
if !use_editor {
124122
hook_command.env("GIT_EDITOR", ":");

0 commit comments

Comments
 (0)