Skip to content

Commit

Permalink
cargo run supports --package argument
Browse files Browse the repository at this point in the history
closes #3529
  • Loading branch information
matklad committed Feb 13, 2017
1 parent 6f1b860 commit 261ae46
Show file tree
Hide file tree
Showing 4 changed files with 121 additions and 24 deletions.
41 changes: 24 additions & 17 deletions src/bin/run.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use std::iter::FromIterator;

use cargo::core::Workspace;
use cargo::ops::{self, MessageFormat, Packages};
use cargo::util::{CliResult, CliError, Config, Human};
Expand All @@ -7,6 +9,7 @@ use cargo::util::important_paths::{find_root_manifest_for_wd};
pub struct Options {
flag_bin: Option<String>,
flag_example: Option<String>,
flag_package: Option<String>,
flag_jobs: Option<u32>,
flag_features: Vec<String>,
flag_all_features: bool,
Expand All @@ -30,22 +33,23 @@ Usage:
cargo run [options] [--] [<args>...]
Options:
-h, --help Print this message
--bin NAME Name of the bin target to run
--example NAME Name of the example target to run
-j N, --jobs N Number of parallel jobs, defaults to # of CPUs
--release Build artifacts in release mode, with optimizations
--features FEATURES Space-separated list of features to also build
--all-features Build all available features
--no-default-features Do not build the `default` feature
--target TRIPLE Build for the target triple
--manifest-path PATH Path to the manifest to execute
-v, --verbose ... Use verbose output (-vv very verbose/build.rs output)
-q, --quiet No output printed to stdout
--color WHEN Coloring: auto, always, never
--message-format FMT Error format: human, json [default: human]
--frozen Require Cargo.lock and cache are up to date
--locked Require Cargo.lock is up to date
-h, --help Print this message
--bin NAME Name of the bin target to run
--example NAME Name of the example target to run
-p SPEC, --package SPEC Package with the target to run
-j N, --jobs N Number of parallel jobs, defaults to # of CPUs
--release Build artifacts in release mode, with optimizations
--features FEATURES Space-separated list of features to also build
--all-features Build all available features
--no-default-features Do not build the `default` feature
--target TRIPLE Build for the target triple
--manifest-path PATH Path to the manifest to execute
-v, --verbose ... Use verbose output (-vv very verbose/build.rs output)
-q, --quiet No output printed to stdout
--color WHEN Coloring: auto, always, never
--message-format FMT Error format: human, json [default: human]
--frozen Require Cargo.lock and cache are up to date
--locked Require Cargo.lock is up to date
If neither `--bin` nor `--example` are given, then if the project only has one
bin target it will be run. Otherwise `--bin` specifies the bin target to run,
Expand Down Expand Up @@ -74,14 +78,17 @@ pub fn execute(options: Options, config: &Config) -> CliResult {
examples.push(s);
}

let packages = Vec::from_iter(options.flag_package.iter().cloned());
let spec = Packages::Packages(&packages);

let compile_opts = ops::CompileOptions {
config: config,
jobs: options.flag_jobs,
target: options.flag_target.as_ref().map(|t| &t[..]),
features: &options.flag_features,
all_features: options.flag_all_features,
no_default_features: options.flag_no_default_features,
spec: Packages::Packages(&[]),
spec: spec,
release: options.flag_release,
mode: ops::CompileMode::Build,
filter: if examples.is_empty() && bins.is_empty() {
Expand Down
4 changes: 2 additions & 2 deletions src/cargo/ops/cargo_compile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ pub enum MessageFormat {
Json
}

#[derive(Clone, Copy, PartialEq, Eq)]
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub enum Packages<'a> {
All,
Packages(&'a [String]),
Expand Down Expand Up @@ -141,7 +141,7 @@ pub fn compile<'a>(ws: &Workspace<'a>, options: &CompileOptions<'a>)
}

pub fn compile_with_exec<'a>(ws: &Workspace<'a>,
options: &CompileOptions<'a>,
options: &CompileOptions<'a>,
exec: Arc<Executor>)
-> CargoResult<ops::Compilation<'a>> {
for member in ws.members() {
Expand Down
23 changes: 18 additions & 5 deletions src/cargo/ops/cargo_run.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,28 @@
use std::path::Path;

use ops::{self, CompileFilter};
use util::{self, CargoResult, ProcessError};
use ops::{self, CompileFilter, Packages};
use util::{self, human, CargoResult, ProcessError};
use core::Workspace;

pub fn run(ws: &Workspace,
options: &ops::CompileOptions,
args: &[String]) -> CargoResult<Option<ProcessError>> {
let config = ws.config();
let root = ws.current()?;

let mut bins = root.manifest().targets().iter().filter(|a| {
let pkg = match options.spec {
Packages::All => unreachable!("cargo run supports single package only"),
Packages::Packages(xs) => match xs.len() {
0 => ws.current()?,
1 => ws.members()
.find(|pkg| pkg.name() == xs[0])
.ok_or_else(|| human(
format!("package `{}` is not a member of the workspace", xs[0])
))?,
_ => unreachable!("cargo run supports single package only"),
}
};

let mut bins = pkg.manifest().targets().iter().filter(|a| {
!a.is_lib() && !a.is_custom_build() && match options.filter {
CompileFilter::Everything => a.is_bin(),
CompileFilter::Only { .. } => options.filter.matches(a),
Expand Down Expand Up @@ -41,14 +53,15 @@ pub fn run(ws: &Workspace,
}

let compile = ops::compile(ws, options)?;
assert_eq!(compile.binaries.len(), 1);
let exe = &compile.binaries[0];
let exe = match util::without_prefix(&exe, config.cwd()) {
Some(path) if path.file_name() == Some(path.as_os_str())
=> Path::new(".").join(path).to_path_buf(),
Some(path) => path.to_path_buf(),
None => exe.to_path_buf(),
};
let mut process = compile.target_process(exe, &root)?;
let mut process = compile.target_process(exe, &pkg)?;
process.args(args).cwd(config.cwd());

config.shell().status("Running", process.to_string())?;
Expand Down
77 changes: 77 additions & 0 deletions tests/run.rs
Original file line number Diff line number Diff line change
Expand Up @@ -652,3 +652,80 @@ fn fail_no_extra_verbose() {
.with_stdout("")
.with_stderr(""));
}

#[test]
fn run_multiple_packages() {
let p = project("foo")
.file("foo/Cargo.toml", r#"
[package]
name = "foo"
version = "0.0.1"
authors = []
[workspace]
[dependencies]
d1 = { path = "d1" }
d2 = { path = "d2" }
d3 = { path = "../d3" } # outside of the workspace
[[bin]]
name = "foo"
"#)
.file("foo/src/foo.rs", "fn main() { println!(\"foo\"); }")
.file("foo/d1/Cargo.toml", r#"
[package]
name = "d1"
version = "0.0.1"
authors = []
[[bin]]
name = "d1"
"#)
.file("foo/d1/src/lib.rs", "")
.file("foo/d1/src/main.rs", "fn main() { println!(\"d1\"); }")
.file("foo/d2/Cargo.toml", r#"
[package]
name = "d2"
version = "0.0.1"
authors = []
[[bin]]
name = "d2"
"#)
.file("foo/d2/src/main.rs", "fn main() { println!(\"d2\"); }")
.file("d3/Cargo.toml", r#"
[package]
name = "d3"
version = "0.0.1"
authors = []
"#)
.file("d3/src/main.rs", "fn main() { println!(\"d2\"); }");

let p = p.build();

let cargo = || {
let mut process_builder = p.cargo("run");
process_builder.cwd(p.root().join("foo"));
process_builder
};

assert_that(cargo().arg("-p").arg("d1"),
execs().with_status(0).with_stdout("d1"));

assert_that(cargo().arg("-p").arg("d2").arg("--bin").arg("d2"),
execs().with_status(0).with_stdout("d2"));

assert_that(cargo(),
execs().with_status(0).with_stdout("foo"));

assert_that(cargo().arg("-p").arg("d1").arg("-p").arg("d2"),
execs()
.with_status(1)
.with_stderr_contains("[ERROR] Invalid arguments."));

assert_that(cargo().arg("-p").arg("d3"),
execs()
.with_status(101)
.with_stderr_contains("[ERROR] package `d3` is not a member of the workspace"));
}

0 comments on commit 261ae46

Please sign in to comment.