sdoc/commands/
init.rs

1use ansi_term::Color::{Blue, Green, Red};
2use config::Context;
3use dto::Request;
4use dto::Response;
5use model::{Command, Section, Value};
6use serde_yaml;
7use std::{
8    env,
9    fs::{create_dir_all, File, Permissions},
10    io::{Error, ErrorKind, prelude::Write, stdin},
11    os::unix::fs::PermissionsExt,
12    path::PathBuf,
13    process,
14    result::Result,
15    str::FromStr,
16};
17use workflow::Instruction;
18use workflow::Work;
19use model::default_behaviour;
20
21fn default_config() -> Vec<Section> {
22    let hello_world = Command {
23        name: s!("hello"),
24        description: s!("Prints hello world"),
25        alias: Some(s!("hw")),
26        value: Some(Value::Shell(s!("echo hello world"))),
27        internal: default_behaviour(),
28        usage: None,
29        min_args: None,
30        dependencies: None,
31    };
32
33    vec![Section {
34        heading: s!("Commands"),
35        commands: vec![hello_world],
36        core: false
37    }]
38}
39
40#[derive(Debug)]
41enum Answer {
42    Yes,
43    No,
44}
45
46impl FromStr for Answer {
47    type Err = ();
48
49    fn from_str(s: &str) -> Result<Self, <Self as FromStr>::Err> {
50        match s {
51            "y" => Ok(Answer::Yes),
52            "n" => Ok(Answer::No),
53            _ => Err(())
54        }
55    }
56}
57
58fn ask(question: &String) -> String {
59    let mut input = String::new();
60    loop {
61        println!("{}", question);
62        if let Ok(v) = stdin().read_line(&mut input).map(|_| input.trim()) {
63            if v.len() > 0 {
64                return v.to_owned();
65            }
66        }
67        input.clear();
68    }
69}
70
71fn confirm(question: &str) -> Answer {
72    let formatted_question = format!("{} (y/n)", question);
73    loop {
74        if let Ok(a) = ask(&formatted_question).parse::<Answer>() {
75            return a;
76        }
77    }
78}
79
80fn create_dir_if_not_exists(path: &PathBuf) -> Result<(), Error> {
81    if path.is_dir() {
82        Ok(())
83    } else {
84        create_dir_all(path)
85    }
86}
87
88pub fn run_setup(request: Request, _: &Context) -> Work {
89    let no_output = Work::instruction(Instruction::ExitCode(Response::Ok));
90
91    let directory = request.next().current
92        .map(PathBuf::from)
93        .unwrap_or(env::current_dir().unwrap());
94
95    println!("{}", Blue.paint("sdoc init"));
96
97    if let Answer::No = confirm(&format!("Setup a new CLI in {:?}?", directory)) {
98        println!("Goodbye");
99        return no_output;
100    }
101
102    let cli_name = ask(&s!("Enter your CLI name:"));
103    let content = format!("\
104#! /bin/bash -ue
105dir=$(cd $( dirname $( realpath \"{}\" ) ) && cd .. && pwd )
106COMMANDS_DIRECTORY=\"$dir\" CLI_NAME='{}' sdoc \"$@\"", "${BASH_SOURCE[0]}", cli_name);
107
108    let bin_directory = directory.join("bin");
109    let bin = &bin_directory.join(&cli_name);
110    let commands_directory = &directory.join(&cli_name);
111    let commands_yaml = &commands_directory.join("commands.yaml");
112
113    match create_dir_if_not_exists(&bin_directory)
114        .and_then(|_| File::create(&bin))
115        .and_then(|mut bin| {
116            bin.write_all(content.as_bytes())
117                .and_then(|_| bin.set_permissions(Permissions::from_mode(0o755)))
118        })
119        .and_then(|_| create_dir_if_not_exists(&commands_directory))
120        .and_then(|_| File::create(&commands_yaml))
121        .and_then(|mut y|
122            serde_yaml::to_string(&default_config())
123                .map_err(|e| Error::new(ErrorKind::Other, e))
124                .and_then(|yaml| y.write_all(yaml.as_bytes()))
125        ) {
126        Ok(_) => {
127            println!("{}", Green.paint("Setup Complete"));
128            println!("Execute ./bin/{} to begin. Even better, add '$(pwd)/bin' to your $PATH", cli_name);
129        }
130        Err(e) => {
131            println!("{}: {:?}", Red.paint("Setup Failed"), e);
132            process::exit(1);
133        }
134    };
135
136    no_output
137}