mirror of https://github.com/rust-lang/cargo
131 lines
4.5 KiB
Rust
131 lines
4.5 KiB
Rust
use crate::core::compiler::Unit;
|
|
use crate::core::manifest::TargetSourcePath;
|
|
use crate::core::{Target, Workspace};
|
|
use crate::ops::CompileOptions;
|
|
use crate::util::CargoResult;
|
|
use anyhow::bail;
|
|
use cargo_util::ProcessBuilder;
|
|
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
|
|
.into_iter()
|
|
.flat_map(|pkg| {
|
|
pkg.manifest()
|
|
.targets()
|
|
.iter()
|
|
.filter(|target| filter_fn(target))
|
|
})
|
|
.map(Target::name)
|
|
.collect();
|
|
|
|
targets.sort();
|
|
|
|
Ok(targets)
|
|
}
|
|
|
|
fn print_available_targets(
|
|
filter_fn: fn(&Target) -> bool,
|
|
ws: &Workspace<'_>,
|
|
options: &CompileOptions,
|
|
option_name: &str,
|
|
plural_name: &str,
|
|
) -> CargoResult<()> {
|
|
let targets = get_available_targets(filter_fn, ws, options)?;
|
|
|
|
let mut output = String::new();
|
|
writeln!(output, "\"{}\" takes one argument.", option_name)?;
|
|
|
|
if targets.is_empty() {
|
|
writeln!(output, "No {} available.", plural_name)?;
|
|
} else {
|
|
writeln!(output, "Available {}:", plural_name)?;
|
|
for target in targets {
|
|
writeln!(output, " {}", target)?;
|
|
}
|
|
}
|
|
bail!("{}", output)
|
|
}
|
|
|
|
pub fn print_available_packages(ws: &Workspace<'_>) -> CargoResult<()> {
|
|
let packages = ws
|
|
.members()
|
|
.map(|pkg| pkg.name().as_str())
|
|
.collect::<Vec<_>>();
|
|
|
|
let mut output = "\"--package <SPEC>\" requires a SPEC format value, \
|
|
which can be any package ID specifier in the dependency graph.\n\
|
|
Run `cargo help pkgid` for more information about SPEC format.\n\n"
|
|
.to_string();
|
|
|
|
if packages.is_empty() {
|
|
// This would never happen.
|
|
// Just in case something regresses we covers it here.
|
|
writeln!(output, "No packages available.")?;
|
|
} else {
|
|
writeln!(output, "Possible packages/workspace members:")?;
|
|
for package in packages {
|
|
writeln!(output, " {}", package)?;
|
|
}
|
|
}
|
|
bail!("{}", output)
|
|
}
|
|
|
|
pub fn print_available_examples(ws: &Workspace<'_>, options: &CompileOptions) -> CargoResult<()> {
|
|
print_available_targets(Target::is_example, ws, options, "--example", "examples")
|
|
}
|
|
|
|
pub fn print_available_binaries(ws: &Workspace<'_>, options: &CompileOptions) -> CargoResult<()> {
|
|
print_available_targets(Target::is_bin, ws, options, "--bin", "binaries")
|
|
}
|
|
|
|
pub fn print_available_benches(ws: &Workspace<'_>, options: &CompileOptions) -> CargoResult<()> {
|
|
print_available_targets(Target::is_bench, ws, options, "--bench", "benches")
|
|
}
|
|
|
|
pub fn print_available_tests(ws: &Workspace<'_>, options: &CompileOptions) -> CargoResult<()> {
|
|
print_available_targets(Target::is_test, ws, options, "--test", "tests")
|
|
}
|
|
|
|
/// The path that we pass to rustc is actually fairly important because it will
|
|
/// show up in error messages (important for readability), debug information
|
|
/// (important for caching), etc. As a result we need to be pretty careful how we
|
|
/// actually invoke rustc.
|
|
///
|
|
/// In general users don't expect `cargo build` to cause rebuilds if you change
|
|
/// directories. That could be if you just change directories in the package or
|
|
/// if you literally move the whole package wholesale to a new directory. As a
|
|
/// result we mostly don't factor in `cwd` to this calculation. Instead we try to
|
|
/// track the workspace as much as possible and we update the current directory
|
|
/// of rustc/rustdoc where appropriate.
|
|
///
|
|
/// The first returned value here is the argument to pass to rustc, and the
|
|
/// second is the cwd that rustc should operate in.
|
|
pub fn path_args(ws: &Workspace<'_>, unit: &Unit) -> (PathBuf, PathBuf) {
|
|
let ws_root = ws.root();
|
|
let src = match unit.target.src_path() {
|
|
TargetSourcePath::Path(path) => path.to_path_buf(),
|
|
TargetSourcePath::Metabuild => unit.pkg.manifest().metabuild_path(ws.target_dir()),
|
|
};
|
|
assert!(src.is_absolute());
|
|
if unit.pkg.package_id().source_id().is_path() {
|
|
if let Ok(path) = src.strip_prefix(ws_root) {
|
|
return (path.to_path_buf(), ws_root.to_path_buf());
|
|
}
|
|
}
|
|
(src, unit.pkg.root().to_path_buf())
|
|
}
|
|
|
|
pub fn add_path_args(ws: &Workspace<'_>, unit: &Unit, cmd: &mut ProcessBuilder) {
|
|
let (arg, cwd) = path_args(ws, unit);
|
|
cmd.arg(arg);
|
|
cmd.cwd(cwd);
|
|
}
|