#![allow(dead_code)]
use crate::paths;
use crate::types::ProjectConfig;
use anyhow::{Context, Result};
use std::path::{Path, PathBuf};
pub struct ConfigService;
impl ConfigService {
pub async fn load_default() -> Result<ProjectConfig> {
Self::load_from(&PathBuf::from(paths::PROJECT_CONFIG)).await
}
pub async fn load_from(path: &Path) -> Result<ProjectConfig> {
if !path.exists() {
anyhow::bail!(
"Project configuration not found at {}. Run 'mecha10 init' first.",
path.display()
);
}
let content = tokio::fs::read_to_string(path)
.await
.with_context(|| format!("Failed to read configuration file: {}", path.display()))?;
let config: ProjectConfig = serde_json::from_str(&content)
.with_context(|| format!("Failed to parse configuration file: {}", path.display()))?;
Ok(config)
}
pub fn find_config() -> Result<PathBuf> {
Self::find_config_from(&std::env::current_dir()?)
}
pub fn find_config_from(start_dir: &Path) -> Result<PathBuf> {
let mut current_dir = start_dir.to_path_buf();
loop {
let config_path = current_dir.join(paths::PROJECT_CONFIG);
if config_path.exists() {
return Ok(config_path);
}
match current_dir.parent() {
Some(parent) => current_dir = parent.to_path_buf(),
None => {
anyhow::bail!(
"No mecha10.json found in {} or any parent directory.\n\n\
Run 'mecha10 init' to create a new project.",
start_dir.display()
)
}
}
}
}
pub fn is_initialized(dir: &Path) -> bool {
dir.join(paths::PROJECT_CONFIG).exists()
}
pub fn is_initialized_here() -> bool {
PathBuf::from(paths::PROJECT_CONFIG).exists()
}
pub async fn load_robot_id(path: &Path) -> Result<String> {
let config = Self::load_from(path).await?;
Ok(config.robot.id)
}
pub fn validate(path: &Path) -> Result<()> {
use mecha10_core::schema_validation::validate_project_config;
if !path.exists() {
anyhow::bail!(
"Configuration file not found: {}\n\nRun 'mecha10 init' to create a new project.",
path.display()
);
}
validate_project_config(path).context("Configuration validation failed")
}
pub fn default_config_paths() -> Vec<PathBuf> {
vec![
PathBuf::from(paths::PROJECT_CONFIG),
PathBuf::from(format!("config/{}", paths::PROJECT_CONFIG)),
PathBuf::from(format!(".mecha10/{}", paths::PROJECT_CONFIG)),
]
}
pub async fn try_load_from_defaults() -> Result<(PathBuf, ProjectConfig)> {
let paths = Self::default_config_paths();
for path in &paths {
if path.exists() {
match Self::load_from(path).await {
Ok(config) => return Ok((path.clone(), config)),
Err(_) => continue,
}
}
}
anyhow::bail!(
"No valid mecha10.json found in default locations.\n\n\
Tried:\n{}\n\n\
Run 'mecha10 init' to create a new project.",
paths
.iter()
.map(|p| format!(" - {}", p.display()))
.collect::<Vec<_>>()
.join("\n")
)
}
}