use anyhow::{Context, Result};
use clap::{Args, Subcommand};
use laterite_core::Db;
use laterite_web::theme::archive;
use std::path::PathBuf;
#[derive(Subcommand)]
pub enum ThemeCommand {
Export(ExportArgs),
Import(ImportArgs),
List,
}
#[derive(Args)]
pub struct ExportArgs {
pub code: String,
#[arg(long, short)]
pub out: Option<PathBuf>,
}
#[derive(Args)]
pub struct ImportArgs {
pub code: String,
pub file: PathBuf,
#[arg(long)]
pub replace: bool,
}
pub async fn run(command: ThemeCommand, db: Db) -> Result<()> {
match command {
ThemeCommand::Export(args) => {
let bytes = archive::export(&db, &args.code)
.await
.with_context(|| format!("could not export the theme {:?}", args.code))?;
let out = args
.out
.unwrap_or_else(|| PathBuf::from(format!("{}.zip", args.code)));
std::fs::write(&out, &bytes)
.with_context(|| format!("could not write {}", out.display()))?;
println!("Wrote {} ({} bytes)", out.display(), bytes.len());
}
ThemeCommand::Import(args) => {
let bytes = std::fs::read(&args.file)
.with_context(|| format!("could not read {}", args.file.display()))?;
let report = archive::import(&db, &args.code, &bytes, args.replace, None)
.await
.with_context(|| format!("could not import into the theme {:?}", args.code))?;
println!(
"{} {}: {} template(s) written, {} skipped{}",
if report.created { "Created" } else { "Updated" },
args.code,
report.imported,
report.skipped,
if report.ignored.is_empty() {
String::new()
} else {
format!(", ignored {}", report.ignored.join(", "))
}
);
if report.skipped > 0 && !args.replace {
println!("Pass --replace to overwrite the templates the theme already has.");
}
}
ThemeCommand::List => {
let active = laterite_web::theme::active_theme(&db)
.await?
.map(|t| t.code);
for theme in laterite_web::theme::store::list_themes(&db).await? {
let mark = if active.as_deref() == Some(theme.code.as_str()) {
" (active)"
} else {
""
};
let parent = theme.parent.map(|p| format!(" < {p}")).unwrap_or_default();
println!("{}{}: {}{}", theme.code, parent, theme.config.name, mark);
}
}
}
Ok(())
}