mirror of
https://github.com/rust-lang/cargo.git
synced 2025-09-28 11:20:36 +00:00
Port bench and build to clap
This commit is contained in:
parent
3f7a42663f
commit
38f81e05b3
@ -54,6 +54,7 @@ tempdir = "0.3"
|
||||
termcolor = "0.3"
|
||||
toml = "0.4"
|
||||
url = "1.1"
|
||||
clap = "2.27.0"
|
||||
|
||||
[target.'cfg(target_os = "macos")'.dependencies]
|
||||
core-foundation = { version = "0.5.1", features = ["mac_os_10_7_support"] }
|
||||
|
@ -9,6 +9,7 @@ extern crate log;
|
||||
#[macro_use]
|
||||
extern crate serde_derive;
|
||||
extern crate serde_json;
|
||||
extern crate clap;
|
||||
|
||||
use std::collections::BTreeSet;
|
||||
use std::collections::HashMap;
|
||||
@ -20,6 +21,8 @@ use cargo::core::shell::{Shell, Verbosity};
|
||||
use cargo::util::{self, CliResult, lev_distance, Config, CargoResult};
|
||||
use cargo::util::{CliError, ProcessError};
|
||||
|
||||
mod cli;
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct Flags {
|
||||
flag_list: bool,
|
||||
@ -85,17 +88,26 @@ fn main() {
|
||||
}
|
||||
};
|
||||
|
||||
let result = (|| {
|
||||
let args: Vec<_> = try!(env::args_os()
|
||||
.map(|s| {
|
||||
s.into_string().map_err(|s| {
|
||||
format_err!("invalid unicode in argument: {:?}", s)
|
||||
let is_clapified = ::std::env::args().any(|arg| match arg.as_ref() {
|
||||
"build" | "bench" => true,
|
||||
_ => false
|
||||
});
|
||||
|
||||
let result = if is_clapified {
|
||||
cli::do_main(&mut config)
|
||||
} else {
|
||||
(|| {
|
||||
let args: Vec<_> = try!(env::args_os()
|
||||
.map(|s| {
|
||||
s.into_string().map_err(|s| {
|
||||
format_err!("invalid unicode in argument: {:?}", s)
|
||||
})
|
||||
})
|
||||
})
|
||||
.collect());
|
||||
let rest = &args;
|
||||
cargo::call_main_without_stdin(execute, &mut config, USAGE, rest, true)
|
||||
})();
|
||||
.collect());
|
||||
let rest = &args;
|
||||
cargo::call_main_without_stdin(execute, &mut config, USAGE, rest, true)
|
||||
})()
|
||||
};
|
||||
|
||||
match result {
|
||||
Err(e) => cargo::exit_with_error(e, &mut *config.shell()),
|
||||
@ -105,8 +117,8 @@ fn main() {
|
||||
|
||||
macro_rules! each_subcommand{
|
||||
($mac:ident) => {
|
||||
$mac!(bench);
|
||||
$mac!(build);
|
||||
// $mac!(bench);
|
||||
// $mac!(build);
|
||||
$mac!(check);
|
||||
$mac!(clean);
|
||||
$mac!(doc);
|
||||
|
66
src/bin/cli/bench.rs
Normal file
66
src/bin/cli/bench.rs
Normal file
@ -0,0 +1,66 @@
|
||||
use super::utils::*;
|
||||
|
||||
pub fn cli() -> App {
|
||||
subcommand("bench")
|
||||
.about("Execute all benchmarks of a local package")
|
||||
.arg(
|
||||
Arg::with_name("BENCHNAME").help(
|
||||
"If specified, only run benches containing this string in their names"
|
||||
)
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("args").help(
|
||||
"Arguments for the bench binary"
|
||||
).multiple(true).last(true)
|
||||
)
|
||||
|
||||
.arg_target(
|
||||
"Benchmark only this package's library",
|
||||
"Benchmark only the specified binary",
|
||||
"Benchmark all binaries",
|
||||
"Benchmark only the specified example",
|
||||
"Benchmark all examples",
|
||||
"Benchmark only the specified test target",
|
||||
"Benchmark all tests",
|
||||
"Benchmark only the specified bench target",
|
||||
"Benchmark all benches",
|
||||
"Benchmark all targets (default)",
|
||||
)
|
||||
|
||||
.arg(
|
||||
opt("no-run", "Compile, but don't run benchmarks")
|
||||
)
|
||||
.arg_package(
|
||||
"Package to run benchmarks for",
|
||||
"Benchmark all packages in the workspace",
|
||||
"Exclude packages from the benchmark",
|
||||
)
|
||||
.arg_jobs()
|
||||
.arg_features()
|
||||
.arg_target_triple()
|
||||
.arg_manifest_path()
|
||||
.arg_message_format()
|
||||
.arg(
|
||||
opt("no-fail-fast", "Run all benchmarks regardless of failure")
|
||||
)
|
||||
.arg_locked()
|
||||
.after_help("\
|
||||
All of the trailing arguments are passed to the benchmark binaries generated
|
||||
for filtering benchmarks and generally providing options configuring how they
|
||||
run.
|
||||
|
||||
If the --package argument is given, then SPEC is a package id specification
|
||||
which indicates which package should be benchmarked. If it is not given, then
|
||||
the current package is benchmarked. For more information on SPEC and its format,
|
||||
see the `cargo help pkgid` command.
|
||||
|
||||
All packages in the workspace are benchmarked if the `--all` flag is supplied. The
|
||||
`--all` flag is automatically assumed for a virtual manifest.
|
||||
Note that `--exclude` has to be specified in conjunction with the `--all` flag.
|
||||
|
||||
The --jobs argument affects the building of the benchmark executable but does
|
||||
not affect how many jobs are used when running the benchmarks.
|
||||
|
||||
Compilation can be customized with the `bench` profile in the manifest.
|
||||
")
|
||||
}
|
47
src/bin/cli/build.rs
Normal file
47
src/bin/cli/build.rs
Normal file
@ -0,0 +1,47 @@
|
||||
use super::utils::*;
|
||||
|
||||
pub fn cli() -> App {
|
||||
subcommand("build")
|
||||
.about("Compile a local package and all of its dependencies")
|
||||
.arg_package(
|
||||
"Package to build",
|
||||
"Build all packages in the workspace",
|
||||
"Exclude packages from the build",
|
||||
)
|
||||
.arg_jobs()
|
||||
.arg_target(
|
||||
"Build only this package's library",
|
||||
"Build only the specified binary",
|
||||
"Build all binaries",
|
||||
"Build only the specified example",
|
||||
"Build all examples",
|
||||
"Build only the specified test target",
|
||||
"Build all tests",
|
||||
"Build only the specified bench target",
|
||||
"Build all benches",
|
||||
"Build all targets (lib and bin targets by default)",
|
||||
)
|
||||
.arg(
|
||||
opt("release", "Build artifacts in release mode, with optimizations")
|
||||
)
|
||||
.arg_features()
|
||||
.arg_target_triple()
|
||||
.arg_manifest_path()
|
||||
.arg_message_format()
|
||||
.arg_locked()
|
||||
.after_help("\
|
||||
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
|
||||
current package is built. For more information on SPEC and its format, see the
|
||||
`cargo help pkgid` command.
|
||||
|
||||
All packages in the workspace are built if the `--all` flag is supplied. The
|
||||
`--all` flag is automatically assumed for a virtual manifest.
|
||||
Note that `--exclude` has to be specified in conjunction with the `--all` flag.
|
||||
|
||||
Compilation can be configured via the use of profiles which are configured in
|
||||
the manifest. The default profile for this command is `dev`, but passing
|
||||
the --release flag will use the `release` profile instead.
|
||||
")
|
||||
|
||||
}
|
319
src/bin/cli/mod.rs
Normal file
319
src/bin/cli/mod.rs
Normal file
@ -0,0 +1,319 @@
|
||||
extern crate clap;
|
||||
#[cfg(never)]
|
||||
extern crate cargo;
|
||||
|
||||
use cargo;
|
||||
|
||||
use clap::AppSettings;
|
||||
use clap::Arg;
|
||||
use clap::SubCommand;
|
||||
use clap::ArgMatches;
|
||||
use cargo::Config;
|
||||
use cargo::CargoResult;
|
||||
use cargo::core::Workspace;
|
||||
use cargo::util::important_paths::find_root_manifest_for_wd;
|
||||
use cargo::ops::Packages;
|
||||
use cargo::ops::CompileOptions;
|
||||
use cargo::ops;
|
||||
use std::slice;
|
||||
use cargo::ops::MessageFormat;
|
||||
use cargo::CliError;
|
||||
use cargo::ops::CompileMode;
|
||||
|
||||
|
||||
pub fn do_main(config: &mut Config) -> Result<(), CliError> {
|
||||
let args = cli().get_matches();
|
||||
if args.is_present("version") {
|
||||
let version = cargo::version();
|
||||
println!("{}", version);
|
||||
if args.occurrences_of("verbose") > 0 {
|
||||
println!("release: {}.{}.{}",
|
||||
version.major,
|
||||
version.minor,
|
||||
version.patch);
|
||||
if let Some(ref cfg) = version.cfg_info {
|
||||
if let Some(ref ci) = cfg.commit_info {
|
||||
println!("commit-hash: {}", ci.commit_hash);
|
||||
println!("commit-date: {}", ci.commit_date);
|
||||
}
|
||||
}
|
||||
}
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
fn values<'a>(args: &ArgMatches, name: &str) -> &'a [String] {
|
||||
let owned: Vec<String> = args.values_of(name).unwrap_or_default()
|
||||
.map(|s| s.to_string())
|
||||
.collect();
|
||||
let owned = owned.into_boxed_slice();
|
||||
let ptr = owned.as_ptr();
|
||||
let len = owned.len();
|
||||
::std::mem::forget(owned);
|
||||
unsafe {
|
||||
slice::from_raw_parts(ptr, len)
|
||||
}
|
||||
}
|
||||
|
||||
fn config_from_args(config: &mut Config, args: &ArgMatches) -> CargoResult<()> {
|
||||
let color = args.value_of("color").map(|s| s.to_string());
|
||||
config.configure(
|
||||
args.occurrences_of("verbose") as u32,
|
||||
if args.is_present("quite") { Some(true) } else { None },
|
||||
&color,
|
||||
args.is_present("frozen"),
|
||||
args.is_present("locked"),
|
||||
&args.values_of_lossy("unstable-features").unwrap_or_default(),
|
||||
)
|
||||
}
|
||||
|
||||
fn workspace_from_args<'a>(config: &'a Config, args: &ArgMatches) -> CargoResult<Workspace<'a>> {
|
||||
let manifest_path = args.value_of("manifest-path").map(|s| s.to_string());
|
||||
let root = find_root_manifest_for_wd(manifest_path, config.cwd())?;
|
||||
Workspace::new(&root, config)
|
||||
}
|
||||
|
||||
fn compile_options_from_args<'a>(
|
||||
config: &'a Config,
|
||||
args: &'a ArgMatches<'a>,
|
||||
mode: CompileMode,
|
||||
) -> CargoResult<CompileOptions<'a>> {
|
||||
let spec = Packages::from_flags(
|
||||
args.is_present("all"),
|
||||
&values(args, "exclude"),
|
||||
&values(args, "package")
|
||||
)?;
|
||||
|
||||
let release = mode == CompileMode::Bench || args.is_present("release");
|
||||
let message_format = match args.value_of("message-format") {
|
||||
Some("json") => MessageFormat::Json,
|
||||
Some("human") => MessageFormat::Human,
|
||||
f => panic!("Impossible message format: {:?}", f),
|
||||
};
|
||||
|
||||
let opts = CompileOptions {
|
||||
config,
|
||||
jobs: args.value_of("jobs").and_then(|v| v.parse().ok()),
|
||||
target: args.value_of("target"),
|
||||
features: &values(args, "features"),
|
||||
all_features: args.is_present("all-features"),
|
||||
no_default_features: args.is_present("no-default-features"),
|
||||
spec,
|
||||
mode,
|
||||
release,
|
||||
filter: ops::CompileFilter::new(args.is_present("lib"),
|
||||
values(args, "bin"), args.is_present("bins"),
|
||||
values(args, "test"), args.is_present("tests"),
|
||||
values(args, "example"), args.is_present("examples"),
|
||||
values(args, "bench"), args.is_present("benches"),
|
||||
args.is_present("all-targets")),
|
||||
message_format,
|
||||
target_rustdoc_args: None,
|
||||
target_rustc_args: None,
|
||||
};
|
||||
Ok(opts)
|
||||
}
|
||||
|
||||
match args.subcommand() {
|
||||
("bench", Some(args)) => {
|
||||
config_from_args(config, args)?;
|
||||
let ws = workspace_from_args(config, args)?;
|
||||
let compile_opts = compile_options_from_args(config, args, CompileMode::Bench)?;
|
||||
|
||||
let ops = ops::TestOptions {
|
||||
no_run: args.is_present("no-run"),
|
||||
no_fail_fast: args.is_present("no-fail-fast"),
|
||||
only_doc: false,
|
||||
compile_opts,
|
||||
};
|
||||
|
||||
let mut bench_args = vec![];
|
||||
bench_args.extend(args.value_of("BENCHNAME").into_iter().map(|s| s.to_string()));
|
||||
bench_args.extend(args.values_of("args").unwrap_or_default().map(|s| s.to_string()));
|
||||
|
||||
let err = ops::run_benches(&ws, &ops, &bench_args)?;
|
||||
return match err {
|
||||
None => Ok(()),
|
||||
Some(err) => {
|
||||
Err(match err.exit.as_ref().and_then(|e| e.code()) {
|
||||
Some(i) => CliError::new(format_err!("bench failed"), i),
|
||||
None => CliError::new(err.into(), 101)
|
||||
})
|
||||
}
|
||||
};
|
||||
}
|
||||
("build", Some(args)) => {
|
||||
config_from_args(config, args)?;
|
||||
let ws = workspace_from_args(config, args)?;
|
||||
let compile_opts = compile_options_from_args(config, args, CompileMode::Build)?;
|
||||
ops::compile(&ws, &compile_opts)?;
|
||||
return Ok(());
|
||||
}
|
||||
_ => return Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
use self::utils::*;
|
||||
|
||||
fn cli() -> App {
|
||||
let app = App::new("cargo")
|
||||
.settings(&[
|
||||
AppSettings::DisableVersion,
|
||||
AppSettings::UnifiedHelpMessage,
|
||||
AppSettings::DeriveDisplayOrder,
|
||||
AppSettings::VersionlessSubcommands,
|
||||
])
|
||||
.about("Rust's package manager")
|
||||
.arg(
|
||||
opt("version", "Print version info and exit")
|
||||
.short("V")
|
||||
)
|
||||
.arg(
|
||||
opt("list", "List installed commands")
|
||||
)
|
||||
.arg(
|
||||
opt("explain", "Run `rustc --explain CODE`")
|
||||
.value_name("CODE")
|
||||
)
|
||||
.arg(
|
||||
opt("verbose", "Use verbose output (-vv very verbose/build.rs output)")
|
||||
.short("v").multiple(true).global(true)
|
||||
)
|
||||
.arg(
|
||||
opt("quite", "No output printed to stdout")
|
||||
.short("q").global(true)
|
||||
)
|
||||
.arg(
|
||||
opt("color", "Coloring: auto, always, never")
|
||||
.value_name("WHEN").global(true)
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("unstable-features").help("Unstable (nightly-only) flags to Cargo")
|
||||
.short("Z").value_name("FLAG").multiple(true).global(true)
|
||||
)
|
||||
.after_help("\
|
||||
Some common cargo commands are (see all commands with --list):
|
||||
build Compile the current project
|
||||
check Analyze the current project and report errors, but don't build object files
|
||||
clean Remove the target directory
|
||||
doc Build this project's and its dependencies' documentation
|
||||
new Create a new cargo project
|
||||
init Create a new cargo project in an existing directory
|
||||
run Build and execute src/main.rs
|
||||
test Run the tests
|
||||
bench Run the benchmarks
|
||||
update Update dependencies listed in Cargo.lock
|
||||
search Search registry for crates
|
||||
publish Package and upload this project to the registry
|
||||
install Install a Rust binary
|
||||
uninstall Uninstall a Rust binary
|
||||
|
||||
See 'cargo help <command>' for more information on a specific command.
|
||||
")
|
||||
.subcommands(vec![
|
||||
bench::cli(),
|
||||
build::cli(),
|
||||
])
|
||||
;
|
||||
app
|
||||
}
|
||||
|
||||
mod utils {
|
||||
use clap::{self, SubCommand, AppSettings};
|
||||
pub use clap::Arg;
|
||||
|
||||
pub type App = clap::App<'static, 'static>;
|
||||
|
||||
pub trait CommonArgs: Sized {
|
||||
fn _arg(self, arg: Arg<'static, 'static>) -> Self;
|
||||
|
||||
fn arg_package(self, package: &'static str, all: &'static str, exclude: &'static str) -> Self {
|
||||
self._arg(opt("package", package).short("p").value_name("SPEC").multiple(true))
|
||||
._arg(opt("all", all))
|
||||
._arg(opt("exclude", exclude).value_name("SPEC").multiple(true))
|
||||
}
|
||||
|
||||
fn arg_jobs(self) -> Self {
|
||||
self._arg(
|
||||
opt("jobs", "Number of parallel jobs, defaults to # of CPUs")
|
||||
.short("j").value_name("N")
|
||||
)
|
||||
}
|
||||
|
||||
fn arg_target(
|
||||
self,
|
||||
lib: &'static str,
|
||||
bin: &'static str,
|
||||
bins: &'static str,
|
||||
examle: &'static str,
|
||||
examles: &'static str,
|
||||
test: &'static str,
|
||||
tests: &'static str,
|
||||
bench: &'static str,
|
||||
benchs: &'static str,
|
||||
all: &'static str,
|
||||
) -> Self {
|
||||
self._arg(opt("lib", lib))
|
||||
._arg(opt("bin", bin).value_name("NAME").multiple(true))
|
||||
._arg(opt("bins", bins))
|
||||
._arg(opt("example", examle).value_name("NAME").multiple(true))
|
||||
._arg(opt("examples", examles))
|
||||
._arg(opt("test", test).value_name("NAME").multiple(true))
|
||||
._arg(opt("tests", tests))
|
||||
._arg(opt("bench", bench).value_name("NAME").multiple(true))
|
||||
._arg(opt("benches", benchs))
|
||||
._arg(opt("all-targets", all))
|
||||
}
|
||||
|
||||
fn arg_features(self) -> Self {
|
||||
self._arg(
|
||||
opt("features", "Space-separated list of features to also build")
|
||||
.value_name("FEATURES")
|
||||
)
|
||||
._arg(opt("all-features", "Build all available features"))
|
||||
._arg(opt("no-default-features", "Do not build the `default` feature"))
|
||||
}
|
||||
|
||||
fn arg_target_triple(self) -> Self {
|
||||
self._arg(opt("target", "Build for the target triple").value_name("TRIPLE"))
|
||||
}
|
||||
|
||||
fn arg_manifest_path(self) -> Self {
|
||||
self._arg(opt("manifest-path", "Path to Cargo.toml").value_name("PATH"))
|
||||
}
|
||||
|
||||
fn arg_message_format(self) -> Self {
|
||||
self._arg(
|
||||
opt("message-format", "Error format")
|
||||
.value_name("FMT").possible_values(&["human", "json"]).default_value("human")
|
||||
)
|
||||
}
|
||||
|
||||
fn arg_locked(self) -> Self {
|
||||
self._arg(opt("frozen", "Require Cargo.lock and cache are up to date"))
|
||||
._arg(opt("locked", "Require Cargo.lock is up to date"))
|
||||
}
|
||||
}
|
||||
|
||||
impl CommonArgs for App {
|
||||
fn _arg(self, arg: Arg<'static, 'static>) -> Self {
|
||||
self.arg(arg)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn opt(name: &'static str, help: &'static str) -> Arg<'static, 'static> {
|
||||
Arg::with_name(name).long(name).help(help)
|
||||
}
|
||||
|
||||
pub fn subcommand(name: &'static str) -> App {
|
||||
SubCommand::with_name(name)
|
||||
.settings(&[
|
||||
AppSettings::UnifiedHelpMessage,
|
||||
AppSettings::DeriveDisplayOrder,
|
||||
AppSettings::TrailingVarArg,
|
||||
AppSettings::DontCollapseArgsInUsage,
|
||||
])
|
||||
}
|
||||
}
|
||||
|
||||
mod bench;
|
||||
mod build;
|
Loading…
x
Reference in New Issue
Block a user