1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208
#![deny(missing_docs)]
//! Task runner and process manager for Rust.
//!
//! If you're not happy managing your infrastructure with a pile of shell scripts,
//! this crate might be helpful. It provides base building blocks for defining
//! and running various kinds of tasks.
//! It's like [`foreman`](https://github.com/ddollar/foreman) but more low-level, with Rust API
//! and more flexibility & features.
//!
//! Works great with [`clap`](https://github.com/clap-rs/clap)!
//!
//! ## Examples
//!
//! Check out runnable examples on GitHub: [`steward/examples`](https://github.com/alexfedoseev/steward/tree/master/examples).
//!
//! ```ignore
//! #[macro_use]
//! extern crate steward;
//!
//! use steward::{Cmd, Env, ProcessPool, Process};
//!
//! #[tokio::main]
//! async fn main() -> steward::Result<()> {
//! client::build_cmd().run().await?;
//! server::build_cmd().run().await?;
//!
//! ProcessPool::run(vec![client::watcher(), server::watcher()]).await?;
//!
//! Ok(())
//! }
//!
//! mod server {
//! fn build_cmd() -> Cmd {
//! cmd! {
//! exe: "cargo build",
//! env: Env::empty(),
//! pwd: Loc::root(),
//! msg: "Building a server",
//! }
//! }
//!
//! fn watcher() -> Process {
//! process! {
//! tag: "server",
//! cmd: cmd! {
//! exe: "cargo watch",
//! env: Env::empty(),
//! pwd: Loc::root(),
//! msg: "Running a reloadable server",
//! },
//! }
//! }
//! }
//!
//! mod client {
//! fn build_cmd() -> Cmd {
//! cmd! {
//! exe: "npm build",
//! env: Env::empty(),
//! pwd: Loc::root(),
//! msg: "Building a client",
//! }
//! }
//!
//! fn watcher() -> Process {
//! process! {
//! tag: "client",
//! cmd: cmd! {
//! exe: "npm watch",
//! env: Env::empty(),
//! pwd: Loc::root(),
//! msg: "Watching a client",
//! },
//! }
//! }
//! }
//! ```
//!
//! ## Limitations
//! ### Async runtimes
//! Tokio only.
/// Base building block of the crate.
///
/// ```ignore
/// async fn build() -> steward::Result<()> {
/// let build_cmd = cmd! {
/// exe: "cargo build",
/// env: Env::empty(),
/// pwd: Loc::root(),
/// msg: "Building a server",
/// };
///
/// build_cmd.run().await
/// }
/// ```
#[macro_use]
pub mod cmd;
/// Long running processes.
///
/// ```ignore
/// async fn run() -> steward::Result<()> {
/// let server_process = process! {
/// tag: "server",
/// cmd: cmd! {
/// exe: "cargo watch",
/// env: Env::empty(),
/// pwd: Loc::root(),
/// msg: "Running a reloadable server",
/// },
/// };
///
/// let client_process = process! {
/// tag: "client",
/// cmd: cmd! {
/// exe: "rescript build -w",
/// env: Env::empty(),
/// pwd: Loc::root(),
/// msg: "Watching a client",
/// },
/// };
///
/// ProcessPool::run(vec![server_process, client_process]).await
/// }
/// ```
#[macro_use]
pub mod process;
/// Dependant processes.
///
/// Sometimes, a job or a service depends on something else to function properly. For example, to generate a GraphQL
/// schema, a server must be available. Or to start a server, DB must be up and running. To handle
/// such cases, there is a [`Dependency`](crate::Dependency) trait.
///
/// Types that implement this trait are able to check if a dependency is available or to wait until
/// the dependency becomes available. For example, if some job requires a TCP service for some job:
///
/// ```ignore
/// let service = TcpService::new(...);
///
/// service.wait().await.unwrap();
///
/// // here, the service is available...
/// job.run().await;
/// ```
///
/// You can use provided [`TcpService`](crate::TcpService), [`HttpService`](crate::HttpService),
/// and [`FsEntry`](crate::FsEntry). Or implement your own
/// (you would need [`async_trait`](https://docs.rs/async-trait/latest/async_trait/)).
///
/// ## Process pool
///
/// It is also useful when you need to spawn a pool of long-running processes,
/// and some of them depend on something else to start properly,
/// such as an HTTP service being available or a file existing.
///
/// ```ignore
/// async fn run() -> steward::Result<()> {
/// server::build().run().await?;
/// client::build().run().await?;
///
/// ProcessPool::run_with_deps(vec![
/// PoolEntry::Process(server::watch()),
/// PoolEntry::ProcessWithDep {
/// process: client::watch(),
/// dependency: Box::new(HttpService {
/// tag: "server".to_string(),
/// addr: format!(
/// "http://{host}:{port}",
/// host = Config::SERVER_HOST(),
/// port = Config::SERVER_PORT()
/// )
/// .parse()
/// .unwrap(),
/// method: HttpMethod::GET,
/// timeout: Duration::from_secs(30),
/// }),
/// },
/// ])
/// .await
/// }
/// ```
pub mod dep;
/// Command environment.
pub mod env;
/// File system related types.
pub mod fs;
/// Network related types.
pub mod net;
/// [`Result`](Result) and [`Error`](Error) types of this crate.
pub mod result;
#[macro_use]
mod fmt;
mod fun;
mod loc;
pub use cmd::{Cmd, KillTimeout, SpawnOptions};
pub use dep::{Dependency, DependencyWaitError};
pub use env::Env;
pub use fs::FsEntry;
pub use fun::{run, run_mut, run_once};
pub use loc::Location;
pub use net::{HttpMethod, HttpService, TcpService};
pub use process::{PoolEntry, Process, ProcessPool, RunningProcess};
pub use result::{Error, Result};
pub(crate) use process::ExitResult;