Skip to main content

driven/cli/
sync.rs

1//! Sync command - synchronize rules across editors
2
3use crate::{DrivenConfig, Result, sync::SyncEngine};
4use std::path::Path;
5
6/// Sync command handler
7#[derive(Debug)]
8pub struct SyncCommand;
9
10impl SyncCommand {
11    /// Run one-time sync
12    pub fn run(project_root: &Path) -> Result<()> {
13        let config = Self::load_config(project_root)?;
14        let engine = SyncEngine::new(&config.sync.source_of_truth, config.editors);
15
16        let spinner = super::create_spinner("Syncing rules to all editors...");
17        let report = engine.sync(project_root)?;
18        spinner.finish_and_clear();
19
20        // Report results
21        if report.is_success() {
22            super::print_success(&format!(
23                "Synced rules to {} editors",
24                report.synced_count()
25            ));
26            for synced in &report.synced {
27                println!("  {} → {}", synced.editor, synced.path.display());
28            }
29        } else {
30            super::print_warning(&format!(
31                "Synced {} editors, {} errors",
32                report.synced_count(),
33                report.errors.len()
34            ));
35            for error in &report.errors {
36                super::print_error(&format!("  {} - {}", error.editor, error.error));
37            }
38        }
39
40        Ok(())
41    }
42
43    /// Run watch mode (continuous sync)
44    pub fn watch(project_root: &Path) -> Result<()> {
45        let config = Self::load_config(project_root)?;
46        let mut engine = SyncEngine::new(&config.sync.source_of_truth, config.editors.clone());
47
48        super::print_info("Starting file watcher...");
49        engine.start_watching(project_root)?;
50
51        super::print_success("Watching for changes. Press Ctrl+C to stop.");
52        println!();
53
54        // Initial sync
55        Self::run(project_root)?;
56
57        // Watch loop would go here - for now just wait
58        // In a real implementation, this would use tokio or similar
59        loop {
60            std::thread::sleep(std::time::Duration::from_secs(1));
61            // Check for changes and re-sync
62        }
63    }
64
65    fn load_config(project_root: &Path) -> Result<DrivenConfig> {
66        let config_path = project_root.join(".driven/config.toml");
67
68        if config_path.exists() {
69            let content = std::fs::read_to_string(&config_path)
70                .map_err(|e| crate::DrivenError::Config(format!("Failed to read config: {}", e)))?;
71            toml::from_str(&content)
72                .map_err(|e| crate::DrivenError::Config(format!("Failed to parse config: {}", e)))
73        } else {
74            Ok(DrivenConfig::default())
75        }
76    }
77}