Expand description
The command-line plumbing every tool in the family shares: dispatch on
argv[0], --version, doctor, the JSON output and the structured
error, the --json/--text switch, and the man pages and shell
completions packaging needs. Behind the cli cargo feature; the default
build, and the static library, contain none of it.
IT KNOWS NOTHING ABOUT ANY FORMAT, and must not learn. A crate describes
its tools once, as a Family — the repository name, the crate and
version, the install hints, and one Tool per dotted name, each a
clap command and a function that runs it — and hands that to main.
Everything here reads only that description.
ONE COPY, NOT ONE PER CRATE. This module began as a directory each
tool carried by hand (src/cli/common/), and the copies drifted within
weeks: one doctor learnt to drain a long --version answer while the
others still stalled on it, one entry point learnt to align its help,
and some could write man pages while others could not. Do not copy it
back out; fix it here.
THE CONTRACT IT CARRIES, so each crate fills it in rather than defining its own:
- One binary, many names. Invoked as a tool’s dotted name
(
mkfs.<fs>,fs.<fs>,img.<fmt>), it is that tool. Invoked under any other name — the repository’s (rust-fs-<fs>), or a renamed copy — the first argument names the tool, by its verb (mkfs) or its full name (mkfs.<fs>). That second form is the one nothing on PATH can shadow. --versionprints<tool> (<crate>) <version>for every name, which is howdoctorand the test suites tell our binary from another package’s program of the same name.- Output. A result is JSON on stdout by default,
--textfor people; file content is raw bytes and is never wrapped. A failure is{"error": "...", "code": N}on STDERR, andNis the exit status, so stdout carries a result or nothing — never half of one, and never an error a pipe would take for data. - Exit statuses, outside a tool that has its own scheme (
fsck’s 0/1/4/8): 0 done, 1 failed, 2 the command line was wrong, 3 the verb exists but this crate cannot do it (not implemented, or the format is read-only). A script moved between formats fails loudly on 3 instead of meaning something else. <repo> doctorresolves every dotted name on PATH and says, per name, whether the program found is ours, and if not, what wins and how to fix it.<repo> generate names|man|completions(hidden) prints the dotted names to link, and writes the man pages and shell completions, from the same clap commands the tools parse with.
use fs_core::cli::{self, CliError, Family, Json, Outcome, Tool};
use fs_core::cli::clap::{ArgMatches, Command};
fn command() -> Command {
Command::new("fs")
.about("Work on an image")
.args(cli::format_args())
.after_help("Examples:\n fs.demo disk.img")
}
fn run(_: &ArgMatches) -> Result<Outcome, CliError> {
Ok(Outcome::report(Json::object([("fs", Json::from("demo"))])))
}
static FAMILY: Family = Family {
repo: "rust-fs-demo",
crate_name: "am-fs-demo",
version: "0.1.0",
about: "Demo tools",
install_hints: &["`cargo install am-fs-demo --features cli`"],
tools: &[Tool {
name: "fs.demo",
verb: "fs",
section: 1,
about: "Work on a demo image",
usage_exit: cli::output::EXIT_USAGE,
command,
run,
}],
};
fn main() -> std::process::ExitCode {
cli::main(&FAMILY)
}Re-exports§
pub use family::Family;pub use family::Tool;pub use output::CliError;pub use output::Format;pub use output::Json;pub use output::Outcome;pub use clap;
Modules§
- dispatch
- Which tool a process is, from the name it was started under.
- docs
- Man pages and shell completions, generated from the clap commands the tools actually parse with, so the documentation cannot describe a flag a program does not take.
- doctor
<repo> doctor: is every name this repository installs, as PATH resolves it, our program?- family
- How a driver describes its tools to the shared plumbing.
- output
- What a tool prints: a JSON result by default, text on request, and a structured error on stderr whose code is the exit status.
- version
- The identifying
--versionline:<tool> (<crate>) <version>.
Structs§
- Response
- What the plumbing prints for one invocation, and the exit status, before any of it is written.
Functions§
- format_
args --jsonand--text, for any command that reports. The last one given wins, so an alias or a wrapper can add either without breaking a command line that already has the other.- main
- The whole program: work out which tool this is, parse its command line, run it and print what it returned.
- repo_
command - The repository-named entry point’s clap command: every tool as a
subcommand (so its help and its man page list them), plus
doctor. - respond
runwithout the writing: resolve, parse, run the tool, and return what would be printed.- run
mainover an explicit argument vector,argv[0]included.- tool_
command - A tool’s clap command, named and versioned for the name it runs under.