cli: Handle broken pipe in `cob show`

When piping the output in for eg. `head -n 1`, the `head` utility
might close down the pipe at some point, yielding a broken pipe error.
We catch that and simply return if that's the case.
This commit is contained in:
cloudhead 2024-12-03 12:36:57 +01:00
parent 7616dcb793
commit 5fe3d5a7ab
No known key found for this signature in database
1 changed files with 56 additions and 30 deletions

View File

@ -1,4 +1,6 @@
use std::ffi::OsString; use std::ffi::OsString;
use std::io;
use std::io::Write;
use std::str::FromStr; use std::str::FromStr;
use anyhow::anyhow; use anyhow::anyhow;
@ -10,7 +12,9 @@ use radicle::identity::Identity;
use radicle::issue::cache::Issues; use radicle::issue::cache::Issues;
use radicle::patch::cache::Patches; use radicle::patch::cache::Patches;
use radicle::prelude::RepoId; use radicle::prelude::RepoId;
use radicle::storage::git;
use radicle::storage::ReadStorage; use radicle::storage::ReadStorage;
use radicle::Profile;
use radicle_cob::object::collaboration::list; use radicle_cob::object::collaboration::list;
use serde_json::json; use serde_json::json;
@ -227,41 +231,63 @@ pub fn run(options: Options, ctx: impl term::Context) -> anyhow::Result<()> {
} => { } => {
let repo = storage.repository(repo)?; let repo = storage.repository(repo)?;
match show(revs, &repo, type_name, &profile) {
Err(e) => {
if let Some(err) = e.downcast_ref::<io::Error>() {
if err.kind() == io::ErrorKind::BrokenPipe {
return Ok(());
}
}
return Err(e);
}
Ok(()) => {}
}
}
}
Ok(())
}
fn show(
revs: Vec<Rev>,
repo: &git::Repository,
type_name: cob::TypeName,
profile: &Profile,
) -> Result<(), anyhow::Error> {
let mut stdout = std::io::stdout();
if type_name == cob::patch::TYPENAME.clone() { if type_name == cob::patch::TYPENAME.clone() {
let patches = term::cob::patches(&profile, &repo)?; let patches = term::cob::patches(&profile, repo)?;
for oid in revs { for oid in revs {
let oid = &oid.resolve(&repo.backend)?; let oid = &oid.resolve(&repo.backend)?;
let Some(patch) = patches.get(oid)? else { let Some(patch) = patches.get(oid)? else {
anyhow::bail!(cob::store::Error::NotFound(type_name, *oid)) anyhow::bail!(cob::store::Error::NotFound(type_name, *oid));
}; };
serde_json::to_writer(std::io::stdout(), &patch)?; serde_json::to_writer(&stdout, &patch)?;
println!() stdout.write_all(b"\n")?;
} }
} else if type_name == cob::issue::TYPENAME.clone() { } else if type_name == cob::issue::TYPENAME.clone() {
let issues = term::cob::issues(&profile, &repo)?; let issues = term::cob::issues(&profile, repo)?;
for oid in revs { for oid in revs {
let oid = &oid.resolve(&repo.backend)?; let oid = &oid.resolve(&repo.backend)?;
let Some(issue) = issues.get(oid)? else { let Some(issue) = issues.get(oid)? else {
anyhow::bail!(cob::store::Error::NotFound(type_name, *oid)) anyhow::bail!(cob::store::Error::NotFound(type_name, *oid))
}; };
serde_json::to_writer(std::io::stdout(), &issue)?; serde_json::to_writer(&stdout, &issue)?;
println!() stdout.write_all(b"\n")?;
} }
} else if type_name == cob::identity::TYPENAME.clone() { } else if type_name == cob::identity::TYPENAME.clone() {
for oid in revs { for oid in revs {
let oid = &oid.resolve(&repo.backend)?; let oid = &oid.resolve(&repo.backend)?;
let Some(cob) = cob::get::<Identity, _>(&repo, &type_name, oid)? else { let Some(cob) = cob::get::<Identity, _>(repo, &type_name, oid)? else {
anyhow::bail!(cob::store::Error::NotFound(type_name, *oid)) anyhow::bail!(cob::store::Error::NotFound(type_name, *oid));
}; };
serde_json::to_writer(std::io::stdout(), &cob.object)?; serde_json::to_writer(&stdout, &cob.object)?;
println!() stdout.write_all(b"\n")?;
} }
} else { } else {
anyhow::bail!("the type name '{type_name}' is unknown"); anyhow::bail!("the type name '{type_name}' is unknown");
} }
}
}
Ok(()) Ok(())
} }