]> git.proxmox.com Git - rustc.git/blob - src/tools/cargo/src/cargo/util/workspace.rs
New upstream version 1.75.0+dfsg1
[rustc.git] / src / tools / cargo / src / cargo / util / workspace.rs
1 use crate::core::compiler::Unit;
2 use crate::core::manifest::TargetSourcePath;
3 use crate::core::{Target, Workspace};
4 use crate::ops::CompileOptions;
5 use crate::util::CargoResult;
6 use anyhow::bail;
7 use cargo_util::ProcessBuilder;
8 use std::fmt::Write;
9 use std::path::PathBuf;
10
11 fn get_available_targets<'a>(
12 filter_fn: fn(&Target) -> bool,
13 ws: &'a Workspace<'_>,
14 options: &'a CompileOptions,
15 ) -> CargoResult<Vec<&'a str>> {
16 let packages = options.spec.get_packages(ws)?;
17
18 let mut targets: Vec<_> = packages
19 .into_iter()
20 .flat_map(|pkg| {
21 pkg.manifest()
22 .targets()
23 .iter()
24 .filter(|target| filter_fn(target))
25 })
26 .map(Target::name)
27 .collect();
28
29 targets.sort();
30
31 Ok(targets)
32 }
33
34 fn print_available_targets(
35 filter_fn: fn(&Target) -> bool,
36 ws: &Workspace<'_>,
37 options: &CompileOptions,
38 option_name: &str,
39 plural_name: &str,
40 ) -> CargoResult<()> {
41 let targets = get_available_targets(filter_fn, ws, options)?;
42
43 let mut output = String::new();
44 writeln!(output, "\"{}\" takes one argument.", option_name)?;
45
46 if targets.is_empty() {
47 writeln!(output, "No {} available.", plural_name)?;
48 } else {
49 writeln!(output, "Available {}:", plural_name)?;
50 for target in targets {
51 writeln!(output, " {}", target)?;
52 }
53 }
54 bail!("{}", output)
55 }
56
57 pub fn print_available_packages(ws: &Workspace<'_>) -> CargoResult<()> {
58 let packages = ws
59 .members()
60 .map(|pkg| pkg.name().as_str())
61 .collect::<Vec<_>>();
62
63 let mut output = "\"--package <SPEC>\" requires a SPEC format value, \
64 which can be any package ID specifier in the dependency graph.\n\
65 Run `cargo help pkgid` for more information about SPEC format.\n\n"
66 .to_string();
67
68 if packages.is_empty() {
69 // This would never happen.
70 // Just in case something regresses we covers it here.
71 writeln!(output, "No packages available.")?;
72 } else {
73 writeln!(output, "Possible packages/workspace members:")?;
74 for package in packages {
75 writeln!(output, " {}", package)?;
76 }
77 }
78 bail!("{}", output)
79 }
80
81 pub fn print_available_examples(ws: &Workspace<'_>, options: &CompileOptions) -> CargoResult<()> {
82 print_available_targets(Target::is_example, ws, options, "--example", "examples")
83 }
84
85 pub fn print_available_binaries(ws: &Workspace<'_>, options: &CompileOptions) -> CargoResult<()> {
86 print_available_targets(Target::is_bin, ws, options, "--bin", "binaries")
87 }
88
89 pub fn print_available_benches(ws: &Workspace<'_>, options: &CompileOptions) -> CargoResult<()> {
90 print_available_targets(Target::is_bench, ws, options, "--bench", "bench targets")
91 }
92
93 pub fn print_available_tests(ws: &Workspace<'_>, options: &CompileOptions) -> CargoResult<()> {
94 print_available_targets(Target::is_test, ws, options, "--test", "test targets")
95 }
96
97 /// The path that we pass to rustc is actually fairly important because it will
98 /// show up in error messages (important for readability), debug information
99 /// (important for caching), etc. As a result we need to be pretty careful how we
100 /// actually invoke rustc.
101 ///
102 /// In general users don't expect `cargo build` to cause rebuilds if you change
103 /// directories. That could be if you just change directories in the package or
104 /// if you literally move the whole package wholesale to a new directory. As a
105 /// result we mostly don't factor in `cwd` to this calculation. Instead we try to
106 /// track the workspace as much as possible and we update the current directory
107 /// of rustc/rustdoc where appropriate.
108 ///
109 /// The first returned value here is the argument to pass to rustc, and the
110 /// second is the cwd that rustc should operate in.
111 pub fn path_args(ws: &Workspace<'_>, unit: &Unit) -> (PathBuf, PathBuf) {
112 let ws_root = ws.root();
113 let src = match unit.target.src_path() {
114 TargetSourcePath::Path(path) => path.to_path_buf(),
115 TargetSourcePath::Metabuild => unit.pkg.manifest().metabuild_path(ws.target_dir()),
116 };
117 assert!(src.is_absolute());
118 if unit.pkg.package_id().source_id().is_path() {
119 if let Ok(path) = src.strip_prefix(ws_root) {
120 return (path.to_path_buf(), ws_root.to_path_buf());
121 }
122 }
123 (src, unit.pkg.root().to_path_buf())
124 }
125
126 pub fn add_path_args(ws: &Workspace<'_>, unit: &Unit, cmd: &mut ProcessBuilder) {
127 let (arg, cwd) = path_args(ws, unit);
128 cmd.arg(arg);
129 cmd.cwd(cwd);
130 }