ferrous_forge/commands/
init.rs

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