rok-cli 0.3.3

Developer CLI for rok-based Axum applications
//! `--template api` — Clones the `rok-api-starter` git repo.
//!
//! The template is maintained at <https://github.com/ateeq1999/rok-api-starter>
//! so it stays up-to-date with the latest Rok crates and best practices
//! without requiring a CLI release.

use std::{fs, path::Path};

pub fn generate(name: &str, root: &Path) -> anyhow::Result<()> {
    let repo_url = "https://github.com/ateeq1999/rok-api-starter.git";

    // new.rs creates an empty root directory first — remove it so git
    // clone can create the directory with the repository contents.
    if root.exists() {
        fs::remove_dir_all(root)?;
    }

    println!("  Cloning template from {repo_url}...");
    let status = std::process::Command::new("git")
        .args(["clone", repo_url, name])
        .status()
        .map_err(|e| anyhow::anyhow!("Failed to run git: {e}"))?;

    if !status.success() {
        anyhow::bail!("git clone failed. Is git installed and accessible?");
    }

    // Remove the cloned .git directory so the project is a clean slate
    // for `rok new`'s own git-init step.
    let git_dir = root.join(".git");
    if git_dir.exists() {
        fs::remove_dir_all(&git_dir)?;
    }

    configure_project(name, root)?;

    println!("  ✓ API starter cloned and configured");
    Ok(())
}

/// Rename the placeholder project name (`rok-api-test`) to the user's
/// chosen name in Cargo.toml, README.md, Dockerfile, and compose files.
fn configure_project(name: &str, root: &Path) -> anyhow::Result<()> {
    let pkg_name = root.file_name().and_then(|n| n.to_str()).unwrap_or(name);
    let snake_name = pkg_name.replace('-', "_");

    for filename in &[
        "Cargo.toml",
        "README.md",
        "Dockerfile",
        "docker-compose.yml",
    ] {
        let path = root.join(filename);
        if !path.exists() {
            continue;
        }
        let content = fs::read_to_string(&path)?;
        let updated = content
            .replace("rok-api-test", pkg_name)
            .replace("rok_api_test", &snake_name);
        if content != updated {
            fs::write(&path, updated)?;
        }
        println!("     wrote  {filename}");
    }

    Ok(())
}