Skip to content

Commit

Permalink
cargo-run-deps: Make commands in dependencies available to run
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
tchernobog committed Aug 30, 2021
1 parent 440cfad commit f5114a4
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 9 deletions.
50 changes: 42 additions & 8 deletions src/bin/cargo/commands/run.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
use crate::command_prelude::*;
use crate::util::restricted_names::is_glob_pattern;
use cargo::core::Verbosity;
use cargo::ops::{self, CompileFilter, Packages};
use cargo::core::{Verbosity, Workspace};
use cargo::ops::{self, CompileFilter, CompileOptions, Packages};
use cargo::util::CargoResult;
use cargo_util::ProcessError;

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

if !args.is_present("example") && !args.is_present("bin") {
let default_runs: Vec<_> = compile_opts
.spec
.get_packages(&ws)?
.iter()
.filter_map(|pkg| pkg.manifest().default_run())
.collect();
let default_runs = get_default_runs(&ws, &compile_opts)?;
if default_runs.len() == 1 {
compile_opts.filter = CompileFilter::from_raw_arguments(
false,
Expand Down Expand Up @@ -106,3 +102,41 @@ pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult {
}
})
}

fn get_default_runs(ws: &Workspace<'_>, compile_opts: &CompileOptions) -> CargoResult<Vec<String>> {
const ERROR: &'static str =
"`cargo run` cannot find pkgid either in the workspace or among the workspace dependencies";

let workspace_packages = compile_opts.spec.get_packages(ws);

let default_runs = if let Ok(packages) = workspace_packages {
// Package is workspace member
packages
.iter()
.filter_map(|pkg| pkg.manifest().default_run())
.map(str::to_owned)
.collect()
} else if let Packages::Packages(ref pkg_names) = compile_opts.spec {
// Search dependencies
let (package_set, resolver) = ops::resolve_ws(ws)?;
let deps: Vec<_> = pkg_names
.iter()
.flat_map(|name| resolver.query(name))
.collect();

if deps.is_empty() {
anyhow::bail!(ERROR);
}

package_set
.get_many(deps)?
.iter()
.filter_map(|pkg| pkg.manifest().default_run())
.map(str::to_owned)
.collect()
} else {
anyhow::bail!(ERROR);
};

Ok(default_runs)
}
12 changes: 11 additions & 1 deletion src/cargo/ops/cargo_run.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,17 @@ pub fn run(

// We compute the `bins` here *just for diagnosis*. The actual set of
// packages to be run is determined by the `ops::compile` call below.
let packages = options.spec.get_packages(ws)?;
let (package_set, resolver) = ops::resolve_ws(ws)?;
let packages = if let ops::Packages::Packages(ref pkg_names) = options.spec {
let pkgids: Vec<_> = pkg_names
.iter()
.flat_map(|name| resolver.query(name))
.collect();
package_set.get_many(pkgids)?
} else {
options.spec.get_packages(ws)?
};

let bins: Vec<_> = packages
.into_iter()
.flat_map(|pkg| {
Expand Down

0 comments on commit f5114a4

Please sign in to comment.