1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
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;
}
|