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
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:

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 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<dyn Error>> {
pub fn launch(mut pc: PathConfig, repo: Repository, freq_secs: u64) -> Result<(), Box<dyn Error>> {
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<dyn Error>>
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()
);

View File

@ -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(())
}

View File

@ -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,