use crate::paths;
use crate::templates::{InfraTemplates, MetaTemplates, RustTemplates};
use anyhow::{Context, Result};
use std::path::Path;
#[allow(dead_code)]
const MECHA10_JSON_TEMPLATE: &str = include_str!("../../templates/config/mecha10.json.template");
const MODEL_JSON_TEMPLATE: &str = include_str!("../../templates/config/model.json.template");
const ENVIRONMENT_JSON_TEMPLATE: &str = include_str!("../../templates/config/environment.json.template");
const AIKO_IMAGE: &[u8] = include_bytes!("../../templates/assets/images/aiko.jpg");
const PHOEBE_IMAGE: &[u8] = include_bytes!("../../templates/assets/images/phoebe.jpg");
const BEHAVIOR_IDLE_WANDER: &str = include_str!("../../templates/behaviors/idle_wander.json");
const BEHAVIOR_PATROL_SIMPLE: &str = include_str!("../../templates/behaviors/patrol_simple.json");
pub struct ProjectTemplateService {
rust: RustTemplates,
infra: InfraTemplates,
meta: MetaTemplates,
}
impl ProjectTemplateService {
pub fn new() -> Self {
Self {
rust: RustTemplates::new(),
infra: InfraTemplates::new(),
meta: MetaTemplates::new(),
}
}
pub async fn create_readme(&self, path: &Path, project_name: &str) -> Result<()> {
self.meta.create_readme(path, project_name).await
}
pub async fn create_gitignore(&self, path: &Path) -> Result<()> {
self.meta.create_gitignore(path).await
}
pub async fn create_cargo_config(&self, path: &Path, framework_path: &str) -> Result<()> {
self.rust.create_cargo_config(path, framework_path).await
}
pub async fn create_cargo_toml(&self, path: &Path, project_name: &str, dev: bool) -> Result<()> {
self.rust.create_cargo_toml(path, project_name, dev).await
}
pub async fn create_main_rs(&self, path: &Path, project_name: &str) -> Result<()> {
self.rust.create_main_rs(path, project_name).await
}
pub async fn create_build_rs(&self, path: &Path) -> Result<()> {
self.rust.create_build_rs(path).await
}
pub async fn create_env_example(
&self,
path: &Path,
project_name: &str,
framework_path: Option<String>,
) -> Result<()> {
self.infra.create_env_example(path, project_name, framework_path).await
}
pub async fn create_rustfmt_toml(&self, path: &Path) -> Result<()> {
self.rust.create_rustfmt_toml(path).await
}
pub async fn create_docker_compose(&self, path: &Path, project_name: &str) -> Result<()> {
self.infra.create_docker_compose(path, project_name).await
}
pub async fn create_remote_docker_files(&self, path: &Path) -> Result<()> {
self.infra.create_remote_docker_files(path).await
}
pub async fn create_dockerfile_robot_builder(&self, path: &Path, project_name: &str) -> Result<()> {
self.infra.create_dockerfile_robot_builder(path, project_name).await
}
pub async fn create_package_json(&self, path: &Path, project_name: &str) -> Result<()> {
self.meta.create_package_json(path, project_name).await
}
pub async fn create_requirements_txt(&self, path: &Path) -> Result<()> {
self.meta.create_requirements_txt(path).await
}
#[allow(dead_code)]
pub async fn create_mecha10_json(&self, path: &Path, project_name: &str, template: &Option<String>) -> Result<()> {
let platform = template.as_deref().unwrap_or("basic");
let project_id = project_name.replace('-', "_");
let config_content = MECHA10_JSON_TEMPLATE
.replace("{{project_name}}", project_name)
.replace("{{project_id}}", &project_id)
.replace("{{platform}}", platform);
tokio::fs::write(path.join(paths::PROJECT_CONFIG), config_content).await?;
Ok(())
}
pub async fn create_simulation_model_json(&self, path: &Path) -> Result<()> {
let model_dest = path.join(paths::project::model_config("rover"));
if let Some(parent) = model_dest.parent() {
tokio::fs::create_dir_all(parent).await?;
}
tokio::fs::write(&model_dest, MODEL_JSON_TEMPLATE)
.await
.context("Failed to write model.json")?;
Ok(())
}
pub async fn create_simulation_environment_json(&self, path: &Path) -> Result<()> {
let env_dest = path.join(paths::project::environment_config("basic_arena"));
if let Some(parent) = env_dest.parent() {
tokio::fs::create_dir_all(parent).await?;
}
tokio::fs::write(&env_dest, ENVIRONMENT_JSON_TEMPLATE)
.await
.context("Failed to write environment.json")?;
Ok(())
}
#[allow(unused_variables)]
pub async fn create_node_configs(&self, _path: &Path) -> Result<()> {
Ok(())
}
#[allow(unused_variables)]
pub async fn create_simulation_configs(&self, _path: &Path) -> Result<()> {
Ok(())
}
pub async fn create_simulation_assets(&self, path: &Path) -> Result<()> {
let images_dest = path.join(paths::project::ASSETS_IMAGES_DIR);
tokio::fs::create_dir_all(&images_dest).await?;
let image_assets: &[(&str, &[u8])] = &[("aiko.jpg", AIKO_IMAGE), ("phoebe.jpg", PHOEBE_IMAGE)];
for (filename, content) in image_assets {
let dest_file = images_dest.join(filename);
tokio::fs::write(&dest_file, content)
.await
.with_context(|| format!("Failed to write assets/images/{}", filename))?;
}
Ok(())
}
pub async fn create_behavior_templates(&self, path: &Path) -> Result<()> {
let behaviors_dest = path.join(paths::project::BEHAVIORS_DIR);
tokio::fs::create_dir_all(&behaviors_dest).await?;
let behavior_templates: &[(&str, &str)] = &[
("idle_wander.json", BEHAVIOR_IDLE_WANDER),
("patrol_simple.json", BEHAVIOR_PATROL_SIMPLE),
];
for (filename, content) in behavior_templates {
let dest_file = behaviors_dest.join(filename);
tokio::fs::write(&dest_file, *content)
.await
.with_context(|| format!("Failed to write behaviors/{}", filename))?;
}
Ok(())
}
}
impl Default for ProjectTemplateService {
fn default() -> Self {
Self::new()
}
}