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
74 #[command(name = "route:list")]
76 RouteList {
77 #[arg(short = 'f', long, default_value = "table")]
79 format: String,
80 },
81
82 #[command(name = "cache:clear")]
84 CacheClear {
85 #[arg(short = 's', long)]
87 store: Option<String>,
88 },
89
90 #[command(name = "scheduler")]
92 Scheduler {
93 #[command(subcommand)]
95 scheduler_command: cmd::scheduler::SchedulerCommand,
96 },
97}
98
99impl Cli {
100 pub fn execute(&self) -> Result<i32, CliError> {
110 match &self.command {
111 None => {
112 println!("SZ-Rust CLI — 使用 --help 查看可用命令");
114 Ok(0)
115 }
116 Some(Command::Make { make_command }) => cmd::make::execute(make_command).map(|_| 0),
117 Some(Command::Migrate { args }) => cmd::migrate::execute_migrate(args).map(|_| 0),
118 Some(Command::MigrateStatus { path }) => cmd::migrate::execute_status(path).map(|_| 0),
119 Some(Command::RouteList { format }) => {
120 cmd::route::execute_route_list(format).map(|_| 0)
121 }
122 Some(Command::CacheClear { store }) => {
123 cmd::cache::execute_cache_clear(store.as_deref()).map(|_| 0)
124 }
125 Some(Command::Scheduler { scheduler_command }) => {
126 cmd::scheduler::execute(scheduler_command).map(|_| 0)
127 }
128 }
129 }
130}
131
132#[cfg(test)]
133mod tests {
134 use super::*;
135 use clap::Parser;
136
137 #[test]
138 fn test_parse_make_model() {
139 let cli = Cli::parse_from(["sz-rust", "make", "model", "User"]);
140 match cli.command {
141 Some(Command::Make { make_command }) => {
142 assert!(matches!(make_command, cmd::make::MakeCommand::Model { .. }));
143 }
144 _ => panic!("expected Make command"),
145 }
146 }
147
148 #[test]
149 fn test_parse_make_controller() {
150 let cli = Cli::parse_from(["sz-rust", "make", "controller", "User"]);
151 match cli.command {
152 Some(Command::Make { make_command }) => {
153 assert!(matches!(
154 make_command,
155 cmd::make::MakeCommand::Controller { .. }
156 ));
157 }
158 _ => panic!("expected Make command"),
159 }
160 }
161
162 #[test]
163 fn test_parse_make_migration() {
164 let cli = Cli::parse_from(["sz-rust", "make", "migration", "create_users"]);
165 match cli.command {
166 Some(Command::Make { make_command }) => {
167 assert!(matches!(
168 make_command,
169 cmd::make::MakeCommand::Migration { .. }
170 ));
171 }
172 _ => panic!("expected Make command"),
173 }
174 }
175
176 #[test]
177 fn test_parse_migrate() {
178 let cli = Cli::parse_from(["sz-rust", "migrate"]);
179 assert!(matches!(cli.command, Some(Command::Migrate { .. })));
180 }
181
182 #[test]
183 fn test_parse_migrate_status() {
184 let cli = Cli::parse_from(["sz-rust", "migrate:status"]);
185 assert!(matches!(cli.command, Some(Command::MigrateStatus { .. })));
186 }
187
188 #[test]
189 fn test_parse_route_list() {
190 let cli = Cli::parse_from(["sz-rust", "route:list"]);
191 assert!(matches!(cli.command, Some(Command::RouteList { .. })));
192 }
193
194 #[test]
195 fn test_parse_cache_clear() {
196 let cli = Cli::parse_from(["sz-rust", "cache:clear"]);
197 assert!(matches!(cli.command, Some(Command::CacheClear { .. })));
198 }
199
200 #[test]
201 fn test_parse_cache_clear_with_store() {
202 let cli = Cli::parse_from(["sz-rust", "cache:clear", "--store", "redis"]);
203 match cli.command {
204 Some(Command::CacheClear { store }) => {
205 assert_eq!(store.as_deref(), Some("redis"));
206 }
207 _ => panic!("expected CacheClear command"),
208 }
209 }
210
211 #[test]
212 fn test_parse_scheduler() {
213 let cli = Cli::parse_from(["sz-rust", "scheduler", "list"]);
214 assert!(matches!(cli.command, Some(Command::Scheduler { .. })));
215 }
216
217 #[test]
218 fn test_execute_no_command_returns_ok() {
219 let cli = Cli { command: None };
220 let result = cli.execute();
221 assert!(result.is_ok());
222 assert_eq!(result.unwrap(), 0);
223 }
224}