From 8b279df3339a87303262beb7c8fb5d0d7e68a4d7 Mon Sep 17 00:00:00 2001 From: root Date: Wed, 11 Mar 2026 23:43:24 +0800 Subject: [PATCH] =?UTF-8?q?=E5=91=BD=E4=BB=A4=E6=A1=86=E6=9E=B6=E6=A8=A1?= =?UTF-8?q?=E5=9D=97=E6=9E=84=E5=BB=BA=E5=AE=8C=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .arts/settings.json | 3 + Cargo.lock | 186 +++++++++++++++++++++++++++ Cargo.toml | 2 + src/commands/db/migrate.rs | 16 +++ src/commands/db/mod.rs | 16 +++ src/commands/mod.rs | 23 ++++ src/commands/server/config/delete.rs | 33 +++++ src/commands/server/config/get.rs | 28 ++++ src/commands/server/config/mod.rs | 28 ++++ src/commands/server/config/set.rs | 30 +++++ src/commands/server/mod.rs | 33 +++++ src/commands/server/start.rs | 20 +++ src/commands/server/stop.rs | 13 ++ src/main.rs | 43 ++++++- src/utils.rs | 0 15 files changed, 472 insertions(+), 2 deletions(-) create mode 100644 .arts/settings.json create mode 100644 src/commands/db/migrate.rs create mode 100644 src/commands/db/mod.rs create mode 100644 src/commands/mod.rs create mode 100644 src/commands/server/config/delete.rs create mode 100644 src/commands/server/config/get.rs create mode 100644 src/commands/server/config/mod.rs create mode 100644 src/commands/server/config/set.rs create mode 100644 src/commands/server/mod.rs create mode 100644 src/commands/server/start.rs create mode 100644 src/commands/server/stop.rs create mode 100644 src/utils.rs diff --git a/.arts/settings.json b/.arts/settings.json new file mode 100644 index 0000000..701b3b0 --- /dev/null +++ b/.arts/settings.json @@ -0,0 +1,3 @@ +{ + "diffEditor.renderSideBySide": false +} \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index 6918b98..e2fde74 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,192 @@ # It is not intended for manual editing. version = 4 +[[package]] +name = "anstream" +version = "0.6.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43d5b281e737544384e969a5ccad3f1cdd24b48086a0fc1b2a5262a26b8f4f4a" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5192cca8006f1fd4f7237516f40fa183bb07f8fbdfedaa0036de5ea9b0b45e78" + +[[package]] +name = "anstyle-parse" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc" +dependencies = [ + "windows-sys", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d" +dependencies = [ + "anstyle", + "once_cell_polyfill", + "windows-sys", +] + +[[package]] +name = "anyhow" +version = "1.0.102" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" + +[[package]] +name = "clap" +version = "4.5.60" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2797f34da339ce31042b27d23607e051786132987f595b02ba4f6a6dffb7030a" +dependencies = [ + "clap_builder", + "clap_derive", +] + +[[package]] +name = "clap_builder" +version = "4.5.60" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24a241312cea5059b13574bb9b3861cabf758b879c15190b37b6d6fd63ab6876" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim", +] + +[[package]] +name = "clap_derive" +version = "4.5.55" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a92793da1a46a5f2a02a6f4c46c6496b28c43638adea8306fcb0caa1634f24e5" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "clap_lex" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a822ea5bc7590f9d40f1ba12c0dc3c2760f3482c6984db1573ad11031420831" + +[[package]] +name = "colorchoice" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "is_terminal_polyfill" +version = "1.70.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" + +[[package]] +name = "once_cell_polyfill" +version = "1.70.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" + +[[package]] +name = "proc-macro2" +version = "1.0.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + [[package]] name = "sunhpc" version = "0.1.0" +dependencies = [ + "anyhow", + "clap", +] + +[[package]] +name = "syn" +version = "2.0.117" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "unicode-ident" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" + +[[package]] +name = "utf8parse" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link", +] diff --git a/Cargo.toml b/Cargo.toml index 24d2830..c871478 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,3 +4,5 @@ version = "0.1.0" edition = "2024" [dependencies] +anyhow = "1.0.102" +clap = { version = "4.5.60", features = ["derive"] } diff --git a/src/commands/db/migrate.rs b/src/commands/db/migrate.rs new file mode 100644 index 0000000..9bedcbe --- /dev/null +++ b/src/commands/db/migrate.rs @@ -0,0 +1,16 @@ +use anyhow::Result; + +#[derive(clap::Args)] +pub struct MigrateArgs { + /// 目标版本 + #[arg(short, long)] + pub version: Option, +} + +pub fn run(args: MigrateArgs) -> Result<()> { + match args.version { + Some(v) => println!("🗄️ 迁移数据库到版本: {}", v), + None => println!("🗄️ 执行最新数据库迁移"), + } + Ok(()) +} \ No newline at end of file diff --git a/src/commands/db/mod.rs b/src/commands/db/mod.rs new file mode 100644 index 0000000..3ddfe74 --- /dev/null +++ b/src/commands/db/mod.rs @@ -0,0 +1,16 @@ +use clap::Subcommand; +use anyhow::Result; + +mod migrate; + +#[derive(Subcommand)] +pub enum DbCommands { + /// 运行数据库迁移 + Migrate(migrate::MigrateArgs), +} + +pub fn execute(cmd: DbCommands) -> Result<()> { + match cmd { + DbCommands::Migrate(args) => migrate::run(args), + } +} \ No newline at end of file diff --git a/src/commands/mod.rs b/src/commands/mod.rs new file mode 100644 index 0000000..65b8194 --- /dev/null +++ b/src/commands/mod.rs @@ -0,0 +1,23 @@ +use clap::Subcommand; + +// 声明子模块,对应 src/commands/ 下的目录 +pub mod server; +pub mod db; +// 未来扩展:pub mod new_feature; + +/// 根级子命令枚举 +/// 每个变体对应一个子命令集(目录) +#[derive(Subcommand)] +pub enum CliCommands { + /// 服务器管理相关命令 (server start, server stop) + #[command(subcommand)] + Server(server::ServerCommands), + + /// 数据库管理相关命令 (db migrate, db seed) + #[command(subcommand)] + Db(db::DbCommands), + + // 未来扩展示例: + // #[command(subcommand)] + // Auth(auth::AuthCommands), +} \ No newline at end of file diff --git a/src/commands/server/config/delete.rs b/src/commands/server/config/delete.rs new file mode 100644 index 0000000..1b56012 --- /dev/null +++ b/src/commands/server/config/delete.rs @@ -0,0 +1,33 @@ +// src/commands/server/config/delete.rs +use clap::Args; +use anyhow::Result; + +#[derive(Args)] +pub struct DeleteArgs { + /// 要删除的配置键名 + #[arg(required = true)] + pub key: String, + + /// 跳过确认提示 + #[arg(short, long, default_value_t = false)] + pub yes: bool, +} + +pub fn run(args: DeleteArgs) -> Result<()> { + if !args.yes { + print!("⚠️ 确定要删除配置 '{}' 吗?(y/N): ", args.key); + use std::io::{self, Write}; + io::stdout().flush().unwrap(); + + let mut input = String::new(); + io::stdin().read_line(&mut input).unwrap(); + + if !input.trim().eq_ignore_ascii_case("y") { + println!("操作已取消。"); + return Ok(()); + } + } + + println!("🗑️ 配置 '{}' 已成功删除。", args.key); + Ok(()) +} \ No newline at end of file diff --git a/src/commands/server/config/get.rs b/src/commands/server/config/get.rs new file mode 100644 index 0000000..39961de --- /dev/null +++ b/src/commands/server/config/get.rs @@ -0,0 +1,28 @@ +// src/commands/server/config/get.rs +use clap::Args; +use anyhow::Result; + +#[derive(Args)] +pub struct GetArgs { + /// 要获取的配置键名 + #[arg(required = true)] + pub key: String, + + /// 是否显示详细元数据 + #[arg(short, long, default_value_t = false)] + pub verbose: bool, +} + +pub fn run(args: GetArgs) -> Result<()> { + println!("🔍 正在获取配置: {}", args.key); + + if args.verbose { + println!(" [INFO] 来源: 本地配置文件"); + println!(" [INFO] 类型: String"); + } + + // 模拟返回值 + println!(" 值: \"secret_value_123\""); + + Ok(()) +} \ No newline at end of file diff --git a/src/commands/server/config/mod.rs b/src/commands/server/config/mod.rs new file mode 100644 index 0000000..3cf6c8b --- /dev/null +++ b/src/commands/server/config/mod.rs @@ -0,0 +1,28 @@ +// src/commands/server/config/mod.rs +use clap::Subcommand; +use anyhow::Result; + +// 引入具体的子命令文件 +mod get; +mod set; +mod delete; + +/// 第三级子命令枚举:config 下的具体动作 +#[derive(Subcommand)] +pub enum ConfigCommands { + /// 获取配置项 + Get(get::GetArgs), + /// 设置配置项 + Set(set::SetArgs), + /// 删除配置项 + Delete(delete::DeleteArgs), +} + +/// Config 命令集的总入口函数 +pub fn execute(cmd: ConfigCommands) -> Result<()> { + match cmd { + ConfigCommands::Get(args) => get::run(args), + ConfigCommands::Set(args) => set::run(args), + ConfigCommands::Delete(args) => delete::run(args), + } +} \ No newline at end of file diff --git a/src/commands/server/config/set.rs b/src/commands/server/config/set.rs new file mode 100644 index 0000000..0e029fa --- /dev/null +++ b/src/commands/server/config/set.rs @@ -0,0 +1,30 @@ +// src/commands/server/config/set.rs +use clap::Args; +use anyhow::Result; + +#[derive(Args)] +pub struct SetArgs { + /// 配置键名 + #[arg(required = true)] + pub key: String, + + /// 配置值 + #[arg(required = true)] + pub value: String, + + /// 立即生效而不重启服务 + #[arg(long, default_value_t = false)] + pub hot_reload: bool, +} + +pub fn run(args: SetArgs) -> Result<()> { + println!("✏️ 正在设置配置: {} = {}", args.key, args.value); + + if args.hot_reload { + println!(" ⚡ 热重载已触发,新配置立即生效"); + } else { + println!(" ⚠️ 需重启服务器以应用新配置"); + } + + Ok(()) +} \ No newline at end of file diff --git a/src/commands/server/mod.rs b/src/commands/server/mod.rs new file mode 100644 index 0000000..9cce78c --- /dev/null +++ b/src/commands/server/mod.rs @@ -0,0 +1,33 @@ +use clap::Subcommand; +use anyhow::Result; + +// 引入具体的命令逻辑文件 +mod start; +mod stop; + +// 引入新的 config 模块 +pub mod config; + +/// Server 子命令集的具体命令 +#[derive(Subcommand)] +pub enum ServerCommands { + /// 启动服务器 + Start(start::StartArgs), + /// 停止服务器 + Stop(stop::StopArgs), + + /// 服务器配置管理(三级命令入口) + #[command(subcommand)] + Config(config::ConfigCommands), // 引用 config 模块中的枚举 +} + +/// 执行 server 命令集的入口函数 +pub fn execute(cmd: ServerCommands) -> Result<()> { + match cmd { + ServerCommands::Start(args) => start::run(args), + ServerCommands::Stop(args) => stop::run(args), + + // 分发到 config 模块的 execute 函数 + ServerCommands::Config(args) => config::execute(args), + } +} \ No newline at end of file diff --git a/src/commands/server/start.rs b/src/commands/server/start.rs new file mode 100644 index 0000000..4d883a9 --- /dev/null +++ b/src/commands/server/start.rs @@ -0,0 +1,20 @@ +use anyhow::Result; + +#[derive(clap::Args)] +pub struct StartArgs { + /// 端口号 + #[arg(short, long, default_value = "8080")] + pub port: u16, + + /// 是否以守护进程运行 + #[arg(long)] + pub daemon: bool, +} + +pub fn run(args: StartArgs) -> Result<()> { + println!("🚀 正在启动服务器..."); + println!(" 端口: {}", args.port); + println!(" 守护模式: {}", if args.daemon { "是" } else { "否" }); + // 在这里编写具体的启动逻辑 + Ok(()) +} \ No newline at end of file diff --git a/src/commands/server/stop.rs b/src/commands/server/stop.rs new file mode 100644 index 0000000..83ba047 --- /dev/null +++ b/src/commands/server/stop.rs @@ -0,0 +1,13 @@ +use anyhow::Result; + +#[derive(clap::Args)] +pub struct StopArgs { + /// 强制停止 + #[arg(short, long)] + pub force: bool, +} + +pub fn run(args: StopArgs) -> Result<()> { + println!("🛑 正在停止服务器... (force: {})", args.force); + Ok(()) +} \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index e7a11a9..ef1b6de 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,3 +1,42 @@ -fn main() { - println!("Hello, world!"); +use clap::Parser; +use anyhow::Result; + +// 引入 commands 模块 +mod commands; +mod utils; // 假设有通用工具 + +use commands::CliCommands; + +/// 我的超级 CLI 工具 +#[derive(Parser)] +#[command(name = "sunhpc")] +#[command(author = "Qichao.Sun")] +#[command(version = "0.1.0")] +#[command(about = "一个可扩展的多级命令行工具框架", long_about = None)] +struct Cli { + /// 全局调试模式 + #[arg(short, long, global = true)] + debug: bool, + + /// 子命令入口 + #[command(subcommand)] + command: CliCommands, } + +fn main() -> Result<()> { + let cli = Cli::parse(); + + if cli.debug { + println!("[DEBUG] 调试模式已开启"); + } + + // 根据子命令分发逻辑 + match cli.command { + CliCommands::Server(args) => commands::server::execute(args)?, + CliCommands::Db(args) => commands::db::execute(args)?, + // 未来扩展新命令时,只需在这里添加新的匹配臂 + // CliCommands::NewFeature(args) => commands::new_feature::execute(args)?, + } + + Ok(()) +} \ No newline at end of file diff --git a/src/utils.rs b/src/utils.rs new file mode 100644 index 0000000..e69de29