diff options
| author | 魏曹先生 <1992414357@qq.com> | 2026-06-18 04:40:25 +0800 |
|---|---|---|
| committer | 魏曹先生 <1992414357@qq.com> | 2026-06-18 04:40:25 +0800 |
| commit | 7879ac01b24eb9723ec0a814adaee1fc9c52610a (patch) | |
| tree | d1c9a07e3ef8819869494c45e96bcd3e98856bdb /rola-cli/src/bucket_mgr | |
| parent | 0b8e6e7d18abb94bd99553dc1d2b0ba5d4f265ea (diff) | |
feat(rola-cli): implement bucket creation and CLI entry point
Add bucket creation logic with pre-checks, localized error handling, and
a basic CLI entry point using the mingling framework. Introduce a
placeholder protocol for bucket transfer testing.
Diffstat (limited to 'rola-cli/src/bucket_mgr')
| -rw-r--r-- | rola-cli/src/bucket_mgr/creation.rs | 119 |
1 files changed, 119 insertions, 0 deletions
diff --git a/rola-cli/src/bucket_mgr/creation.rs b/rola-cli/src/bucket_mgr/creation.rs new file mode 100644 index 0000000..831a3e7 --- /dev/null +++ b/rola-cli/src/bucket_mgr/creation.rs @@ -0,0 +1,119 @@ +use std::{fs::create_dir_all, path::PathBuf}; + +use mingling::{ + macros::{chain, dispatcher, pack, r_println, renderer, route}, + parser::AsPicker, + res::ResExitCode, +}; +use rorolala::bucket::{Bucket, NoProtocol}; +use space_system::{Space, SpaceError}; + +use crate::{ + Next, error::ErrorIo, locale::I18nBucketManager, res::current_dir::ResCurrentDir, tkr, +}; + +pub const EC_BUCKET_CREATE_DIR_NOT_EMPTY: i32 = 2400; +pub const EC_BUCKET_PATH_NOT_PROVIDED: i32 = 2401; +pub const EC_BUCKET_PATH_NOT_DIRECTORY: i32 = 2402; + +dispatcher!("bucket.init"); +dispatcher!("bucket.create"); + +pack!(StateBucketCreationPrecheck = PathBuf); +pack!(StateBucketCreation = PathBuf); + +pack!(ResultBucketCreated = PathBuf); + +pack!(ErrorDirectoryNotEmpty = PathBuf); +pack!(ErrorBucketPathNotProvided = ()); +pack!(ErrorBucketPathNotDirectory = PathBuf); + +#[chain] +pub fn handle_bucket_init(_args: EntryBucketInit, cwd: &mut ResCurrentDir) -> Next { + // NOTE: It's a dirty operation :D + // Directly extract the value of the cwd resource for use, reducing Clone + // because it's guaranteed that `ResCurrentDir` won't be used after `handle_bucket_init` + let cwd = std::mem::take(&mut cwd.cwd); + StateBucketCreationPrecheck::new(cwd) +} + +#[chain] +pub fn handle_bucket_create(args: EntryBucketCreate) -> Next { + let join = route! { + args.pick_or_route::<PathBuf, _>((), + ErrorBucketPathNotProvided::new(()).to_render() + ).unpack() + }; + StateBucketCreationPrecheck::new(join).to_chain() +} + +#[chain] +pub fn handle_state_bucket_creation_precheck(create: StateBucketCreationPrecheck) -> Next { + let path = create.inner; + if path.exists() { + if !path.is_dir() { + return ErrorBucketPathNotDirectory::new(path).to_render(); + } + if path + .read_dir() + .map(|mut it| it.next().is_some()) + .unwrap_or(false) + { + return ErrorDirectoryNotEmpty::new(path).to_render(); + } + } + StateBucketCreation::new(path).to_chain() +} + +#[chain] +pub fn handle_state_bucket_creation(create: StateBucketCreation) -> Next { + let path = create.inner; + + route! { + create_dir_all(&path).map_err(|e| ErrorIo::from(e).to_render()) + }; + + // Use a protocol-less Bucket as a temporary Space for initialization + let bucket_space = Space::<Bucket<NoProtocol>>::new(Bucket::<NoProtocol>::new_local()); + + // 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 } { + return ErrorIo::from(error).to_render(); + } + + ResultBucketCreated::new(path).to_render() +} + +#[renderer] +pub fn render_result_bucket_created(result: ResultBucketCreated) { + let path = result.inner.to_string_lossy(); + r_println!("{}", I18nBucketManager::created(path)); +} + +#[renderer] +pub fn render_error_directory_not_empty(_err: ErrorDirectoryNotEmpty, ec: &mut ResExitCode) { + r_println!("{}", I18nBucketManager::error_directory_not_empty().trim()); + ec.exit_code = EC_BUCKET_CREATE_DIR_NOT_EMPTY; +} + +#[renderer] +pub fn render_error_bucket_path_not_provided( + _err: ErrorBucketPathNotProvided, + ec: &mut ResExitCode, +) { + r_println!( + "{}", + I18nBucketManager::error_bucket_path_not_provided().trim() + ); + ec.exit_code = EC_BUCKET_PATH_NOT_PROVIDED; +} + +#[renderer] +pub fn render_error_bucket_path_not_directory( + _err: ErrorBucketPathNotDirectory, + ec: &mut ResExitCode, +) { + r_println!("{}", I18nBucketManager::error_directory_not_empty().trim()); + ec.exit_code = EC_BUCKET_PATH_NOT_DIRECTORY; +} |
