cli/
lib.rs

1#[macro_use]
2extern crate log;
3
4pub mod cargo_manifest;
5pub mod commands;
6pub mod error;
7
8use clap::Clap;
9use colored::Colorize;
10use commands::*;
11use creator_tools::utils::{Config, Shell, Verbosity};
12use std::path::PathBuf;
13
14#[derive(Clap, Clone, Debug)]
15#[clap(author, about, version)]
16pub struct Opts {
17    /// The current directory where to run all commands
18    #[clap(short, long)]
19    pub current_dir: Option<PathBuf>,
20    /// A level of verbosity, and can be used multiple times
21    #[clap(short, long, parse(from_occurrences))]
22    pub verbose: u32,
23    /// No output printed to stdout
24    #[clap(short, long)]
25    pub quiet: bool,
26
27    #[clap(subcommand)]
28    pub cmd: Commands,
29}
30
31impl Opts {
32    pub fn get_verbosity(&self) -> Verbosity {
33        if self.quiet {
34            Verbosity::Quiet
35        } else {
36            // Vary the output based on how many times the user used the "verbose" flag.
37            // Example: `creator -v -v -v' or 'creator -vvv' vs 'creator -v'
38            match self.verbose {
39                0 => Verbosity::Normal,
40                1 => Verbosity::Verbose,
41                _ => {
42                    pretty_env_logger::formatted_builder()
43                        .filter_level(log::LevelFilter::Trace)
44                        .init();
45                    Verbosity::Verbose
46                }
47            }
48        }
49    }
50
51    pub fn get_current_dir(&self) -> PathBuf {
52        self.current_dir
53            .clone()
54            .unwrap_or_else(|| std::env::current_dir().unwrap())
55    }
56}
57
58pub fn run() -> std::result::Result<(), Box<dyn std::error::Error>> {
59    let opts = Opts::parse();
60    let mut shell = Shell::new();
61    shell.set_verbosity(opts.get_verbosity());
62    let config = Config::new(shell, opts.get_current_dir());
63    opts.cmd.handle_command(&config)?;
64    Ok(())
65}
66
67pub fn handle_errors(run: impl FnOnce() -> std::result::Result<(), Box<dyn std::error::Error>>) {
68    if let Err(error) = run() {
69        eprintln!("{}: {}", "error".red().bold(), error);
70        handle_error_source(error.source());
71        std::process::exit(1);
72    };
73}
74
75fn handle_error_source(source: Option<&(dyn std::error::Error + 'static)>) {
76    if let Some(error) = source {
77        eprintln!("{}: {}", "caused by".red().bold(), error);
78        handle_error_source(error.source());
79    }
80}