use crate::config::model::project_template::ProjectTemplateCategory;
use itertools::Itertools;
use std::collections::BTreeMap;
use std::fmt::Display;
use std::io;
use std::path::PathBuf;
use std::sync::OnceLock;
type GetArchiveFn = fn() -> Result<tar::Archive<flate2::read::GzDecoder<&'static [u8]>>, io::Error>;
#[derive(Debug, Clone)]
pub enum ResourceLocation {
Bundled { get_archive_fn: GetArchiveFn },
Directory { path: PathBuf },
}
#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct ProjectTemplateName(pub String);
impl Display for ProjectTemplateName {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.0)
}
}
#[derive(Debug, Clone)]
pub struct ProjectTemplate {
pub name: ProjectTemplateName,
pub display: String,
pub resource_location: ResourceLocation,
pub category: ProjectTemplateCategory,
pub requirements: Vec<ProjectTemplateName>,
pub post_create: Vec<String>,
pub post_create_spinner_message: Option<String>,
pub post_create_failure_warning: Option<String>,
pub sort_order: u32,
}
type ProjectTemplates = BTreeMap<ProjectTemplateName, ProjectTemplate>;
static PROJECT_TEMPLATES: OnceLock<ProjectTemplates> = OnceLock::new();
pub fn populate(builtin_templates: Vec<ProjectTemplate>, loaded_templates: Vec<ProjectTemplate>) {
let templates: ProjectTemplates = builtin_templates
.into_iter()
.map(|t| (t.name.clone(), t))
.chain(loaded_templates.into_iter().map(|t| (t.name.clone(), t)))
.collect();
PROJECT_TEMPLATES.set(templates).unwrap();
}
pub fn get_project_template(name: &ProjectTemplateName) -> ProjectTemplate {
PROJECT_TEMPLATES.get().unwrap().get(name).cloned().unwrap()
}
pub fn find_project_template(name: &ProjectTemplateName) -> Option<ProjectTemplate> {
PROJECT_TEMPLATES.get().unwrap().get(name).cloned()
}
pub fn get_sorted_templates(category: ProjectTemplateCategory) -> Vec<ProjectTemplate> {
PROJECT_TEMPLATES
.get()
.unwrap()
.values()
.filter(|t| t.category == category)
.cloned()
.sorted_by(|a, b| {
a.sort_order
.cmp(&b.sort_order)
.then_with(|| a.display.cmp(&b.display))
})
.collect()
}
pub fn project_template_cli_names(category: ProjectTemplateCategory) -> Vec<String> {
PROJECT_TEMPLATES
.get()
.map(|templates| {
templates
.values()
.filter(|t| t.category == category)
.map(|t| t.name.0.clone())
.collect()
})
.unwrap_or_default()
}