hyperhive/hive-forge/src/body.rs
atlas 55f01942a2 docs, prompts, hive-forge: stop handing readers the renamed verbs
docs/tools/forge.md already listed the nine renamed verbs as removed, then
used them ~30 more times in pasteable blocks. Sweeps every occurrence a
reader would type, including three runtime messages that told the user to
run a verb the same binary rejects.

The renamed-verb list itself keeps the old names; it is what documents them.

Refs #4155
2026-09-10 17:22:57 +02:00

56 lines
2 KiB
Rust

//! Body-input resolution shared by every verb that posts a body.
//! Matches the bash `resolve_body` helper: exactly one source
//! between `--body`, `--body-file`, and piped stdin. Passing both
//! `--body` and `--body-file` is a clear error.
use std::io::{IsTerminal, Read};
use anyhow::{Context, Result, bail};
/// Resolve the body to send, given the user's explicit flags and the
/// current stdin state. Returns `None` when none of the sources are
/// available (the caller decides whether that's allowed — e.g.
/// `issue edit` treats absent body as "leave unchanged", while
/// `comment` treats absent body as a hard error).
pub fn resolve(body: Option<&str>, file: Option<&str>) -> Result<Option<String>> {
if body.is_some() && file.is_some() {
bail!("hive-forge: --body and --body-file are mutually exclusive");
}
if let Some(b) = body {
return Ok(Some(b.to_owned()));
}
if let Some(path) = file {
if path == "-" {
return Ok(Some(read_stdin().context("read stdin for --body-file -")?));
}
let s =
std::fs::read_to_string(path).with_context(|| format!("read --body-file {path}"))?;
return Ok(Some(s));
}
if !std::io::stdin().is_terminal() {
return Ok(Some(read_stdin().context("read piped stdin")?));
}
Ok(None)
}
/// Resolve, then require a non-empty result (whitespace-trimmed).
/// Used by `comment` / `comment-edit` which refuse to post empty
/// bodies.
pub fn resolve_required(body: Option<&str>, file: Option<&str>, verb: &str) -> Result<String> {
let resolved = resolve(body, file)?;
let Some(s) = resolved else {
bail!(
"hive-forge {verb}: no body — pass --body <text>, --body-file <path>, or pipe via stdin"
);
};
if s.trim().is_empty() {
bail!("hive-forge {verb}: refusing to post empty body");
}
Ok(s)
}
fn read_stdin() -> std::io::Result<String> {
let mut s = String::new();
std::io::stdin().read_to_string(&mut s)?;
Ok(s)
}