feat: silence progress with --quiet
This commit is contained in:
@@ -16,6 +16,10 @@ pub struct Ahab {
|
||||
#[arg(short, long, global = true)]
|
||||
pub verbose: bool,
|
||||
|
||||
/// Print only what was asked for, not the progress along the way
|
||||
#[arg(short, long, global = true, conflicts_with = "verbose")]
|
||||
pub quiet: bool,
|
||||
|
||||
/// Print the docker commands that would run, without running them
|
||||
#[arg(long, global = true)]
|
||||
pub dry_run: bool,
|
||||
|
||||
@@ -1,7 +1,13 @@
|
||||
use super::{Argv, Cmd};
|
||||
|
||||
fn compose() -> Argv {
|
||||
Argv::new("docker").arg("compose")
|
||||
// compose prints its own progress, which --quiet has to ask it to stop
|
||||
fn compose(quiet: bool) -> Argv {
|
||||
let argv = Argv::new("docker").arg("compose");
|
||||
|
||||
match quiet {
|
||||
true => argv.flag("--progress", "quiet"),
|
||||
false => argv,
|
||||
}
|
||||
}
|
||||
|
||||
// docker compose run --rm, which runs the image's entrypoint and so fixes up the
|
||||
@@ -22,7 +28,7 @@ impl Run {
|
||||
|
||||
impl Cmd for Run {
|
||||
fn argv(&self) -> Argv {
|
||||
compose()
|
||||
compose(false)
|
||||
.arg("run")
|
||||
.arg("--rm")
|
||||
.arg(&self.service)
|
||||
@@ -35,7 +41,7 @@ pub struct Config;
|
||||
|
||||
impl Cmd for Config {
|
||||
fn argv(&self) -> Argv {
|
||||
compose().arg("config").flag("--format", "json")
|
||||
compose(false).arg("config").flag("--format", "json")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,39 +60,37 @@ impl Ps {
|
||||
|
||||
impl Cmd for Ps {
|
||||
fn argv(&self) -> Argv {
|
||||
compose().arg("ps").arg("--quiet").arg(&self.service)
|
||||
compose(false).arg("ps").arg("--quiet").arg(&self.service)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Up;
|
||||
pub struct Up {
|
||||
pub quiet: bool,
|
||||
}
|
||||
|
||||
impl Cmd for Up {
|
||||
fn argv(&self) -> Argv {
|
||||
compose().arg("up").arg("--detach")
|
||||
compose(self.quiet).arg("up").arg("--detach")
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Start {
|
||||
service: String,
|
||||
pub struct Start<'a> {
|
||||
pub service: &'a str,
|
||||
pub quiet: bool,
|
||||
}
|
||||
|
||||
impl Start {
|
||||
pub fn service(service: &str) -> Self {
|
||||
Self {
|
||||
service: service.to_string(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Cmd for Start {
|
||||
impl Cmd for Start<'_> {
|
||||
fn argv(&self) -> Argv {
|
||||
compose().arg("start").arg(&self.service)
|
||||
compose(self.quiet).arg("start").arg(self.service)
|
||||
}
|
||||
}
|
||||
pub struct Stop;
|
||||
|
||||
pub struct Stop {
|
||||
pub quiet: bool,
|
||||
}
|
||||
|
||||
impl Cmd for Stop {
|
||||
fn argv(&self) -> Argv {
|
||||
compose().arg("stop")
|
||||
compose(self.quiet).arg("stop")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ pub fn make_command(ctx: &Ctx, app: &PathBuf, name: &str) -> Result<()> {
|
||||
return Err(anyhow!("directory {app_name} does not exist"));
|
||||
}
|
||||
|
||||
note!("found app {app_name}");
|
||||
note!(ctx, "found app {app_name}");
|
||||
|
||||
let management_dir = app_dir.join("management");
|
||||
|
||||
@@ -32,7 +32,7 @@ pub fn make_command(ctx: &Ctx, app: &PathBuf, name: &str) -> Result<()> {
|
||||
create_dir(ctx, &management_dir)?;
|
||||
touch(ctx, &management_dir.join("__init__.py"))?;
|
||||
|
||||
note!("created module {app_name}.management")
|
||||
note!(ctx, "created module {app_name}.management")
|
||||
};
|
||||
|
||||
let commands_dir = management_dir.join("commands");
|
||||
@@ -41,7 +41,7 @@ pub fn make_command(ctx: &Ctx, app: &PathBuf, name: &str) -> Result<()> {
|
||||
create_dir(ctx, &commands_dir)?;
|
||||
touch(ctx, &commands_dir.join("__init__.py"))?;
|
||||
|
||||
note!("created module {app_name}.management.commands")
|
||||
note!(ctx, "created module {app_name}.management.commands")
|
||||
};
|
||||
|
||||
write_new(
|
||||
@@ -50,7 +50,7 @@ pub fn make_command(ctx: &Ctx, app: &PathBuf, name: &str) -> Result<()> {
|
||||
DEBUG_TEMPLATE.as_bytes(),
|
||||
)?;
|
||||
|
||||
note!("created command {app_name}.management.commands.{name}");
|
||||
note!(ctx, "created command {app_name}.management.commands.{name}");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ pub fn add(ctx: &Ctx, paths: &[PathBuf], force: bool, store: Option<&Path>) -> R
|
||||
let mut failed = 0;
|
||||
for path in paths {
|
||||
if let Err(e) = link_one(ctx, &repo, path, force, &report) {
|
||||
note!("error: {e:#}");
|
||||
note!(ctx, "error: {e:#}");
|
||||
failed += 1;
|
||||
}
|
||||
}
|
||||
@@ -52,7 +52,7 @@ pub fn restore(ctx: &Ctx, paths: &[PathBuf], all: bool, store: Option<&Path>) ->
|
||||
};
|
||||
|
||||
if paths.is_empty() {
|
||||
note!("nothing in the store for this repository");
|
||||
note!(ctx, "nothing in the store for this repository");
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
@@ -63,7 +63,7 @@ pub fn restore(ctx: &Ctx, paths: &[PathBuf], all: bool, store: Option<&Path>) ->
|
||||
let mut failed = 0;
|
||||
for path in &paths {
|
||||
if let Err(e) = restore_one(ctx, &repo, path, &report) {
|
||||
note!("error: {e:#}");
|
||||
note!(ctx, "error: {e:#}");
|
||||
failed += 1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -86,7 +86,10 @@ fn repo_components(ctx: &Ctx, root: &Path) -> Result<PathBuf> {
|
||||
if let Some(components) = components_from_remote(&url) {
|
||||
return Ok(components);
|
||||
}
|
||||
note!("could not parse git remote `{url}`, falling back to the checkout name");
|
||||
note!(
|
||||
ctx,
|
||||
"could not parse git remote `{url}`, falling back to the checkout name"
|
||||
);
|
||||
}
|
||||
|
||||
let name = root
|
||||
|
||||
@@ -45,11 +45,12 @@ fn restore_cluster(ctx: &Ctx, db: &Database, restore: &dyn Cmd, file: &Path) ->
|
||||
continue;
|
||||
}
|
||||
|
||||
note!("{line}");
|
||||
note!(ctx, "{line}");
|
||||
}
|
||||
|
||||
if existing > 0 {
|
||||
note!(
|
||||
ctx,
|
||||
"left {existing} existing role{} alone",
|
||||
if existing == 1 { "" } else { "s" }
|
||||
);
|
||||
@@ -66,11 +67,15 @@ pub fn import(ctx: &Ctx, file: &Path) -> Result<()> {
|
||||
let dump = Dump::of(file)?;
|
||||
let db = Database::resolve(ctx)?;
|
||||
|
||||
note!("stopping all containers");
|
||||
Stop.run(ctx)?;
|
||||
note!(ctx, "stopping all containers");
|
||||
Stop { quiet: ctx.quiet }.run(ctx)?;
|
||||
|
||||
note!("starting db container");
|
||||
Start::service(&db.service).run(ctx)?;
|
||||
note!(ctx, "starting db container");
|
||||
Start {
|
||||
service: &db.service,
|
||||
quiet: ctx.quiet,
|
||||
}
|
||||
.run(ctx)?;
|
||||
|
||||
let remote = remote_dump();
|
||||
|
||||
@@ -121,7 +126,7 @@ pub fn import(ctx: &Ctx, file: &Path) -> Result<()> {
|
||||
let restore = db.restore_with(kind);
|
||||
// the name of what actually runs, so the message cannot drift from it
|
||||
let tool = restore.argv().program().to_string();
|
||||
note!("restoring database with {tool}");
|
||||
note!(ctx, "restoring database with {tool}");
|
||||
|
||||
when_ready(
|
||||
ctx,
|
||||
@@ -149,7 +154,7 @@ pub fn import(ctx: &Ctx, file: &Path) -> Result<()> {
|
||||
|
||||
wait_until_ready(ctx, &db)?;
|
||||
if ctx.dry_run {
|
||||
note!("would restore with {tool}");
|
||||
note!(ctx, "would restore with {tool}");
|
||||
} else {
|
||||
// a directory dump was copied in whole, so pg_restore reads it from the
|
||||
// container; every other shape is fed in on stdin, through gunzip when it
|
||||
@@ -190,9 +195,9 @@ pub fn import(ctx: &Ctx, file: &Path) -> Result<()> {
|
||||
let _ = Rm::recursive(&remote).in_container(&db.container).run(ctx);
|
||||
}
|
||||
|
||||
note!("restarting containers");
|
||||
Stop.run(ctx)?;
|
||||
Up.run(ctx)?;
|
||||
note!(ctx, "restarting containers");
|
||||
Stop { quiet: ctx.quiet }.run(ctx)?;
|
||||
Up { quiet: ctx.quiet }.run(ctx)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -208,7 +213,7 @@ pub fn dump(ctx: &Ctx, file: &Path, format: Format, gzip: bool) -> Result<()> {
|
||||
return dump_directory(ctx, &db, file);
|
||||
}
|
||||
|
||||
note!("dumping to local file {}", file.to_string_lossy());
|
||||
note!(ctx, "dumping to local file {}", file.to_string_lossy());
|
||||
|
||||
// written beside the target and renamed once the dump succeeds, so a failure
|
||||
// cannot destroy the dump that is already there
|
||||
@@ -259,7 +264,7 @@ fn dump_directory(ctx: &Ctx, db: &Database, target: &Path) -> Result<()> {
|
||||
);
|
||||
}
|
||||
|
||||
note!("dumping to local directory {}", target.display());
|
||||
note!(ctx, "dumping to local directory {}", target.display());
|
||||
let remote = remote_dump();
|
||||
|
||||
PgDump::new(&db.user, &db.name, "d")
|
||||
|
||||
@@ -2,4 +2,5 @@
|
||||
pub struct Ctx {
|
||||
pub verbose: bool,
|
||||
pub dry_run: bool,
|
||||
pub quiet: bool,
|
||||
}
|
||||
|
||||
@@ -20,12 +20,13 @@ fn main() -> ExitCode {
|
||||
let ctx = Ctx {
|
||||
verbose: args.verbose,
|
||||
dry_run: args.dry_run,
|
||||
quiet: args.quiet,
|
||||
};
|
||||
|
||||
// said once here rather than by each command, so every line that follows
|
||||
// reads as the plan it is
|
||||
if ctx.dry_run {
|
||||
note!("dry run, nothing will be changed");
|
||||
note!(ctx, "dry run, nothing will be changed");
|
||||
}
|
||||
|
||||
match run(&ctx, args.command) {
|
||||
|
||||
@@ -1,9 +1,13 @@
|
||||
// progress and warnings go to stderr, so what a caller pipes is only ever the
|
||||
// data a command was asked for
|
||||
// progress, on stderr and only when it was asked for
|
||||
macro_rules! note {
|
||||
($($arg:tt)*) => { eprintln!($($arg)*) };
|
||||
($ctx:expr, $($arg:tt)*) => {
|
||||
if !$ctx.quiet {
|
||||
eprintln!($($arg)*)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// not progress: it speaks about the result, so --quiet keeps it
|
||||
macro_rules! warning {
|
||||
($($arg:tt)*) => { eprintln!("warning: {}", format_args!($($arg)*)) };
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user