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}