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 to build (see `cargo help pkgid`)
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 build
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 tests
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 benches
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 (unstable)
122    #[arg(long)]
123    #[cfg_attr(feature = "serde", serde(default))]
124    pub future_incompat_report: bool,
125}
126
127impl CheckOptions {
128    pub fn apply(&self, cmd: &mut Command) {
129        for pkg in &self.packages {
130            cmd.arg("--package").arg(pkg);
131        }
132        if self.workspace {
133            cmd.arg("--workspace");
134        }
135        for item in &self.exclude {
136            cmd.arg("--exclude").arg(item);
137        }
138        if self.all {
139            cmd.arg("--all");
140        }
141        if self.lib {
142            cmd.arg("--lib");
143        }
144        for bin in &self.bin {
145            cmd.arg("--bin").arg(bin);
146        }
147        if self.bins {
148            cmd.arg("--bins");
149        }
150        for example in &self.example {
151            cmd.arg("--example").arg(example);
152        }
153        if self.examples {
154            cmd.arg("--examples");
155        }
156        for test in &self.test {
157            cmd.arg("--test").arg(test);
158        }
159        if self.tests {
160            cmd.arg("--tests");
161        }
162        for bench in &self.bench {
163            cmd.arg("--bench").arg(bench);
164        }
165        if self.benches {
166            cmd.arg("--benches");
167        }
168        if self.all_targets {
169            cmd.arg("--all-targets");
170        }
171        if self.future_incompat_report {
172            cmd.arg("--future-incompat-report");
173        }
174    }
175}
176
177/// Check a local package and all of its dependencies for errors
178#[derive(Clone, Debug, Default, Parser)]
179#[command(
180    display_order = 1,
181    after_help = "Run `cargo help check` for more detailed information."
182)]
183#[group(skip)]
184#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
185pub struct Check {
186    #[command(flatten)]
187    #[cfg_attr(feature = "serde", serde(flatten))]
188    pub common: CommonOptions,
189
190    #[command(flatten)]
191    #[cfg_attr(feature = "serde", serde(flatten))]
192    pub check: CheckOptions,
193
194    /// Path to Cargo.toml
195    #[arg(long, value_name = "PATH", help_heading = heading::MANIFEST_OPTIONS)]
196    #[cfg_attr(feature = "serde", serde(default))]
197    pub manifest_path: Option<PathBuf>,
198
199    /// Build artifacts in release mode, with optimizations
200    #[arg(short = 'r', long, help_heading = heading::COMPILATION_OPTIONS)]
201    #[cfg_attr(feature = "serde", serde(default))]
202    pub release: bool,
203
204    /// Ignore `rust-version` specification in packages
205    #[arg(long)]
206    #[cfg_attr(feature = "serde", serde(default))]
207    pub ignore_rust_version: bool,
208
209    /// Output build graph in JSON (unstable)
210    #[arg(long, help_heading = heading::COMPILATION_OPTIONS)]
211    #[cfg_attr(feature = "serde", serde(default))]
212    pub unit_graph: bool,
213}
214
215impl Check {
216    /// Build a `cargo check` command
217    pub fn command(&self) -> Command {
218        let mut cmd = CommonOptions::cargo_command();
219        cmd.arg("check");
220
221        self.common.apply(&mut cmd);
222        self.check.apply(&mut cmd);
223
224        if let Some(path) = self.manifest_path.as_ref() {
225            cmd.arg("--manifest-path").arg(path);
226        }
227        if self.release {
228            cmd.arg("--release");
229        }
230        if self.ignore_rust_version {
231            cmd.arg("--ignore-rust-version");
232        }
233        if self.unit_graph {
234            cmd.arg("--unit-graph");
235        }
236
237        cmd
238    }
239}
240
241impl Deref for Check {
242    type Target = CommonOptions;
243
244    fn deref(&self) -> &Self::Target {
245        &self.common
246    }
247}
248
249impl DerefMut for Check {
250    fn deref_mut(&mut self) -> &mut Self::Target {
251        &mut self.common
252    }
253}
254
255#[cfg(test)]
256mod test {
257    use super::Check;
258    use clap::CommandFactory;
259
260    #[test]
261    fn verify_cli() {
262        <Check as CommandFactory>::command().debug_assert()
263    }
264}