1use std::path::Path;
2
3use anyhow::Result;
4
5use crate::index::{count_unit_formats, ArchiveIndex, Index};
6
7pub struct SyncResult {
9 pub unit_count: usize,
10 pub archive_count: usize,
11 pub md_count: usize,
12 pub yaml_count: usize,
13 pub mixed_formats: bool,
14}
15
16pub fn sync(mana_dir: &Path) -> Result<SyncResult> {
21 let (md_count, yaml_count) = count_unit_formats(mana_dir)?;
22
23 let index = Index::build(mana_dir)?;
24 let unit_count = index.units.len();
25 index.save(mana_dir)?;
26
27 let archive_index = ArchiveIndex::build(mana_dir)?;
28 let archive_count = archive_index.units.len();
29 if archive_count > 0 || mana_dir.join("archive.yaml").exists() {
30 archive_index.save(mana_dir)?;
31 }
32
33 Ok(SyncResult {
34 unit_count,
35 archive_count,
36 md_count,
37 yaml_count,
38 mixed_formats: md_count > 0 && yaml_count > 0,
39 })
40}
41
42#[cfg(test)]
43mod tests {
44 use super::*;
45 use crate::unit::{Status, Unit};
46 use crate::util::title_to_slug;
47 use std::fs;
48 use tempfile::TempDir;
49
50 #[test]
51 fn sync_rebuilds_index() {
52 let dir = TempDir::new().unwrap();
53 let mana_dir = dir.path().join(".mana");
54 fs::create_dir(&mana_dir).unwrap();
55
56 let unit1 = Unit::new("1", "Task one");
57 let unit2 = Unit::new("2", "Task two");
58 let slug1 = title_to_slug(&unit1.title);
59 let slug2 = title_to_slug(&unit2.title);
60 unit1
61 .to_file(mana_dir.join(format!("1-{}.md", slug1)))
62 .unwrap();
63 unit2
64 .to_file(mana_dir.join(format!("2-{}.md", slug2)))
65 .unwrap();
66
67 let result = sync(&mana_dir).unwrap();
68
69 assert_eq!(result.unit_count, 2);
70 assert!(!result.mixed_formats);
71 }
72
73 #[test]
74 fn sync_empty_project() {
75 let dir = TempDir::new().unwrap();
76 let mana_dir = dir.path().join(".mana");
77 fs::create_dir(&mana_dir).unwrap();
78
79 let result = sync(&mana_dir).unwrap();
80
81 assert_eq!(result.unit_count, 0);
82 assert_eq!(result.archive_count, 0);
83 }
84
85 #[test]
86 fn sync_rebuilds_archive() {
87 let dir = TempDir::new().unwrap();
88 let mana_dir = dir.path().join(".mana");
89 fs::create_dir(&mana_dir).unwrap();
90
91 let archive_dir = mana_dir.join("archive").join("2026").join("03");
92 fs::create_dir_all(&archive_dir).unwrap();
93
94 let mut unit = Unit::new("10", "Archived ten");
95 unit.status = Status::Closed;
96 unit.is_archived = true;
97 let slug = title_to_slug(&unit.title);
98 unit.to_file(archive_dir.join(format!("10-{}.md", slug)))
99 .unwrap();
100
101 let result = sync(&mana_dir).unwrap();
102
103 assert_eq!(result.archive_count, 1);
104 assert!(mana_dir.join("archive.yaml").exists());
105 }
106}