use std::path::{Path, PathBuf};
use std::time::SystemTime;
use anyhow::{Context, Result};
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct WorkspaceRecord {
pub path: PathBuf,
#[serde(with = "humantime_serde")]
pub created_at: SystemTime,
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
#[serde(default)]
pub struct WorkspaceRegistry {
#[serde(rename = "workspace")]
pub workspace: Vec<WorkspaceRecord>,
}
impl WorkspaceRegistry {
pub fn path() -> Result<PathBuf> {
let home = dirs::home_dir().context("Could not determine home directory")?;
Ok(home
.join(".config")
.join("worktree")
.join("workspaces.toml"))
}
fn load_from(path: &Path) -> Result<Self> {
if !path.exists() {
return Ok(Self::default());
}
let content = std::fs::read_to_string(path)
.context(format!("Failed to read registry from {}", path.display()))?;
toml::from_str(&content).context(format!("Failed to parse registry at {}", path.display()))
}
fn write_to(&self, path: &Path) -> Result<()> {
let parent = path.parent().context("registry path has no parent")?;
std::fs::create_dir_all(parent)
.context(format!("Failed to create config dir {}", parent.display()))?;
let content = toml::to_string(self).context("Failed to serialize workspace registry")?;
std::fs::write(path, content)
.context(format!("Failed to write registry to {}", path.display()))
}
pub fn load() -> Result<Self> {
Self::load_from(&Self::path()?)
}
pub fn save(&self) -> Result<()> {
self.write_to(&Self::path()?)
}
pub fn register(&mut self, path: PathBuf) {
if !self.workspace.iter().any(|r| r.path == path) {
self.workspace.push(WorkspaceRecord {
path,
created_at: SystemTime::now(),
});
}
}
}
#[cfg(test)]
#[path = "registry_tests.rs"]
mod registry_tests;