1use crate::core::compiler::Unit;
2use crate::core::manifest::TargetSourcePath;
3use crate::core::{Target, Workspace};
4use crate::ops::CompileOptions;
5use crate::util::CargoResult;
6use anyhow::bail;
7use cargo_util::paths::normalize_path;
8use cargo_util::ProcessBuilder;
9use std::fmt::Write;
10use std::path::Path;
11use std::path::PathBuf;
12
13const ITEM_INDENT: &str = " ";
14
15fn get_available_targets<'a>(
16 filter_fn: fn(&Target) -> bool,
17 ws: &'a Workspace<'_>,
18 options: &'a CompileOptions,
19) -> CargoResult<Vec<(&'a str, &'a Path)>> {
20 let packages = options.spec.get_packages(ws)?;
21
22 let mut targets: Vec<_> = packages
23 .into_iter()
24 .flat_map(|pkg| {
25 pkg.manifest()
26 .targets()
27 .iter()
28 .filter(|target| filter_fn(target))
29 })
30 .map(|target| {
31 (
32 target.name(),
33 target.src_path().path().expect("Target is not a `Metabuild` but one of `Bin` | `Test` | `Bench` | `ExampleBin`")
34 )
35 })
36 .collect();
37
38 targets.sort();
39
40 Ok(targets)
41}
42
43fn print_available_targets(
44 filter_fn: fn(&Target) -> bool,
45 ws: &Workspace<'_>,
46 options: &CompileOptions,
47 option_name: &str,
48 plural_name: &str,
49) -> CargoResult<()> {
50 let targets = get_available_targets(filter_fn, ws, options)?;
51
52 let mut output = String::new();
53 writeln!(output, "\"{}\" takes one argument.", option_name)?;
54
55 if targets.is_empty() {
56 writeln!(output, "No {} available.", plural_name)?;
57 } else {
58 writeln!(output, "Available {}:", plural_name)?;
59 let mut shell = ws.gctx().shell();
60 for (name, src_path) in targets {
61 let link = shell.err_file_hyperlink(src_path);
62 writeln!(output, "{ITEM_INDENT}{link}{}{link:#}", name)?;
63 }
64 }
65 bail!("{}", output)
66}
67
68pub fn print_available_packages(ws: &Workspace<'_>) -> CargoResult<()> {
69 let packages = ws
70 .members()
71 .map(|pkg| (pkg.name().as_str(), pkg.manifest_path()))
72 .collect::<Vec<_>>();
73
74 let mut output = "\"--package <SPEC>\" requires a SPEC format value, \
75 which can be any package ID specifier in the dependency graph.\n\
76 Run `cargo help pkgid` for more information about SPEC format.\n\n"
77 .to_string();
78
79 if packages.is_empty() {
80 writeln!(output, "No packages available.")?;
83 } else {
84 writeln!(output, "Possible packages/workspace members:")?;
85 let mut shell = ws.gctx().shell();
86 for (name, manifest_path) in packages {
87 let link = shell.err_file_hyperlink(manifest_path);
88 writeln!(output, "{ITEM_INDENT}{link}{}{link:#}", name)?;
89 }
90 }
91 bail!("{}", output)
92}
93
94pub fn print_available_examples(ws: &Workspace<'_>, options: &CompileOptions) -> CargoResult<()> {
95 print_available_targets(Target::is_example, ws, options, "--example", "examples")
96}
97
98pub fn print_available_binaries(ws: &Workspace<'_>, options: &CompileOptions) -> CargoResult<()> {
99 print_available_targets(Target::is_bin, ws, options, "--bin", "binaries")
100}
101
102pub fn print_available_benches(ws: &Workspace<'_>, options: &CompileOptions) -> CargoResult<()> {
103 print_available_targets(Target::is_bench, ws, options, "--bench", "bench targets")
104}
105
106pub fn print_available_tests(ws: &Workspace<'_>, options: &CompileOptions) -> CargoResult<()> {
107 print_available_targets(Target::is_test, ws, options, "--test", "test targets")
108}
109
110pub fn path_args(ws: &Workspace<'_>, unit: &Unit) -> (PathBuf, PathBuf) {
127 let src = match unit.target.src_path() {
128 TargetSourcePath::Path(path) => path.to_path_buf(),
129 TargetSourcePath::Metabuild => unit.pkg.manifest().metabuild_path(ws.build_dir()),
130 };
131 assert!(src.is_absolute());
132 if unit.pkg.package_id().source_id().is_path() {
133 let root = match &ws.gctx().cli_unstable().root_dir {
136 None => ws.root().to_owned(),
137 Some(root_dir) => normalize_path(&ws.gctx().cwd().join(root_dir)),
138 };
139 if let Ok(path) = src.strip_prefix(&root) {
140 return (path.to_path_buf(), root);
141 }
142 }
143 (src, unit.pkg.root().to_path_buf())
144}
145
146pub fn add_path_args(ws: &Workspace<'_>, unit: &Unit, cmd: &mut ProcessBuilder) {
147 let (arg, cwd) = path_args(ws, unit);
148 cmd.arg(arg);
149 cmd.cwd(cwd);
150}