fs_core/cli/family.rs
1//! How a driver describes its tools to the shared plumbing.
2
3use clap::{ArgMatches, Command as Cmd};
4
5use super::output::{CliError, Outcome};
6
7/// One dotted name, and the program behind it.
8pub struct Tool {
9 /// The name it is installed and invoked under: `mkfs.<fs>`.
10 pub name: &'static str,
11 /// The word that selects it after the repository name:
12 /// `rust-fs-<fs> mkfs ...`.
13 pub verb: &'static str,
14 /// Its manual section: 8 for `mkfs.*` and `fsck.*`, 1 otherwise.
15 pub section: u8,
16 /// One line for the repository's help.
17 pub about: &'static str,
18 /// The exit status of a wrong command line: 2 by the shared contract,
19 /// but a tool whose name promises another scheme keeps that scheme's
20 /// (`fsck.*` answers 16, as fsck(8) documents, because 2 there means
21 /// "reboot").
22 pub usage_exit: u8,
23 /// Its arguments. The name and version are set by the caller.
24 pub command: fn() -> Cmd,
25 /// Run it. `Ok` is printed on stdout in the format asked for; `Err`
26 /// as a structured error on stderr, with its code as the exit status.
27 pub run: fn(&ArgMatches) -> Result<Outcome, CliError>,
28}
29
30/// Everything a repository says about itself, once.
31pub struct Family {
32 /// The repository name, which is also the multi-call binary's own
33 /// name and the one entry point nothing else installs.
34 pub repo: &'static str,
35 /// The crate the binary is built from, as `--version` names it.
36 pub crate_name: &'static str,
37 /// The crate's version.
38 pub version: &'static str,
39 /// One line for the repository-named entry point's help.
40 pub about: &'static str,
41 /// How a missing tool gets installed, most specific first. `doctor`
42 /// and the test suites print these when a name does not resolve.
43 pub install_hints: &'static [&'static str],
44 /// Every dotted name, in the order help lists them.
45 pub tools: &'static [Tool],
46}
47
48impl Family {
49 /// The tool installed under `name`.
50 pub fn by_name(&self, name: &str) -> Option<&Tool> {
51 self.tools.iter().find(|tool| tool.name == name)
52 }
53
54 /// The tool a word after the repository name selects: its verb or its
55 /// full dotted name.
56 pub fn by_word(&self, word: &str) -> Option<&Tool> {
57 self.tools
58 .iter()
59 .find(|tool| tool.verb == word || tool.name == word)
60 }
61}