radicle-heartwood-lfs/crates/radicle-cli/src/commands
Fintan Halpenny 1a31a9f541 cli: Handle broken pipe (SIGPIPE) gracefully
Prevent `rad` from panicking when its stdout is a closed pipe, e.g.
when running `rad config | head`.

The broken pipes are handled at the output boundaries using three
layers of defence:

1. Inner: Route all stdout output through `term::print()` and
   `term::print_inline()`, which use explicit `writeln!`/`write!` to
   a locked stdout and silently ignore write errors. All `println!`
   calls in `radicle-cli` and `radicle-term` are converted.
2. Middle: Catch `BrokenPipe` errors that propagate up via `anyhow`
   from subcommands in `main::run()`, and exit cleanly with code 0.
3. Outer: Install a panic hook that intercepts `println!` panics
   containing "Broken pipe" (from dependencies like clap) and exits
   cleanly, chained in front of human_panic's hook.

To prevent regressions, `#![deny(clippy::print_stdout)]` is added to
`radicle-cli`, requiring all future stdout output to go through the
safe `term::` functions.

Note: `eprintln!` calls (stderr) are not handled, as broken stderr
pipes are extremely rare in practice.
2026-04-29 10:57:24 +02:00
..
auth cli/help: remove the help module 2025-11-01 11:20:43 +01:00
block rust/edition/fmt: 2021 → 2024 2026-03-30 16:57:51 +02:00
checkout cli/help: remove the help module 2025-11-01 11:20:43 +01:00
clean cli/help: remove the help module 2025-11-01 11:20:43 +01:00
clone rust/edition/fmt: 2021 → 2024 2026-03-30 16:57:51 +02:00
cob cli: Handle broken pipe (SIGPIPE) gracefully 2026-04-29 10:57:24 +02:00
config cli/config: Obsolete `{get,set,push,remove,unset}` 2026-04-22 15:45:57 +01:00
debug cli/help: remove the help module 2025-11-01 11:20:43 +01:00
follow cli/help: remove the help module 2025-11-01 11:20:43 +01:00
fork cli: Rename all `RepoId` args to `repo` 2026-04-17 17:09:15 +01:00
id rust/edition/fmt: 2021 → 2024 2026-03-30 16:57:51 +02:00
inbox cli/help: remove the help module 2025-11-01 11:20:43 +01:00
init cli/init: Deduplicate `ScopeParser` 2026-04-20 09:21:00 +01:00
inspect cli/help: remove the help module 2025-11-01 11:20:43 +01:00
issue cli: Fix typo "writeable" → "writable" 2026-04-16 21:01:11 +02:00
ls cli/help: remove the help module 2025-11-01 11:20:43 +01:00
node cli: Handle broken pipe (SIGPIPE) gracefully 2026-04-29 10:57:24 +02:00
patch cli: Fix typo "writeable" → "writable" 2026-04-16 21:01:11 +02:00
path cli/help: remove the help module 2025-11-01 11:20:43 +01:00
publish cli: Rename all `RepoId` args to `repo` 2026-04-17 17:09:15 +01:00
remote radicle: Prevent `RAD_SOCKET` from polluting tests 2026-04-09 17:53:49 +02:00
seed Use humantime to parse timeouts 2026-03-17 11:39:09 +00:00
self cli/help: remove the help module 2025-11-01 11:20:43 +01:00
stats cli/help: remove the help module 2025-11-01 11:20:43 +01:00
sync cli: Rename all `RepoId` args to `repo` 2026-04-17 17:09:15 +01:00
unblock cli/help: remove the help module 2025-11-01 11:20:43 +01:00
unfollow cli/help: remove the help module 2025-11-01 11:20:43 +01:00
unseed cli/help: remove the help module 2025-11-01 11:20:43 +01:00
watch Use humantime to parse timeouts 2026-03-17 11:39:09 +00:00
auth.rs Spell "Radicle" with a captial R 2026-04-17 17:15:31 +01:00
block.rs cli/help: remove the help module 2025-11-01 11:20:43 +01:00
checkout.rs clippy: Disallow unused lints 2026-04-15 10:06:05 +02:00
clean.rs cli/help: remove the help module 2025-11-01 11:20:43 +01:00
clone.rs radicle: Prevent `RAD_SOCKET` from polluting tests 2026-04-09 17:53:49 +02:00
cob.rs cli: Handle broken pipe (SIGPIPE) gracefully 2026-04-29 10:57:24 +02:00
config.rs cli/config: Obsolete `{get,set,push,remove,unset}` 2026-04-22 15:45:57 +01:00
debug.rs cli: Handle broken pipe (SIGPIPE) gracefully 2026-04-29 10:57:24 +02:00
diff.rs cli/diff: Use clap 2025-10-15 10:30:34 +02:00
follow.rs radicle: Prevent `RAD_SOCKET` from polluting tests 2026-04-09 17:53:49 +02:00
fork.rs cli: Deduplicate RID Argument Handling 2026-04-17 17:09:15 +01:00
id.rs cli: Handle broken pipe (SIGPIPE) gracefully 2026-04-29 10:57:24 +02:00
inbox.rs cli: Deduplicate RID Argument Handling 2026-04-17 17:09:15 +01:00
init.rs Spell "Radicle" with a captial R 2026-04-17 17:15:31 +01:00
inspect.rs cli: Handle broken pipe (SIGPIPE) gracefully 2026-04-29 10:57:24 +02:00
issue.rs cli: Deduplicate RID Argument Handling 2026-04-17 17:09:15 +01:00
ls.rs radicle: Have migration repair downgrades 2026-03-25 08:01:29 +00:00
node.rs cli: Handle broken pipe (SIGPIPE) gracefully 2026-04-29 10:57:24 +02:00
patch.rs cli: Deduplicate RID Argument Handling 2026-04-17 17:09:15 +01:00
path.rs cli: Handle broken pipe (SIGPIPE) gracefully 2026-04-29 10:57:24 +02:00
publish.rs cli: Deduplicate RID Argument Handling 2026-04-17 17:09:15 +01:00
remote.rs cli: Deduplicate RID Argument Handling 2026-04-17 17:09:15 +01:00
seed.rs radicle: Prevent `RAD_SOCKET` from polluting tests 2026-04-09 17:53:49 +02:00
self.rs radicle: Prevent `RAD_SOCKET` from polluting tests 2026-04-09 17:53:49 +02:00
stats.rs cli/help: remove the help module 2025-11-01 11:20:43 +01:00
sync.rs cli: Deduplicate RID Argument Handling 2026-04-17 17:09:15 +01:00
unblock.rs cli/help: remove the help module 2025-11-01 11:20:43 +01:00
unfollow.rs radicle: Prevent `RAD_SOCKET` from polluting tests 2026-04-09 17:53:49 +02:00
unseed.rs radicle: Prevent `RAD_SOCKET` from polluting tests 2026-04-09 17:53:49 +02:00
watch.rs treewide: Avoid `git2::Oid::zero` 2026-04-28 14:35:38 +02:00