cli/main: refactor external command

Refactors the external command logic into a struct.

This allows for methods to maitain the logic of an external command.
It also allows for a cleaner output for the executable name – avoiding the debug
output of OsString using `""`.
This commit is contained in:
Fintan Halpenny 2025-10-29 13:29:56 +00:00 committed by Lorenz Leutgeb
parent f60922d125
commit 83f26abaa0
1 changed files with 56 additions and 26 deletions

View File

@ -1,4 +1,5 @@
use std::ffi::OsString;
use std::fmt::Display;
use std::io;
use std::io::Write;
use std::{io::ErrorKind, process};
@ -175,32 +176,62 @@ fn run_command(command: Command, ctx: impl term::Context) -> Result<(), anyhow::
Command::Unseed(args) => unseed::run(args, ctx),
Command::Watch(args) => watch::run(args, ctx),
Command::Version { json } => write_version(json),
Command::External(mut args) => {
let exe = args.remove(0);
Command::External(args) => ExternalCommand::new(args).run(),
}
}
struct ExternalCommand {
command: OsString,
args: Vec<OsString>,
}
impl ExternalCommand {
fn new(mut args: Vec<OsString>) -> Self {
let command = args.remove(0);
Self { command, args }
}
fn is_diff(&self) -> bool {
self.command == "diff"
}
fn exe(&self) -> OsString {
let mut exe = OsString::from(NAME);
exe.push("-");
exe.push(self.command.clone());
exe
}
fn display_exe(&self) -> impl Display {
match self.exe().into_string() {
Ok(exe) => exe,
Err(exe) => format!("{exe:?}"),
}
}
fn run(self) -> anyhow::Result<()> {
// This command is deprecated and delegates to `git diff`.
// Even before it was deprecated, it was not printed by
// `rad -h`.
//
// Since it is external, `--help` will delegate to `git diff --help`.
if exe == "diff" {
return diff::run(args);
if self.is_diff() {
return diff::run(self.args);
}
let exe = format!("{NAME}-{exe:?}");
let status = process::Command::new(&exe).args(&args).status();
let status = process::Command::new(self.exe()).args(&self.args).status();
match status {
Ok(status) => {
if !status.success() {
return Err(anyhow!("`{exe}` exited with an error."));
return Err(anyhow!("`{}` exited with an error.", self.display_exe()));
}
Ok(())
}
Err(err) => {
if let ErrorKind::NotFound = err.kind() {
Err(anyhow!(
"`{exe}` is not a command. See `rad --help` for a list of commands.",
"`{}` is not a known command. See `rad --help` for a list of commands.",
self.display_exe(),
))
} else {
Err(err.into())
@ -209,4 +240,3 @@ fn run_command(command: Command, ctx: impl term::Context) -> Result<(), anyhow::
}
}
}
}