Skip to main content

nargo_hooks/
lib.rs

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    /// Install git hooks that redirect to `nargo hooks run <hook_name>`
16    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        // Get the current executable path to point the hooks to it
30        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            // Create a shell script (or batch file for windows) that calls nargo
37            // On Windows, git typically uses sh.exe from MinGW/Git Bash
38            let hook_content = format!(
39                "#!/bin/sh\n\n# Nargo Native Hook\n\"{}\" hooks run {} \"$@\"\n",
40                exe_path_str.replace("\\", "/"), // Use forward slashes for sh
41                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    /// Uninstall git hooks installed by Nargo
61    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    /// Run the logic for a specific hook
83    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        // 简化实现,实际需要根据 nargo_config 的 API 进行调整
87        let config = NargoConfig::default();
88
89        // 简化实现,实际需要根据 nargo_config 的 API 进行调整
90        // 暂时不执行任何钩子命令
91        info!("No command configured for hook: {}, skipping.", hook_name);
92
93        Ok(())
94    }
95}