fix: stop --dry-run from writing to the working tree
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
use super::{Django, Link, Postgres};
|
||||
use clap::builder::styling::{AnsiColor, Effects, Styles};
|
||||
use clap::{Parser, Subcommand};
|
||||
use clap::error::ErrorKind;
|
||||
use clap::{CommandFactory, Parser, Subcommand};
|
||||
use clap_complete::Shell;
|
||||
|
||||
/// A program for interacting with various dockerized applications
|
||||
@@ -55,13 +56,63 @@ fn help_styles() -> Styles {
|
||||
.placeholder(AnsiColor::Cyan.on_default())
|
||||
}
|
||||
|
||||
/// Exit with a usage error when `--dry-run` would be a lie
|
||||
pub fn reject_unsupported_dry_run(command: &Commands) {
|
||||
if let Some(name) = writes_locally(command) {
|
||||
Ahab::command()
|
||||
.error(
|
||||
ErrorKind::ArgumentConflict,
|
||||
format!("--dry-run is not supported by `{name}`, which writes to the working tree"),
|
||||
)
|
||||
.exit()
|
||||
}
|
||||
}
|
||||
|
||||
// TODO:(@janezicmatej) honour --dry-run in these commands instead of refusing it
|
||||
fn writes_locally(command: &Commands) -> Option<&'static str> {
|
||||
match command {
|
||||
Commands::Link { command } => match command {
|
||||
Link::Add { .. } => Some("link add"),
|
||||
Link::Restore { .. } => Some("link restore"),
|
||||
Link::Check { .. } => None,
|
||||
},
|
||||
Commands::Django { command } => match command {
|
||||
Django::MakeCommand { .. } => Some("django make-command"),
|
||||
_ => None,
|
||||
},
|
||||
Commands::Postgres { .. } | Commands::Completions { .. } => None,
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::Ahab;
|
||||
use clap::CommandFactory;
|
||||
use clap::{CommandFactory, Parser};
|
||||
|
||||
#[test]
|
||||
fn the_command_is_well_formed() {
|
||||
Ahab::command().debug_assert();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn dry_run_is_refused_only_where_it_cannot_be_honoured() {
|
||||
let command = |args: &[&str]| Ahab::try_parse_from(args).unwrap().command;
|
||||
|
||||
assert_eq!(
|
||||
super::writes_locally(&command(&["ahab", "link", "add", ".env"])),
|
||||
Some("link add")
|
||||
);
|
||||
assert_eq!(
|
||||
super::writes_locally(&command(&["ahab", "django", "make-command", "app", "name"])),
|
||||
Some("django make-command")
|
||||
);
|
||||
assert_eq!(
|
||||
super::writes_locally(&command(&["ahab", "link", "check"])),
|
||||
None
|
||||
);
|
||||
assert_eq!(
|
||||
super::writes_locally(&command(&["ahab", "postgres", "dump", "out.sql"])),
|
||||
None
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ mod django;
|
||||
mod link;
|
||||
mod postgres;
|
||||
|
||||
pub use ahab::{Ahab, Commands};
|
||||
pub use ahab::{Ahab, Commands, reject_unsupported_dry_run};
|
||||
pub use django::Django;
|
||||
pub use link::{Link, Store};
|
||||
pub use postgres::{Format, Postgres};
|
||||
|
||||
@@ -13,6 +13,10 @@ fn main() -> ExitCode {
|
||||
dry_run: args.dry_run,
|
||||
});
|
||||
|
||||
if args.dry_run {
|
||||
cli::reject_unsupported_dry_run(&args.command);
|
||||
}
|
||||
|
||||
match run(args.command) {
|
||||
Ok(code) => code,
|
||||
Err(e) => {
|
||||
|
||||
@@ -387,9 +387,14 @@ pub fn dump(file: &PathBuf, format: Format, gzip: bool) -> Result<()> {
|
||||
// written beside the target and renamed once the dump succeeds, so a failure
|
||||
// cannot destroy the dump that is already there
|
||||
let partial = suffixed(file, ".partial");
|
||||
let stdout = Stdio::from(
|
||||
// a dry run produces no dump, so it must not lay a hand on the target either
|
||||
let stdout = if command_builder::is_dry_run() {
|
||||
Stdio::null()
|
||||
} else {
|
||||
Stdio::from(
|
||||
File::create(&partial).with_context(|| format!("creating {}", partial.display()))?,
|
||||
);
|
||||
)
|
||||
};
|
||||
|
||||
let dumped = if gzip {
|
||||
// the whole pipeline has to arrive as one shell argument
|
||||
@@ -417,6 +422,10 @@ pub fn dump(file: &PathBuf, format: Format, gzip: bool) -> Result<()> {
|
||||
return Err(e);
|
||||
}
|
||||
|
||||
if command_builder::is_dry_run() {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
fs::rename(&partial, file)
|
||||
.with_context(|| format!("renaming {} to {}", partial.display(), file.display()))?;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user