Skip to content

Commit

Permalink
feat(workspace): Get all members even though default-members was sp…
Browse files Browse the repository at this point in the history
…ecified
  • Loading branch information
linyihai committed Feb 19, 2025
1 parent 6a478ef commit ee13fd6
Show file tree
Hide file tree
Showing 3 changed files with 79 additions and 40 deletions.
71 changes: 49 additions & 22 deletions src/cargo/ops/cargo_compile/unit_generator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ use crate::util::{closest_msg, CargoResult};

use super::compile_filter::{CompileFilter, FilterRule, LibRule};
use super::packages::build_glob;
use super::Packages;

/// A proposed target.
///
Expand Down Expand Up @@ -267,35 +268,61 @@ impl<'a> UnitGenerator<'a, '_> {
})
.collect::<Vec<_>>();
let suggestion = closest_msg(target_name, targets.iter(), |t| t.name(), "target");
if !suggestion.is_empty() {
anyhow::bail!(
"no {} target {} `{}`{}",
target_desc,
if is_glob { "matches pattern" } else { "named" },
target_name,
suggestion
);
let target_elsewhere = if is_glob {
let pattern = build_glob(target_name)?;
let filter = |t: &Target| is_expected_kind(t) && pattern.matches(t.name());
self.get_targets_from_other_packages(filter)?
} else {
let mut msg = String::new();
writeln!(
msg,
"no {} target {} `{}`.",
target_desc,
if is_glob { "matches pattern" } else { "named" },
target_name,
)?;
if !targets.is_empty() {
writeln!(msg, "Available {} targets:", target_desc)?;
for target in targets {
writeln!(msg, " {}", target.name())?;
}
let filter = |t: &Target| t.name() == target_name && is_expected_kind(t);
self.get_targets_from_other_packages(filter)?
};

let mut msg = String::new();
writeln!(
msg,
"no {} target {} `{}`",
target_desc,
if is_glob { "matches pattern" } else { "named" },
target_name
)?;
if let Some((package, target)) = target_elsewhere {
writeln!(msg, "Available {target_desc} targets in {package}:")?;
writeln!(msg, " {target}")?;
} else if !suggestion.is_empty() {
writeln!(msg, "{suggestion}")?;
} else if !targets.is_empty() {
writeln!(msg, "Available {} targets:", target_desc)?;
for target in targets {
writeln!(msg, " {}", target.name())?;
}
anyhow::bail!(msg);
}

anyhow::bail!(msg);
}
Ok(proposals)
}

fn get_targets_from_other_packages(
&self,
filter_fn: impl Fn(&Target) -> bool,
) -> CargoResult<Option<(String, String)>> {
let packages = Packages::All(Vec::new()).get_packages(self.ws)?;
let targets = packages.into_iter().find_map(|pkg| {
if let Some(target) = pkg
.manifest()
.targets()
.iter()
.find(|target| filter_fn(target))
{
Some((pkg.name().to_string(), target.name().to_string()))
} else {
None
}
});

Ok(targets)
}

/// Returns a list of proposed targets based on command-line target selection flags.
fn list_rule_targets(
&self,
Expand Down
33 changes: 21 additions & 12 deletions src/cargo/util/workspace.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,33 +2,40 @@ use crate::core::compiler::Unit;
use crate::core::manifest::TargetSourcePath;
use crate::core::{Target, Workspace};
use crate::ops::CompileOptions;
use crate::ops::Packages;
use crate::util::CargoResult;
use anyhow::bail;
use cargo_util::paths::normalize_path;
use cargo_util::ProcessBuilder;
use std::collections::BTreeMap;
use std::fmt::Write;
use std::path::PathBuf;

fn get_available_targets<'a>(
filter_fn: fn(&Target) -> bool,
ws: &'a Workspace<'_>,
options: &'a CompileOptions,
) -> CargoResult<Vec<&'a str>> {
let packages = options.spec.get_packages(ws)?;

let mut targets: Vec<_> = packages
) -> CargoResult<BTreeMap<String, Vec<String>>> {
let packages = if matches!(options.spec, Packages::Default) {
Packages::All(Vec::new()).get_packages(ws)?
} else {
options.spec.get_packages(ws)?
};
let targets: BTreeMap<String, Vec<String>> = packages
.into_iter()
.flat_map(|pkg| {
pkg.manifest()
.map(|pkg| {
let mut targets = pkg
.manifest()
.targets()
.iter()
.filter(|target| filter_fn(target))
.map(|t| t.name().to_owned())
.collect::<Vec<String>>();
targets.sort();
(pkg.name().to_string(), targets)
})
.map(Target::name)
.collect();

targets.sort();

Ok(targets)
}

Expand All @@ -47,9 +54,11 @@ fn print_available_targets(
if targets.is_empty() {
writeln!(output, "No {} available.", plural_name)?;
} else {
writeln!(output, "Available {}:", plural_name)?;
for target in targets {
writeln!(output, " {}", target)?;
for (package, targets) in targets {
writeln!(output, "Available {} in {}:", plural_name, package)?;
for target in targets {
writeln!(output, " {}", target)?;
}
}
}
bail!("{}", output)
Expand Down
15 changes: 9 additions & 6 deletions tests/testsuite/workspaces.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2767,8 +2767,10 @@ fn print_available_targets_within_virtual_workspace() {
.with_status(101)
.with_stderr_data(str![[r#"
[ERROR] "--bin" takes one argument.
Available binaries:
Available binaries in crate1:
crate1
Available binaries in crate2:
crate2
"#]])
Expand All @@ -2778,13 +2780,14 @@ Available binaries:
.with_status(101)
.with_stderr_data(str![[r#"
[ERROR] no bin target named `crate2`
Available bin targets in crate2:
crate2
[HELP] a target with a similar name exists: `crate1`
"#]])
.run();

// This another branch that none of similar name exists, and print available targets in the
// This another branch that none of similar name exists, and print available targets in the
// default-members.
p.change_file(
"Cargo.toml",
Expand All @@ -2800,9 +2803,9 @@ Available binaries:
p.cargo("run --bin crate2")
.with_status(101)
.with_stderr_data(str![[r#"
[ERROR] no bin target named `crate2`.
Available bin targets:
another
[ERROR] no bin target named `crate2`
Available bin targets in crate2:
crate2
"#]])
Expand Down

0 comments on commit ee13fd6

Please sign in to comment.