Skip to main content

sz_rust_cli/
lib.rs

1// SPDX-License-Identifier: Apache-2.0
2// Copyright (c) 2024-2026 SZ-Rust Team
3//
4//! SZ-Rust CLI — 命令行工具
5//!
6//! 替代 PHP `think` 命令,借鉴 Laravel Artisan 风格。
7//!
8//! ## PHP 对齐
9//!
10//! 本包对齐 PHP ThinkPHP 6 `think` 命令体系:
11//!
12//! - `php think make:model` → `sz-rust make:model`
13//! - `php think make:controller` → `sz-rust make:controller`
14//! - `php think make:migration` → `sz-rust make:migration`(Phinx 风格)
15//! - `php think migrate` → `sz-rust migrate`
16//! - `php think migrate:status` → `sz-rust migrate:status`
17//! - `php think route:list` → `sz-rust route:list`
18//! - `php think cache:clear` → `sz-rust cache:clear`
19//!
20//! ## 模块结构
21//!
22//! | 模块 | 功能 |
23//! |------|------|
24//! | `cli` | clap 命令定义(Cli / Commands / Options) |
25//! | `console` | 自定义命令注册与分发(对齐 PHP `think\console\Console`) |
26//! | `cmd::make` | make:* 代码生成命令 |
27//! | `cmd::migrate` | migrate / migrate:status 迁移命令 |
28//! | `cmd::route` | route:list 路由列表命令 |
29//! | `cmd::cache` | cache:clear 缓存清理命令 |
30//! | `cmd::scheduler` | scheduler:* 调度器命令 |
31//! | `error` | CLI 错误类型 |
32//! | `stubs` | 代码生成模板(对齐 PHP make/stubs) |
33//!
34//! ## R5 硬约束
35//!
36//! - R5-48:`make:model` 生成 Model 骨架代码对齐 PHP `think\console\command\make\Model`
37//! - R5-49:`make:controller` 生成 Controller 骨架代码对齐 PHP `think\console\command\make\Controller`
38//! - R5-50:`migrate:status` 显示迁移进度对齐 PHP `think migrate:status`
39//! - R5-51:`cache:clear` 清空缓存对齐 PHP `think cache:clear`
40
41#![forbid(unsafe_code)]
42#![warn(missing_docs)]
43
44pub mod cargo_checker;
45pub mod cli;
46pub mod cmd;
47pub mod console;
48pub mod context_builder;
49pub mod error;
50pub mod field_parser;
51pub mod interactive;
52pub mod safety_validator;
53pub mod skeleton;
54pub mod stubs;
55pub mod template_engine;
56pub mod validator;
57
58pub use cli::{Cli, Command as CliCommand};
59pub use console::{Command, CommandSignature, Console};
60pub use error::CliError;
61
62/// 运行 CLI(入口函数)
63///
64/// 解析命令行参数并执行对应命令,返回退出码。
65///
66/// # 参数
67///
68/// - `args`:命令行参数(含程序名,如 `["sz-rust", "make", "model", "User"]`)
69///
70/// # 返回
71///
72/// - `Ok(0)`:成功
73/// - `Ok(code)`:命令指定的退出码
74/// - `Err(_)`:内部错误
75pub async fn run<I, S>(args: I) -> Result<i32, CliError>
76where
77    I: IntoIterator<Item = S>,
78    S: Into<std::ffi::OsString> + Clone,
79{
80    use clap::Parser;
81    let cli = Cli::parse_from(args);
82    cli.execute().await
83}
84
85#[cfg(test)]
86mod tests {
87    use super::*;
88
89    #[tokio::test]
90    async fn test_run_no_args_returns_ok() {
91        // 仅程序名、无子命令:command=None,execute 返回 Ok(0)
92        let result = run(vec!["sz-rust"]).await;
93        assert!(result.is_ok());
94        assert_eq!(result.unwrap(), 0);
95    }
96
97    #[tokio::test]
98    #[allow(clippy::await_holding_lock)]
99    async fn test_run_cache_clear_command() {
100        // 通过 run() 分发执行 cache:clear 命令。
101        // cache:clear 读写进程级工作目录下的 runtime/cache,
102        // 必须持有全局互斥锁并隔离到临时目录,避免与 make/optimize
103        // 模块的 set_current_dir 测试并行竞态。
104        // clippy::await_holding_lock: 本测试运行在 current_thread runtime,
105        // std::sync::MutexGuard 跨 await 不会跨线程,安全。
106        let _lock = crate::cmd::test_support::acquire_global_lock();
107        let temp = tempfile::tempdir().expect("tempdir failed");
108        let original = std::env::current_dir().expect("current_dir failed");
109        std::env::set_current_dir(temp.path()).expect("set_current_dir failed");
110        let result = run(vec!["sz-rust", "cache:clear"]).await;
111        let restore = std::env::set_current_dir(&original);
112        assert!(restore.is_ok(), "恢复工作目录失败");
113        assert!(result.is_ok());
114    }
115}