Skip to main content

cargo_smith/commands/
resource.rs

1use clap::Args;
2use anyhow::{bail, Result};
3use std::path::Path;
4use tokio::fs;
5
6use crate::templates::{template_engine::TemplateEngine, types::CargoMold};
7
8#[derive(Args)]
9pub struct ResourceArgs {
10    pub name: String,
11}
12
13const MODEL_RS_TPL: &str = include_str!("../templates/resource/traditional/model_rs.tpl");
14const HANDLER_RS_TPL: &str = include_str!("../templates/resource/traditional/handler_rs.tpl");
15const ROUTES_RS_TPL: &str = include_str!("../templates/resource/traditional/routes_rs.tpl");
16
17pub async fn execute(args: ResourceArgs) -> anyhow::Result<()> {
18
19    if !Path::new(".cargo-smith").exists() {
20        bail!(
21            "Not a cargo-mold project.\n\
22             Run this command in a project created with `cargo mold new`\n\
23             Or create a new project with: `cargo mold new {}`",
24            args.name
25        );
26    }
27
28    println!("Generating resource: {}", args.name);
29
30    let files = [
31        ("src/models/{}.rs", MODEL_RS_TPL),
32        ("src/handlers/{}_handlers.rs", HANDLER_RS_TPL),
33        ("src/routes/{}_routes.rs", ROUTES_RS_TPL),
34    ];
35
36    for (output_path_pattern, template_content) in files {
37        let output_path = output_path_pattern.replace("{}", &args.name);
38        TemplateEngine::generate_resource_template(&args.name, &output_path, template_content).await?;
39    }
40
41    update_modules(&args.name).await?;
42    update_resource_cargo_mold(args.name.clone()).await?;
43    
44    println!("Resource '{}' created successfully!", args.name);
45    println!("Generated files:");
46    println!("   - src/models/{}.rs", args.name);
47    println!("   - src/handlers/{}_handlers.rs", args.name);
48    println!("   - src/routes/{}_routes.rs", args.name);
49
50    Ok(())
51}
52
53async fn update_modules(resource_name: &str) -> Result<()> {
54    // Update mod files
55    update_mod_file("src/models/mod.rs", &format!("pub mod {};", resource_name)).await?;
56    update_mod_file("src/handlers/mod.rs", &format!("pub mod {}_handlers;", resource_name)).await?;
57    update_mod_file("src/routes/mod.rs", &format!("pub mod {}_routes;", resource_name)).await?;
58    
59    Ok(())
60}
61
62async fn update_mod_file(file_path: &str, module_declaration: &str) -> Result<()> {
63    if !Path::new(file_path).exists() {
64        return Ok(());
65    }
66    
67    let mut content = fs::read_to_string(file_path).await?;
68    
69    if !content.contains(module_declaration) {
70        if !content.ends_with('\n') {
71            content.push('\n');
72        }
73        content.push_str(module_declaration);
74        content.push('\n');
75        
76        fs::write(file_path, content).await?;
77    }
78    
79    Ok(())
80}
81
82async fn update_resource_cargo_mold(name: String) -> Result<()> {
83    
84    let content = fs::read_to_string(".cargo-smith").await?;
85
86    let mut config: CargoMold = toml::from_str(&content)?;
87
88    if !config.generated.resources.contains(&name) {
89        config.generated.resources.push(name);
90        let updated_content = toml::to_string_pretty(&config)?;
91        fs::write(".cargo-smith", updated_content).await?;
92    }
93    Ok(())
94} 
95
96// Someday I will do some routing framework os something to make it really well and useful