summaryrefslogtreecommitdiff
path: root/rola-cli/src/bucket_mgr
diff options
context:
space:
mode:
Diffstat (limited to 'rola-cli/src/bucket_mgr')
-rw-r--r--rola-cli/src/bucket_mgr/creation.rs119
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;
+}