mirror of
https://github.com/rust-lang/cargo
synced 2024-09-13 04:51:31 +00:00
feat: glob support for target selection
This commit is contained in:
parent
be31989a43
commit
42696ae234
|
@ -41,8 +41,11 @@ use crate::core::{PackageId, PackageIdSpec, TargetKind, Workspace};
|
|||
use crate::ops;
|
||||
use crate::ops::resolve::WorkspaceResolve;
|
||||
use crate::util::config::Config;
|
||||
use crate::util::restricted_names::is_glob_pattern;
|
||||
use crate::util::{closest_msg, profile, CargoResult, StableHasher};
|
||||
|
||||
use anyhow::Context as _;
|
||||
|
||||
/// Contains information about how a package should be compiled.
|
||||
///
|
||||
/// Note on distinction between `CompileOptions` and `BuildConfig`:
|
||||
|
@ -577,6 +580,13 @@ impl FilterRule {
|
|||
FilterRule::Just(ref targets) => Some(targets.clone()),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn contains_glob_patterns(&self) -> bool {
|
||||
match self {
|
||||
FilterRule::All => false,
|
||||
FilterRule::Just(targets) => targets.iter().any(is_glob_pattern),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl CompileFilter {
|
||||
|
@ -706,6 +716,24 @@ impl CompileFilter {
|
|||
CompileFilter::Only { .. } => true,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn contains_glob_patterns(&self) -> bool {
|
||||
match self {
|
||||
CompileFilter::Default { .. } => false,
|
||||
CompileFilter::Only {
|
||||
bins,
|
||||
examples,
|
||||
tests,
|
||||
benches,
|
||||
..
|
||||
} => {
|
||||
bins.contains_glob_patterns()
|
||||
|| examples.contains_glob_patterns()
|
||||
|| tests.contains_glob_patterns()
|
||||
|| benches.contains_glob_patterns()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A proposed target.
|
||||
|
@ -1163,8 +1191,16 @@ fn find_named_targets<'a>(
|
|||
is_expected_kind: fn(&Target) -> bool,
|
||||
mode: CompileMode,
|
||||
) -> CargoResult<Vec<Proposal<'a>>> {
|
||||
let filter = |t: &Target| t.name() == target_name && is_expected_kind(t);
|
||||
let proposals = filter_targets(packages, filter, true, mode);
|
||||
let is_glob = is_glob_pattern(target_name);
|
||||
let proposals = if is_glob {
|
||||
let pattern = build_glob(target_name)?;
|
||||
let filter = |t: &Target| is_expected_kind(t) && pattern.matches(t.name());
|
||||
filter_targets(packages, filter, true, mode)
|
||||
} else {
|
||||
let filter = |t: &Target| t.name() == target_name && is_expected_kind(t);
|
||||
filter_targets(packages, filter, true, mode)
|
||||
};
|
||||
|
||||
if proposals.is_empty() {
|
||||
let targets = packages.iter().flat_map(|pkg| {
|
||||
pkg.targets()
|
||||
|
@ -1173,8 +1209,9 @@ fn find_named_targets<'a>(
|
|||
});
|
||||
let suggestion = closest_msg(target_name, targets, |t| t.name());
|
||||
anyhow::bail!(
|
||||
"no {} target named `{}`{}",
|
||||
"no {} target {} `{}`{}",
|
||||
target_desc,
|
||||
if is_glob { "matches pattern" } else { "named" },
|
||||
target_name,
|
||||
suggestion
|
||||
);
|
||||
|
@ -1291,3 +1328,8 @@ fn traverse_and_share(
|
|||
new_graph.entry(new_unit.clone()).or_insert(new_deps);
|
||||
new_unit
|
||||
}
|
||||
|
||||
/// TODO: @weihanglo
|
||||
fn build_glob(pat: &str) -> CargoResult<glob::Pattern> {
|
||||
glob::Pattern::new(pat).with_context(|| format!("Cannot build glob pattern from `{}`", pat))
|
||||
}
|
||||
|
|
|
@ -13,6 +13,10 @@ pub fn run(
|
|||
) -> CargoResult<()> {
|
||||
let config = ws.config();
|
||||
|
||||
if options.filter.contains_glob_patterns() {
|
||||
anyhow::bail!("`cargo run` does not support glob patterns on target selection")
|
||||
}
|
||||
|
||||
// We compute the `bins` here *just for diagnosis*. The actual set of
|
||||
// packages to be run is determined by the `ops::compile` call below.
|
||||
let packages = options.spec.get_packages(ws)?;
|
||||
|
|
|
@ -83,7 +83,7 @@ pub fn validate_package_name(name: &str, what: &str, help: &str) -> CargoResult<
|
|||
Ok(())
|
||||
}
|
||||
|
||||
// Check the entire path for names reserved in Windows.
|
||||
/// Check the entire path for names reserved in Windows.
|
||||
pub fn is_windows_reserved_path(path: &Path) -> bool {
|
||||
path.iter()
|
||||
.filter_map(|component| component.to_str())
|
||||
|
@ -92,3 +92,8 @@ pub fn is_windows_reserved_path(path: &Path) -> bool {
|
|||
is_windows_reserved(stem)
|
||||
})
|
||||
}
|
||||
|
||||
/// Returns `true` if the name contains any glob pattern wildcards.
|
||||
pub fn is_glob_pattern<T: AsRef<str>>(name: T) -> bool {
|
||||
name.as_ref().contains(&['*', '?', '[', ']'][..])
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue