1use anyhow::Result;
2use chrono::{DateTime, Utc};
3use gn_core::{MergeStrategy, Namespace, NotesEngine};
4use serde::{Deserialize, Serialize};
5use std::path::Path;
6use std::process::Command;
7
8#[derive(Debug, Clone, Serialize, Deserialize)]
9pub struct SyncReport {
10 pub fetched: usize,
11 pub merged: usize,
12 pub conflicts: usize,
13 pub timestamp: DateTime<Utc>,
14}
15
16pub fn fetch_notes(
17 repo_path: &Path,
18 remote: &str,
19 namespaces: &[Namespace],
20 strategy: &dyn MergeStrategy,
21) -> Result<SyncReport> {
22 let engine = NotesEngine::new(repo_path);
23 let mut total_fetched = 0;
24 let mut total_merged = 0;
25
26 for ns in namespaces {
27 let ref_path = ns.ref_path();
28
29 let remote_ref = format!("refs/notes/{}_{}_remote", remote, ns);
31 let refspec = format!("{}:{}", ref_path, remote_ref);
32
33 let _ = Command::new("git")
34 .current_dir(repo_path)
35 .args(["fetch", remote, &refspec])
36 .status(); let local_notes = engine.read_notes(ns).unwrap_or_default();
44
45 let remote_ns = Namespace::Custom(format!("{}_{}_remote", remote, ns));
47 let remote_notes = engine.read_notes(&remote_ns).unwrap_or_default();
48
49 total_fetched += remote_notes.len();
50
51 if !remote_notes.is_empty() {
52 let merged_notes = strategy.merge(&local_notes, &remote_notes);
53
54 for note in &merged_notes {
58 engine.write_note(note)?;
59 }
60 total_merged += merged_notes.len();
61 }
62
63 let _ = Command::new("git")
65 .current_dir(repo_path)
66 .args(["update-ref", "-d", &remote_ref])
67 .status();
68 }
69
70 Ok(SyncReport {
71 fetched: total_fetched,
72 merged: total_merged,
73 conflicts: 0, timestamp: Utc::now(),
75 })
76}