Motivation
Logging is hand-rolled and that's fine for a tool this size — -v / -q with three levels is plenty, and we don't want the weight of a logging ecosystem here (simplicity first). Two concrete cleanups would make the current code simpler without adding any dependency.
1. Drop the unused indicatif dependency
indicatif is declared in Cargo.toml but used nowhere in src/. Remove it (and its lockfile entries). Dead weight.
2. Replace the threaded verbosity parameter with a set-once global
The pain point isn't the log() function (~15 lines, fine) — it's that verbosity is threaded as a parameter through sync::run -> deploy_mutations -> execute_uploads -> auto_init, purely so those functions can log.
Set the verbosity once in main into a process global (e.g. static AtomicU8 or OnceLock<Verbosity>) and have log() read it. This is exactly what env_logger / tracing do internally; for three levels we can do it ourselves in ~10 lines, with zero new crates.
Result: the verbosity parameter disappears from deploy_mutations, execute_uploads, and auto_init, simplifying their signatures.
Notes / invariants to preserve
- Keep the stdout/stderr split: progress/status logs go to stderr (
eprintln!); the dry-run plan (UPLOAD … / DELETE …) stays on stdout (println!). These are program output, not logs.
Quiet suppresses status logs but not errors (errors propagate via Result / anyhow to main).
- Uploads run on multiple tasks; a global read by concurrent workers must be safe (an atomic /
OnceLock is, eprintln! already locks stderr).
- Passwords must never be logged (unchanged).
Explicitly out of scope
tracing — reserved for "if/when" we actually want RUST_LOG-style filtering or structured/async-instrumented logs. Overkill for a one-shot deploy CLI today.
- A built-in
--log-file — not needed. Because logs are on stderr, users can already redirect: ftpsync … 2> deploy.log (or > deploy.log 2>&1 for everything). Only revisit if a concrete need appears (e.g. Windows environments where redirection is awkward), in which case the global logger gains an optional Mutex<File> that log() also writes to.
Acceptance
indicatif gone from Cargo.toml / Cargo.lock; build still green.
- No
verbosity parameter threaded through sync functions.
cargo build / clippy / test pass; logging behavior (levels, stdout/stderr split, quiet) unchanged.
Motivation
Logging is hand-rolled and that's fine for a tool this size —
-v/-qwith three levels is plenty, and we don't want the weight of a logging ecosystem here (simplicity first). Two concrete cleanups would make the current code simpler without adding any dependency.1. Drop the unused
indicatifdependencyindicatifis declared inCargo.tomlbut used nowhere insrc/. Remove it (and its lockfile entries). Dead weight.2. Replace the threaded
verbosityparameter with a set-once globalThe pain point isn't the
log()function (~15 lines, fine) — it's thatverbosityis threaded as a parameter throughsync::run->deploy_mutations->execute_uploads->auto_init, purely so those functions can log.Set the verbosity once in
maininto a process global (e.g.staticAtomicU8orOnceLock<Verbosity>) and havelog()read it. This is exactly whatenv_logger/tracingdo internally; for three levels we can do it ourselves in ~10 lines, with zero new crates.Result: the
verbosityparameter disappears fromdeploy_mutations,execute_uploads, andauto_init, simplifying their signatures.Notes / invariants to preserve
eprintln!); the dry-run plan (UPLOAD …/DELETE …) stays on stdout (println!). These are program output, not logs.Quietsuppresses status logs but not errors (errors propagate viaResult/anyhowtomain).OnceLockis,eprintln!already locks stderr).Explicitly out of scope
tracing— reserved for "if/when" we actually wantRUST_LOG-style filtering or structured/async-instrumented logs. Overkill for a one-shot deploy CLI today.--log-file— not needed. Because logs are on stderr, users can already redirect:ftpsync … 2> deploy.log(or> deploy.log 2>&1for everything). Only revisit if a concrete need appears (e.g. Windows environments where redirection is awkward), in which case the global logger gains an optionalMutex<File>thatlog()also writes to.Acceptance
indicatifgone fromCargo.toml/Cargo.lock; build still green.verbosityparameter threaded through sync functions.cargo build/clippy/testpass; logging behavior (levels, stdout/stderr split, quiet) unchanged.