scost/command/
mod.rs

1use std::marker::PhantomData;
2
3use anyhow::anyhow;
4use prettytable::Table;
5
6use crate::bucket::BucketPtr;
7use crate::GlobalInstance;
8use crate::Result;
9
10mod copy;
11mod list;
12mod remove;
13mod sign;
14
15pub trait Command {
16    const COMMAND: &'static str;
17    const NUM_ARGS: usize;
18    const HELP: &'static str;
19
20    async fn execute(buckets: &[BucketPtr], path: &str) -> Result<Table>;
21}
22
23pub struct CommandHelper<C> {
24    _c: PhantomData<C>,
25}
26
27impl<C: Command> CommandHelper<C> {
28    pub const COMMAND: &'static str = C::COMMAND;
29
30    /// Parse and execute the command.
31    ///
32    /// A command's `args` always starts with a list of bucket aliases,
33    /// and the last argument is a path.
34    pub async fn execute(args: &[String]) -> Result<Table> {
35        if args.len() != C::NUM_ARGS {
36            return Err(anyhow!(
37                "Command {} requires {} argument(s), but got {}. Usage: {}",
38                C::COMMAND,
39                C::NUM_ARGS,
40                args.len(),
41                C::HELP
42            ));
43        }
44
45        let instance = GlobalInstance::instance();
46
47        let mut buckets = Vec::with_capacity(C::NUM_ARGS - 1);
48        for b in args[0..C::NUM_ARGS - 1].iter() {
49            if b == "*" {
50                buckets.extend(instance.get_buckets());
51            } else {
52                let op = instance
53                    .get_bucket(b)
54                    .ok_or(anyhow!("Bucket '{}' not found", b))?;
55                buckets.push(op);
56            }
57        }
58        let path = &args.last().unwrap();
59
60        C::execute(&buckets, path).await
61    }
62}
63
64pub type CommandCopy = CommandHelper<copy::Copy>;
65pub type CommandList = CommandHelper<list::List>;
66pub type CommandRemove = CommandHelper<remove::Remove>;
67pub type CommandSign = CommandHelper<sign::Sign>;
68
69pub const COMMANDS: [&str; 4] = [
70    CommandCopy::COMMAND,
71    CommandList::COMMAND,
72    CommandRemove::COMMAND,
73    CommandSign::COMMAND,
74];