summaryrefslogtreecommitdiff
path: root/src/bin/jvv.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/bin/jvv.rs')
-rw-r--r--src/bin/jvv.rs434
1 files changed, 434 insertions, 0 deletions
diff --git a/src/bin/jvv.rs b/src/bin/jvv.rs
new file mode 100644
index 0000000..828a093
--- /dev/null
+++ b/src/bin/jvv.rs
@@ -0,0 +1,434 @@
+use std::{env::set_current_dir, path::Path};
+
+use clap::{Parser, Subcommand};
+use env_logger::{Builder, Target};
+use just_enough_vcs::{
+ utils::{
+ cfg_file::config::ConfigFile,
+ string_proc::{self, pascal_case},
+ },
+ vcs::{
+ connection::action_service::server_entry,
+ constants::SERVER_FILE_VAULT,
+ current::current_vault_path,
+ data::{
+ member::Member,
+ vault::{Vault, config::VaultConfig},
+ },
+ },
+};
+use just_enough_vcs_cli::utils::{lang_selector::current_locales, md_colored::md};
+use log::LevelFilter;
+use rust_i18n::{set_locale, t};
+use tokio::fs::{self};
+
+// Import i18n files
+rust_i18n::i18n!("locales/help_docs", fallback = "en");
+
+#[derive(Parser, Debug)]
+#[command(
+ disable_help_flag = true,
+ disable_version_flag = true,
+ disable_help_subcommand = true,
+ help_template = "{all-args}"
+)]
+struct JustEnoughVcsVault {
+ #[command(subcommand)]
+ command: JustEnoughVcsCommand,
+}
+
+#[derive(Subcommand, Debug)]
+enum JustEnoughVcsCommand {
+ /// Get vault info in the current directory
+ Here(HereArgs),
+
+ /// Create a new directory and initialize a vault
+ Create(CreateVaultArgs),
+
+ /// Create a vault in the current directory
+ Init(InitVaultArgs),
+
+ /// Member manage
+ #[command(subcommand)]
+ Member(MemberManage),
+
+ /// Manage service
+ #[command(subcommand)]
+ Service(ServiceManage),
+}
+
+#[derive(Subcommand, Debug)]
+enum MemberManage {
+ /// Register a member to the vault
+ Register(MemberRegisterArgs),
+
+ /// Remove a member from the vault
+ Remove(MemberRemoveArgs),
+
+ /// List all members in the vault
+ List(MemberListArgs),
+
+ /// Show help information
+ #[command(alias = "--help", alias = "-h")]
+ Help,
+}
+
+#[derive(Subcommand, Debug)]
+enum ServiceManage {
+ /// Listen connection at current vault
+ Listen(ListenArgs),
+
+ /// Show help information
+ #[command(alias = "--help", alias = "-h")]
+ Help,
+}
+
+#[derive(Parser, Debug)]
+struct HereArgs {
+ /// Show help information
+ #[arg(short, long)]
+ help: bool,
+}
+
+#[derive(Parser, Debug)]
+struct CreateVaultArgs {
+ /// Show help information
+ #[arg(short, long)]
+ help: bool,
+
+ /// Vault name to create
+ vault_name: String,
+}
+
+#[derive(Parser, Debug)]
+struct InitVaultArgs {
+ /// Show help information
+ #[arg(short, long)]
+ help: bool,
+}
+
+#[derive(Parser, Debug)]
+struct MemberRegisterArgs {
+ /// Show help information
+ #[arg(short, long)]
+ help: bool,
+
+ /// Member name
+ member_name: String,
+}
+
+#[derive(Parser, Debug)]
+struct MemberRemoveArgs {
+ /// Show help information
+ #[arg(short, long)]
+ help: bool,
+
+ /// Member name
+ member_name: String,
+}
+
+#[derive(Parser, Debug)]
+struct MemberListArgs {
+ /// Show help information
+ #[arg(short, long)]
+ help: bool,
+}
+
+#[derive(Parser, Debug)]
+struct ListenArgs {
+ /// Show help information
+ #[arg(short, long)]
+ help: bool,
+
+ /// Disable logging
+ #[arg(short, long)]
+ no_log: bool,
+}
+
+#[tokio::main]
+async fn main() {
+ set_locale(&current_locales());
+
+ let Ok(parser) = JustEnoughVcsVault::try_parse() else {
+ println!("{}", md(t!("jvv.help")));
+ return;
+ };
+
+ match parser.command {
+ JustEnoughVcsCommand::Here(here_args) => {
+ if here_args.help {
+ println!("{}", md(t!("jvv.here")));
+ return;
+ }
+ jvv_here(here_args).await;
+ }
+ JustEnoughVcsCommand::Create(create_vault_args) => {
+ if create_vault_args.help {
+ println!("{}", md(t!("jvv.create")));
+ return;
+ }
+ jvv_create(create_vault_args).await;
+ }
+ JustEnoughVcsCommand::Init(init_vault_args) => {
+ if init_vault_args.help {
+ println!("{}", md(t!("jvv.init")));
+ return;
+ }
+ jvv_init(init_vault_args).await;
+ }
+ JustEnoughVcsCommand::Member(member_manage) => {
+ let vault_cfg = VaultConfig::read()
+ .await
+ .expect(t!("jvv.fail.no_vault_here").trim());
+
+ let vault = match Vault::init_current_dir(vault_cfg) {
+ Some(vault) => vault,
+ None => {
+ eprintln!(
+ "{}",
+ t!("jvv.fail.jvcs", err = "Failed to initialize vault")
+ );
+ return;
+ }
+ };
+
+ match member_manage {
+ MemberManage::Register(member_register_args) => {
+ if member_register_args.help {
+ println!("{}", md(t!("jvv.member")));
+ return;
+ }
+ jvv_member_register(vault, member_register_args).await;
+ }
+ MemberManage::Remove(member_remove_args) => {
+ if member_remove_args.help {
+ println!("{}", md(t!("jvv.member")));
+ return;
+ }
+ jvv_member_remove(vault, member_remove_args).await;
+ }
+ MemberManage::List(member_list_args) => {
+ if member_list_args.help {
+ println!("{}", md(t!("jvv.member")));
+ return;
+ }
+ jvv_member_list(vault, member_list_args).await;
+ }
+ MemberManage::Help => {
+ println!("{}", md(t!("jvv.member")));
+ return;
+ }
+ }
+ }
+ JustEnoughVcsCommand::Service(service_manage) => match service_manage {
+ ServiceManage::Listen(listen_args) => {
+ if listen_args.help {
+ println!("{}", md(t!("jvv.service")));
+ return;
+ }
+ jvv_service_listen(listen_args).await;
+ }
+ ServiceManage::Help => {
+ println!("{}", md(t!("jvv.service")));
+ return;
+ }
+ },
+ }
+}
+
+async fn jvv_here(_args: HereArgs) {
+ let Some(current_vault) = current_vault_path() else {
+ eprintln!("{}", t!("jvv.fail.here.cfg_not_found").trim());
+ return;
+ };
+
+ // Read vault cfg
+ let vault_cfg_file = current_vault.join(SERVER_FILE_VAULT);
+ if !vault_cfg_file.exists() {
+ eprintln!("{}", t!("jvv.fail.here.cfg_not_found").trim());
+ return;
+ }
+
+ let vault_cfg = VaultConfig::read()
+ .await
+ .expect(t!("jvv.fail.here.cfg_not_found").trim());
+
+ // Get vault name
+ let vault_name = vault_cfg.vault_name();
+
+ // Success
+ println!("{}", md(t!("jvv.success.here.root", name = vault_name)))
+}
+
+async fn jvv_init(_args: InitVaultArgs) {
+ let current_dir = std::env::current_dir().expect(t!("jvv.fail.std.current_dir").trim());
+ if !current_dir.read_dir().unwrap().next().is_none() {
+ eprintln!("{}", t!("jvv.fail.init.not_empty"));
+ return;
+ }
+
+ // Setup vault
+ let vault_name = current_dir
+ .file_name()
+ .expect(t!("jvv.fail.std.current_dir_name").trim())
+ .to_string_lossy()
+ .to_string();
+ let vault_name = pascal_case!(vault_name);
+
+ if let Err(err) = Vault::setup_vault(current_dir.clone()).await {
+ eprintln!("{}", t!("jvv.fail.jvcs", err = err.to_string()));
+ return;
+ }
+
+ // Read vault cfg
+ let mut vault_cfg = match VaultConfig::read().await {
+ Ok(cfg) => cfg,
+ Err(err) => {
+ eprintln!("{}", t!("jvv.fail.jvcs", err = err.to_string()));
+ return;
+ }
+ };
+
+ vault_cfg.change_name(vault_name);
+ if let Err(err) = VaultConfig::write(&vault_cfg).await {
+ eprintln!("{}", t!("jvv.fail.jvcs", err = err.to_string()));
+ return;
+ }
+
+ // Success
+ println!(
+ "{}",
+ t!("jvv.success.init", name = current_dir.to_string_lossy())
+ )
+}
+
+async fn jvv_create(args: CreateVaultArgs) {
+ let current_dir = std::env::current_dir().expect(t!("jvv.fail.std.current_dir").trim());
+ let target_dir = current_dir.join(args.vault_name.clone());
+
+ // Create directory
+ if let Err(_) = fs::create_dir_all(&target_dir).await {
+ eprintln!(
+ "{}",
+ t!(
+ "jvv.fail.tokio.fs.create_dir",
+ dir = target_dir.to_string_lossy()
+ )
+ );
+ return;
+ }
+
+ if !target_dir.read_dir().unwrap().next().is_none() {
+ eprintln!("{}", t!("jvv.fail.create.not_empty"));
+ return;
+ }
+
+ // Setup vault
+ let vault_name = pascal_case!(args.vault_name);
+ if let Err(err) = Vault::setup_vault(target_dir.clone()).await {
+ eprintln!("{}", t!("jvv.fail.jvcs", err = err.to_string()));
+ return;
+ }
+
+ // Enter target_dir
+ if let Err(_) = set_current_dir(&target_dir) {
+ eprintln!(
+ "{}",
+ t!(
+ "jvv.fail.std.set_current_dir",
+ dir = target_dir.to_string_lossy()
+ )
+ );
+ return;
+ }
+
+ // Read vault cfg
+ let mut vault_cfg = match VaultConfig::read().await {
+ Ok(cfg) => cfg,
+ Err(err) => {
+ eprintln!("{}", t!("jvv.fail.jvcs", err = err.to_string()));
+ return;
+ }
+ };
+
+ vault_cfg.change_name(vault_name);
+ if let Err(err) = VaultConfig::write(&vault_cfg).await {
+ eprintln!("{}", t!("jvv.fail.jvcs", err = err.to_string()));
+ return;
+ }
+
+ // Success
+ println!(
+ "{}",
+ t!("jvv.success.create", name = target_dir.to_string_lossy())
+ )
+}
+
+async fn jvv_member_register(vault: Vault, args: MemberRegisterArgs) {
+ let register = vault
+ .register_member_to_vault(Member::new(args.member_name.clone()))
+ .await;
+
+ if register.is_err() {
+ eprintln!("{}", t!("jvv.fail.member.register").trim());
+ return;
+ }
+
+ println!(
+ "{}",
+ t!("jvv.success.member.register", member = args.member_name)
+ )
+}
+
+async fn jvv_member_remove(vault: Vault, args: MemberRemoveArgs) {
+ let _ = vault.remove_member_from_vault(&args.member_name);
+
+ println!(
+ "{}",
+ t!("jvv.success.member.remove", member = args.member_name)
+ )
+}
+
+async fn jvv_member_list(vault: Vault, _args: MemberListArgs) {
+ // Get id list
+ let ids = vault.member_ids().expect(t!("jvv.fail.member.list").trim());
+
+ // Print header
+ println!("{}", md(t!("jvv.success.member.list.header")));
+
+ // Print list
+ let mut i = 0;
+ for member in ids {
+ println!("{}. {}", i + 1, member);
+ i += 1;
+ }
+
+ // Print footer
+ println!("{}", md(t!("jvv.success.member.list.footer", num = i)));
+}
+
+async fn jvv_service_listen(args: ListenArgs) {
+ let Some(current_vault) = current_vault_path() else {
+ eprintln!("{}", t!("jvv.fail.here.cfg_not_found").trim());
+ return;
+ };
+
+ if !args.no_log {
+ build_env_logger(current_vault.join("log.txt"));
+ }
+
+ let _ = server_entry(current_vault).await;
+}
+
+fn build_env_logger(log_path: impl AsRef<Path>) {
+ let mut builder = Builder::from_default_env();
+ builder
+ .filter_level(LevelFilter::Info)
+ .target(Target::Stdout);
+
+ let log_file = std::fs::File::create(log_path).expect("Failed to create log file");
+ builder
+ .filter_module("just_enough_vcs", LevelFilter::Trace)
+ .target(Target::Pipe(Box::new(log_file)))
+ .init();
+}