ferrous_forge/commands/
init.rs

1//! Initialize command implementation
2
3use crate::{config::Config, Result};
4use console::style;
5
6/// Execute the init command
7pub async fn execute(force: bool) -> Result<()> {
8    println!(
9        "{}",
10        style("🔨 Initializing Ferrous Forge...").bold().cyan()
11    );
12
13    // Check if already initialized
14    let config = Config::load_or_default().await?;
15    if config.is_initialized() && !force {
16        println!(
17            "{}",
18            style("✅ Ferrous Forge is already initialized!").green()
19        );
20        println!("Use --force to reinitialize.");
21        return Ok(());
22    }
23
24    // Create configuration directories
25    println!("📁 Creating configuration directories...");
26    config.ensure_directories().await?;
27
28    // Install system-wide cargo hijacking
29    println!("🔧 Setting up cargo command hijacking...");
30    install_cargo_hijacking().await?;
31
32    // Copy clippy configuration
33    println!("📋 Installing clippy configuration...");
34    install_clippy_config().await?;
35
36    // Setup shell integration
37    println!("🐚 Installing shell integration...");
38    install_shell_integration().await?;
39
40    // Mark as initialized
41    let mut config = config;
42    config.mark_initialized();
43    config.save().await?;
44
45    println!(
46        "{}",
47        style("🎉 Ferrous Forge initialization complete!")
48            .bold()
49            .green()
50    );
51    println!();
52    println!("Next steps:");
53    println!("• Restart your shell or run: source ~/.bashrc");
54    println!("• Create a new project: cargo new my-project");
55    println!("• All new projects will automatically use Edition 2024 + strict standards!");
56
57    Ok(())
58}
59
60async fn install_cargo_hijacking() -> Result<()> {
61    // This will create wrapper scripts that intercept cargo commands
62    // and apply our standards before delegating to the real cargo
63
64    let home_dir =
65        dirs::home_dir().ok_or_else(|| crate::Error::config("Could not find home directory"))?;
66
67    let bin_dir = home_dir.join(".local").join("bin");
68    tokio::fs::create_dir_all(&bin_dir).await?;
69
70    // Create cargo wrapper script
71    let cargo_wrapper = include_str!("../../templates/cargo-wrapper.sh");
72    let cargo_path = bin_dir.join("cargo");
73    tokio::fs::write(&cargo_path, cargo_wrapper).await?;
74
75    // Make executable
76    #[cfg(unix)]
77    {
78        use std::os::unix::fs::PermissionsExt;
79        let mut perms = tokio::fs::metadata(&cargo_path).await?.permissions();
80        perms.set_mode(0o755);
81        tokio::fs::set_permissions(&cargo_path, perms).await?;
82    }
83
84    Ok(())
85}
86
87async fn install_clippy_config() -> Result<()> {
88    // Copy our strict clippy.toml to the home directory
89    let home_dir =
90        dirs::home_dir().ok_or_else(|| crate::Error::config("Could not find home directory"))?;
91
92    let clippy_config = include_str!("../../templates/clippy.toml");
93    let clippy_path = home_dir.join(".clippy.toml");
94    tokio::fs::write(&clippy_path, clippy_config).await?;
95
96    Ok(())
97}
98
99async fn install_shell_integration() -> Result<()> {
100    // Add Ferrous Forge to PATH and setup completion
101    let home_dir =
102        dirs::home_dir().ok_or_else(|| crate::Error::config("Could not find home directory"))?;
103
104    let shell_config = format!(
105        r#"
106# Ferrous Forge - Rust Development Standards Enforcer
107export PATH="$HOME/.local/bin:$PATH"
108
109# Enable Ferrous Forge for all Rust development
110export FERROUS_FORGE_ENABLED=1
111"#
112    );
113
114    // Add to common shell config files
115    for shell_file in &[".bashrc", ".zshrc", ".profile"] {
116        let shell_path = home_dir.join(shell_file);
117        if shell_path.exists() {
118            let mut contents = tokio::fs::read_to_string(&shell_path).await?;
119            if !contents.contains("Ferrous Forge") {
120                contents.push_str(&shell_config);
121                tokio::fs::write(&shell_path, contents).await?;
122            }
123        }
124    }
125
126    Ok(())
127}