use std::fs;
use std::path::PathBuf;
use anyhow::{bail, Context, Result};
use clap::{Parser, ValueEnum};
#[derive(Debug, Clone, ValueEnum)]
pub enum InitTemplate {
Default,
Empty,
}
#[derive(Debug, Parser)]
pub struct InitArgs {
pub name: String,
#[arg(long, value_enum, default_value_t = InitTemplate::Default)]
pub template: InitTemplate,
#[arg(long)]
pub path: Option<PathBuf>,
}
pub fn run(args: InitArgs) -> Result<()> {
let dest = args
.path
.clone()
.unwrap_or_else(|| PathBuf::from(&args.name));
if dest.exists() {
bail!("destination already exists: {}", dest.display());
}
let template_dir = match args.template {
InitTemplate::Default => template_root().join("default-module"),
InitTemplate::Empty => template_root().join("empty-module"),
};
if !template_dir.exists() {
bail!(
"template not found: {} (run from portaki-sdk checkout)",
template_dir.display()
);
}
copy_template(&template_dir, &dest, &args.name)?;
println!("Created module at {}", dest.display());
println!("Next: cd {} && portaki build", dest.display());
Ok(())
}
fn template_root() -> PathBuf {
PathBuf::from(env!("CARGO_MANIFEST_DIR"))
.join("../../templates")
.canonicalize()
.unwrap_or_else(|_| PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("../../templates"))
}
fn copy_template(source: &PathBuf, dest: &PathBuf, module_name: &str) -> Result<()> {
fs::create_dir_all(dest).with_context(|| format!("create {}", dest.display()))?;
for entry in fs::read_dir(source)? {
let entry = entry?;
let file_name = entry.file_name();
let name = file_name.to_string_lossy();
let target = dest.join(&*name);
if entry.file_type()?.is_dir() {
copy_template(&entry.path(), &target, module_name)?;
continue;
}
let source_path = entry.path();
let mut target_name = name.to_string();
if target_name.ends_with(".template") {
target_name = target_name.trim_end_matches(".template").to_string();
}
let target = dest.join(&target_name);
let text = fs::read_to_string(&source_path)?;
let rendered = text.replace("{{MODULE_NAME}}", module_name);
fs::write(&target, rendered).with_context(|| format!("write {}", target.display()))?;
}
Ok(())
}