Have our daemon apply changes to the local repository.

pull/3/head
Joshua Potter 2022-01-06 07:46:39 -05:00
parent dc56dbf80c
commit 90065a4ffe
4 changed files with 53 additions and 14 deletions

View File

@ -65,6 +65,19 @@ $ homesync pull --all
This will load up a diff wrapper for you to ensure you make the changes you'd This will load up a diff wrapper for you to ensure you make the changes you'd
like. 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 ## Contribution
Install git hooks as follows: Install git hooks as follows:

View File

@ -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 notify::{DebouncedEvent, RecommendedWatcher, RecursiveMode, Watcher};
use simplelog::{error, paris, trace, warn}; use simplelog::{error, paris, trace, warn};
use std::{ use std::{
@ -138,7 +139,7 @@ impl<'a> WatchState<'a> {
// Daemon // Daemon
// ======================================== // ========================================
pub fn launch(mut pc: PathConfig, freq_secs: u64) -> Result<(), Box<dyn Error>> { pub fn launch(mut pc: PathConfig, repo: Repository, freq_secs: u64) -> Result<(), Box<dyn Error>> {
let (poll_tx, poll_rx) = channel(); let (poll_tx, poll_rx) = channel();
let (watch_tx, watch_rx) = channel(); let (watch_tx, watch_rx) = channel();
let watch_tx1 = watch_tx.clone(); let watch_tx1 = watch_tx.clone();
@ -156,48 +157,62 @@ pub fn launch(mut pc: PathConfig, freq_secs: u64) -> Result<(), Box<dyn Error>>
let mut state = WatchState::new(poll_tx, &mut watcher)?; let mut state = WatchState::new(poll_tx, &mut watcher)?;
state.update(&pc); state.update(&pc);
loop { loop {
// Received paths should always be the fully resolved ones so safe to git::apply(&pc, &repo)?;
// compare against our current config path. // Received paths should always be fully resolved.
match watch_rx.recv() { match watch_rx.recv() {
Ok(DebouncedEvent::NoticeWrite(p)) => { Ok(DebouncedEvent::NoticeWrite(p)) => {
trace!("NoticeWrite {}", p.display()); trace!("NoticeWrite '{}'", p.display());
} }
Ok(DebouncedEvent::NoticeRemove(p)) => { Ok(DebouncedEvent::NoticeRemove(p)) => {
trace!("NoticeRemove {}", p.display()); trace!("NoticeRemove '{}'", p.display());
} }
Ok(DebouncedEvent::Create(p)) => { Ok(DebouncedEvent::Create(p)) => {
trace!("Create '{}'", p.display());
if pc.homesync_yml == p { if pc.homesync_yml == p {
pc = config::reload(&pc)?; pc = config::reload(&pc)?;
state.update(&pc); state.update(&pc);
} }
trace!("Create {}", p.display());
} }
Ok(DebouncedEvent::Write(p)) => { Ok(DebouncedEvent::Write(p)) => {
trace!("Write '{}'", p.display());
if pc.homesync_yml == p { if pc.homesync_yml == p {
pc = config::reload(&pc)?; pc = config::reload(&pc)?;
state.update(&pc); state.update(&pc);
} }
trace!("Write {}", p.display());
} }
// Do not try reloading our primary config in any of the following // Do not try reloading our primary config in any of the following
// cases since it may lead to undesired behavior. If our config has // 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 // e.g. been removed, let's just keep using what we have in memory
// in the chance it may be added back. // in the chance it may be added back.
Ok(DebouncedEvent::Chmod(p)) => { Ok(DebouncedEvent::Chmod(p)) => {
trace!("Chmod {}", p.display()); trace!("Chmod '{}'", p.display());
} }
Ok(DebouncedEvent::Remove(p)) => { 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)) => { 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) => { Ok(DebouncedEvent::Rescan) => {
trace!("Rescanning"); trace!("Rescanning");
} }
Ok(DebouncedEvent::Error(e, path)) => { Ok(DebouncedEvent::Error(e, path)) => {
warn!( warn!(
"Error {} at {}", "Error {} at '{}'",
e, e,
path.unwrap_or_else(|| PathBuf::from("N/A")).display() path.unwrap_or_else(|| PathBuf::from("N/A")).display()
); );

View File

@ -16,7 +16,8 @@ pub fn run_apply(config: PathConfig) -> Result {
} }
pub fn run_daemon(config: PathConfig, freq_secs: u64) -> 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(()) Ok(())
} }

View File

@ -4,11 +4,21 @@ use simplelog;
use simplelog::{error, paris}; use simplelog::{error, paris};
use std::{error::Error, io, path::PathBuf}; 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() { fn main() {
// Only one logger should ever be initialized and it should be done at the // Only one logger should ever be initialized and it should be done at the
// beginning of the program. Otherwise logs are ignored. // beginning of the program. Otherwise logs are ignored.
simplelog::TermLogger::init( simplelog::TermLogger::init(
simplelog::LevelFilter::Info, log_level(),
simplelog::Config::default(), simplelog::Config::default(),
simplelog::TerminalMode::Mixed, simplelog::TerminalMode::Mixed,
simplelog::ColorChoice::Auto, simplelog::ColorChoice::Auto,