Merge pull request #1451

CLI: finish file output after stdout closes
This commit is contained in:
Brandon Thomas
2026-10-30 15:58:53 -04:00
4 changed files with 136 additions and 6 deletions
+4 -1
View File
@@ -180,7 +180,10 @@ A presentation is edited by running commands on it:
deckcraft-cli run --cmd 'slide.new={{\"title\":\"Q3 results\"}}' --save q3.deckcraft
`deckcraft-cli help SUBCOMMAND`, or `deckcraft-cli SUBCOMMAND --help`, explains one subcommand;
`deckcraft-cli help run` explains how to write a command.",
`deckcraft-cli help run` explains how to write a command.
If an output reader closes early, run, render, render-transition and convert continue; their exit
status reflects the work, not output delivery. Stop the process to cancel them.",
list.join("\n")
)
}
+20 -5
View File
@@ -7,23 +7,38 @@ mod automation_args;
mod help;
use std::process::ExitCode;
use std::sync::atomic::{AtomicBool, Ordering};
use deckcraft_engine::Session;
use serde_json::{Value, json};
static STDOUT_CLOSED: AtomicBool = AtomicBool::new(false);
macro_rules! outln {
($($arg:tt)*) => {{
use std::io::Write as _;
if let Err(e) = writeln!(std::io::stdout(), $($arg)*) {
if !STDOUT_CLOSED.load(Ordering::Relaxed) && let Err(e) = stdout_line(format_args!($($arg)*)) {
if e.kind() == std::io::ErrorKind::BrokenPipe {
std::process::exit(0);
STDOUT_CLOSED.store(true, Ordering::Relaxed);
} else {
eprintln!("deckcraft-cli: can't write to stdout: {e}");
std::process::exit(1);
}
eprintln!("deckcraft-cli: can't write to stdout: {e}");
std::process::exit(1);
}
}};
}
fn stdout_line(args: std::fmt::Arguments<'_>) -> std::io::Result<()> {
use std::io::Write as _;
#[cfg(unix)]
let mut stdout = {
use std::os::fd::AsFd as _;
std::fs::File::from(std::io::stdout().as_fd().try_clone_to_owned()?)
};
#[cfg(not(unix))]
let mut stdout = std::io::stdout();
stdout.write_all(format!("{args}\n").as_bytes())
}
fn main() -> ExitCode {
let args: Vec<String> = std::env::args().skip(1).collect();
let rest = args.get(1..).unwrap_or(&[]);