Skip to main content

cargo_cbt/
cli.rs

1use crate::{shell_command, Result};
2use clap::Parser;
3use iocore::Path;
4
5#[derive(Parser, Debug)]
6#[command(author, version, about, long_about = "cargo_cbt command-line utility")]
7pub struct Cli {
8    #[arg()]
9    path: Option<Path>,
10
11    #[arg(short, long)]
12    quiet: bool,
13
14    #[arg(short, long, help = "build docs with `cargo docs'")]
15    docs: bool,
16
17    #[arg(short = 'O', long, requires = "docs", help = "runs `cargo docs --open'")]
18    open_docs: bool,
19
20    #[arg(short, long)]
21    purge: bool,
22
23    #[arg(short, long)]
24    release: bool,
25
26    #[arg(short = 'A', long)]
27    all_targets: bool,
28
29    #[arg(short, long)]
30    all_features: bool,
31
32    #[arg(short, long)]
33    ignore_errors: bool,
34
35    #[arg(short = 'c', long, help = "capture test output")]
36    test_capture: bool,
37
38    #[arg(short, long, help = "do not clear console before running")]
39    no_clear_console: bool,
40
41    #[arg(long)]
42    test: Option<String>,
43
44    #[arg()]
45    opts: Vec<String>,
46}
47impl Cli {
48    pub fn rustc_and_cargo_opts(&self) -> String {
49        if iocore::env::var("COLORTERM")
50            .unwrap_or_default()
51            .trim()
52            .to_lowercase()
53            == "truecolor"
54            || iocore::env::var("TERM")
55                .unwrap_or_default()
56                .trim()
57                .starts_with("xterm")
58        {
59            format!("--color always")
60        } else {
61            String::new()
62        }
63    }
64    pub fn opts(&self) -> String {
65        [
66            self.rustc_and_cargo_opts(),
67            self.release
68                .then_some("--release".to_string())
69                .unwrap_or_default(),
70            self.all_targets
71                .then_some("--all-targets".to_string())
72                .unwrap_or_default(),
73            self.all_features
74                .then_some("--all-features".to_string())
75                .unwrap_or_default(),
76            self.opts.join(" "),
77        ]
78        .join(" ")
79        .trim()
80        .to_string()
81    }
82    pub fn check_opts(&self) -> String {
83        format!("{}", self.opts())
84    }
85    pub fn build_opts(&self) -> String {
86        format!("{}", self.opts())
87    }
88    pub fn test_opts(&self) -> String {
89        format!(
90            "{}",
91            if self.test_capture {
92                self.opts.join(" ")
93            } else {
94                format!(
95                    " -j 1{}{} -- --nocapture {}",
96                    self.opts.join(" "),
97                    if let Some(test) = &self.test {
98                        format!("--test {}", test)
99                    } else {
100                        String::new()
101                    },
102                    self.rustc_and_cargo_opts()
103                )
104            }
105        )
106    }
107    pub fn docs_opts(&self) -> String {
108        let opts = self.opts();
109        if self.open_docs {
110            format!("{opts} --open")
111        } else {
112            opts
113        }
114    }
115    pub fn check_command(&self) -> String {
116        format!("cargo check {}", self.check_opts())
117            .trim()
118            .to_string()
119    }
120    pub fn build_command(&self) -> String {
121        format!("cargo build {}", self.build_opts())
122            .trim()
123            .to_string()
124    }
125    pub fn test_command(&self) -> String {
126        format!("cargo test {}", self.test_opts())
127            .trim()
128            .to_string()
129    }
130    pub fn docs_command(&self) -> String {
131        format!("cargo docs {}", self.docs_opts())
132            .trim()
133            .to_string()
134    }
135}
136
137pub fn go(cli: &Cli) -> Result<()> {
138    if cli.purge {
139        let target = Path::new("target");
140        if target.is_dir() {
141            target.delete()?;
142        }
143    }
144    if !cli.no_clear_console {
145        shell_command(format!("tput clear"), Path::cwd())?;
146    }
147
148    let mut commands = if let Some(_) = &cli.test {
149        vec![cli.test_command()]
150    } else {
151        vec![cli.check_command(), cli.build_command(), cli.test_command()]
152    };
153
154    if cli.docs {
155        commands.push(cli.docs_command());
156    }
157
158    let cwd = Path::cwd();
159    if cli.ignore_errors {
160        for command in commands.into_iter() {
161            if shell_command(&command, &cwd).is_ok() {
162                println!("{command}: OK");
163            } else {
164                eprintln!("{command}: ERROR");
165            }
166        }
167    } else {
168        for command in commands.into_iter() {
169            shell_command(&command, &cwd)?;
170        }
171    }
172    Ok(())
173}