Skip to content

Commit 67c8241

Browse files
committed
proper pre-push hook implementation
1 parent 5527160 commit 67c8241

File tree

5 files changed

+469
-88
lines changed

5 files changed

+469
-88
lines changed

asyncgit/src/sync/hooks.rs

Lines changed: 27 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,17 @@ pub enum HookResult {
1515
impl From<git2_hooks::HookResult> for HookResult {
1616
fn from(v: git2_hooks::HookResult) -> Self {
1717
match v {
18-
git2_hooks::HookResult::Ok { .. }
19-
| git2_hooks::HookResult::NoHookFound => Self::Ok,
20-
git2_hooks::HookResult::RunNotSuccessful {
21-
stdout,
22-
stderr,
23-
..
24-
} => Self::NotOk(format!("{stdout}{stderr}")),
18+
git2_hooks::HookResult::NoHookFound => Self::Ok,
19+
git2_hooks::HookResult::Run(response) => {
20+
if response.is_successful() {
21+
Self::Ok
22+
} else {
23+
Self::NotOk(format!(
24+
"{}{}",
25+
response.stdout, response.stderr
26+
))
27+
}
28+
}
2529
}
2630
}
2731
}
@@ -73,12 +77,26 @@ pub fn hooks_prepare_commit_msg(
7377
}
7478

7579
/// see `git2_hooks::hooks_pre_push`
76-
pub fn hooks_pre_push(repo_path: &RepoPath) -> Result<HookResult> {
80+
pub fn hooks_pre_push(
81+
repo_path: &RepoPath,
82+
remote: Option<&str>,
83+
url: &str,
84+
branch_name: Option<&str>,
85+
remote_branch_name: Option<&str>,
86+
) -> Result<HookResult> {
7787
scope_time!("hooks_pre_push");
7888

7989
let repo = repo(repo_path)?;
8090

81-
Ok(git2_hooks::hooks_pre_push(&repo, None)?.into())
91+
Ok(git2_hooks::hooks_pre_push(
92+
&repo,
93+
None,
94+
remote,
95+
url,
96+
branch_name,
97+
remote_branch_name,
98+
)?
99+
.into())
82100
}
83101

84102
#[cfg(test)]

git2-hooks/src/hookspath.rs

Lines changed: 43 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,20 @@ impl HookPaths {
141141
/// this function calls hook scripts based on conventions documented here
142142
/// see <https://git-scm.com/docs/githooks>
143143
pub fn run_hook_os_str<I, S>(&self, args: I) -> Result<HookResult>
144+
where
145+
I: IntoIterator<Item = S> + Copy,
146+
S: AsRef<OsStr>,
147+
{
148+
self.run_hook_os_str_with_stdin(args, None)
149+
}
150+
151+
/// this function calls hook scripts with stdin input based on conventions documented here
152+
/// see <https://git-scm.com/docs/githooks>
153+
pub fn run_hook_os_str_with_stdin<I, S>(
154+
&self,
155+
args: I,
156+
stdin: Option<&[u8]>,
157+
) -> Result<HookResult>
144158
where
145159
I: IntoIterator<Item = S> + Copy,
146160
S: AsRef<OsStr>,
@@ -153,11 +167,23 @@ impl HookPaths {
153167
);
154168

155169
let run_command = |command: &mut Command| {
156-
command
170+
let mut child = command
157171
.args(args)
158172
.current_dir(&self.pwd)
159173
.with_no_window()
160-
.output()
174+
.stdin(std::process::Stdio::piped())
175+
.stdout(std::process::Stdio::piped())
176+
.stderr(std::process::Stdio::piped())
177+
.spawn()?;
178+
179+
if let Some(input) = stdin {
180+
use std::io::Write;
181+
if let Some(mut stdin_handle) = child.stdin.take() {
182+
stdin_handle.write_all(input)?;
183+
}
184+
}
185+
186+
child.wait_with_output()
161187
};
162188

163189
let output = if cfg!(windows) {
@@ -210,21 +236,21 @@ impl HookPaths {
210236
}
211237
}?;
212238

213-
if output.status.success() {
214-
Ok(HookResult::Ok { hook })
215-
} else {
216-
let stderr =
217-
String::from_utf8_lossy(&output.stderr).to_string();
218-
let stdout =
219-
String::from_utf8_lossy(&output.stdout).to_string();
220-
221-
Ok(HookResult::RunNotSuccessful {
222-
code: output.status.code(),
223-
stdout,
224-
stderr,
225-
hook,
226-
})
227-
}
239+
let stderr =
240+
String::from_utf8_lossy(&output.stderr).to_string();
241+
let stdout =
242+
String::from_utf8_lossy(&output.stdout).to_string();
243+
244+
Ok(HookResult::Run(crate::HookRunResponse {
245+
hook,
246+
stdout,
247+
stderr,
248+
code: if output.status.success() {
249+
None
250+
} else {
251+
output.status.code()
252+
},
253+
}))
228254
}
229255
}
230256

0 commit comments

Comments
 (0)