# 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.
```rust
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.
```rust
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:
```txt
[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`
```rust
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:
```txt
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:
```rust
use command_ext::CommandExtWrap;