1use clap::{Parser, Subcommand};
24
25use crate::cmd;
26use crate::error::CliError;
27
28#[derive(Parser, Debug)]
32#[command(
33 name = "sz-rust",
34 bin_name = "sz-rust",
35 version,
36 about = "SZ-Rust 命令行工具 — 替代 PHP think 命令",
37 long_about = "SZ-Rust CLI 对齐 PHP ThinkPHP 6 think 命令体系,提供 make:migration / make:model / make:controller / migrate / route:list / cache:clear 等命令。"
38)]
39pub struct Cli {
40 #[command(subcommand)]
42 pub command: Option<Command>,
43}
44
45#[derive(Subcommand, Debug)]
49pub enum Command {
50 #[command(name = "make")]
52 Make {
53 #[command(subcommand)]
55 make_command: cmd::make::MakeCommand,
56 },
57
58 #[command(name = "migrate")]
60 Migrate {
61 #[command(flatten)]
63 args: cmd::migrate::MigrateArgs,
64 },
65
66 #[command(name = "migrate:status")]
68 MigrateStatus {
69 #[arg(short = 'p', long, default_value = "migrations")]
71 path: String,
72
73 #[arg(long, default_value = "postgres")]
75 db_type: String,
76
77 #[arg(long)]
79 show_sql: bool,
80 },
81
82 #[command(name = "route:list")]
84 RouteList {
85 #[arg(short = 'f', long, default_value = "table")]
87 format: String,
88 },
89
90 #[command(name = "cache:clear")]
92 CacheClear {
93 #[arg(short = 's', long)]
95 store: Option<String>,
96 },
97
98 #[command(name = "scheduler")]
100 Scheduler {
101 #[command(subcommand)]
103 scheduler_command: cmd::scheduler::SchedulerCommand,
104 },
105}
106
107impl Cli {
108 pub fn execute(&self) -> Result<i32, CliError> {
118 match &self.command {
119 None => {
120 println!("SZ-Rust CLI — 使用 --help 查看可用命令");
122 Ok(0)
123 }
124 Some(Command::Make { make_command }) => cmd::make::execute(make_command).map(|_| 0),
125 Some(Command::Migrate { args }) => cmd::migrate::execute_migrate(args).map(|_| 0),
126 Some(Command::MigrateStatus {
127 path,
128 db_type,
129 show_sql,
130 }) => cmd::migrate::execute_status_with(path, db_type, *show_sql).map(|_| 0),
131 Some(Command::RouteList { format }) => {
132 cmd::route::execute_route_list(format).map(|_| 0)
133 }
134 Some(Command::CacheClear { store }) => {
135 cmd::cache::execute_cache_clear(store.as_deref()).map(|_| 0)
136 }
137 Some(Command::Scheduler { scheduler_command }) => {
138 cmd::scheduler::execute(scheduler_command).map(|_| 0)
139 }
140 }
141 }
142}
143
144#[cfg(test)]
145mod tests {
146 use super::*;
147 use clap::Parser;
148
149 #[test]
150 fn test_parse_make_model() {
151 let cli = Cli::parse_from(["sz-rust", "make", "model", "User"]);
152 match cli.command {
153 Some(Command::Make { make_command }) => {
154 assert!(matches!(make_command, cmd::make::MakeCommand::Model { .. }));
155 }
156 _ => panic!("expected Make command"),
157 }
158 }
159
160 #[test]
161 fn test_parse_make_controller() {
162 let cli = Cli::parse_from(["sz-rust", "make", "controller", "User"]);
163 match cli.command {
164 Some(Command::Make { make_command }) => {
165 assert!(matches!(
166 make_command,
167 cmd::make::MakeCommand::Controller { .. }
168 ));
169 }
170 _ => panic!("expected Make command"),
171 }
172 }
173
174 #[test]
175 fn test_parse_make_migration() {
176 let cli = Cli::parse_from(["sz-rust", "make", "migration", "create_users"]);
177 match cli.command {
178 Some(Command::Make { make_command }) => {
179 assert!(matches!(
180 make_command,
181 cmd::make::MakeCommand::Migration { .. }
182 ));
183 }
184 _ => panic!("expected Make command"),
185 }
186 }
187
188 #[test]
189 fn test_parse_migrate() {
190 let cli = Cli::parse_from(["sz-rust", "migrate"]);
191 assert!(matches!(cli.command, Some(Command::Migrate { .. })));
192 }
193
194 #[test]
195 fn test_parse_migrate_status() {
196 let cli = Cli::parse_from(["sz-rust", "migrate:status"]);
197 assert!(matches!(cli.command, Some(Command::MigrateStatus { .. })));
198 }
199
200 #[test]
201 fn test_parse_route_list() {
202 let cli = Cli::parse_from(["sz-rust", "route:list"]);
203 assert!(matches!(cli.command, Some(Command::RouteList { .. })));
204 }
205
206 #[test]
207 fn test_parse_cache_clear() {
208 let cli = Cli::parse_from(["sz-rust", "cache:clear"]);
209 assert!(matches!(cli.command, Some(Command::CacheClear { .. })));
210 }
211
212 #[test]
213 fn test_parse_cache_clear_with_store() {
214 let cli = Cli::parse_from(["sz-rust", "cache:clear", "--store", "redis"]);
215 match cli.command {
216 Some(Command::CacheClear { store }) => {
217 assert_eq!(store.as_deref(), Some("redis"));
218 }
219 _ => panic!("expected CacheClear command"),
220 }
221 }
222
223 #[test]
224 fn test_parse_scheduler() {
225 let cli = Cli::parse_from(["sz-rust", "scheduler", "list"]);
226 assert!(matches!(cli.command, Some(Command::Scheduler { .. })));
227 }
228
229 #[test]
230 fn test_execute_no_command_returns_ok() {
231 let cli = Cli { command: None };
232 let result = cli.execute();
233 assert!(result.is_ok());
234 assert_eq!(result.unwrap(), 0);
235 }
236}