diff options
| author | 魏曹先生 <1992414357@qq.com> | 2025-10-24 18:26:47 +0800 |
|---|---|---|
| committer | 魏曹先生 <1992414357@qq.com> | 2025-10-24 18:26:47 +0800 |
| commit | b40443cae7b963048ddd3be8b55a4feaf1e6612d (patch) | |
| tree | 5d4019633a4ef86bd64dff653b07042bc74494be /src/bin | |
| parent | 77d162ad9974752c0caa3340b20c91049c69feba (diff) | |
Completed "Account Manage" parts of jv
Diffstat (limited to 'src/bin')
| -rw-r--r-- | src/bin/jv.rs | 322 | ||||
| -rw-r--r-- | src/bin/jvv.rs | 76 |
2 files changed, 356 insertions, 42 deletions
diff --git a/src/bin/jv.rs b/src/bin/jv.rs index f67b37b..3a22528 100644 --- a/src/bin/jv.rs +++ b/src/bin/jv.rs @@ -1,4 +1,16 @@ -use std::{net::SocketAddr, str::FromStr}; +use std::{env::current_dir, net::SocketAddr, path::PathBuf, str::FromStr}; + +use just_enough_vcs::{ + utils::cfg_file::config::ConfigFile, + vcs::{ + current::current_local_path, + data::{ + local::{LocalWorkspace, config::LocalConfig}, + member::Member, + user::UserDirectory, + }, + }, +}; use clap::{Parser, Subcommand, arg, command}; use just_enough_vcs::{ @@ -8,6 +20,7 @@ use just_enough_vcs::{ }; use just_enough_vcs_cli::utils::{lang_selector::current_locales, md_colored::md}; use rust_i18n::{set_locale, t}; +use tokio::fs; // Import i18n files rust_i18n::i18n!("locales", fallback = "en"); @@ -29,7 +42,7 @@ struct JustEnoughVcsWorkspace { enum JustEnoughVcsWorkspaceCommand { // Member management /// Manage your local accounts - #[command(subcommand)] + #[command(subcommand, alias = "acc")] Account(AccountManage), /// Create an empty workspace @@ -96,7 +109,19 @@ enum AccountManage { Add(AccountAddArgs), /// Remove a account from this computer + #[command(alias = "rm")] Remove(AccountRemoveArgs), + + /// List all accounts in this computer + #[command(alias = "ls")] + List(AccountListArgs), + + /// Set current local workspace account + As(SetLocalWorkspaceAccountArgs), + + /// Move private key file to account + #[command(alias = "mvkey", alias = "mvk")] + MoveKey(MoveKeyToAccountArgs), } #[derive(Subcommand, Debug)] @@ -107,36 +132,85 @@ enum SheetManage { } #[derive(Parser, Debug)] +struct CreateWorkspaceArgs { + /// Show help information + #[arg(short, long)] + help: bool, + + /// Workspace directory path + path: PathBuf, + + /// Force create, ignore files in the directory + #[arg(short, long)] + force: bool, +} + +#[derive(Parser, Debug)] +struct InitWorkspaceArgs { + /// Show help information + #[arg(short, long)] + help: bool, + + /// Force create, ignore files in the directory + #[arg(short, long)] + force: bool, +} + +#[derive(Parser, Debug)] +struct HereArgs { + /// Show help information + #[arg(short, long)] + help: bool, +} + +#[derive(Parser, Debug)] struct AccountAddArgs { - /// Member name - member_name: String, + /// Show help information + #[arg(short, long)] + help: bool, + + /// Account name + account_name: String, } #[derive(Parser, Debug)] struct AccountRemoveArgs { - /// Member name - member_name: String, + /// Show help information + #[arg(short, long)] + help: bool, + + /// Account name + account_name: String, } #[derive(Parser, Debug)] -struct CreateWorkspaceArgs { +struct AccountListArgs { /// Show help information #[arg(short, long)] help: bool, } #[derive(Parser, Debug)] -struct InitWorkspaceArgs { +struct SetLocalWorkspaceAccountArgs { /// Show help information #[arg(short, long)] help: bool, + + /// Account name + account_name: String, } #[derive(Parser, Debug)] -struct HereArgs { +struct MoveKeyToAccountArgs { /// Show help information #[arg(short, long)] help: bool, + + /// Account name + account_name: String, + + /// Private key file path + key_path: PathBuf, } #[derive(Parser, Debug)] @@ -220,13 +294,56 @@ async fn main() { }; match parser.command { - JustEnoughVcsWorkspaceCommand::Account(account_manage) => match account_manage { - AccountManage::Help => { - println!("{}", md(t!("jv.account"))); + JustEnoughVcsWorkspaceCommand::Account(account_manage) => { + let user_dir = match UserDirectory::current_doc_dir() { + Some(dir) => dir, + None => { + eprintln!("{}", t!("jv.fail.account.no_user_dir")); + return; + } + }; + + match account_manage { + AccountManage::Help => { + println!("{}", md(t!("jv.account"))); + } + AccountManage::Add(account_add_args) => { + if account_add_args.help { + println!("{}", md(t!("jv.account"))); + return; + } + jv_account_add(user_dir, account_add_args).await; + } + AccountManage::Remove(account_remove_args) => { + if account_remove_args.help { + println!("{}", md(t!("jv.account"))); + return; + } + jv_account_remove(user_dir, account_remove_args).await; + } + AccountManage::List(account_list_args) => { + if account_list_args.help { + println!("{}", md(t!("jv.account"))); + return; + } + jv_account_list(user_dir, account_list_args).await; + } + AccountManage::As(set_local_workspace_account_args) => { + if set_local_workspace_account_args.help { + println!("{}", md(t!("jv.account"))); + return; + } + jv_account_as(user_dir, set_local_workspace_account_args).await; + } + AccountManage::MoveKey(move_key_to_account_args) => { + if move_key_to_account_args.help { + println!("{}", md(t!("jv.account"))); + return; + } + jv_account_move_key(user_dir, move_key_to_account_args).await; + } } - AccountManage::Add(account_add_args) => todo!(), - AccountManage::Remove(account_remove_args) => todo!(), - }, + } JustEnoughVcsWorkspaceCommand::Create(create_workspace_args) => { if create_workspace_args.help { println!("{}", md(t!("jv.create"))); @@ -320,12 +437,53 @@ async fn main() { } } -async fn jv_create(_args: CreateWorkspaceArgs) { - todo!() +async fn jv_create(args: CreateWorkspaceArgs) { + let path = args.path; + + if !args.force && path.exists() && !is_directory_empty(&path).await { + eprintln!("{}", t!("jv.fail.init_create_dir_not_empty").trim()); + return; + } + + match LocalWorkspace::setup_local_workspace(path).await { + Ok(_) => { + println!("{}", t!("jv.success.create")); + } + Err(e) => { + eprintln!("{}", t!("jv.fail.create", error = e.to_string())); + } + } } -async fn jv_init(_args: InitWorkspaceArgs) { - todo!() +async fn jv_init(args: InitWorkspaceArgs) { + let path = match current_dir() { + Ok(path) => path, + Err(e) => { + eprintln!("{}", t!("jv.fail.get_current_dir", error = e.to_string())); + return; + } + }; + + if !args.force && path.exists() && !is_directory_empty(&path).await { + eprintln!("{}", t!("jv.fail.init_create_dir_not_empty").trim()); + return; + } + + match LocalWorkspace::setup_local_workspace(path).await { + Ok(_) => { + println!("{}", t!("jv.success.init")); + } + Err(e) => { + eprintln!("{}", t!("jv.fail.init", error = e.to_string())); + } + } +} + +async fn is_directory_empty(path: &PathBuf) -> bool { + match fs::read_dir(path).await { + Ok(mut entries) => entries.next_entry().await.unwrap().is_none(), + Err(_) => false, + } } async fn jv_here(_args: HereArgs) { @@ -356,6 +514,132 @@ async fn jv_import(_args: ImportFileArgs) { todo!() } +async fn jv_account_add(user_dir: UserDirectory, args: AccountAddArgs) { + let member = Member::new(args.account_name.clone()); + + match user_dir.register_account(member).await { + Ok(_) => { + println!( + "{}", + t!("jv.success.account.add", account = args.account_name) + ); + } + Err(_) => { + eprintln!("{}", t!("jv.fail.account.add", account = args.account_name)); + } + } +} + +async fn jv_account_remove(user_dir: UserDirectory, args: AccountRemoveArgs) { + match user_dir.remove_account(&args.account_name) { + Ok(_) => { + println!( + "{}", + t!("jv.success.account.remove", account = args.account_name) + ); + } + Err(_) => { + eprintln!( + "{}", + t!("jv.fail.account.remove", account = args.account_name) + ); + } + } +} + +async fn jv_account_list(user_dir: UserDirectory, _args: AccountListArgs) { + match user_dir.account_ids() { + Ok(account_ids) => { + println!( + "{}", + md(t!( + "jv.success.account.list.header", + num = account_ids.len() + )) + ); + + let mut i = 0; + for account_id in account_ids { + println!("{}. {} {}", i + 1, &account_id, { + if user_dir.has_private_key(&account_id) { + t!("jv.success.account.list.status_has_key") + } else { + std::borrow::Cow::Borrowed("") + } + }); + i += 1; + } + } + Err(_) => { + eprintln!("{}", t!("jv.fail.account.list")); + } + } +} + +async fn jv_account_as(user_dir: UserDirectory, args: SetLocalWorkspaceAccountArgs) { + // Account exist + let Ok(member) = user_dir.account(&args.account_name).await else { + eprintln!( + "{}", + t!("jv.fail.account.not_found", account = args.account_name) + ); + return; + }; + + let Some(_local_dir) = current_local_path() else { + eprintln!("{}", t!("jv.fail.workspace_not_found").trim()); + return; + }; + + let Ok(mut local_cfg) = LocalConfig::read().await else { + eprintln!("{}", md(t!("jv.fail.read_cfg"))); + return; + }; + + local_cfg.set_current_account(member.id()); + + let Ok(_) = LocalConfig::write(&local_cfg).await else { + eprintln!("{}", t!("jv.fail.write_cfg").trim()); + return; + }; + + println!( + "{}", + t!("jv.success.account.as", account = member.id()).trim() + ); +} + +async fn jv_account_move_key(user_dir: UserDirectory, args: MoveKeyToAccountArgs) { + // Key file exist + if !args.key_path.exists() { + eprintln!( + "{}", + t!("jv.fail.path_not_found", path = args.key_path.display()) + ); + return; + } + + // Account exist + let Ok(_member) = user_dir.account(&args.account_name).await else { + eprintln!( + "{}", + t!("jv.fail.account.not_found", account = args.account_name) + ); + return; + }; + + // Rename key file + match fs::rename( + args.key_path, + user_dir.account_private_key_path(&args.account_name), + ) + .await + { + Ok(_) => println!("{}", t!("jv.success.account.move_key")), + Err(_) => eprintln!("{}", t!("jv.fail.account.move_key")), + } +} + async fn jv_direct(args: DirectArgs) { let pool = client_registry::client_action_pool(); let upstream = match SocketAddr::from_str(&args.upstream) { diff --git a/src/bin/jvv.rs b/src/bin/jvv.rs index 50dc3b3..1886daa 100644 --- a/src/bin/jvv.rs +++ b/src/bin/jvv.rs @@ -153,7 +153,10 @@ async fn main() { // Init colored #[cfg(windows)] - colored::control::set_virtual_terminal(true).unwrap(); + if let Err(err) = colored::control::set_virtual_terminal(true) { + eprintln!("{}", t!("jvv.fail.colored_control", err = err.to_string())); + return; + } let Ok(parser) = JustEnoughVcsVault::try_parse() else { println!("{}", md(t!("jvv.help"))); @@ -183,9 +186,13 @@ async fn main() { jvv_init(init_vault_args).await; } JustEnoughVcsVaultCommand::Member(member_manage) => { - let vault_cfg = VaultConfig::read() - .await - .unwrap_or_else(|_| panic!("{}", t!("jvv.fail.no_vault_here").trim().to_string())); + let vault_cfg = match VaultConfig::read().await { + Ok(cfg) => cfg, + Err(_) => { + eprintln!("{}", t!("jvv.fail.no_vault_here").trim()); + return; + } + }; let vault = match Vault::init_current_dir(vault_cfg) { Some(vault) => vault, @@ -358,19 +365,28 @@ async fn jvv_here(_args: HereArgs) { } async fn jvv_init(_args: InitVaultArgs) { - let current_dir = std::env::current_dir() - .unwrap_or_else(|_| panic!("{}", t!("jvv.fail.std.current_dir").trim().to_string())); - if current_dir.read_dir().unwrap().next().is_some() { - eprintln!("{}", t!("jvv.fail.init.not_empty")); - return; + let current_dir = match std::env::current_dir() { + Ok(dir) => dir, + Err(_) => { + eprintln!("{}", t!("jvv.fail.std.current_dir").trim()); + return; + } + }; + if let Ok(mut entries) = current_dir.read_dir() { + if entries.next().is_some() { + eprintln!("{}", t!("jvv.fail.init.not_empty")); + return; + } } // Setup vault - let vault_name = current_dir - .file_name() - .unwrap_or_else(|| panic!("{}", t!("jvv.fail.std.current_dir_name").trim().to_string())) - .to_string_lossy() - .to_string(); + let vault_name = match current_dir.file_name() { + Some(name) => name.to_string_lossy().to_string(), + None => { + eprintln!("{}", t!("jvv.fail.std.current_dir_name").trim()); + return; + } + }; let vault_name = pascal_case!(vault_name); if let Err(err) = Vault::setup_vault(current_dir.clone()).await { @@ -401,8 +417,13 @@ async fn jvv_init(_args: InitVaultArgs) { } async fn jvv_create(args: CreateVaultArgs) { - let current_dir = std::env::current_dir() - .unwrap_or_else(|_| panic!("{}", t!("jvv.fail.std.current_dir").trim().to_string())); + let current_dir = match std::env::current_dir() { + Ok(dir) => dir, + Err(_) => { + eprintln!("{}", t!("jvv.fail.std.current_dir").trim()); + return; + } + }; let target_dir = current_dir.join(args.vault_name.clone()); // Create directory @@ -417,9 +438,11 @@ async fn jvv_create(args: CreateVaultArgs) { return; } - if target_dir.read_dir().unwrap().next().is_some() { - eprintln!("{}", t!("jvv.fail.create.not_empty")); - return; + if let Ok(mut entries) = target_dir.read_dir() { + if entries.next().is_some() { + eprintln!("{}", t!("jvv.fail.create.not_empty")); + return; + } } // Setup vault @@ -490,9 +513,13 @@ async fn jvv_member_remove(vault: Vault, args: MemberRemoveArgs) { async fn jvv_member_list(vault: Vault, _args: MemberListArgs) { // Get id list - let ids = vault - .member_ids() - .unwrap_or_else(|_| panic!("{}", t!("jvv.fail.member.list").trim().to_string())); + let ids = match vault.member_ids() { + Ok(ids) => ids, + Err(_) => { + eprintln!("{}", t!("jvv.fail.member.list").trim()); + return; + } + }; // Print header println!( @@ -560,7 +587,10 @@ async fn jvv_service_listen(args: ListenArgs) { "{}", t!( "jvv.success.service.listen", - path = current_vault.file_name().unwrap().display() + path = match current_vault.file_name() { + Some(name) => name.to_string_lossy(), + None => std::borrow::Cow::Borrowed("unknown"), + } ) ) } |
