# Creche
Configure, run, and monitor single child processes or entire pipelines
of processes. Redirect file descriptors to and from those processes.
Control environment variables.
Creche is an alternative to `Command` and friends in the standard library.
## Goals
- Minimal dependencies
- No macros, just regular Rust syntax
- Keep the easy stuff easy, without sacrificing configurability
## Limitations
- Linux only
- Doesn't support `nostd`
- Doesn't handle child process priveleges/capabilities yet
- No async support yet
## How to Use
The `ChildBuilder` and `SimplePipelineBuilder` types are top level
exports, so many common use cases are enabled with a simple `use`:
```rust
use creche::*;
```
Read the
[changelog](https://github.com/catnapper321/creche/blob/main/CHANGELOG.md)
for a description of breaking changes to the API.
## Examples
Read output of `cat` into a `String`:
```rust
// configure the child process
let mut cmd = ChildBuilder::new("cat");
cmd.arg("somefile")
.redirect21(); // redirect stderr to stdout
let read_fd = cmd.pipe_from_stdout();
// run it
let mut child = cmd.spawn();
// read stdout from the child process
let f = std::fs::File::from(read_fd);
let output = std::io::read_to_string(f)?;
println!("output is: {:?}", output);
println!("exit status: {:?}", child.wait());
```
Write data to a child process:
```rust
let mut cmd = creche::ChildBuilder::new("tr");
cmd.arg("[:lower:]")
.arg("[:upper:]");
let write_fd = cmd.pipe_to_stdin();
let child = cmd.spawn();
// write some data
let mut f = std::fs::File::from(write_fd);
writeln!(f, "this is a test message");
// don't forget to close your fd. Or at least .flush() the thing.
drop(f);
println!("child exit: {:?}", child.wait());
```
Set up [fzf](https://github.com/junegunn/fzf) to run in an environment
with just PATH, HOME, and FZF_DEFAULT_COMMAND. Then run it and get its
output:
```rust
// configure the environment
let mut env = envconfig::EnvironmentBuilder::new();
env.keep("PATH")
.set("HOME", "/etc")
// Note: $HOME is expanded in the shell spawned by fzf.
// It's not creche magic.
.set("FZF_DEFAULT_COMMAND", "ls -1 $HOME");
// configure the child process
let mut cmd = ChildBuilder::new("fzf");
cmd.arg("-m")
.arg(r#"--preview=bat $HOME/{}"#)
.set_env(env.realize());
let read_fd = cmd.pipe_from_stdout();
// run it
let child = cmd.spawn();
// read the result
let mut f = std::fs::File::from(read_fd);
let output = std::io::read_to_string(f)?;
println!("output is: {:?}", output);
println!("exit status: {:?}", child.wait());
```
Pipe the output of `ls` into `sort` into `tr`. Redirect stderr for all of that to /dev/null:
```rust
let mut ls_cmd = ChildBuilder::new("ls");
ls_cmd.arg("-1");
let mut sort_cmd = ChildBuilder::new("sort");
sort_cmd.arg("-r");
let mut tr_cmd = ChildBuilder::new("tr");
tr_cmd.arg("[:lower:]");
tr_cmd.arg("[:upper:]");
let mut pipeline = SimplePipelineBuilder::new();
let mut children = pipeline
.add_builder(ls_cmd)
.add_builder(sort_cmd)
.add_builder(tr_cmd)
.quiet()
.spawn();
println!("{:?}", children.wait());
```
Block on `.wait()`ing a child process and send a SIGTERM from another thread:
```rust
// sleep for a few seconds
let mut cmd = ChildBuilder::new("sleep");
cmd.arg("6");
println!("sleeping for six seconds");
let child = cmd.spawn();
// get a "handle" to the child process so that we may signal it
let handle = child.get_handle();
// start a thread that sends SIGTERM after a short pause
println!("sending SIGTERM from thread");
_ = handle.terminate();
});
// collect the child exit status
println!("child exit: {:?}", child.wait());
```