From e1817a6824cc1dc3b4aa7757a316b542fcd94f22 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Jane=C5=BEi=C4=8D?= Date: Tue, 8 Sep 2026 10:23:42 +0000 Subject: [PATCH] fix: fail a dump when its first pipeline stage dies --- src/scripts/postgres.rs | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/scripts/postgres.rs b/src/scripts/postgres.rs index 4a0dda2..3bb73f5 100644 --- a/src/scripts/postgres.rs +++ b/src/scripts/postgres.rs @@ -180,6 +180,13 @@ fn read_header(path: &Path) -> Result> { Ok(header) } +// a pipeline reports the last stage's status by default, so a first stage that +// dies mid-stream looks like success; not for pipelines that close the pipe +// early on purpose, where SIGPIPE would then read as failure +fn pipefail(script: &str) -> String { + format!("set -o pipefail; {script}") +} + fn piped(db: &Database, script: &str, input: &Path) -> Result { let file = File::open(input).with_context(|| format!("opening {}", input.display()))?; let mut command = CommandBuilder::docker() @@ -294,7 +301,10 @@ pub fn import(file: &Path) -> Result<()> { let kind = Kind::of(&out.stdout); - (kind, Some(format!("gunzip -c | {}", db.restore_with(kind)))) + ( + kind, + Some(pipefail(&format!("gunzip -c | {}", db.restore_with(kind)))), + ) } }; @@ -387,7 +397,7 @@ pub fn dump(file: &PathBuf, format: Format, gzip: bool) -> Result<()> { .args("exec") .arg(&db.container) .args("sh -c") - .arg(format!("{} | gzip", dump_command(&db, format))) + .arg(pipefail(&format!("{} | gzip", dump_command(&db, format)))) .exec_redirect_stdout(stdout) } else { let dumping = match format.flag() {