zebrad/
commands.rs

1//! Zebrad Subcommands
2
3#![allow(non_local_definitions)]
4
5use std::path::PathBuf;
6
7use abscissa_core::{config::Override, Command, Configurable, FrameworkError, Runnable};
8
9use crate::config::ZebradConfig;
10
11pub use self::{entry_point::EntryPoint, start::StartCmd};
12
13use self::{copy_state::CopyStateCmd, generate::GenerateCmd, tip_height::TipHeightCmd};
14
15pub mod start;
16
17mod copy_state;
18mod entry_point;
19mod generate;
20mod tip_height;
21
22#[cfg(test)]
23mod tests;
24
25use ZebradCmd::*;
26
27/// Zebrad Configuration Filename
28pub const CONFIG_FILE: &str = "zebrad.toml";
29
30/// Zebrad Subcommands
31#[derive(Command, Debug, clap::Subcommand)]
32pub enum ZebradCmd {
33    /// The `copy-state` subcommand, used to debug cached chain state (expert users only)
34    // TODO: hide this command from users in release builds (#3279)
35    CopyState(CopyStateCmd),
36
37    /// Generate a default `zebrad.toml` configuration
38    Generate(GenerateCmd),
39
40    /// Start the application (default command)
41    Start(StartCmd),
42
43    /// Print the tip block height of Zebra's chain state on disk
44    TipHeight(TipHeightCmd),
45}
46
47impl ZebradCmd {
48    /// Returns true if this command is a server command.
49    ///
50    /// Servers load extra components, and use the configured tracing filter.
51    ///
52    /// For example, `Start` acts as a Zcash node.
53    pub(crate) fn is_server(&self) -> bool {
54        // List all the commands, so new commands have to make a choice here
55        match self {
56            // Commands that run as a configured server
57            CopyState(_) | Start(_) => true,
58
59            // Utility commands that don't use server components
60            Generate(_) | TipHeight(_) => false,
61        }
62    }
63
64    /// Returns true if this command shows the Zebra intro logo and text.
65    ///
66    /// For example, `Start` acts as a Zcash node.
67    pub(crate) fn uses_intro(&self) -> bool {
68        // List all the commands, so new commands have to make a choice here
69        match self {
70            // Commands that need an intro
71            Start(_) => true,
72
73            // Utility commands
74            CopyState(_) | Generate(_) | TipHeight(_) => false,
75        }
76    }
77
78    /// Returns true if this command should ignore errors when
79    /// attempting to load a config file.
80    pub(crate) fn should_ignore_load_config_error(&self) -> bool {
81        matches!(self, ZebradCmd::Generate(_))
82    }
83
84    /// Returns the default log level for this command, based on the `verbose` command line flag.
85    ///
86    /// Some commands need to be quiet by default.
87    pub(crate) fn default_tracing_filter(&self, verbose: bool) -> &'static str {
88        let only_show_warnings = match self {
89            // Commands that generate quiet output by default.
90            // This output:
91            // - is used by automated tools, or
92            // - needs to be read easily.
93            Generate(_) | TipHeight(_) => true,
94
95            // Commands that generate informative logging output by default.
96            CopyState(_) | Start(_) => false,
97        };
98
99        if only_show_warnings && !verbose {
100            "warn"
101        } else if only_show_warnings || !verbose {
102            "info"
103        } else {
104            "debug"
105        }
106    }
107}
108
109impl Runnable for ZebradCmd {
110    fn run(&self) {
111        match self {
112            CopyState(cmd) => cmd.run(),
113            Generate(cmd) => cmd.run(),
114            Start(cmd) => cmd.run(),
115            TipHeight(cmd) => cmd.run(),
116        }
117    }
118}
119
120/// This trait allows you to define how application configuration is loaded.
121impl Configurable<ZebradConfig> for ZebradCmd {
122    /// Location of the configuration file
123    fn config_path(&self) -> Option<PathBuf> {
124        let if_exists = |f: PathBuf| if f.exists() { Some(f) } else { None };
125
126        dirs::preference_dir()
127            .map(|path| path.join(CONFIG_FILE))
128            .and_then(if_exists)
129
130        // Note: Changes in how configuration is loaded may need usage
131        // edits in generate.rs
132    }
133
134    /// Apply changes to the config after it's been loaded, e.g. overriding
135    /// values in a config file using command-line options.
136    ///
137    /// This can be safely deleted if you don't want to override config
138    /// settings from command-line options.
139    fn process_config(&self, config: ZebradConfig) -> Result<ZebradConfig, FrameworkError> {
140        match self {
141            ZebradCmd::Start(cmd) => cmd.override_config(config),
142            _ => Ok(config),
143        }
144    }
145}