1use crate::project_info::{metadata, version_info};
2use clap::{Args, Parser, Subcommand};
3use std::path::PathBuf;
4
5#[derive(Args, Debug)]
7pub struct UpgradeArgs {
8 #[arg(long)]
10 pub force: bool,
11
12 #[arg(long)]
14 pub check: bool,
15}
16
17#[derive(Subcommand, Debug)]
19pub enum UpgradeSubcommand {
20 Download {
22 #[arg(long, hide = true)]
24 full: bool,
25 },
26 Check {
28 #[arg(long)]
30 force: bool,
31 },
32}
33
34#[derive(Subcommand, Debug)]
36pub enum AutoBackupCommand {
37 Run,
39 Status,
41}
42
43#[derive(Subcommand, Debug)]
45pub enum AutoUpgradeDeployCommand {
46 Run {
48 #[arg(
50 long,
51 help = "Specify frontend service port, corresponds to FRONTEND_HOST_PORT variable in docker-compose.yml (default: port 80)"
52 )]
53 port: Option<u16>,
54 #[arg(
56 long,
57 help = "Specify custom docker-compose config file path (default: docker/docker-compose.yml)"
58 )]
59 config: Option<PathBuf>,
60 #[arg(
62 short = 'p',
63 long,
64 help = "Specify docker-compose project name (default: read from compose file or use 'docker')"
65 )]
66 project: Option<String>,
67 },
68 Status,
70 OfflineDeploy {
72 #[arg(long, help = "Path to local archive file")]
74 archive: PathBuf,
75 #[arg(long, help = "Target version for deployment")]
77 version: String,
78 #[arg(long)]
80 port: Option<u16>,
81 #[arg(long)]
83 config: Option<PathBuf>,
84 #[arg(short = 'p', long)]
86 project: Option<String>,
87 },
88}
89
90#[derive(Subcommand, Debug)]
92pub enum CheckUpdateCommand {
93 Check,
95 Install {
97 #[arg(long)]
99 version: Option<String>,
100 #[arg(long)]
102 force: bool,
103 },
104}
105
106#[derive(Subcommand, Debug)]
107pub enum DockerServiceCommand {
108 Start {
110 #[arg(
112 short = 'p',
113 long,
114 help = "Specify docker-compose project name (default: read from compose file or use 'docker')"
115 )]
116 project: Option<String>,
117 },
118 Stop {
120 #[arg(
122 short = 'p',
123 long,
124 help = "Specify docker-compose project name (default: read from compose file or use 'docker')"
125 )]
126 project: Option<String>,
127 },
128 Restart {
130 #[arg(
132 short = 'p',
133 long,
134 help = "Specify docker-compose project name (default: read from compose file or use 'docker')"
135 )]
136 project: Option<String>,
137 },
138 Status {
140 #[arg(
142 short = 'p',
143 long,
144 help = "Specify docker-compose project name (default: read from compose file or use 'docker')"
145 )]
146 project: Option<String>,
147 },
148 RestartContainer {
150 container_name: String,
152 },
153 LoadImages,
155 SetupTags,
157 ArchInfo,
159 ListImages,
161 CheckMountDirs,
163}
164
165#[derive(Subcommand, Debug)]
167pub enum CacheCommand {
168 Clear,
170 Status,
172 CleanDownloads {
174 #[arg(long, default_value = "3", help = "Number of versions to keep")]
176 keep: u32,
177 },
178}
179
180#[derive(Parser)]
182#[command(name = "nuwax-cli")]
183#[command(about = metadata::PROJECT_DESCRIPTION)]
184#[command(version = version_info::CLI_VERSION)]
185#[command(long_about = metadata::display::DESCRIPTION_LONG)]
186#[command(author = metadata::PROJECT_AUTHORS)]
187pub struct Cli {
188 #[arg(short, long, default_value = "config.toml")]
190 pub config: PathBuf,
191
192 #[arg(short, long)]
194 pub verbose: bool,
195
196 #[arg(long, global = true)]
198 pub lang: Option<String>,
199
200 #[command(subcommand)]
201 pub command: Commands,
202}
203
204#[derive(Subcommand)]
205pub enum Commands {
206 Status,
208 Init {
210 #[arg(long)]
212 force: bool,
213 },
214 #[command(subcommand)]
216 CheckUpdate(CheckUpdateCommand),
217 ApiInfo,
219 Upgrade {
221 #[command(subcommand)]
222 subcommand: Option<UpgradeSubcommand>,
223
224 #[command(flatten)]
225 args: UpgradeArgs,
226 },
227 ListBackups,
229 Rollback {
231 backup_id: Option<i64>,
233 #[arg(long)]
235 force: bool,
236 #[arg(long)]
238 list_json: bool,
239 #[arg(
241 long,
242 default_value = "false",
243 help = "Whether to rollback data files, default no"
244 )]
245 rollback_data: bool,
246 },
247 #[command(subcommand)]
249 DockerService(DockerServiceCommand),
250
251 Ducker {
253 #[arg(trailing_var_arg = true, allow_hyphen_values = true)]
255 args: Vec<String>,
256 },
257
258 #[command(subcommand)]
260 AutoBackup(AutoBackupCommand),
261
262 #[command(subcommand)]
264 AutoUpgradeDeploy(AutoUpgradeDeployCommand),
265
266 #[command(subcommand)]
268 Cache(CacheCommand),
269
270 DiffSql {
272 #[arg(help = "Old version SQL file path")]
274 old_sql: PathBuf,
275 #[arg(help = "New version SQL file path")]
277 new_sql: PathBuf,
278 #[arg(long, help = "Old version number for diff description")]
280 old_version: Option<String>,
281 #[arg(long, help = "New version number for diff description")]
283 new_version: Option<String>,
284 #[arg(
286 long,
287 default_value = "upgrade_diff.sql",
288 help = "Diff SQL output file name"
289 )]
290 output: String,
291 },
292}
293
294#[cfg(test)]
295mod tests {
296 use super::*;
297 use clap::Parser;
298
299 #[test]
300 fn parses_legacy_upgrade_command() {
301 let cli = Cli::parse_from(["nuwax-cli", "upgrade"]);
302
303 match cli.command {
304 Commands::Upgrade { subcommand, args } => {
305 assert!(subcommand.is_none());
306 assert!(!args.check);
307 assert!(!args.force);
308 }
309 _ => panic!("expected upgrade command"),
310 }
311 }
312
313 #[test]
314 fn parses_legacy_upgrade_check_and_force_flags() {
315 let cli = Cli::parse_from(["nuwax-cli", "upgrade", "--check", "--force"]);
316
317 match cli.command {
318 Commands::Upgrade { subcommand, args } => {
319 assert!(subcommand.is_none());
320 assert!(args.check);
321 assert!(args.force);
322 }
323 _ => panic!("expected upgrade command"),
324 }
325 }
326
327 #[test]
328 fn parses_upgrade_check_subcommand() {
329 let cli = Cli::parse_from(["nuwax-cli", "upgrade", "check", "--force"]);
330
331 match cli.command {
332 Commands::Upgrade {
333 subcommand: Some(UpgradeSubcommand::Check { force }),
334 args,
335 } => {
336 assert!(force);
337 assert!(!args.check);
338 assert!(!args.force);
339 }
340 _ => panic!("expected upgrade check command"),
341 }
342 }
343
344 #[test]
345 fn parses_upgrade_download_subcommand() {
346 let cli = Cli::parse_from(["nuwax-cli", "upgrade", "download", "--full"]);
347
348 match cli.command {
349 Commands::Upgrade {
350 subcommand: Some(UpgradeSubcommand::Download { full }),
351 args,
352 } => {
353 assert!(full);
354 assert!(!args.check);
355 assert!(!args.force);
356 }
357 _ => panic!("expected upgrade download command"),
358 }
359 }
360}