Expand description
§rituals
What a ritual task is, and how a composed command line dispatches to one. This is the only crate a task author depends on.
§A task crate
A task is an ordinary library crate. Its manifest depends on rituals and
marks the crate as a task:
[package]
name = "hello"
version = "0.1.0"
edition = "2024"
[dependencies]
rituals = "0.2"
[package.metadata.ritual]
task = trueIts library exposes one function, task(), built from a clap argument
struct and the function that runs it:
use rituals::{Outcome, Task, clap, report};
/// What this task accepts on the command line.
#[derive(clap::Args)]
struct Arguments {
/// who to greet
who: String,
}
fn run(arguments: Arguments) -> Outcome {
report(format!("hello, {}", arguments.who));
Ok(())
}
#[must_use]
pub fn task() -> Task {
Task::new("say hello to somebody", run)
}The first argument to Task::new is the one-line description --help
shows, whatever the arguments struct’s doc comment says, and not the task’s
name. A task never names itself: the command it
answers to is the dependency key of whichever project imports it.
report writes one line to stdout, where a caller reads results; warn writes
one to stderr, for something the person should heed that is not the result.
Arguments are ordinary clap, re-exported as rituals::clap, so a task crate
needs no parser dependency of its own.
§Refusing
A task that cannot do its job returns a Failure. The command line prints
it after its own name and exits with status 1, unless the task chose another:
use std::path::PathBuf;
use rituals::{Failure, Outcome, clap, report};
#[derive(clap::Args)]
struct Arguments {
/// the file to count lines in
path: PathBuf,
}
fn run(arguments: Arguments) -> Outcome {
let text = std::fs::read_to_string(&arguments.path).map_err(|error| {
Failure::new(format!("reading {} failed", arguments.path.display())).caused_by(error)
})?;
report(format!("{} lines", text.lines().count()));
Ok(())
}$ cargo ritual lines missing.txt
ritual: reading missing.txt failed: No such file or directory (os error 2)The line names the cause after the message, then the cause’s own
source(), and so on down the chain, each joined with : . A Failure
follows the usual convention for an error: its Display is the message
alone, and the cause is its source(). To write a Failure into text of your
own, with every cause, use failure.with_causes().
A cause whose own Display already includes its source shows that source
twice in the refusal line, as thiserror’s #[error("failed to start: {0}")] Io(#[from] io::Error) does, since #[from] makes the io error its source
too; for such an error, use Failure::new(error.to_string()) in place of
caused_by, or take the source out of the error’s message.
A task with more than one way to refuse can give each its own exit status, so a caller such as a CI job can tell “the check found differences” from “the check could not run” without reading stderr:
use rituals::{Failure, Outcome, RefusalStatus};
const COULD_NOT_RUN: RefusalStatus = match RefusalStatus::new(4) {
Ok(status) => status,
Err(_) => panic!("4 is a refusal status"),
};
fn sync() -> Outcome {
Err(Failure::new("the registry did not answer").exiting_with(COULD_NOT_RUN))
}A status is 1, or anything from 3 to 125 but 101. RefusalStatus::new
refuses 0, which is success, 2, which a usage error exits with, 101, which a
panic exits with, and 126 and above, which a shell uses for itself. When one
Failure wraps another, the outer one’s status is the one the process exits
with. new is const, so a status named as a constant, as above, is checked
when the task compiles.
§Running a task
A task runs inside a project’s command line. The ritual binary, from
rituals-cli, makes both:
cargo install --locked rituals-cli
ritual new demo
cd demo
cargo ritual create hello
cargo ritual hellocreate writes a task crate into .rituals/hello, imports it, and
regenerates the command line. Its task() is a placeholder, so
cargo ritual hello answers hello has nothing to do yet. Replace
.rituals/hello/src/lib.rs with the greeting task above, and
cargo ritual hello world answers hello, world. Run outside any project,
ritual create hello writes a task crate of its own instead, for several
projects to share; import it.
§More than one command
Task::groupbuilds a bundle: a task whose command is a group of named child tasks. A bundle is imported like any other task, and bundles nest.Task::receiving_command_linebuilds a task that is handed the command line it runs in: its name and version, the commands at its top level, the command path that reached the task (command_path()), and the command a person types to run it again (cargo_command()).
The ritual readme covers the concepts, and the design explains why ritual is shaped this way.
§What this crate provides
- For writing a task:
Task,Outcome,Failure,report(),warn(), andclap; and for a refusal that exits with a status other than 1,RefusalStatusandInvalidRefusalStatus. - For a task that needs the command line it runs in:
Task::receiving_command_line,CommandLineandIdentity. - For generated code and scaffolding tools rather than tasks:
run,identity!,Name,InvalidNameandVERSION.
Re-exports§
pub use clap;
Macros§
Structs§
- Command
Line - The composed command line a task is running inside, and where in it the task was reached.
- Failure
- A refusal: the message a person reads when a task cannot do its job.
- Identity
- The identity of the composed command line a task is running inside — not the task’s own identity, and not a person’s.
- Invalid
Name - Why a piece of text was refused as a
Name. - Invalid
Refusal Status - Why a number was refused as a
RefusalStatus. - Name
- A name checked to be safe as a command, a directory name, a Cargo package name and a Rust identifier.
- Refusal
Status - The exit status a refusal ends the process with: 1, anything from 3 to 100, or anything from 102 to 125.
- Task
- One task: a one-line description, and either the command-line arguments it declares the ordinary clap way and the function that runs them, or a group of named children.
Constants§
- VERSION
- The version of this crate, as the build that compiled it saw it.
Functions§
- report
- Writes one line to stdout, the way a task talks to the person running it.
- run
- Assembles
importedinto one command line, dispatches the process’s own arguments against it, and maps the outcome to a process exit status. - warn
- Writes one line to stderr, for something the person should heed that is not the run’s result, such as a command that is going away.