Skip to content

Commit f5114a4

Browse files
committed
cargo-run-deps: Make commands in dependencies available to run
This approach teaches `cargo run` to handle also binary targets in dependencies. In turn, it allows using cargo as a shim when needing to invoke a specific package version from the set of dependencies, without resorting to install a user-wide version of a binary. Users of e.g. `mdbook` should rejoice. Fixes #2267.
1 parent 440cfad commit f5114a4

File tree

2 files changed

+53
-9
lines changed

2 files changed

+53
-9
lines changed

src/bin/cargo/commands/run.rs

Lines changed: 42 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
use crate::command_prelude::*;
22
use crate::util::restricted_names::is_glob_pattern;
3-
use cargo::core::Verbosity;
4-
use cargo::ops::{self, CompileFilter, Packages};
3+
use cargo::core::{Verbosity, Workspace};
4+
use cargo::ops::{self, CompileFilter, CompileOptions, Packages};
5+
use cargo::util::CargoResult;
56
use cargo_util::ProcessError;
67

78
pub fn cli() -> App {
@@ -52,12 +53,7 @@ pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult {
5253
}
5354

5455
if !args.is_present("example") && !args.is_present("bin") {
55-
let default_runs: Vec<_> = compile_opts
56-
.spec
57-
.get_packages(&ws)?
58-
.iter()
59-
.filter_map(|pkg| pkg.manifest().default_run())
60-
.collect();
56+
let default_runs = get_default_runs(&ws, &compile_opts)?;
6157
if default_runs.len() == 1 {
6258
compile_opts.filter = CompileFilter::from_raw_arguments(
6359
false,
@@ -106,3 +102,41 @@ pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult {
106102
}
107103
})
108104
}
105+
106+
fn get_default_runs(ws: &Workspace<'_>, compile_opts: &CompileOptions) -> CargoResult<Vec<String>> {
107+
const ERROR: &'static str =
108+
"`cargo run` cannot find pkgid either in the workspace or among the workspace dependencies";
109+
110+
let workspace_packages = compile_opts.spec.get_packages(ws);
111+
112+
let default_runs = if let Ok(packages) = workspace_packages {
113+
// Package is workspace member
114+
packages
115+
.iter()
116+
.filter_map(|pkg| pkg.manifest().default_run())
117+
.map(str::to_owned)
118+
.collect()
119+
} else if let Packages::Packages(ref pkg_names) = compile_opts.spec {
120+
// Search dependencies
121+
let (package_set, resolver) = ops::resolve_ws(ws)?;
122+
let deps: Vec<_> = pkg_names
123+
.iter()
124+
.flat_map(|name| resolver.query(name))
125+
.collect();
126+
127+
if deps.is_empty() {
128+
anyhow::bail!(ERROR);
129+
}
130+
131+
package_set
132+
.get_many(deps)?
133+
.iter()
134+
.filter_map(|pkg| pkg.manifest().default_run())
135+
.map(str::to_owned)
136+
.collect()
137+
} else {
138+
anyhow::bail!(ERROR);
139+
};
140+
141+
Ok(default_runs)
142+
}

src/cargo/ops/cargo_run.rs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,17 @@ pub fn run(
2020

2121
// We compute the `bins` here *just for diagnosis*. The actual set of
2222
// packages to be run is determined by the `ops::compile` call below.
23-
let packages = options.spec.get_packages(ws)?;
23+
let (package_set, resolver) = ops::resolve_ws(ws)?;
24+
let packages = if let ops::Packages::Packages(ref pkg_names) = options.spec {
25+
let pkgids: Vec<_> = pkg_names
26+
.iter()
27+
.flat_map(|name| resolver.query(name))
28+
.collect();
29+
package_set.get_many(pkgids)?
30+
} else {
31+
options.spec.get_packages(ws)?
32+
};
33+
2434
let bins: Vec<_> = packages
2535
.into_iter()
2636
.flat_map(|pkg| {

0 commit comments

Comments
 (0)