Skip to main content

cdk_mintd/
cli.rs

1use std::path::PathBuf;
2
3use clap::{Args, Parser, Subcommand};
4
5#[derive(Debug, Parser)]
6#[command(about = "A cashu mint written in rust", author = env!("CARGO_PKG_AUTHORS"), version = env!("CARGO_PKG_VERSION"))]
7pub struct CLIArgs {
8    #[arg(
9        short,
10        long,
11        help = "Use the <directory> as the location of the database",
12        required = false
13    )]
14    pub work_dir: Option<PathBuf>,
15    #[cfg(feature = "sqlcipher")]
16    #[arg(
17        short,
18        long,
19        global = true,
20        help = "Database password for SQLCipher (required when opening an encrypted database)"
21    )]
22    pub password: Option<String>,
23    #[arg(
24        short,
25        long,
26        global = true,
27        help = "Legacy startup flag; use `config init` or `config apply` instead",
28        required = false
29    )]
30    pub config: Option<PathBuf>,
31    #[arg(
32        long,
33        global = true,
34        help = "Legacy seed file; accepted only by `config migrate`",
35        required = false
36    )]
37    pub seed_file: Option<PathBuf>,
38    #[arg(
39        long,
40        help = "Enable logging output",
41        required = false,
42        action = clap::ArgAction::SetTrue,
43        default_value = "true"
44    )]
45    pub enable_logging: bool,
46    #[command(subcommand)]
47    pub command: Option<Commands>,
48}
49
50/// Commands exposed by the `cdk-mintd` binary.
51#[derive(Debug, Subcommand)]
52pub enum Commands {
53    /// Manage the database-backed mintd configuration.
54    Config(ConfigArgs),
55}
56
57/// Arguments for database-backed configuration management.
58#[derive(Debug, Args)]
59pub struct ConfigArgs {
60    #[command(subcommand)]
61    pub command: ConfigCommands,
62}
63
64/// Database-backed configuration operations.
65#[derive(Debug, Subcommand)]
66pub enum ConfigCommands {
67    /// Convert a legacy TOML plus environment overrides into an import document.
68    Migrate(MigrateConfigArgs),
69    /// Initialize an unconfigured database from a TOML document.
70    Init(ConfigFileArgs),
71    /// Validate a TOML document without changing the database.
72    Validate(ConfigFileArgs),
73    /// Replace the configuration used by the next mintd start.
74    Apply(ApplyConfigArgs),
75    /// Restore the last configuration known to have been applied.
76    Rollback,
77    /// Print the stored configuration document.
78    Show,
79    /// Export the stored configuration document.
80    Export(ExportConfigArgs),
81}
82
83/// Arguments for migrating a legacy configuration.
84#[derive(Debug, Args)]
85pub struct MigrateConfigArgs {
86    /// Legacy TOML document to read.
87    #[arg(long)]
88    pub file: PathBuf,
89    /// Migrated TOML document to write.
90    #[arg(long)]
91    pub output: PathBuf,
92    /// Directory for literal secrets extracted from the legacy TOML.
93    #[arg(long)]
94    pub secrets_dir: Option<PathBuf>,
95    /// Overwrite generated output and secret files.
96    #[arg(long)]
97    pub force: bool,
98}
99
100/// Arguments containing a configuration document path.
101#[derive(Debug, Args)]
102pub struct ConfigFileArgs {
103    /// TOML document to read or write.
104    #[arg(long)]
105    pub file: PathBuf,
106}
107
108/// Arguments for exporting the stored configuration.
109#[derive(Debug, Args)]
110pub struct ExportConfigArgs {
111    /// TOML document to write.
112    #[arg(long)]
113    pub file: PathBuf,
114    /// Overwrite the destination if it already exists.
115    #[arg(long)]
116    pub force: bool,
117}
118
119/// Arguments for replacing the stored configuration.
120#[derive(Debug, Args)]
121pub struct ApplyConfigArgs {
122    /// TOML document to validate and store.
123    #[arg(long)]
124    pub file: PathBuf,
125    /// Validate the document and persisted constraints without writing it.
126    #[arg(long)]
127    pub validate_only: bool,
128}
129
130#[cfg(test)]
131mod tests {
132    use super::*;
133
134    #[test]
135    fn parses_configuration_commands() {
136        for command in ["init", "validate"] {
137            CLIArgs::try_parse_from(["cdk-mintd", "config", command, "--file", "/tmp/mint.toml"])
138                .expect("configuration command should parse");
139        }
140
141        let args =
142            CLIArgs::try_parse_from(["cdk-mintd", "config", "export", "--file", "/tmp/mint.toml"])
143                .expect("configuration export should parse");
144        assert!(matches!(
145            args.command,
146            Some(Commands::Config(ConfigArgs {
147                command: ConfigCommands::Export(ExportConfigArgs { force: false, .. }),
148            }))
149        ));
150
151        let args = CLIArgs::try_parse_from([
152            "cdk-mintd",
153            "config",
154            "export",
155            "--file",
156            "/tmp/mint.toml",
157            "--force",
158        ])
159        .expect("configuration export should parse");
160        assert!(matches!(
161            args.command,
162            Some(Commands::Config(ConfigArgs {
163                command: ConfigCommands::Export(ExportConfigArgs { force: true, .. }),
164            }))
165        ));
166
167        CLIArgs::try_parse_from([
168            "cdk-mintd",
169            "config",
170            "apply",
171            "--file",
172            "/tmp/mint.toml",
173            "--validate-only",
174        ])
175        .expect("configuration apply should parse");
176        CLIArgs::try_parse_from(["cdk-mintd", "config", "show"])
177            .expect("configuration show should parse");
178        CLIArgs::try_parse_from(["cdk-mintd", "config", "rollback"])
179            .expect("configuration rollback should parse");
180
181        let args = CLIArgs::try_parse_from([
182            "cdk-mintd",
183            "config",
184            "migrate",
185            "--file",
186            "/tmp/legacy.toml",
187            "--output",
188            "/tmp/migrated.toml",
189            "--secrets-dir",
190            "/tmp/mint-secrets",
191        ])
192        .expect("configuration migration should parse");
193        assert!(matches!(
194            args.command,
195            Some(Commands::Config(ConfigArgs {
196                command: ConfigCommands::Migrate(MigrateConfigArgs { force: false, .. }),
197            }))
198        ));
199
200        let args = CLIArgs::try_parse_from([
201            "cdk-mintd",
202            "--seed-file",
203            "/tmp/seed.txt",
204            "config",
205            "migrate",
206            "--file",
207            "/tmp/legacy.toml",
208            "--output",
209            "/tmp/migrated.toml",
210        ])
211        .expect("legacy seed-file migration should parse");
212        assert_eq!(args.seed_file, Some(PathBuf::from("/tmp/seed.txt")));
213    }
214
215    #[test]
216    fn no_subcommand_still_parses_daemon_startup() {
217        let args = CLIArgs::try_parse_from(["cdk-mintd"]).expect("daemon arguments should parse");
218        assert!(args.command.is_none());
219    }
220}