3 releases
0.1.2 | Mar 1, 2024 |
---|---|
0.1.1 | Dec 13, 2023 |
0.1.0 | Dec 13, 2023 |
#329 in Debugging
139 downloads per month
Used in 8 crates
(5 directly)
61KB
1K
SLoC
CommandExt
CommandExt
is a set of convenient extension traits for std::process::Command
which
make it easier to use, particularly in cargo scripts where many commands may be executed
with different requirements for error checking, logging, and so forth.
CommandExtCheck
CommandExtCheck
allows you to check the result of a command and get a nicely packaged
error containing printable output and error streams.
use std::process::Command;
use command_ext::CommandExtCheck;
fn main() -> anyhow::Result<()> {
Command::new("echo").arg("x").check()?; // Ok!
Command::new("noexistcmd").arg("badarg").check().map_err(|e| {
// StdIoError(Os { code: 2, kind: NotFound, message: "No such file or directory" })
eprintln!("{}", e);
}).ok();
Command::new("false").check().map_err(|e| {
// Command failed with status (exit status: 1), stdout (), stderr ()
eprintln!("{}", e);
}).ok();
Ok(())
}
Usually, scripts probably will just use Command::new("cmd").args(["arg1", "arg2"]).check()?
.
CommandExtLog
CommandExtLog
allows you to add customizable logging to your commands.
use std::process::Command;
use command_ext::{CommandExtCheck, CommandExtLog};
use env_logger::Builder;
use log::{LevelFilter, Level};
fn main() -> anyhow::Result<()> {
Builder::new().filter_level(LevelFilter::max()).init();
Command::new("bash")
.args(["-c", "echo err >&2; echo ok"])
.log_args(Level::Debug)
.log_status(Level::Info)
.log_stdout(Level::Trace)
.log_stderr(Level::Warn)
.check()?;
Ok(())
}
This logs:
[2023-12-13T21:04:17Z DEBUG command_ext::log] args: bash -c echo err >&2; echo ok
[2023-12-13T21:04:17Z INFO command_ext::log] status: exit status: 0
[2023-12-13T21:04:17Z TRACE command_ext::log] stdout: ok
[2023-12-13T21:04:17Z WARN command_ext::log] stderr: err
CommandExtTrace
CommandExtTrace
works very similarly to CommandExtLog
use command_ext::{CommandExtCheck, CommandExtTrace};
use std::io::stdout;
use std::process::Command;
use tracing::{metadata::LevelFilter, Level};
use tracing_subscriber::{fmt, prelude::*, registry, Layer};
fn main() -> Result<(), Box<dyn std::error::Error>> {
registry()
.with(
fmt::layer()
.with_writer(stdout)
.with_filter(LevelFilter::TRACE),
)
.try_init()?;
Command::new("bash")
.args(["-c", "echo err >&2; echo ok"])
.trace_args(Level::DEBUG)
.trace_status(Level::INFO)
.trace_stdout(Level::TRACE)
.trace_stderr(Level::WARN)
.check()?;
Ok(())
}
This traces:
2023-12-13T21:06:31.739932Z DEBUG command_ext::trace: args: bash -c echo err >&2; echo ok
2023-12-13T21:06:31.741100Z INFO command_ext::trace: status: exit status: 0
2023-12-13T21:06:31.741138Z TRACE command_ext::trace: stdout: ok
2023-12-13T21:06:31.741147Z WARN command_ext::trace: stderr: err
CommandWrap
For other cases where you might want to hook into what Command
is doing, you can use
CommandWrap
to implement your own wrappers. For example, let's say you want to
wrap the Command
type so it prints a message when it executes:
use command_ext::CommandExtWrap;
Dependencies
~0.6–1.2MB
~24K SLoC