mirror of
https://github.com/rust-lang/cargo
synced 2024-10-14 03:32:39 +00:00
Add --name
and --example
to cargo run
This lets us compile and run examples using `cargo run --example NAME`. Selecting the other binary targets is now done using the `--name` flag. `cargo run` falls back to the old behaviour (running the only bin target in the project, failing if there are more) in neither `--name` nor `--example` are present. Closes #538
This commit is contained in:
parent
947a62b7db
commit
f2770b31be
|
@ -2,11 +2,14 @@ use std::io::process::ExitStatus;
|
|||
|
||||
use cargo::ops;
|
||||
use cargo::core::{MultiShell};
|
||||
use cargo::util::{CliResult, CliError};
|
||||
use cargo::core::manifest::{BinTarget, ExampleTarget};
|
||||
use cargo::util::{CliResult, CliError, human};
|
||||
use cargo::util::important_paths::{find_root_manifest_for_cwd};
|
||||
|
||||
#[deriving(Decodable)]
|
||||
struct Options {
|
||||
flag_name: Option<String>,
|
||||
flag_example: Option<String>,
|
||||
flag_jobs: Option<uint>,
|
||||
flag_features: Vec<String>,
|
||||
flag_no_default_features: bool,
|
||||
|
@ -25,6 +28,8 @@ Usage:
|
|||
|
||||
Options:
|
||||
-h, --help Print this message
|
||||
--name NAME Name of the bin target to run
|
||||
--example NAME Name of the example target to run
|
||||
-j N, --jobs N The number of jobs to run in parallel
|
||||
--release Build artifacts in release mode, with optimizations
|
||||
--features FEATURES Space-separated list of features to also build
|
||||
|
@ -33,6 +38,11 @@ Options:
|
|||
--manifest-path PATH Path to the manifest to execute
|
||||
-v, --verbose Use verbose output
|
||||
|
||||
If neither `--name` or `--example` are given, then if the project only has one
|
||||
bin target it will be run. Otherwise `--name` specifies the bin target to run,
|
||||
and `--example` specifies the example target to run. At most one of `--name` or
|
||||
`--example` can be provided.
|
||||
|
||||
All of the trailing arguments are passed as to the binary to run.
|
||||
";
|
||||
|
||||
|
@ -40,8 +50,16 @@ pub fn execute(options: Options, shell: &mut MultiShell) -> CliResult<Option<()>
|
|||
shell.set_verbose(options.flag_verbose);
|
||||
let root = try!(find_root_manifest_for_cwd(options.flag_manifest_path));
|
||||
|
||||
let env = if options.flag_example.is_some() {
|
||||
"test"
|
||||
} else if options.flag_release {
|
||||
"release"
|
||||
} else {
|
||||
"compile"
|
||||
};
|
||||
|
||||
let mut compile_opts = ops::CompileOptions {
|
||||
env: if options.flag_release { "release" } else { "compile" },
|
||||
env: env,
|
||||
shell: shell,
|
||||
jobs: options.flag_jobs,
|
||||
target: options.flag_target.as_ref().map(|t| t.as_slice()),
|
||||
|
@ -51,7 +69,18 @@ pub fn execute(options: Options, shell: &mut MultiShell) -> CliResult<Option<()>
|
|||
spec: None,
|
||||
};
|
||||
|
||||
let err = try!(ops::run(&root, &mut compile_opts,
|
||||
let (target_kind, name) = match (options.flag_name, options.flag_example) {
|
||||
(Some(bin), None) => (BinTarget, Some(bin)),
|
||||
(None, Some(example)) => (ExampleTarget, Some(example)),
|
||||
(None, None) => (BinTarget, None),
|
||||
(Some(_), Some(_)) => return Err(CliError::from_boxed(
|
||||
human("specify either `--name` or `--example`, not both"), 1)),
|
||||
};
|
||||
|
||||
let err = try!(ops::run(&root,
|
||||
target_kind,
|
||||
name,
|
||||
&mut compile_opts,
|
||||
options.arg_args.as_slice()).map_err(|err| {
|
||||
CliError::from_boxed(err, 101)
|
||||
}));
|
||||
|
@ -65,4 +94,3 @@ pub fn execute(options: Options, shell: &mut MultiShell) -> CliResult<Option<()>
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -2,10 +2,13 @@ use std::os;
|
|||
|
||||
use ops;
|
||||
use util::{CargoResult, human, process, ProcessError, Require};
|
||||
use core::manifest::{TargetKind, LibTarget, BinTarget, ExampleTarget};
|
||||
use core::source::Source;
|
||||
use sources::PathSource;
|
||||
|
||||
pub fn run(manifest_path: &Path,
|
||||
target_kind: TargetKind,
|
||||
name: Option<String>,
|
||||
options: &mut ops::CompileOptions,
|
||||
args: &[String]) -> CargoResult<Option<ProcessError>> {
|
||||
let mut src = try!(PathSource::for_path(&manifest_path.dir_path()));
|
||||
|
@ -13,14 +16,21 @@ pub fn run(manifest_path: &Path,
|
|||
let root = try!(src.get_root_package());
|
||||
let env = options.env;
|
||||
let mut bins = root.get_manifest().get_targets().iter().filter(|a| {
|
||||
a.is_bin() && a.get_profile().get_env() == env
|
||||
let matches_kind = match target_kind {
|
||||
BinTarget => a.is_bin(),
|
||||
ExampleTarget => a.is_example(),
|
||||
LibTarget(_) => false,
|
||||
};
|
||||
let matches_name = name.as_ref().map_or(true, |n| n.as_slice() == a.get_name());
|
||||
matches_kind && matches_name && a.get_profile().get_env() == env
|
||||
});
|
||||
let bin = try!(bins.next().require(|| {
|
||||
human("a bin target must be available for `cargo run`")
|
||||
}));
|
||||
match bins.next() {
|
||||
Some(..) => return Err(human("`cargo run` requires that a project only \
|
||||
have one executable")),
|
||||
Some(..) => return Err(
|
||||
human("`cargo run` requires that a project only have one executable. \
|
||||
Use the `--name` option to specify which one to run")),
|
||||
None => {}
|
||||
}
|
||||
|
||||
|
@ -28,7 +38,7 @@ pub fn run(manifest_path: &Path,
|
|||
let dst = manifest_path.dir_path().join("target");
|
||||
let dst = match options.target {
|
||||
Some(target) => dst.join(target),
|
||||
None => dst,
|
||||
None => if bin.is_example() { dst.join("examples") } else { dst },
|
||||
};
|
||||
let exe = match bin.get_profile().get_dest() {
|
||||
Some(s) => dst.join(s).join(bin.get_name()),
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use std::path;
|
||||
|
||||
use support::{project, execs, path2url};
|
||||
use support::{project, cargo_dir, execs, path2url};
|
||||
use support::{COMPILING, RUNNING};
|
||||
use hamcrest::{assert_that, existing_file};
|
||||
|
||||
|
@ -98,7 +98,126 @@ test!(too_many_bins {
|
|||
assert_that(p.cargo_process("run"),
|
||||
execs().with_status(101)
|
||||
.with_stderr("`cargo run` requires that a project only \
|
||||
have one executable\n"));
|
||||
have one executable. Use the `--name` option \
|
||||
to specify which one to run\n"));
|
||||
})
|
||||
|
||||
test!(specify_name {
|
||||
let p = project("foo")
|
||||
.file("Cargo.toml", r#"
|
||||
[project]
|
||||
name = "foo"
|
||||
version = "0.0.1"
|
||||
authors = []
|
||||
"#)
|
||||
.file("src/lib.rs", "")
|
||||
.file("src/bin/a.rs", r#"
|
||||
extern crate foo;
|
||||
fn main() { println!("hello a.rs"); }
|
||||
"#)
|
||||
.file("src/bin/b.rs", r#"
|
||||
extern crate foo;
|
||||
fn main() { println!("hello b.rs"); }
|
||||
"#);
|
||||
|
||||
assert_that(p.cargo_process("run").arg("--name").arg("a"),
|
||||
execs().with_status(0).with_stdout(format!("\
|
||||
{compiling} foo v0.0.1 ({dir})
|
||||
{running} `target{sep}a`
|
||||
hello a.rs
|
||||
",
|
||||
compiling = COMPILING,
|
||||
running = RUNNING,
|
||||
dir = path2url(p.root()),
|
||||
sep = path::SEP).as_slice()));
|
||||
|
||||
assert_that(p.process(cargo_dir().join("cargo")).arg("run").arg("--name").arg("b"),
|
||||
execs().with_status(0).with_stdout(format!("\
|
||||
{running} `target{sep}b`
|
||||
hello b.rs
|
||||
",
|
||||
running = RUNNING,
|
||||
sep = path::SEP).as_slice()));
|
||||
})
|
||||
|
||||
test!(run_example {
|
||||
let p = project("foo")
|
||||
.file("Cargo.toml", r#"
|
||||
[project]
|
||||
name = "foo"
|
||||
version = "0.0.1"
|
||||
authors = []
|
||||
"#)
|
||||
.file("src/lib.rs", "")
|
||||
.file("examples/a.rs", r#"
|
||||
fn main() { println!("example"); }
|
||||
"#)
|
||||
.file("src/bin/a.rs", r#"
|
||||
fn main() { println!("bin"); }
|
||||
"#);
|
||||
|
||||
assert_that(p.cargo_process("run").arg("--example").arg("a"),
|
||||
execs().with_status(0).with_stdout(format!("\
|
||||
{compiling} foo v0.0.1 ({dir})
|
||||
{running} `target{sep}examples{sep}a`
|
||||
example
|
||||
",
|
||||
compiling = COMPILING,
|
||||
running = RUNNING,
|
||||
dir = path2url(p.root()),
|
||||
sep = path::SEP).as_slice()));
|
||||
})
|
||||
|
||||
test!(either_name_or_example {
|
||||
let p = project("foo")
|
||||
.file("Cargo.toml", r#"
|
||||
[project]
|
||||
name = "foo"
|
||||
version = "0.0.1"
|
||||
authors = []
|
||||
"#)
|
||||
.file("src/bin/a.rs", r#"
|
||||
fn main() { println!("hello a.rs"); }
|
||||
"#)
|
||||
.file("examples/b.rs", r#"
|
||||
fn main() { println!("hello b.rs"); }
|
||||
"#);
|
||||
|
||||
assert_that(p.cargo_process("run").arg("--name").arg("a").arg("--example").arg("b"),
|
||||
execs().with_status(1)
|
||||
.with_stderr("specify either `--name` or `--example`, \
|
||||
not both"));
|
||||
})
|
||||
|
||||
test!(one_bin_multiple_examples {
|
||||
let p = project("foo")
|
||||
.file("Cargo.toml", r#"
|
||||
[project]
|
||||
name = "foo"
|
||||
version = "0.0.1"
|
||||
authors = []
|
||||
"#)
|
||||
.file("src/lib.rs", "")
|
||||
.file("src/bin/main.rs", r#"
|
||||
fn main() { println!("hello main.rs"); }
|
||||
"#)
|
||||
.file("examples/a.rs", r#"
|
||||
fn main() { println!("hello a.rs"); }
|
||||
"#)
|
||||
.file("examples/b.rs", r#"
|
||||
fn main() { println!("hello b.rs"); }
|
||||
"#);
|
||||
|
||||
assert_that(p.cargo_process("run"),
|
||||
execs().with_status(0).with_stdout(format!("\
|
||||
{compiling} foo v0.0.1 ({dir})
|
||||
{running} `target{sep}main`
|
||||
hello main.rs
|
||||
",
|
||||
compiling = COMPILING,
|
||||
running = RUNNING,
|
||||
dir = path2url(p.root()),
|
||||
sep = path::SEP).as_slice()));
|
||||
})
|
||||
|
||||
test!(run_dylib_dep {
|
||||
|
|
Loading…
Reference in a new issue