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}