Add a logging solution, and remove ANSI crate.

pull/3/head
Joshua Potter 2022-01-02 11:14:05 -05:00
parent 2c95c43124
commit 61b9a338a5
6 changed files with 54 additions and 30 deletions

View File

@ -10,13 +10,14 @@ version = "0.1.0"
edition = "2021"
[dependencies]
ansi_term = "0.12.1"
clap = { version = "3.0.0-rc.9", features = ["derive"] }
git2 = "0.13.25"
log = "0.4.14"
notify = "4.0.16"
regex = "1.5.4"
serde = "1.0"
serde_derive = "1.0.132"
serde_yaml = "0.8"
yaml-rust = "0.4.4"
simplelog = { version = "^0.11.1", features = ["paris"] }
url = { version = "2.2.2", features = ["serde"] }
yaml-rust = "0.4.4"

View File

@ -1,6 +1,7 @@
use super::{path, path::ResPathBuf};
use ansi_term::Colour::{Green, Yellow};
use paris::formatter::colorize_string;
use serde_derive::{Deserialize, Serialize};
use simplelog::{info, paris};
use std::{
collections::BTreeMap,
env::VarError,
@ -143,8 +144,10 @@ pub fn load(candidates: &Vec<ResPathBuf>) -> Result<PathConfig> {
}
pub fn reload(config: &PathConfig) -> Result<PathConfig> {
// TODO(jrpotter): Let's add a proper logging solution.
println!("Configuration reloaded.");
info!(
"<green>{}</> configuration reloaded.",
config.1.local.display()
);
load(&vec![config.0.clone()])
}
@ -156,7 +159,7 @@ fn prompt_local(path: Option<&Path>) -> Result<PathBuf> {
let default = path.map_or("$HOME/.homesync".to_owned(), |p| p.display().to_string());
print!(
"Local git repository <{}> (enter to continue): ",
Yellow.paint(&default)
colorize_string(format!("<yellow>{}</>", &default)),
);
io::stdout().flush()?;
let mut local = String::new();
@ -176,7 +179,7 @@ fn prompt_remote(url: Option<&Url>) -> Result<Url> {
});
print!(
"Remote git repository <{}> (enter to continue): ",
Yellow.paint(&default)
colorize_string(format!("<yellow>{}</>", &default)),
);
io::stdout().flush()?;
let mut remote = String::new();
@ -192,7 +195,7 @@ fn prompt_remote(url: Option<&Url>) -> Result<Url> {
pub fn write(path: &ResPathBuf, loaded: Option<Config>) -> Result<PathConfig> {
println!(
"Generating config at {}...\n",
Green.paint(path.unresolved().display().to_string())
colorize_string(format!("<green>{}</>", path.unresolved().display())),
);
let local = prompt_local(match &loaded {
Some(c) => Some(c.local.as_ref()),
@ -221,7 +224,7 @@ pub fn write(path: &ResPathBuf, loaded: Option<Config>) -> Result<PathConfig> {
pub fn list_packages(config: PathConfig) {
println!(
"Listing packages in {}...\n",
Green.paint(config.0.unresolved().display().to_string())
colorize_string(format!("<green>{}</>", config.0.unresolved().display())),
);
// Alphabetical ordered ensured by B-tree implementation.
for (k, _) in config.1.packages {

View File

@ -1,5 +1,6 @@
use super::{config, config::PathConfig, path, path::ResPathBuf};
use notify::{DebouncedEvent, RecommendedWatcher, RecursiveMode, Watcher};
use simplelog::{error, paris, trace, warn};
use std::{
collections::HashSet,
error::Error,
@ -9,7 +10,6 @@ use std::{
time::Duration,
};
// TODO(jrpotter): Add logging.
// TODO(jrpotter): Add pid file to only allow one daemon at a time.
// TODO(jrpotter): Sync files to local git repository.
@ -34,7 +34,7 @@ fn resolve_pending(tx: &Sender<DebouncedEvent>, pending: &HashSet<PathBuf>) -> V
Ok(None) => (),
Err(e) => {
to_remove.push(path.clone());
eprintln!(
error!(
"Encountered unexpected error {} when processing path {}",
e,
path.display()
@ -96,7 +96,7 @@ impl<'a> WatchState<'a> {
self.watching.insert(path);
}
Err(e) => {
eprintln!(
error!(
"Encountered unexpected error {} when watching path {}",
e,
path.unresolved().display()
@ -113,7 +113,7 @@ impl<'a> WatchState<'a> {
match self.watcher.unwatch(&path) {
Ok(()) => (),
Err(e) => {
eprintln!(
error!(
"Encountered unexpected error {} when unwatching path {}",
e,
path.unresolved().display()
@ -159,47 +159,51 @@ pub fn launch(mut config: PathConfig, freq_secs: u64) -> Result<(), Box<dyn Erro
// Received paths should always be the fully resolved ones so safe to
// compare against our current config path.
match watch_rx.recv() {
Ok(DebouncedEvent::NoticeWrite(_)) => {
// Intentionally ignore in favor of stronger signals.
Ok(DebouncedEvent::NoticeWrite(p)) => {
trace!("NoticeWrite {}", p.display());
}
Ok(DebouncedEvent::NoticeRemove(_)) => {
// Intentionally ignore in favor of stronger signals.
Ok(DebouncedEvent::NoticeRemove(p)) => {
trace!("NoticeRemove {}", p.display());
}
Ok(DebouncedEvent::Create(p)) => {
if config.0 == p {
config = config::reload(&config)?;
state.update(&config);
}
println!("Create {}", p.display());
trace!("Create {}", p.display());
}
Ok(DebouncedEvent::Write(p)) => {
if config.0 == p {
config = config::reload(&config)?;
state.update(&config);
}
println!("Write {}", p.display());
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)) => {
println!("Chmod {}", p.display());
trace!("Chmod {}", p.display());
}
Ok(DebouncedEvent::Remove(p)) => {
println!("Remove {}", p.display());
trace!("Remove {}", p.display());
}
Ok(DebouncedEvent::Rename(src, dst)) => {
println!("Rename {} {}", src.display(), dst.display())
trace!("Rename {} {}", src.display(), dst.display())
}
Ok(DebouncedEvent::Rescan) => {
println!("Rescanning");
trace!("Rescanning");
}
Ok(DebouncedEvent::Error(e, _maybe_path)) => {
println!("Error {}", e);
Ok(DebouncedEvent::Error(e, path)) => {
warn!(
"Error {} at {}",
e,
path.unwrap_or_else(|| PathBuf::from("N/A")).display()
);
}
Err(e) => {
println!("watch error: {:?}", e);
error!("Watch error: {:?}", e);
}
}
}

View File

@ -1,5 +1,6 @@
use super::{config::PathConfig, path};
use git2::Repository;
use simplelog::{info, paris};
use std::{env::VarError, error, fmt, fs, io, path::PathBuf, result};
// ========================================
@ -143,7 +144,10 @@ pub fn init(config: &PathConfig) -> Result<git2::Repository> {
// issues that we need to resolve anyways (e.g. setting remote, pulling,
// managing possible merge conflicts, etc.).
None => {
println!("Creating new homesync repository.");
info!(
"Creating new homesync repository at <green>{}</>.",
config.1.local.display()
);
let repo = Repository::init(&expanded)?;
fs::File::create(sentinel)?;
Ok(repo)

View File

@ -45,7 +45,7 @@ pub fn run_init(candidates: Vec<ResPathBuf>) -> Result<(), Box<dyn Error>> {
// git library we chose to use employs async/await so let's wrap around a
// channel.
git::init(&config)?;
println!("Finished initialization.");
println!("\nFinished initialization.");
Ok(())
}

View File

@ -1,8 +1,20 @@
use clap::{App, AppSettings, Arg};
use homesync::path::ResPathBuf;
use simplelog;
use simplelog::{error, paris};
use std::{error::Error, io, path::PathBuf};
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,
simplelog::Config::default(),
simplelog::TerminalMode::Mixed,
simplelog::ColorChoice::Auto,
)
.expect("Could not initialize logger library.");
let matches = App::new("homesync")
.about("Cross desktop configuration sync tool.")
.version("0.1.0")
@ -43,7 +55,7 @@ fn main() {
.get_matches();
if let Err(e) = dispatch(matches) {
eprintln!("{}", e);
error!("{}", e);
}
}
@ -68,7 +80,7 @@ fn dispatch(matches: clap::ArgMatches) -> Result<(), Box<dyn Error>> {
if freq_secs > 0 {
homesync::run_daemon(config, freq_secs)?;
} else {
eprintln!("Invalid frequency. Expected a positive integer.");
error!("Invalid frequency. Expected a positive integer.");
}
Ok(())
}