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" edition = "2021"
[dependencies] [dependencies]
ansi_term = "0.12.1"
clap = { version = "3.0.0-rc.9", features = ["derive"] } clap = { version = "3.0.0-rc.9", features = ["derive"] }
git2 = "0.13.25" git2 = "0.13.25"
log = "0.4.14"
notify = "4.0.16" notify = "4.0.16"
regex = "1.5.4" regex = "1.5.4"
serde = "1.0" serde = "1.0"
serde_derive = "1.0.132" serde_derive = "1.0.132"
serde_yaml = "0.8" serde_yaml = "0.8"
yaml-rust = "0.4.4" simplelog = { version = "^0.11.1", features = ["paris"] }
url = { version = "2.2.2", features = ["serde"] } url = { version = "2.2.2", features = ["serde"] }
yaml-rust = "0.4.4"

View File

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

View File

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

View File

@ -1,5 +1,6 @@
use super::{config::PathConfig, path}; use super::{config::PathConfig, path};
use git2::Repository; use git2::Repository;
use simplelog::{info, paris};
use std::{env::VarError, error, fmt, fs, io, path::PathBuf, result}; 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, // issues that we need to resolve anyways (e.g. setting remote, pulling,
// managing possible merge conflicts, etc.). // managing possible merge conflicts, etc.).
None => { None => {
println!("Creating new homesync repository."); info!(
"Creating new homesync repository at <green>{}</>.",
config.1.local.display()
);
let repo = Repository::init(&expanded)?; let repo = Repository::init(&expanded)?;
fs::File::create(sentinel)?; fs::File::create(sentinel)?;
Ok(repo) 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 // git library we chose to use employs async/await so let's wrap around a
// channel. // channel.
git::init(&config)?; git::init(&config)?;
println!("Finished initialization."); println!("\nFinished initialization.");
Ok(()) Ok(())
} }

View File

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