Skip to main content

cargo_options/
check.rs

1use std::ops::{Deref, DerefMut};
2use std::path::PathBuf;
3use std::process::Command;
4
5use clap::{ArgAction, Parser};
6
7#[cfg(feature = "serde")]
8use serde::{Deserialize, Serialize};
9
10use crate::common::CommonOptions;
11use crate::heading;
12
13/// `cargo check` options which are also a subset of `cargo clippy`
14#[derive(Clone, Debug, Default, Parser)]
15#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
16pub struct CheckOptions {
17    /// Package(s) to check
18    #[arg(
19        short = 'p',
20        long = "package",
21        value_name = "SPEC",
22        action = ArgAction::Append,
23        num_args=0..=1,
24        help_heading = heading::PACKAGE_SELECTION,
25    )]
26    #[cfg_attr(feature = "serde", serde(default))]
27    pub packages: Vec<String>,
28
29    /// Check all packages in the workspace
30    #[arg(long, help_heading = heading::PACKAGE_SELECTION)]
31    #[cfg_attr(feature = "serde", serde(default))]
32    pub workspace: bool,
33
34    /// Exclude packages from the check
35    #[arg(
36        long,
37        value_name = "SPEC",
38        action = ArgAction::Append,
39        help_heading = heading::PACKAGE_SELECTION,
40    )]
41    #[cfg_attr(feature = "serde", serde(default))]
42    pub exclude: Vec<String>,
43
44    /// Alias for workspace (deprecated)
45    #[arg(long, help_heading = heading::PACKAGE_SELECTION,)]
46    #[cfg_attr(feature = "serde", serde(default))]
47    pub all: bool,
48
49    /// Check only this package's library
50    #[arg(long, help_heading = heading::TARGET_SELECTION)]
51    #[cfg_attr(feature = "serde", serde(default))]
52    pub lib: bool,
53
54    /// Check only the specified binary
55    #[arg(
56        long,
57        value_name = "NAME",
58        action = ArgAction::Append,
59        num_args=0..=1,
60        help_heading = heading::TARGET_SELECTION,
61    )]
62    #[cfg_attr(feature = "serde", serde(default))]
63    pub bin: Vec<String>,
64
65    /// Check all binaries
66    #[arg(long, help_heading = heading::TARGET_SELECTION)]
67    #[cfg_attr(feature = "serde", serde(default))]
68    pub bins: bool,
69
70    /// Check only the specified example
71    #[arg(
72        long,
73        value_name = "NAME",
74        action = ArgAction::Append,
75        num_args=0..=1,
76        help_heading = heading::TARGET_SELECTION,
77    )]
78    #[cfg_attr(feature = "serde", serde(default))]
79    pub example: Vec<String>,
80
81    /// Check all examples
82    #[arg(long, help_heading = heading::TARGET_SELECTION)]
83    #[cfg_attr(feature = "serde", serde(default))]
84    pub examples: bool,
85
86    /// Check only the specified test target
87    #[arg(
88        long,
89        value_name = "NAME",
90        action = ArgAction::Append,
91        help_heading = heading::TARGET_SELECTION,
92    )]
93    #[cfg_attr(feature = "serde", serde(default))]
94    pub test: Vec<String>,
95
96    /// Check all targets that have `test = true` set
97    #[arg(long, help_heading = heading::TARGET_SELECTION)]
98    #[cfg_attr(feature = "serde", serde(default))]
99    pub tests: bool,
100
101    /// Check only the specified bench target
102    #[arg(
103        long,
104        value_name = "NAME",
105        action = ArgAction::Append,
106        help_heading = heading::TARGET_SELECTION,
107    )]
108    #[cfg_attr(feature = "serde", serde(default))]
109    pub bench: Vec<String>,
110
111    /// Check all targets that have `bench = true` set
112    #[arg(long, help_heading = heading::TARGET_SELECTION)]
113    #[cfg_attr(feature = "serde", serde(default))]
114    pub benches: bool,
115
116    /// Check all targets
117    #[arg(long, help_heading = heading::TARGET_SELECTION)]
118    #[cfg_attr(feature = "serde", serde(default))]
119    pub all_targets: bool,
120
121    /// Outputs a future incompatibility report at the end of the build
122    #[arg(long)]
123    #[cfg_attr(feature = "serde", serde(default))]
124    pub future_incompat_report: bool,
125
126    /// Check only compile-time dependencies (unstable)
127    #[arg(long, hide = true)]
128    #[cfg_attr(feature = "serde", serde(default))]
129    pub compile_time_deps: bool,
130}
131
132impl CheckOptions {
133    pub fn apply(&self, cmd: &mut Command) {
134        for pkg in &self.packages {
135            cmd.arg("--package").arg(pkg);
136        }
137        if self.workspace {
138            cmd.arg("--workspace");
139        }
140        for item in &self.exclude {
141            cmd.arg("--exclude").arg(item);
142        }
143        if self.all {
144            cmd.arg("--all");
145        }
146        if self.lib {
147            cmd.arg("--lib");
148        }
149        for bin in &self.bin {
150            cmd.arg("--bin").arg(bin);
151        }
152        if self.bins {
153            cmd.arg("--bins");
154        }
155        for example in &self.example {
156            cmd.arg("--example").arg(example);
157        }
158        if self.examples {
159            cmd.arg("--examples");
160        }
161        for test in &self.test {
162            cmd.arg("--test").arg(test);
163        }
164        if self.tests {
165            cmd.arg("--tests");
166        }
167        for bench in &self.bench {
168            cmd.arg("--bench").arg(bench);
169        }
170        if self.benches {
171            cmd.arg("--benches");
172        }
173        if self.all_targets {
174            cmd.arg("--all-targets");
175        }
176        if self.future_incompat_report {
177            cmd.arg("--future-incompat-report");
178        }
179        if self.compile_time_deps {
180            cmd.arg("--compile-time-deps");
181        }
182    }
183}
184
185/// Check a local package and all of its dependencies for errors
186#[derive(Clone, Debug, Default, Parser)]
187#[command(
188    display_order = 1,
189    after_help = "Run `cargo help check` for more detailed information."
190)]
191#[group(skip)]
192#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
193pub struct Check {
194    #[command(flatten)]
195    #[cfg_attr(feature = "serde", serde(flatten))]
196    pub common: CommonOptions,
197
198    #[command(flatten)]
199    #[cfg_attr(feature = "serde", serde(flatten))]
200    pub check: CheckOptions,
201
202    /// Path to Cargo.toml
203    #[arg(long, value_name = "PATH", help_heading = heading::MANIFEST_OPTIONS)]
204    #[cfg_attr(feature = "serde", serde(default))]
205    pub manifest_path: Option<PathBuf>,
206
207    /// Check artifacts in release mode, with optimizations
208    #[arg(
209        short = 'r',
210        long,
211        conflicts_with = "profile",
212        help_heading = heading::COMPILATION_OPTIONS,
213    )]
214    #[cfg_attr(feature = "serde", serde(default))]
215    pub release: bool,
216
217    /// Ignore `rust-version` specification in packages
218    #[arg(long, help_heading = heading::MANIFEST_OPTIONS)]
219    #[cfg_attr(feature = "serde", serde(default))]
220    pub ignore_rust_version: bool,
221
222    /// Output build graph in JSON (unstable)
223    #[arg(long, help_heading = heading::COMPILATION_OPTIONS)]
224    #[cfg_attr(feature = "serde", serde(default))]
225    pub unit_graph: bool,
226}
227
228impl Check {
229    /// Build a `cargo check` command
230    pub fn command(&self) -> Command {
231        let mut cmd = CommonOptions::cargo_command();
232        cmd.arg("check");
233
234        self.common.apply(&mut cmd);
235        self.check.apply(&mut cmd);
236
237        if let Some(path) = self.manifest_path.as_ref() {
238            cmd.arg("--manifest-path").arg(path);
239        }
240        if self.release {
241            cmd.arg("--release");
242        }
243        if self.ignore_rust_version {
244            cmd.arg("--ignore-rust-version");
245        }
246        if self.unit_graph {
247            cmd.arg("--unit-graph");
248        }
249
250        cmd
251    }
252}
253
254impl Deref for Check {
255    type Target = CommonOptions;
256
257    fn deref(&self) -> &Self::Target {
258        &self.common
259    }
260}
261
262impl DerefMut for Check {
263    fn deref_mut(&mut self) -> &mut Self::Target {
264        &mut self.common
265    }
266}
267
268#[cfg(test)]
269mod test {
270    use super::Check;
271    use clap::CommandFactory;
272
273    #[test]
274    fn verify_cli() {
275        <Check as CommandFactory>::command().debug_assert()
276    }
277}