use std::fs;
use std::path::Path;
use anyhow::{bail, Result};
use colored::Colorize;
use inquire::{Confirm, MultiSelect, Select};
use crate::cli::Language;
use crate::templates::TemplateRegistry;
pub fn execute(file: &str, lang: Option<Language>, force: bool, interactive: bool) -> Result<()> {
if Path::new(file).exists() && !force {
bail!(
"Makefile already exists at {} (use --force to overwrite)",
file
);
}
let registry = TemplateRegistry::new();
if interactive {
return execute_interactive(file, ®istry);
}
let mut content = String::new();
content.push_str("# Generated by makectl\n");
content.push_str("# https://github.com/rochacbruno/makectl\n\n");
content.push_str(".DEFAULT_GOAL := help\n\n");
let help = registry.get("generic/help").unwrap();
content.push_str(&format!(
"# MAKECTL MANAGED START help generic/help\n{}\n# MAKECTL MANAGED END help\n",
help.content
));
if let Some(ref lang) = lang {
let lang_str = lang.as_str();
let templates = registry.list_by_language(lang_str);
for t in &templates {
if t.id == "generic/help" {
continue;
}
let target_name = &t.name;
content.push_str(&format!(
"\n# MAKECTL MANAGED START {} {}\n{}\n# MAKECTL MANAGED END {}\n",
target_name, t.id, t.content, target_name
));
}
if lang_str != "generic" {
let generic_templates = registry.list_by_language("generic");
for t in &generic_templates {
if t.id == "generic/help" {
continue;
}
let target_name = &t.name;
content.push_str(&format!(
"\n# MAKECTL MANAGED START {} {}\n{}\n# MAKECTL MANAGED END {}\n",
target_name, t.id, t.content, target_name
));
}
}
}
fs::write(file, &content)?;
println!("{} {}", "Created".green().bold(), file);
if let Some(ref lang) = lang {
println!(
" Included {} templates and generic utilities",
lang.as_str()
);
}
println!(
" Run {} to see available targets",
"make help".cyan().bold()
);
Ok(())
}
fn execute_interactive(file: &str, registry: &TemplateRegistry) -> Result<()> {
let lang_options = vec!["Python", "Rust", "Go", "Node", "Generic", "None (minimal)"];
let lang_choice = Select::new("Project language?", lang_options).prompt()?;
let lang_str = match lang_choice {
"Python" => Some("python"),
"Rust" => Some("rust"),
"Go" => Some("go"),
"Node" => Some("node"),
"Generic" => Some("generic"),
_ => None,
};
let mut candidates: Vec<&crate::templates::Template> = Vec::new();
if let Some(lang) = lang_str {
candidates.extend(registry.list_by_language(lang));
if lang != "generic" {
candidates.extend(registry.list_by_language("generic"));
}
} else {
candidates.extend(registry.list_by_language("generic"));
}
let display_items: Vec<String> = candidates
.iter()
.map(|t| format!("{} - {}", t.id, t.description))
.collect();
let defaults: Vec<usize> = (0..display_items.len()).collect();
let selected = MultiSelect::new("Select templates to include:", display_items)
.with_default(&defaults)
.prompt()?;
let selected_ids: Vec<&str> = selected
.iter()
.filter_map(|s| s.split(" - ").next())
.collect();
let include_default_goal = Confirm::new("Set .DEFAULT_GOAL := help?")
.with_default(true)
.prompt()?;
let mut content = String::new();
content.push_str("# Generated by makectl\n");
content.push_str("# https://github.com/rochacbruno/makectl\n\n");
if include_default_goal {
content.push_str(".DEFAULT_GOAL := help\n\n");
}
for id in &selected_ids {
if let Some(t) = registry.get(id) {
let target_name = &t.name;
content.push_str(&format!(
"# MAKECTL MANAGED START {} {}\n{}\n# MAKECTL MANAGED END {}\n\n",
target_name, t.id, t.content, target_name
));
}
}
fs::write(file, &content)?;
println!("{} {}", "Created".green().bold(), file);
println!(" Included {} template(s)", selected_ids.len());
println!(
" Run {} to see available targets",
"make help".cyan().bold()
);
Ok(())
}