diff options
Diffstat (limited to 'rola-cli/src/bucket_mgr')
| -rw-r--r-- | rola-cli/src/bucket_mgr/bind.rs | 262 | ||||
| -rw-r--r-- | rola-cli/src/bucket_mgr/creation.rs | 27 |
2 files changed, 277 insertions, 12 deletions
diff --git a/rola-cli/src/bucket_mgr/bind.rs b/rola-cli/src/bucket_mgr/bind.rs new file mode 100644 index 0000000..48186a2 --- /dev/null +++ b/rola-cli/src/bucket_mgr/bind.rs @@ -0,0 +1,262 @@ +use colored::Colorize; +use mingling::{ + Groupped, LazyRes, + macros::{chain, dispatcher_clap, pack, pack_err, r_println, renderer}, + res::ResExitCode, +}; +use rorolala::bucket::{self, bind::BucketBind}; +use serde::Serialize; +use shared_functions::info; + +use crate::{ + Next, + bucket_mgr::ResultEnumBucketOperation::Set, + error::{ErrorRequireOverwrite, ErrorSpace}, + locale::I18nBucketManager, + output::display::markdown, + res::{bucket::ResBucketWithoutProtocol, overwrite::ResOverwrite}, +}; + +pub const EC_BUCKET_BIND_INDEX_NOT_PROVIDED: i32 = 251; +pub const EC_BUCKET_BIND_INDEX_NOT_FOUND: i32 = 252; + +#[derive(Default, clap::Parser, Serialize, Groupped)] +#[dispatcher_clap("bucket.bind", CMDBucketBind)] +pub struct EntryBucketBind { + index: Option<u8>, + + #[arg(long, conflicts_with_all = ["set"])] + remove: bool, + + #[arg(long, conflicts_with_all = ["remove"])] + set: Option<String>, +} + +pack!(StateBucketBindListAll = ()); +pack!(StateBucketBindListSpecified = u8); +pack!(StateBucketBindRemove = u8); +pack!(StateBucketBindSet = (u8, String)); // idx, url + +#[derive(Default, Serialize, Groupped)] +pub struct ResultAllBucketBind { + bind_list: Vec<BucketBind>, +} + +#[derive(Default, Serialize, Groupped)] +pub struct ResultOneBucketBind { + index: u8, + url: String, +} + +#[derive(Default, Serialize, Groupped)] +pub struct ResultBucketOperated { + pub operation: ResultEnumBucketOperation, + pub index: u8, + pub url: Option<String>, +} + +#[derive(Default, Serialize)] +pub enum ResultEnumBucketOperation { + #[serde(rename = "none")] + #[default] + None, + #[serde(rename = "set_bind")] + Set, + #[serde(rename = "remove_bind")] + Remove, +} + +pack_err!(ErrorBucketBindIndexNotProvided); +pack_err!(ErrorBucketBindIndexNotFound = u8); + +// Chains + +#[chain] +pub fn handle_bucket_bind(args: EntryBucketBind) -> Next { + match args.index { + Some(op_idx) => { + if let Some(url) = args.set { + // bind idx --set url + return StateBucketBindSet::new((op_idx, url)).to_chain(); + } else if args.remove { + // bind idx --remove + return StateBucketBindRemove::new(op_idx).to_chain(); + } else { + // bind idx + return StateBucketBindListSpecified::new(op_idx).to_chain(); + } + } + None => { + if !args.remove && args.set.is_none() { + // bind + return StateBucketBindListAll::new(()).to_chain(); + } else { + // index not provided + // bind --set url + // or + // bind --remove + return ErrorBucketBindIndexNotProvided::default().to_render(); + } + } + } +} + +#[chain] +pub fn handle_state_bucket_bind_set( + set: StateBucketBindSet, + bucket: &mut LazyRes<ResBucketWithoutProtocol>, + overwrite: &ResOverwrite, +) -> Next { + let (index, url) = set.inner; + let bucket_space_ref = &bucket.get_ref().space; + + let exist = match bucket::bind::check_bucket_bind_exists(bucket_space_ref, index) { + Ok(exists) => exists, + Err(e) => return ErrorSpace::from(e).to_chain(), + }; + + // When the bind already exists but overwrite is not specified + // Dispatch to ErrorRequireOverwrite + if exist && !overwrite.overwrite { + return ErrorRequireOverwrite::default().to_render(); + } + + if let Err(space_error) = + bucket::bind::write_bucket_bind(bucket_space_ref, index, url.clone().as_str()) + { + ErrorSpace::from(space_error).to_chain(); + } + + ResultBucketOperated { + operation: Set, + index, + url: Some(url), + } + .to_render() +} + +#[chain] +pub fn handle_state_bucket_bind_remove( + remove: StateBucketBindRemove, + bucket: &mut LazyRes<ResBucketWithoutProtocol>, +) -> Next { + let index = remove.inner; + let bucket_space_ref = &bucket.get_ref().space; + + if let Err(space_error) = bucket::bind::remove_bucket_bind(bucket_space_ref, index) { + return ErrorSpace::from(space_error).to_chain(); + } + + ResultBucketOperated { + operation: ResultEnumBucketOperation::Remove, + index, + url: None, + } + .to_render() +} + +#[chain] +pub fn handle_state_bucket_bind_list_specified( + index: StateBucketBindListSpecified, + bucket: &mut LazyRes<ResBucketWithoutProtocol>, +) -> Next { + let index = index.inner; + let bucket_space_ref = &bucket.get_ref().space; + let bind_info = match bucket::bind::read_bucket_bind(bucket_space_ref, index) { + Err(e) => return ErrorSpace::from(e).to_chain(), + Ok(None) => return ErrorBucketBindIndexNotFound::new(index).to_render(), + Ok(Some(r)) => r, + }; + + ResultOneBucketBind { + index: bind_info.get_index(), + url: bind_info.get_url().to_string(), + } + .to_render() +} + +#[chain] +pub fn handle_state_bucket_bind_list_all( + _p: StateBucketBindListAll, + bucket: &mut LazyRes<ResBucketWithoutProtocol>, +) -> Next { + let bucket_space_ref = &bucket.get_ref().space; + info!("Reading all bucket binds from space"); + let bind_list = match bucket::bind::read_bucket_binds(bucket_space_ref) { + Err(e) => return ErrorSpace::from(e).to_chain(), + Ok(r) => r, + }; + info!("Read {} bucket binds", bind_list.len()); + ResultAllBucketBind { bind_list }.to_render() +} + +// Result Renderers + +#[renderer] +pub fn render_result_one_bucket_bind(result: ResultOneBucketBind) { + r_println!("BIND_{} => \"{}\"", result.index, result.url.trim().bold()); +} + +#[renderer] +pub fn render_result_all_bucket_bind(result: ResultAllBucketBind) { + let list: Vec<String> = result + .bind_list + .iter() + .map(|b| { + format!( + "BIND_{} => \"{}\"", + b.get_index(), + b.get_url().trim().bold() + ) + }) + .collect(); + for item in list { + r_println!("{}", item); + } +} + +#[renderer] +pub fn render_result_bucket_operated(result: ResultBucketOperated) { + let index = result.index; + let url = result.url.unwrap_or("".to_string()); + match result.operation { + ResultEnumBucketOperation::Set => { + r_println!( + "{} BIND_{} => \"{}\"", + "+++".bold().bright_green(), + index, + url.bold().trim() + ) + } + ResultEnumBucketOperation::Remove => { + r_println!("{} BIND_{}", "---".bold().bright_red(), index) + } + _ => {} + } +} + +// Error Renderers + +#[renderer] +pub fn render_error_bucket_bind_index_not_provided( + _err: ErrorBucketBindIndexNotProvided, + ec: &mut ResExitCode, +) { + r_println!( + "{}", + markdown(I18nBucketManager::error_bind_index_not_provided().trim()) + ); + ec.exit_code = EC_BUCKET_BIND_INDEX_NOT_PROVIDED; +} + +#[renderer] +pub fn render_error_bucket_bind_index_not_found( + err: ErrorBucketBindIndexNotFound, + ec: &mut ResExitCode, +) { + r_println!( + "{}", + markdown(I18nBucketManager::error_bind_index_not_found(err.info.to_string()).trim()) + ); + ec.exit_code = EC_BUCKET_BIND_INDEX_NOT_FOUND; +} diff --git a/rola-cli/src/bucket_mgr/creation.rs b/rola-cli/src/bucket_mgr/creation.rs index c363773..2394228 100644 --- a/rola-cli/src/bucket_mgr/creation.rs +++ b/rola-cli/src/bucket_mgr/creation.rs @@ -1,16 +1,16 @@ use std::{fs::create_dir_all, path::PathBuf}; use mingling::{ - macros::{chain, dispatcher, pack, r_println, renderer, route}, + Groupped, + macros::{chain, dispatcher, pack, pack_err, r_println, renderer, route}, parser::AsPicker, res::ResExitCode, }; use rorolala::bucket::{Bucket, NoProtocol}; +use serde::Serialize; use space_system::{Space, SpaceError, SpaceRoot, find_space_root_with}; -use crate::{ - Next, error::ErrorIo, locale::I18nBucketManager, res::current_dir::ResCurrentDir, tkr, -}; +use crate::{Next, error::ErrorIo, locale::I18nBucketManager, res::current_dir::ResCurrentDir}; pub const EC_BUCKET_CREATE_DIR_NOT_EMPTY: i32 = 2400; pub const EC_BUCKET_PATH_NOT_PROVIDED: i32 = 2401; @@ -23,12 +23,15 @@ dispatcher!("bucket.create"); pack!(StateBucketCreationPrecheck = PathBuf); pack!(StateBucketCreation = PathBuf); -pack!(ResultBucketCreated = PathBuf); +#[derive(Debug, Groupped, Serialize)] +pub struct ResultBucketCreated { + bucket_path: PathBuf, +} -pack!(ErrorDirectoryNotEmpty = PathBuf); -pack!(ErrorBucketPathNotProvided = ()); -pack!(ErrorBucketPathNotDirectory = PathBuf); -pack!(ErrorBucketPathNested = PathBuf); +pack_err!(ErrorDirectoryNotEmpty = PathBuf); +pack_err!(ErrorBucketPathNotProvided = ()); +pack_err!(ErrorBucketPathNotDirectory = PathBuf); +pack_err!(ErrorBucketPathNested = PathBuf); #[chain] pub fn handle_bucket_init(_args: EntryBucketInit, cwd: &mut ResCurrentDir) -> Next { @@ -86,16 +89,16 @@ pub fn handle_state_bucket_creation(create: StateBucketCreation) -> Next { // Initialize the Space and capture any SpaceError::Io let path_to_init = path.clone(); - if let Err(SpaceError::Io(error)) = tkr! { bucket_space.init(path_to_init).await } { + if let Err(SpaceError::Io(error)) = bucket_space.init(path_to_init) { return ErrorIo::from(error).to_render(); } - ResultBucketCreated::new(path).to_render() + ResultBucketCreated { bucket_path: path }.to_render() } #[renderer] pub fn render_result_bucket_created(result: ResultBucketCreated) { - let path = result.inner.to_string_lossy(); + let path = result.bucket_path.to_string_lossy(); r_println!("{}", I18nBucketManager::created(path)); } |
