Crate cradle[−][src]
Expand description
(cradle
is in an early stage of development.
APIs may change drastically!
Use at your own risk!)
cradle
provides the run!
macro, that makes
it easy to run child processes from rust programs.
use cradle::prelude::*;
use std::path::Path;
run!(%"touch foo");
assert!(Path::new("foo").is_file());
Input
You can pass in multiple arguments (of different types) to run!
to specify arguments, as long as they implement the Input
trait:
use cradle::prelude::*;
use std::path::Path;
run!("mkdir", "-p", "foo/bar/baz");
assert!(Path::new("foo/bar/baz").is_dir());
For all possible inputs to run!
, see the documentation of Input
.
Output
cradle
also provides a run_output!
macro.
It allows to capture outputs of the child process.
It uses return-type polymorphism, so you can control which outputs
are captured by choosing the return type of run_output!
.
The only constraint is that the chosen return type has to implement Output
.
For example you can use e.g. StdoutTrimmed
to collect what the child process writes to stdout
,
trimmed of leading and trailing whitespace:
use cradle::prelude::*;
let StdoutTrimmed(output) = run_output!(%"echo foo");
assert_eq!(output, "foo");
(By default, the child’s stdout
is written to the parent’s stdout
.
Using StdoutTrimmed
as the return type suppresses that.)
If you don’t want any result from run_output!
, you can use ()
as the return value:
use cradle::prelude::*;
let () = run_output!(%"touch foo");
Since that’s a very common case, cradle
provides the run!
shortcut,
that we’ve already seen above.
It behaves exactly like run_output!
but always returns ()
:
use cradle::prelude::*;
run!(%"touch foo");
See the implementations for output::Output
for all the supported types.
Whitespace Splitting of Inputs
cradle
does not split given string arguments on whitespace by default.
So for example this code fails:
use cradle::prelude::*;
let StdoutTrimmed(_) = run_output!("echo foo");
In this code cradle
tries to run a process from an executable called
"echo foo"
, including the space in the file name of the executable.
That fails, because an executable with that name doesn’t exist.
cradle
provides a new-type wrapper Split
to help with that:
use cradle::prelude::*;
let StdoutTrimmed(output) = run_output!(Split("echo foo"));
assert_eq!(output, "foo");
Wrapping an argument of type &str
in Split
will cause cradle
to first
split it by whitespace and then use the resulting words as if they were passed
into run_output!
as separate arguments.
And – since this is such a common case – cradle
provides a syntactic shortcut
for Split
, the %
symbol:
use cradle::prelude::*;
let StdoutTrimmed(output) = run_output!(%"echo foo");
assert_eq!(output, "foo");
Error Handling
tl;dr: run!
and run_output!
will panic on errors,
run_result!
will not.
Panicking
By default run!
and run_output!
panic when something goes wrong,
for example when the executable cannot be found or
when a child process exits with a non-zero exit code.
This is by design to allow cradle
to be used in contexts
where more complex error handling is not needed or desired,
for example in scripts.
use cradle::prelude::*;
// panics with "false:\n exited with exit code: 1"
run!("false");
For a full list of reasons why run!
and run_output!
may panic,
see the documentation of cradle
’s Error
type.
Preventing Panics
You can also turn all panics into std::result::Result::Err
s
by using run_result!
. This will return a value of type
Result<T, cradle::Error>
, where
T
is any type that implements output::Output
.
Here’s some examples:
use cradle::prelude::*;
let result: Result<(), cradle::Error> = run_result!("false");
let error_message = format!("{}", result.unwrap_err());
assert_eq!(
error_message,
"false:\n exited with exit code: 1"
);
let result = run_result!(%"echo foo");
let StdoutTrimmed(output) = result.unwrap();
assert_eq!(output, "foo".to_string());
run_result!
can also be combined with ?
to handle errors in an
idiomatic way, for example:
use cradle::prelude::*;
fn build() -> Result<(), Error> {
run_result!(%"which make")?;
run_result!(%"which gcc")?;
run_result!(%"which ld")?;
run_result!(%"make build")?;
Ok(())
}
If you don’t want to prevent all panics,
but just panics caused by non-zero exit codes,
you can use Status
.
Alternative Interface: Methods on input::Input
cradle
also provides an alternative interface to execute commands
through methods on the Input
trait:
.run()
, .run_output()
and .run_result()
.
These methods can be invoked on all values whose types implement
Input
.
When using these methods, it’s especially useful that
Input
is implemented by tuples.
They work analog to run!
, run_output!
and run_result!
.
Here are some examples:
use cradle::prelude::*;
("touch", "foo").run();
let StdoutTrimmed(output) = ("echo", "foo").run_output();
assert_eq!(output, "foo");
let result: Result<(), cradle::Error> = "false".run_result();
let error_message = format!("{}", result.unwrap_err());
assert_eq!(
error_message,
"false:\n exited with exit code: 1"
);
Note: The %
shortcut for Split
is not available in this notation.
You can either use tuples, or Split
explicitly:
use cradle::prelude::*;
("echo", "foo").run();
Split("echo foo").run();
Prior Art
cradle
is heavily inspired by shake,
specifically by its
cmd
function.
Re-exports
pub use crate::error::Error;
pub use crate::input::CurrentDir;
pub use crate::input::Env;
pub use crate::input::Input;
pub use crate::input::LogCommand;
pub use crate::input::Split;
pub use crate::input::Stdin;
pub use crate::output::Output;
pub use crate::output::Status;
pub use crate::output::Stderr;
pub use crate::output::StdoutTrimmed;
pub use crate::output::StdoutUntrimmed;
Modules
The Error
type used in the return type of run_result!
.
The Input
trait that defines all possible inputs to a child process.
The Output
trait that defines all possible outputs of a child process.
cradle
’s prelude
module.
It re-exports the most commonly used items from cradle.
We recommend importing cradle like this:
use cradle::prelude::*;
Macros
Executes a child process without capturing any output.
Execute child processes, and capture some output. For example you can capture what the child process writes to stdout:
Like run_output!
, but fixes the return type to Result<T, Error>
,
where T
is any type that implements Output
.