Use docopt's new syntax for repeatable options

This commit is contained in:
Florian Hahn 2015-09-12 23:32:35 +02:00
parent b3ade7c7f1
commit 9d301d6e9e
11 changed files with 321 additions and 156 deletions

View File

@ -26,25 +26,25 @@ pub const USAGE: &'static str = "
Execute all benchmarks of a local package
Usage:
cargo bench [options] [-p SPEC --package SPEC]... [--] [<args>...]
cargo bench [options] [--] [<args>...]
Options:
-h, --help Print this message
--lib Benchmark only this package's library
--bin NAME Benchmark only the specified binary
--example NAME Benchmark only the specified example
--test NAME Benchmark only the specified test target
--bench NAME Benchmark only the specified bench target
--no-run Compile, but don't run benchmarks
-p SPEC, --package SPEC Package to run benchmarks for
-j N, --jobs N The number of jobs to run in parallel
--features FEATURES Space-separated list of features to also build
--no-default-features Do not build the `default` feature
--target TRIPLE Build for the target triple
--manifest-path PATH Path to the manifest to build benchmarks for
-v, --verbose Use verbose output
-q, --quiet No output printed to stdout
--color WHEN Coloring: auto, always, never
-h, --help Print this message
--lib Benchmark only this package's library
--bin NAME Benchmark only the specified binary
--example NAME Benchmark only the specified example
--test NAME Benchmark only the specified test target
--bench NAME Benchmark only the specified bench target
--no-run Compile, but don't run benchmarks
-p SPEC, --package SPEC ... Package to run benchmarks for
-j N, --jobs N The number of jobs to run in parallel
--features FEATURES Space-separated list of features to also build
--no-default-features Do not build the `default` feature
--target TRIPLE Build for the target triple
--manifest-path PATH Path to the manifest to build benchmarks for
-v, --verbose Use verbose output
-q, --quiet No output printed to stdout
--color WHEN Coloring: auto, always, never
All of the trailing arguments are passed to the benchmark binaries generated
for filtering benchmarks and generally providing options configuring how they

View File

@ -28,25 +28,25 @@ pub const USAGE: &'static str = "
Compile a local package and all of its dependencies
Usage:
cargo build [options] [-p SPEC --package SPEC]...
cargo build [options]
Options:
-h, --help Print this message
-p SPEC, --package SPEC Package to build
-j N, --jobs N The number of jobs to run in parallel
--lib Build only this package's library
--bin NAME Build only the specified binary
--example NAME Build only the specified example
--test NAME Build only the specified test target
--bench NAME Build only the specified benchmark target
--release Build artifacts in release mode, with optimizations
--features FEATURES Space-separated list of features to also build
--no-default-features Do not build the `default` feature
--target TRIPLE Build for the target triple
--manifest-path PATH Path to the manifest to compile
-v, --verbose Use verbose output
-q, --quiet No output printed to stdout
--color WHEN Coloring: auto, always, never
-h, --help Print this message
-p SPEC, --package SPEC ... Package to build
-j N, --jobs N The number of jobs to run in parallel
--lib Build only this package's library
--bin NAME Build only the specified binary
--example NAME Build only the specified example
--test NAME Build only the specified test target
--bench NAME Build only the specified benchmark target
--release Build artifacts in release mode, with optimizations
--features FEATURES Space-separated list of features to also build
--no-default-features Do not build the `default` feature
--target TRIPLE Build for the target triple
--manifest-path PATH Path to the manifest to compile
-v, --verbose Use verbose output
-q, --quiet No output printed to stdout
--color WHEN Coloring: auto, always, never
If the --package argument is given, then SPEC is a package id specification
which indicates which package should be built. If it is not given, then the

View File

@ -22,22 +22,22 @@ pub const USAGE: &'static str = "
Build a package's documentation
Usage:
cargo doc [options] [-p SPEC --package SPEC]...
cargo doc [options]
Options:
-h, --help Print this message
--open Opens the docs in a browser after the operation
-p SPEC, --package SPEC Package to document
--no-deps Don't build documentation for dependencies
-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
--no-default-features Do not build the `default` feature
--target TRIPLE Build for the target triple
--manifest-path PATH Path to the manifest to document
-v, --verbose Use verbose output
-q, --quiet No output printed to stdout
--color WHEN Coloring: auto, always, never
-h, --help Print this message
--open Opens the docs in a browser after the operation
-p SPEC, --package SPEC ... Package to document
--no-deps Don't build documentation for dependencies
-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
--no-default-features Do not build the `default` feature
--target TRIPLE Build for the target triple
--manifest-path PATH Path to the manifest to document
-v, --verbose Use verbose output
-q, --quiet No output printed to stdout
--color WHEN Coloring: auto, always, never
By default the documentation for the local package and all dependencies is
built. The output is all placed in `target/doc` in rustdoc's usual format.

View File

@ -29,25 +29,25 @@ pub const USAGE: &'static str = "
Compile a package and all of its dependencies
Usage:
cargo rustc [options] [-p SPEC --package SPEC]... [--] [<opts>...]
cargo rustc [options] [--] [<opts>...]
Options:
-h, --help Print this message
-p SPEC, --package SPEC The profile to compile for
-j N, --jobs N The number of jobs to run in parallel
--lib Build only this package's library
--bin NAME Build only the specified binary
--example NAME Build only the specified example
--test NAME Build only the specified test target
--bench NAME Build only the specified benchmark target
--release Build artifacts in release mode, with optimizations
--features FEATURES Features to compile for the package
--no-default-features Do not compile default features for the package
--target TRIPLE Target triple which compiles will be for
--manifest-path PATH Path to the manifest to fetch dependencies for
-v, --verbose Use verbose output
-q, --quiet No output printed to stdout
--color WHEN Coloring: auto, always, never
-h, --help Print this message
-p SPEC, --package SPEC ... The profile to compile for
-j N, --jobs N The number of jobs to run in parallel
--lib Build only this package's library
--bin NAME Build only the specified binary
--example NAME Build only the specified example
--test NAME Build only the specified test target
--bench NAME Build only the specified benchmark target
--release Build artifacts in release mode, with optimizations
--features FEATURES Features to compile for the package
--no-default-features Do not compile default features for the package
--target TRIPLE Target triple which compiles will be for
--manifest-path PATH Path to the manifest to fetch dependencies for
-v, --verbose Use verbose output
-q, --quiet No output printed to stdout
--color WHEN Coloring: auto, always, never
The specified target for the current package (or package specified by SPEC if
provided) will be compiled along with all of its dependencies. The specified

View File

@ -28,27 +28,27 @@ pub const USAGE: &'static str = "
Execute all unit and integration tests of a local package
Usage:
cargo test [options] [-p SPEC --package SPEC]... [--] [<args>...]
cargo test [options] [--] [<args>...]
Options:
-h, --help Print this message
--lib Test only this package's library
--bin NAME Test only the specified binary
--example NAME Test only the specified example
--test NAME Test only the specified integration test target
--bench NAME Test only the specified benchmark target
--no-run Compile, but don't run tests
-p SPEC, --package SPEC Package to run tests for
-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
--no-default-features Do not build the `default` feature
--target TRIPLE Build for the target triple
--manifest-path PATH Path to the manifest to build tests for
-v, --verbose Use verbose output
-q, --quiet No output printed to stdout
--color WHEN Coloring: auto, always, never
--no-fail-fast Run all tests regardless of failure
-h, --help Print this message
--lib Test only this package's library
--bin NAME Test only the specified binary
--example NAME Test only the specified example
--test NAME Test only the specified integration test target
--bench NAME Test only the specified benchmark target
--no-run Compile, but don't run tests
-p SPEC, --package SPEC ... Package to run tests for
-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
--no-default-features Do not build the `default` feature
--target TRIPLE Build for the target triple
--manifest-path PATH Path to the manifest to build tests for
-v, --verbose Use verbose output
-q, --quiet No output printed to stdout
--color WHEN Coloring: auto, always, never
--no-fail-fast Run all tests regardless of failure
All of the trailing arguments are passed to the test binaries generated for
filtering tests and generally providing options configuring how they run. For

View File

@ -54,6 +54,7 @@ pub struct TargetConfig {
// Returns a mapping of the root package plus its immediate dependencies to
// where the compiled libraries are all located.
#[allow(deprecated)] // connect => join in 1.3
pub fn compile_targets<'a, 'cfg: 'a>(pkg_targets: &'a [(&Package,
Vec<(&Target,
&'a Profile)>)],
@ -66,7 +67,7 @@ pub fn compile_targets<'a, 'cfg: 'a>(pkg_targets: &'a [(&Package,
-> CargoResult<Compilation<'cfg>> {
debug!("compile_targets: {}", pkg_targets.iter().map(|&(ref p, _)| p.name())
.collect::<Vec<_>>().join(", "));
.collect::<Vec<_>>().connect(", "));
try!(links::validate(deps));

View File

@ -62,7 +62,10 @@ fn compile_tests<'a>(manifest_path: &Path,
options: &TestOptions<'a>)
-> CargoResult<Compilation<'a>> {
let mut compilation = try!(ops::compile(manifest_path, &options.compile_opts));
compilation.tests.sort();
compilation.tests.iter_mut()
.map(|&mut (_, ref mut tests)|
tests.sort_by(|&(ref n1, _), &(ref n2, _)| n1.cmp(n2)))
.collect::<Vec<_>>();
Ok(compilation)
}
@ -76,24 +79,26 @@ fn run_unit_tests(options: &TestOptions,
let mut errors = Vec::new();
for &(_, ref exe) in &compilation.tests {
let to_display = match util::without_prefix(exe, &cwd) {
Some(path) => path,
None => &**exe,
};
let mut cmd = try!(compilation.target_process(exe, &compilation.package));
cmd.args(test_args);
try!(config.shell().concise(|shell| {
shell.status("Running", to_display.display().to_string())
}));
try!(config.shell().verbose(|shell| {
shell.status("Running", cmd.to_string())
}));
for &(ref pkg, ref tests) in &compilation.tests {
for &(_, ref exe) in tests {
let to_display = match util::without_prefix(exe, &cwd) {
Some(path) => path,
None => &**exe,
};
let mut cmd = try!(compilation.target_process(exe, pkg));
cmd.args(test_args);
try!(config.shell().concise(|shell| {
shell.status("Running", to_display.display().to_string())
}));
try!(config.shell().verbose(|shell| {
shell.status("Running", cmd.to_string())
}));
if let Err(e) = ExecEngine::exec(&mut ProcessEngine, cmd) {
errors.push(e);
if !options.no_fail_fast {
break
if let Err(e) = ExecEngine::exec(&mut ProcessEngine, cmd) {
errors.push(e);
if !options.no_fail_fast {
break
}
}
}
}
@ -107,15 +112,20 @@ fn run_doc_tests(options: &TestOptions,
-> CargoResult<Vec<ProcessError>> {
let mut errors = Vec::new();
let config = options.compile_opts.config;
let libs = compilation.package.targets().iter()
.filter(|t| t.doctested())
.map(|t| (t.src_path(), t.name(), t.crate_name()));
for (lib, name, crate_name) in libs {
let mut libs = vec![];
for package in compilation.to_doc_test.iter() {
libs.extend(package.targets().iter()
.filter(|t| t.doctested())
.map(|t| (package, t.src_path(), t.name(), t.crate_name())));
}
for (package, lib, name, crate_name) in libs {
try!(config.shell().status("Doc-tests", name));
let mut p = try!(compilation.rustdoc_process(&compilation.package));
let mut p = try!(compilation.rustdoc_process(package));
p.arg("--test").arg(lib)
.arg("--crate-name").arg(&crate_name)
.cwd(compilation.package.root());
.cwd(package.root());
for &rust_dep in &[&compilation.deps_output, &compilation.root_output] {
let mut arg = OsString::from("dependency=");
@ -169,44 +179,3 @@ fn run_doc_tests(options: &TestOptions,
}
Ok(errors)
}
fn build_and_run<'a>(manifest_path: &Path,
options: &TestOptions<'a>,
test_args: &[String])
-> CargoResult<Result<Compilation<'a>, ProcessError>> {
let config = options.compile_opts.config;
let mut source = try!(PathSource::for_path(&manifest_path.parent().unwrap(),
config));
try!(source.update());
let mut compile = try!(ops::compile(manifest_path, &options.compile_opts));
if options.no_run { return Ok(Ok(compile)) }
compile.tests.iter_mut()
.map(|&mut (_, ref mut tests)|
tests.sort_by(|&(ref n1, _), &(ref n2, _)| n1.cmp(n2)))
.collect::<Vec<_>>();
let cwd = config.cwd();
for &(ref pkg, ref tests) in &compile.tests {
for &(_, ref exe) in tests {
let to_display = match util::without_prefix(exe, &cwd) {
Some(path) => path,
None => &**exe,
};
let mut cmd = try!(compile.target_process(exe, pkg));
cmd.args(test_args);
try!(config.shell().concise(|shell| {
shell.status("Running", to_display.display().to_string())
}));
try!(config.shell().verbose(|shell| {
shell.status("Running", cmd.to_string())
}));
match ExecEngine::exec(&mut ProcessEngine, cmd) {
Ok(()) => {}
Err(e) => return Ok(Err(e))
}
}
}
Ok(Ok(compile))
}

View File

@ -269,7 +269,8 @@ pub struct Execs {
expect_stdout: Option<String>,
expect_stdin: Option<String>,
expect_stderr: Option<String>,
expect_exit_code: Option<i32>
expect_exit_code: Option<i32>,
expect_stdout_contains: Vec<String>
}
impl Execs {
@ -289,6 +290,11 @@ impl Execs {
self
}
pub fn with_stdout_contains<S: ToString>(mut self, expected: S) -> Execs {
self.expect_stdout_contains.push(expected.to_string());
self
}
fn match_output(&self, actual: &Output) -> ham::MatchResult {
self.match_status(actual)
.and(self.match_stdout(actual))
@ -312,6 +318,8 @@ impl Execs {
fn match_stdout(&self, actual: &Output) -> ham::MatchResult {
self.match_std(self.expect_stdout.as_ref(), &actual.stdout,
"stdout", &actual.stderr)
.and(self.match_contains(self.expect_stdout_contains.as_ref(),
&actual.stdout, "stdout"))
}
fn match_stderr(&self, actual: &Output) -> ham::MatchResult {
@ -319,6 +327,40 @@ impl Execs {
"stderr", &actual.stdout)
}
#[allow(deprecated)] // connect => join in 1.3
fn match_contains(&self, expect: &[String], actual: &[u8],
description: &str) -> ham::MatchResult {
for s in expect {
let a: Vec<&str> = match str::from_utf8(actual) {
Err(..) => return Err(format!("{} was not utf8 encoded",
description)),
Ok(actual) => actual.lines().collect(),
};
let e: Vec<&str> = s.lines().collect();
let first = e.first().unwrap();
let mut ai = a.iter();
match ai.position(|s| lines_match(first, s)) {
Some(_) => {
let match_count = ai.zip(e.iter().skip(1))
.take_while(|&(a, e)| lines_match(a, e)).count();
if match_count != (e.len() - 1) {
return ham::expect(false,
format!("expected: {}\n\
actual: {}",
e.connect("\n"),
a.iter().take(e.len()).map(|&s| s)
.collect::<Vec<_>>().connect("\n")));
}
},
None => {
return ham::expect(false, format!("no match"));
}
};
}
ham::expect(true, format!("OK"))
}
#[allow(deprecated)] // connect => join in 1.3
fn match_std(&self, expected: Option<&String>, actual: &[u8],
description: &str, extra: &[u8]) -> ham::MatchResult {
@ -446,7 +488,8 @@ pub fn execs() -> Execs {
expect_stdout: None,
expect_stderr: None,
expect_stdin: None,
expect_exit_code: None
expect_exit_code: None,
expect_stdout_contains: vec![]
}
}

View File

@ -922,3 +922,88 @@ test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured
", compiling = COMPILING, running = RUNNING)));
});
test!(test_bench_multiple_packages {
if !::is_nightly() { return }
let p = project("foo")
.file("Cargo.toml", r#"
[project]
name = "foo"
authors = []
version = "0.1.0"
[dependencies.bar]
path = "../bar"
[dependencies.baz]
path = "../baz"
"#)
.file("src/lib.rs", "");
let bar = project("bar")
.file("Cargo.toml", r#"
[project]
name = "bar"
authors = []
version = "0.1.0"
[[bench]]
name = "bbar"
test = true
"#)
.file("src/lib.rs", "")
.file("benches/bbar.rs", r#"
#![feature(test)]
extern crate test;
use test::Bencher;
#[bench]
fn bench_bar(_b: &mut Bencher) {}
"#);
bar.build();
let baz = project("baz")
.file("Cargo.toml", r#"
[project]
name = "baz"
authors = []
version = "0.1.0"
[[bench]]
name = "bbaz"
test = true
"#)
.file("src/lib.rs", "")
.file("benches/bbaz.rs", r#"
#![feature(test)]
extern crate test;
use test::Bencher;
#[bench]
fn bench_baz(_b: &mut Bencher) {}
"#);
baz.build();
assert_that(p.cargo_process("bench").arg("-p").arg("bar").arg("-p").arg("baz"),
execs().with_status(0)
.with_stdout_contains(&format!("\
{running} target[..]release[..]bbaz-[..]
running 1 test
test bench_baz ... bench: 0 ns/iter (+/- 0)
test result: ok. 0 passed; 0 failed; 0 ignored; 1 measured
", running = RUNNING))
.with_stdout_contains(&format!("\
{running} target[..]release[..]bbar-[..]
running 1 test
test bench_bar ... bench: 0 ns/iter (+/- 0)
test result: ok. 0 passed; 0 failed; 0 ignored; 1 measured
", running = RUNNING)));
});

View File

@ -1927,8 +1927,6 @@ test!(rustc_no_trans {
});
test!(build_multiple_packages {
let p = project("foo")
.file("Cargo.toml", r#"
[package]
@ -1969,7 +1967,9 @@ test!(build_multiple_packages {
.file("d2/src/main.rs", "fn main() { println!(\"d2\"); }");
p.build();
assert_that(p.cargo_process("build").arg("-p").arg("d1").arg("-p").arg("d2").arg("-p").arg("foo"), execs());
assert_that(p.cargo_process("build").arg("-p").arg("d1").arg("-p").arg("d2")
.arg("-p").arg("foo"),
execs());
assert_that(&p.bin("foo"), existing_file());
assert_that(process(&p.bin("foo")).unwrap(),

View File

@ -1,7 +1,9 @@
use std::path::MAIN_SEPARATOR as SEP;
use support::{execs, project};
use support::{COMPILING, RUNNING};
use hamcrest::{assert_that};
use hamcrest::{assert_that, existing_file};
use cargo::util::process;
fn setup() {
}
@ -296,3 +298,68 @@ test!(build_only_bar_dependency {
compiling = COMPILING, running = RUNNING,
url = foo.url())));
});
test!(build_multiple_dependencies {
let foo = project("foo")
.file("Cargo.toml", r#"
[package]
name = "foo"
version = "0.0.1"
authors = []
[dependencies.bar]
path = "../bar"
[dependencies.baz]
path = "../baz"
"#)
.file("src/main.rs", r#"
fn main() {}
"#);
foo.build();
let bar = project("bar")
.file("Cargo.toml", r#"
[package]
name = "bar"
version = "0.1.0"
authors = []
"#)
.file("src/main.rs", r#"
fn main() {
if cfg!(flag = "1") { println!("Yeah from bar!"); }
}
"#);
bar.build();
let baz = project("baz")
.file("Cargo.toml", r#"
[package]
name = "baz"
version = "0.1.0"
authors = []
"#)
.file("src/main.rs", r#"
fn main() {
if cfg!(flag = "1") { println!("Yeah from baz!"); }
}
"#);
baz.build();
assert_that(foo.cargo_process("rustc").arg("-v").arg("-p").arg("bar")
.arg("-p").arg("baz").arg("--").arg("--cfg").arg("flag=\"1\""),
execs()
.with_status(0));
let bar_bin = &foo.build_dir().join("debug").join("deps").join("bar");
assert_that(bar_bin, existing_file());
assert_that(
process(bar_bin).unwrap(),
execs().with_stdout("Yeah from bar!\n"));
let baz_bin = &foo.build_dir().join("debug").join("deps").join("baz");
assert_that(bar_bin, existing_file());
assert_that(
process(baz_bin).unwrap(),
execs().with_stdout("Yeah from baz!\n"));
});