summaryrefslogtreecommitdiff
path: root/rola-cli/src/bucket_mgr/creation.rs
blob: 831a3e70f2eda665534f12da32ffa69c37437164 (plain) (blame)
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;
}