use super::error::{ProfileError, ProfileResult};
use super::provider_registry::ProviderSource;
use super::reference::ProfileReference;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::path::Path;
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct ProfilesConfig {
#[serde(default = "default_version")]
pub version: u32,
#[serde(
default,
rename = "extraKnownProviders",
skip_serializing_if = "HashMap::is_empty"
)]
pub extra_known_providers: HashMap<String, ExtraProvider>,
#[serde(default)]
pub profiles: Vec<String>,
}
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct ExtraProvider {
pub source: ProviderSource,
}
fn default_version() -> u32 {
1
}
impl ProfilesConfig {
pub fn new() -> Self {
Self {
version: 1,
extra_known_providers: HashMap::new(),
profiles: Vec::new(),
}
}
pub fn load(path: &Path) -> ProfileResult<Self> {
if !path.exists() {
return Ok(Self::new());
}
let content = std::fs::read_to_string(path)?;
let config: Self = serde_json::from_str(&content)?;
Ok(config)
}
pub fn save(&self, path: &Path) -> ProfileResult<()> {
if let Some(parent) = path.parent() {
std::fs::create_dir_all(parent)?;
}
let json = serde_json::to_string_pretty(self)?;
std::fs::write(path, json)?;
Ok(())
}
pub fn add_profile(&mut self, profile_ref: &str) {
if !self.profiles.contains(&profile_ref.to_string()) {
self.profiles.push(profile_ref.to_string());
}
}
pub fn remove_profile(&mut self, profile_ref: &str) -> bool {
if let Some(pos) = self.profiles.iter().position(|p| p == profile_ref) {
self.profiles.remove(pos);
true
} else {
false
}
}
pub fn parse_profiles(&self) -> Vec<ProfileReference> {
self.profiles
.iter()
.map(|s| ProfileReference::parse(s))
.collect()
}
pub fn is_empty(&self) -> bool {
self.profiles.is_empty()
}
pub fn get_required_provider_ids(&self) -> Vec<String> {
let mut providers = Vec::new();
for provider_id in self.extra_known_providers.keys() {
providers.push(provider_id.clone());
}
for profile_ref in &self.profiles {
let reference = ProfileReference::parse(profile_ref);
if let Some(provider) = reference.provider {
if !providers.contains(&provider) {
providers.push(provider);
}
}
}
providers
}
}
impl Default for ProfilesConfig {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct ProjectManifest {
pub profile: String,
}
impl ProjectManifest {
pub fn new() -> Self {
Self {
profile: String::new(),
}
}
pub fn load(path: &Path) -> ProfileResult<Self> {
let content = std::fs::read_to_string(path)?;
Self::from_json(&content)
}
pub fn save(&self, path: &Path) -> ProfileResult<()> {
if let Some(parent) = path.parent() {
std::fs::create_dir_all(parent)?;
}
let json = serde_json::to_string_pretty(self)?;
std::fs::write(path, json)?;
Ok(())
}
pub fn load_or_create(path: &Path) -> ProfileResult<Self> {
if path.exists() {
Self::load(path)
} else {
Ok(Self::new())
}
}
pub fn from_json(json: &str) -> ProfileResult<Self> {
let manifest: Self = serde_json::from_str(json)?;
manifest.validate()?;
Ok(manifest)
}
fn validate(&self) -> ProfileResult<()> {
if self.profile.is_empty() {
return Err(ProfileError::InvalidManifest {
reason: "Profile name cannot be empty".to_string(),
});
}
Ok(())
}
}
impl Default for ProjectManifest {
fn default() -> Self {
Self::new()
}
}