Skip to content

Commit 3ff0443

Browse files
committed
Auto merge of #11243 - weihanglo:refactor/cargo_compile, r=epage
Some tiny refactors around `ops::cargo_compile` ### What does this PR try to resolve? Some tiny refactors I found during polishing documentations. - Extract `CompileFilter` and `Packages` from `ops::cargo_compile` to their own modules. - Remove `FilterRule::try_collect` as its intent is not clear, and we don't need this indirection. - Remove `CompileOptions::local_rustdoc_args`, which is obsolete since 1ef954e.
2 parents e008032 + 886c9d2 commit 3ff0443

File tree

6 files changed

+561
-559
lines changed

6 files changed

+561
-559
lines changed
Lines changed: 302 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,302 @@
1+
//! Filters and their rules to select which Cargo targets will be built.
2+
3+
use crate::core::compiler::CompileMode;
4+
use crate::core::{Target, TargetKind};
5+
use crate::util::restricted_names::is_glob_pattern;
6+
7+
#[derive(Debug, PartialEq, Eq)]
8+
/// Indicates whether or not the library target gets included.
9+
pub enum LibRule {
10+
/// Include the library, fail if not present
11+
True,
12+
/// Include the library if present
13+
Default,
14+
/// Exclude the library
15+
False,
16+
}
17+
18+
#[derive(Debug)]
19+
/// Indicates which Cargo targets will be selected to be built.
20+
pub enum FilterRule {
21+
/// All included.
22+
All,
23+
/// Just a subset of Cargo targets based on names given.
24+
Just(Vec<String>),
25+
}
26+
27+
/// Filter to apply to the root package to select which Cargo targets will be built.
28+
/// (examples, bins, benches, tests, ...)
29+
///
30+
/// The actual filter process happens inside [`generate_targets`].
31+
///
32+
/// Not to be confused with [`Packages`], which opts in packages to be built.
33+
///
34+
/// [`generate_targets`]: super::generate_targets
35+
/// [`Packages`]: crate::ops::Packages
36+
#[derive(Debug)]
37+
pub enum CompileFilter {
38+
/// The default set of Cargo targets.
39+
Default {
40+
/// Flag whether targets can be safely skipped when required-features are not satisfied.
41+
required_features_filterable: bool,
42+
},
43+
/// Only includes a subset of all Cargo targets.
44+
Only {
45+
/// Include all Cargo targets.
46+
all_targets: bool,
47+
lib: LibRule,
48+
bins: FilterRule,
49+
examples: FilterRule,
50+
tests: FilterRule,
51+
benches: FilterRule,
52+
},
53+
}
54+
55+
impl FilterRule {
56+
pub fn new(targets: Vec<String>, all: bool) -> FilterRule {
57+
if all {
58+
FilterRule::All
59+
} else {
60+
FilterRule::Just(targets)
61+
}
62+
}
63+
64+
/// Creates a filter with no rule.
65+
///
66+
/// In the current Cargo implementation, filter without a rule implies
67+
/// Cargo will follows the default behaviour to filter targets.
68+
pub fn none() -> FilterRule {
69+
FilterRule::Just(Vec::new())
70+
}
71+
72+
/// Checks if a target definition matches this filter rule.
73+
fn matches(&self, target: &Target) -> bool {
74+
match *self {
75+
FilterRule::All => true,
76+
FilterRule::Just(ref targets) => targets.iter().any(|x| *x == target.name()),
77+
}
78+
}
79+
80+
/// Check if a filter is specific.
81+
///
82+
/// Only filters without rules are considered as not specific.
83+
fn is_specific(&self) -> bool {
84+
match *self {
85+
FilterRule::All => true,
86+
FilterRule::Just(ref targets) => !targets.is_empty(),
87+
}
88+
}
89+
90+
/// Checks if any specified target name contains glob patterns.
91+
pub(crate) fn contains_glob_patterns(&self) -> bool {
92+
match self {
93+
FilterRule::All => false,
94+
FilterRule::Just(targets) => targets.iter().any(is_glob_pattern),
95+
}
96+
}
97+
}
98+
99+
impl CompileFilter {
100+
/// Constructs a filter from raw command line arguments.
101+
pub fn from_raw_arguments(
102+
lib_only: bool,
103+
bins: Vec<String>,
104+
all_bins: bool,
105+
tsts: Vec<String>,
106+
all_tsts: bool,
107+
exms: Vec<String>,
108+
all_exms: bool,
109+
bens: Vec<String>,
110+
all_bens: bool,
111+
all_targets: bool,
112+
) -> CompileFilter {
113+
if all_targets {
114+
return CompileFilter::new_all_targets();
115+
}
116+
let rule_lib = if lib_only {
117+
LibRule::True
118+
} else {
119+
LibRule::False
120+
};
121+
let rule_bins = FilterRule::new(bins, all_bins);
122+
let rule_tsts = FilterRule::new(tsts, all_tsts);
123+
let rule_exms = FilterRule::new(exms, all_exms);
124+
let rule_bens = FilterRule::new(bens, all_bens);
125+
126+
CompileFilter::new(rule_lib, rule_bins, rule_tsts, rule_exms, rule_bens)
127+
}
128+
129+
/// Constructs a filter from underlying primitives.
130+
pub fn new(
131+
rule_lib: LibRule,
132+
rule_bins: FilterRule,
133+
rule_tsts: FilterRule,
134+
rule_exms: FilterRule,
135+
rule_bens: FilterRule,
136+
) -> CompileFilter {
137+
if rule_lib == LibRule::True
138+
|| rule_bins.is_specific()
139+
|| rule_tsts.is_specific()
140+
|| rule_exms.is_specific()
141+
|| rule_bens.is_specific()
142+
{
143+
CompileFilter::Only {
144+
all_targets: false,
145+
lib: rule_lib,
146+
bins: rule_bins,
147+
examples: rule_exms,
148+
benches: rule_bens,
149+
tests: rule_tsts,
150+
}
151+
} else {
152+
CompileFilter::Default {
153+
required_features_filterable: true,
154+
}
155+
}
156+
}
157+
158+
/// Constructs a filter that includes all targets.
159+
pub fn new_all_targets() -> CompileFilter {
160+
CompileFilter::Only {
161+
all_targets: true,
162+
lib: LibRule::Default,
163+
bins: FilterRule::All,
164+
examples: FilterRule::All,
165+
benches: FilterRule::All,
166+
tests: FilterRule::All,
167+
}
168+
}
169+
170+
/// Constructs a filter that includes all test targets.
171+
///
172+
/// Being different from the behavior of [`CompileFilter::Default`], this
173+
/// function only recognizes test targets, which means cargo might compile
174+
/// all targets with `tested` flag on, whereas [`CompileFilter::Default`]
175+
/// may include additional example targets to ensure they can be compiled.
176+
///
177+
/// Note that the actual behavior is subject to `filter_default_targets`
178+
/// and `generate_targets` though.
179+
pub fn all_test_targets() -> Self {
180+
Self::Only {
181+
all_targets: false,
182+
lib: LibRule::Default,
183+
bins: FilterRule::none(),
184+
examples: FilterRule::none(),
185+
tests: FilterRule::All,
186+
benches: FilterRule::none(),
187+
}
188+
}
189+
190+
/// Constructs a filter that includes lib target only.
191+
pub fn lib_only() -> Self {
192+
Self::Only {
193+
all_targets: false,
194+
lib: LibRule::True,
195+
bins: FilterRule::none(),
196+
examples: FilterRule::none(),
197+
tests: FilterRule::none(),
198+
benches: FilterRule::none(),
199+
}
200+
}
201+
202+
/// Constructs a filter that includes the given binary. No more. No less.
203+
pub fn single_bin(bin: String) -> Self {
204+
Self::Only {
205+
all_targets: false,
206+
lib: LibRule::False,
207+
bins: FilterRule::new(vec![bin], false),
208+
examples: FilterRule::none(),
209+
tests: FilterRule::none(),
210+
benches: FilterRule::none(),
211+
}
212+
}
213+
214+
/// Indicates if Cargo needs to build any dev dependency.
215+
pub fn need_dev_deps(&self, mode: CompileMode) -> bool {
216+
match mode {
217+
CompileMode::Test | CompileMode::Doctest | CompileMode::Bench => true,
218+
CompileMode::Check { test: true } => true,
219+
CompileMode::Build
220+
| CompileMode::Doc { .. }
221+
| CompileMode::Docscrape
222+
| CompileMode::Check { test: false } => match *self {
223+
CompileFilter::Default { .. } => false,
224+
CompileFilter::Only {
225+
ref examples,
226+
ref tests,
227+
ref benches,
228+
..
229+
} => examples.is_specific() || tests.is_specific() || benches.is_specific(),
230+
},
231+
CompileMode::RunCustomBuild => panic!("Invalid mode"),
232+
}
233+
}
234+
235+
/// Selects targets for "cargo run". for logic to select targets for other
236+
/// subcommands, see `generate_targets` and `filter_default_targets`.
237+
pub fn target_run(&self, target: &Target) -> bool {
238+
match *self {
239+
CompileFilter::Default { .. } => true,
240+
CompileFilter::Only {
241+
ref lib,
242+
ref bins,
243+
ref examples,
244+
ref tests,
245+
ref benches,
246+
..
247+
} => {
248+
let rule = match *target.kind() {
249+
TargetKind::Bin => bins,
250+
TargetKind::Test => tests,
251+
TargetKind::Bench => benches,
252+
TargetKind::ExampleBin | TargetKind::ExampleLib(..) => examples,
253+
TargetKind::Lib(..) => {
254+
return match *lib {
255+
LibRule::True => true,
256+
LibRule::Default => true,
257+
LibRule::False => false,
258+
};
259+
}
260+
TargetKind::CustomBuild => return false,
261+
};
262+
rule.matches(target)
263+
}
264+
}
265+
}
266+
267+
pub fn is_specific(&self) -> bool {
268+
match *self {
269+
CompileFilter::Default { .. } => false,
270+
CompileFilter::Only { .. } => true,
271+
}
272+
}
273+
274+
pub fn is_all_targets(&self) -> bool {
275+
matches!(
276+
*self,
277+
CompileFilter::Only {
278+
all_targets: true,
279+
..
280+
}
281+
)
282+
}
283+
284+
/// Checks if any specified target name contains glob patterns.
285+
pub(crate) fn contains_glob_patterns(&self) -> bool {
286+
match self {
287+
CompileFilter::Default { .. } => false,
288+
CompileFilter::Only {
289+
bins,
290+
examples,
291+
tests,
292+
benches,
293+
..
294+
} => {
295+
bins.contains_glob_patterns()
296+
|| examples.contains_glob_patterns()
297+
|| tests.contains_glob_patterns()
298+
|| benches.contains_glob_patterns()
299+
}
300+
}
301+
}
302+
}

0 commit comments

Comments
 (0)