1use std::process::exit;
2
3use clap::{App, Arg, ArgMatches, SubCommand};
4use failure::Fail;
5
6use super::super::SubCmd;
7
8use crate::config::Config;
9use crate::core::repo::{self, Repository};
10
11pub fn new() -> Box<dyn SubCmd> {
12 Box::new(Bank::new())
13}
14
15pub struct Bank();
16
17impl Bank {
18 pub fn new() -> Bank {
19 Bank()
20 }
21
22 fn wrapped_exec(&self, matches: &ArgMatches, config: Config) -> Result<()> {
23 let repo_path = matches
24 .value_of("repo")
25 .map(|s| s.parse().unwrap())
26 .or_else(|| config.repository_path().map(|p| p.to_owned()))
27 .ok_or_else(|| Error::Arg("no repository path"))?;
28
29 let repository = Repository::open(&repo_path)?;
30 let name = matches.value_of("name").unwrap();
31 let path = matches.value_of("path").unwrap();
32
33 if repository.bank_exists(name)? {
34 println!("bank '{}' already exists.", name);
35 return Ok(());
36 }
37
38 repository.create_bank(name, path)?;
39
40 Ok(())
41 }
42}
43
44impl SubCmd for Bank {
45 fn name(&self) -> &'static str {
46 "bank"
47 }
48
49 fn command_args(&self) -> App {
50 SubCommand::with_name(self.name())
51 .about("create or initialize bank")
52 .arg(
53 Arg::with_name("repo")
54 .long("repo")
55 .takes_value(true)
56 .help("Overwrite repository path"),
57 )
58 .arg(
59 Arg::with_name("name")
60 .short("n")
61 .long("name")
62 .takes_value(true)
63 .required(true)
64 .help("Bank name"),
65 )
66 .arg(
67 Arg::with_name("path")
68 .short("p")
69 .long("path")
70 .takes_value(true)
71 .required(true)
72 .help("Target path"),
73 )
74 }
75
76 fn exec(&self, matches: &ArgMatches, config: Config) -> ! {
77 match self.wrapped_exec(matches, config) {
78 Ok(()) => exit(0),
79 Err(e) => {
80 eprintln!("{}", e);
81 if cfg!(debug_assertions) {
82 eprintln!("{:#?}", e);
83 }
84 exit(1)
85 }
86 }
87 }
88}
89
90type Result<T> = std::result::Result<T, Error>;
91
92#[derive(Debug, Fail)]
93pub enum Error {
94 #[fail(display = "repository operation error: {}", _0)]
95 Repo(#[fail(cause)] repo::Error),
96
97 #[fail(display = "{}", _0)]
98 Arg(&'static str),
99}
100
101impl From<repo::Error> for Error {
102 fn from(e: repo::Error) -> Error {
103 Error::Repo(e)
104 }
105}