diff --git a/README.md b/README.md index d43a549..58d034e 100644 --- a/README.md +++ b/README.md @@ -65,6 +65,19 @@ $ homesync pull --all This will load up a diff wrapper for you to ensure you make the changes you'd like. +## Known Issues + +If using (neo)vim, the daemon watcher will stop watching a given configuration +file after editing. Refer to [this issue](https://github.com/notify-rs/notify/issues/247) +for more details. As a workaround, you can set the following in your `init.vim` +file: + +```vimscript +backupcopy=yes +``` + +Refer to `:h backupcopy` for details on how this works. + ## Contribution Install git hooks as follows: diff --git a/src/daemon.rs b/src/daemon.rs index 9c74459..628a1bb 100644 --- a/src/daemon.rs +++ b/src/daemon.rs @@ -1,4 +1,5 @@ -use super::{config, config::PathConfig, path, path::ResPathBuf}; +use super::{config, config::PathConfig, git, path, path::ResPathBuf}; +use git2::Repository; use notify::{DebouncedEvent, RecommendedWatcher, RecursiveMode, Watcher}; use simplelog::{error, paris, trace, warn}; use std::{ @@ -138,7 +139,7 @@ impl<'a> WatchState<'a> { // Daemon // ======================================== -pub fn launch(mut pc: PathConfig, freq_secs: u64) -> Result<(), Box> { +pub fn launch(mut pc: PathConfig, repo: Repository, freq_secs: u64) -> Result<(), Box> { let (poll_tx, poll_rx) = channel(); let (watch_tx, watch_rx) = channel(); let watch_tx1 = watch_tx.clone(); @@ -156,48 +157,62 @@ pub fn launch(mut pc: PathConfig, freq_secs: u64) -> Result<(), Box> let mut state = WatchState::new(poll_tx, &mut watcher)?; state.update(&pc); loop { - // Received paths should always be the fully resolved ones so safe to - // compare against our current config path. + git::apply(&pc, &repo)?; + // Received paths should always be fully resolved. match watch_rx.recv() { Ok(DebouncedEvent::NoticeWrite(p)) => { - trace!("NoticeWrite {}", p.display()); + trace!("NoticeWrite '{}'", p.display()); } Ok(DebouncedEvent::NoticeRemove(p)) => { - trace!("NoticeRemove {}", p.display()); + trace!("NoticeRemove '{}'", p.display()); } Ok(DebouncedEvent::Create(p)) => { + trace!("Create '{}'", p.display()); if pc.homesync_yml == p { pc = config::reload(&pc)?; state.update(&pc); } - trace!("Create {}", p.display()); } Ok(DebouncedEvent::Write(p)) => { + trace!("Write '{}'", p.display()); if pc.homesync_yml == p { pc = config::reload(&pc)?; state.update(&pc); } - trace!("Write {}", p.display()); } // Do not try reloading our primary config in any of the following // cases since it may lead to undesired behavior. If our config has // e.g. been removed, let's just keep using what we have in memory // in the chance it may be added back. Ok(DebouncedEvent::Chmod(p)) => { - trace!("Chmod {}", p.display()); + trace!("Chmod '{}'", p.display()); } Ok(DebouncedEvent::Remove(p)) => { - trace!("Remove {}", p.display()); + if pc.homesync_yml == p { + warn!( + "Removed primary config '{}'. Continuing to use last loaded state", + p.display() + ); + } else { + trace!("Remove '{}'", p.display()); + } } Ok(DebouncedEvent::Rename(src, dst)) => { - trace!("Rename {} {}", src.display(), dst.display()) + if pc.homesync_yml == src && pc.homesync_yml != dst { + warn!( + "Renamed primary config '{}'. Continuing to use last loaded state", + src.display() + ); + } else { + trace!("Renamed '{}' to '{}'", src.display(), dst.display()) + } } Ok(DebouncedEvent::Rescan) => { trace!("Rescanning"); } Ok(DebouncedEvent::Error(e, path)) => { warn!( - "Error {} at {}", + "Error {} at '{}'", e, path.unwrap_or_else(|| PathBuf::from("N/A")).display() ); diff --git a/src/lib.rs b/src/lib.rs index f32d712..00f2d32 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -16,7 +16,8 @@ pub fn run_apply(config: PathConfig) -> Result { } pub fn run_daemon(config: PathConfig, freq_secs: u64) -> Result { - daemon::launch(config, freq_secs)?; + let repo = git::init(&config)?; + daemon::launch(config, repo, freq_secs)?; Ok(()) } diff --git a/src/main.rs b/src/main.rs index 73292b1..8280814 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,11 +4,21 @@ use simplelog; use simplelog::{error, paris}; use std::{error::Error, io, path::PathBuf}; +#[cfg(debug_assertions)] +fn log_level() -> simplelog::LevelFilter { + simplelog::LevelFilter::Trace +} + +#[cfg(not(debug_assertions))] +fn log_level() { + simplelog::LevelFilter::Info +} + fn main() { // Only one logger should ever be initialized and it should be done at the // beginning of the program. Otherwise logs are ignored. simplelog::TermLogger::init( - simplelog::LevelFilter::Info, + log_level(), simplelog::Config::default(), simplelog::TerminalMode::Mixed, simplelog::ColorChoice::Auto,