Skip to main content

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}