Have our daemon apply changes to the local repository.
parent
dc56dbf80c
commit
90065a4ffe
13
README.md
13
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
|
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:
|
||||||
|
|
|
@ -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()
|
||||||
);
|
);
|
||||||
|
|
|
@ -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(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
12
src/main.rs
12
src/main.rs
|
@ -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,
|
||||||
|
|
Loading…
Reference in New Issue