worktree_io/ttl/
registry.rs1use std::path::{Path, PathBuf};
2use std::time::SystemTime;
3
4use anyhow::{Context, Result};
5use serde::{Deserialize, Serialize};
6
7#[derive(Debug, Clone, Serialize, Deserialize)]
9pub struct WorkspaceRecord {
10 pub path: PathBuf,
12 #[serde(with = "humantime_serde")]
14 pub created_at: SystemTime,
15}
16
17#[derive(Debug, Clone, Serialize, Deserialize, Default)]
19#[serde(default)]
20pub struct WorkspaceRegistry {
21 #[serde(rename = "workspace")]
23 pub workspace: Vec<WorkspaceRecord>,
24}
25
26impl WorkspaceRegistry {
27 pub fn path() -> Result<PathBuf> {
34 let home = dirs::home_dir().context("Could not determine home directory")?;
35 Ok(home
36 .join(".config")
37 .join("worktree")
38 .join("workspaces.toml"))
39 }
40
41 fn load_from(path: &Path) -> Result<Self> {
42 if !path.exists() {
43 return Ok(Self::default());
44 }
45 let content = std::fs::read_to_string(path)
46 .context(format!("Failed to read registry from {}", path.display()))?;
47 toml::from_str(&content).context(format!("Failed to parse registry at {}", path.display()))
48 }
49
50 fn write_to(&self, path: &Path) -> Result<()> {
51 let parent = path.parent().context("registry path has no parent")?;
52 std::fs::create_dir_all(parent)
53 .context(format!("Failed to create config dir {}", parent.display()))?;
54 let content = toml::to_string(self).context("Failed to serialize workspace registry")?;
55 std::fs::write(path, content)
56 .context(format!("Failed to write registry to {}", path.display()))
57 }
58
59 pub fn load() -> Result<Self> {
65 Self::load_from(&Self::path()?)
66 }
67
68 pub fn save(&self) -> Result<()> {
75 self.write_to(&Self::path()?)
76 }
77
78 pub fn register(&mut self, path: PathBuf) {
83 if !self.workspace.iter().any(|r| r.path == path) {
84 self.workspace.push(WorkspaceRecord {
85 path,
86 created_at: SystemTime::now(),
87 });
88 }
89 }
90}
91
92#[cfg(test)]
93#[path = "registry_tests.rs"]
94mod registry_tests;