gitu 0.41.0

A git client inspired by Magit
Documentation
use crate::{Res, error::Error, open_repo};
use notify::{Event, EventKind, RecommendedWatcher, RecursiveMode, Watcher};
use std::{
    path::Path,
    sync::{
        Arc,
        atomic::{AtomicBool, Ordering},
    },
};

pub struct FileWatcher {
    pending_updates: Arc<AtomicBool>,
}

impl FileWatcher {
    pub fn new(repo_dir: &Path) -> Res<Self> {
        let pending_updates = Arc::new(AtomicBool::new(false));
        let pending_updates_w = pending_updates.clone();
        let repo_dir_clone = repo_dir.to_path_buf();

        std::thread::spawn(move || {
            if let Err(e) = watch(&repo_dir_clone, pending_updates_w) {
                log::error!("File watcher error: {:?}", e)
            }
        });

        Ok(Self { pending_updates })
    }

    pub fn pending_updates(&self) -> bool {
        self.pending_updates.swap(false, Ordering::Relaxed)
    }
}

fn watch(repo_dir: &Path, pending_updates_w: Arc<AtomicBool>) -> Res<()> {
    let repo = open_repo(repo_dir)?;
    let mut watcher = notify::recommended_watcher(move |res: Result<Event, notify::Error>| {
        if let Ok(event) = res {
            if !is_changed(&event) {
                return;
            }

            for path in event.paths {
                if !repo.status_should_ignore(&path).unwrap_or(false) {
                    log::info!("File changed: {:?} ({:?})", path, event.kind);
                    pending_updates_w.store(true, Ordering::Relaxed);
                    break;
                }
            }
        }
    })
    .map_err(Error::FileWatcher)?;

    let path_buf = repo_dir.to_owned();
    watcher
        .watch(&path_buf, RecursiveMode::Recursive)
        .map_err(Error::FileWatcher)?;

    log::info!(
        "File watcher started (kind: {:?})",
        RecommendedWatcher::kind()
    );

    std::mem::forget(watcher);
    Ok(())
}

fn is_changed(event: &Event) -> bool {
    matches!(
        event.kind,
        EventKind::Create(_) | EventKind::Modify(_) | EventKind::Remove(_)
    )
}