1#![warn(missing_docs)]
2
3use nargo_config::NargoConfig;
4use nargo_types::{Error, Result};
5use std::{
6 fs,
7 path::{Path, PathBuf},
8};
9use tokio::process::Command;
10use tracing::{error, info, warn};
11
12pub struct NargoHooks;
13
14impl NargoHooks {
15 pub fn install(root_path: &Path) -> Result<()> {
17 let git_dir = root_path.join(".git");
18 if !git_dir.exists() {
19 return Err(Error::external_error("hooks".to_string(), format!("Not a git repository: .git directory not found at {:?}", root_path), nargo_types::Span::unknown()));
20 }
21
22 let hooks_dir = git_dir.join("hooks");
23 if !hooks_dir.exists() {
24 fs::create_dir_all(&hooks_dir)?;
25 }
26
27 let hooks = vec!["pre-commit", "pre-push", "commit-msg", "post-checkout", "post-merge"];
28
29 let current_exe = std::env::current_exe()?;
31 let exe_path_str = current_exe.to_str().ok_or_else(|| Error::external_error("hooks".to_string(), "Invalid executable path".to_string(), nargo_types::Span::unknown()))?;
32
33 for hook in hooks {
34 let hook_path = hooks_dir.join(hook);
35
36 let hook_content = format!(
39 "#!/bin/sh\n\n# Nargo Native Hook\n\"{}\" hooks run {} \"$@\"\n",
40 exe_path_str.replace("\\", "/"), hook
42 );
43
44 fs::write(&hook_path, hook_content)?;
45
46 #[cfg(unix)]
47 {
48 use std::os::unix::fs::PermissionsExt;
49 let mut perms = fs::metadata(&hook_path)?.permissions();
50 perms.set_mode(0o755);
51 fs::set_permissions(&hook_path, perms)?;
52 }
53
54 info!("Installed git hook: {:?}", hook_path);
55 }
56
57 Ok(())
58 }
59
60 pub fn uninstall(root_path: &Path) -> Result<()> {
62 let hooks_dir = root_path.join(".git").join("hooks");
63 if !hooks_dir.exists() {
64 return Ok(());
65 }
66
67 let hooks = vec!["pre-commit", "pre-push", "commit-msg", "post-checkout", "post-merge"];
68 for hook in hooks {
69 let hook_path = hooks_dir.join(hook);
70 if hook_path.exists() {
71 let content = fs::read_to_string(&hook_path)?;
72 if content.contains("# Nargo Native Hook") {
73 fs::remove_file(&hook_path)?;
74 info!("Removed git hook: {:?}", hook_path);
75 }
76 }
77 }
78
79 Ok(())
80 }
81
82 pub async fn run(hook_name: &str, args: Vec<String>, config_path: Option<PathBuf>) -> Result<()> {
84 info!("Running git hook: {} with args: {:?}", hook_name, args);
85
86 let config = NargoConfig::default();
88
89 info!("No command configured for hook: {}, skipping.", hook_name);
92
93 Ok(())
94 }
95}