From: Aleksey Kladov Date: Sat, 10 Mar 2018 13:23:05 +0000 (+0300) Subject: Reorganize subcommands as a separate submodule X-Git-Tag: archive/raspbian/0.35.0-2+rpi1~3^2^2^2^2^2^2^2~22^2~2^2~47^2~15 X-Git-Url: https://dgit.raspbian.org/?a=commitdiff_plain;h=66bb9dc3a46e7c4b7b0e8e92c39b995e910a84b5;p=cargo.git Reorganize subcommands as a separate submodule --- diff --git a/src/bin/cargo.rs b/src/bin/cargo.rs index b7aa9a412..83c0f78cf 100644 --- a/src/bin/cargo.rs +++ b/src/bin/cargo.rs @@ -20,6 +20,7 @@ use cargo::util::{CliError, ProcessError}; mod cli; mod command_prelude; +mod commands; fn main() { diff --git a/src/bin/cli.rs b/src/bin/cli.rs new file mode 100644 index 000000000..6894d3bb6 --- /dev/null +++ b/src/bin/cli.rs @@ -0,0 +1,664 @@ +extern crate clap; +#[cfg(never)] +extern crate cargo; + +use std::io::{self, Read, BufRead}; +use std::cmp::min; +use std::fs::File; +use std::collections::HashMap; +use std::process; + +use clap::{AppSettings, Arg, ArgMatches}; +use toml; + +use cargo::{self, Config, CargoError, CliResult, CliError}; +use cargo::core::{Source, SourceId, GitReference, Package}; +use cargo::util::{ToUrl, CargoResultExt}; +use cargo::ops::{self, CompileMode, OutputMetadataOptions}; +use cargo::sources::{GitSource, RegistrySource}; + +use std::collections::BTreeSet; +use std::env; +use std::fs; + +use search_directories; +use is_executable; +use command_prelude::*; +use commands; + +pub fn do_main(config: &mut Config) -> CliResult { + let args = cli().get_matches_safe()?; + let is_verbose = args.occurrences_of("verbose") > 0; + if args.is_present("version") { + let version = cargo::version(); + println!("{}", version); + if is_verbose { + 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(()); + } + + if let Some(ref code) = args.value_of("explain") { + let mut procss = config.rustc()?.process(); + procss.arg("--explain").arg(code).exec()?; + return Ok(()); + } + + if args.is_present("list") { + println!("Installed Commands:"); + for command in list_commands(config) { + let (command, path) = command; + if is_verbose { + match path { + Some(p) => println!(" {:<20} {}", command, p), + None => println!(" {:<20}", command), + } + } else { + println!(" {}", command); + } + } + return Ok(()); + } + + execute_subcommand(config, args) +} + +fn execute_subcommand(config: &mut Config, args: ArgMatches) -> CliResult { + config_from_args(config, &args)?; + + match args.subcommand() { + ("bench", Some(args)) => { + let ws = workspace_from_args(config, args)?; + let mut compile_opts = compile_options_from_args(config, args, CompileMode::Bench)?; + compile_opts.release = true; + + 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)?; + 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)) => { + let mut ws = workspace_from_args(config, args)?; + if config.cli_unstable().avoid_dev_deps { + ws.set_require_optional_deps(false); + } + let compile_opts = compile_options_from_args(config, args, CompileMode::Build)?; + ops::compile(&ws, &compile_opts)?; + Ok(()) + } + ("check", Some(args)) => { + let ws = workspace_from_args(config, args)?; + let test = match args.value_of("profile") { + Some("test") => true, + None => false, + Some(profile) => { + let err = format_err!("unknown profile: `{}`, only `test` is \ + currently supported", profile); + return Err(CliError::new(err, 101)); + } + }; + let mode = CompileMode::Check { test }; + let compile_opts = compile_options_from_args(config, args, mode)?; + ops::compile(&ws, &compile_opts)?; + Ok(()) + } + ("clean", Some(args)) => { + let ws = workspace_from_args(config, args)?; + let opts = ops::CleanOptions { + config, + spec: values(args, "package"), + target: args.value_of("target"), + release: args.is_present("release"), + }; + ops::clean(&ws, &opts)?; + Ok(()) + } + ("doc", Some(args)) => { + let ws = workspace_from_args(config, args)?; + let mode = ops::CompileMode::Doc { deps: !args.is_present("no-deps") }; + let compile_opts = compile_options_from_args(config, args, mode)?; + let doc_opts = ops::DocOptions { + open_result: args.is_present("open"), + compile_opts, + }; + ops::doc(&ws, &doc_opts)?; + Ok(()) + } + ("fetch", Some(args)) => { + let ws = workspace_from_args(config, args)?; + ops::fetch(&ws)?; + Ok(()) + } + ("generate-lockfile", Some(args)) => { + let ws = workspace_from_args(config, args)?; + ops::generate_lockfile(&ws)?; + Ok(()) + } + ("git-checkout", Some(args)) => { + let url = args.value_of("url").unwrap().to_url()?; + let reference = args.value_of("reference").unwrap(); + + let reference = GitReference::Branch(reference.to_string()); + let source_id = SourceId::for_git(&url, reference)?; + + let mut source = GitSource::new(&source_id, config)?; + + source.update()?; + + Ok(()) + } + ("init", Some(args)) => { + let path = args.value_of("path").unwrap_or("."); + let opts = new_opts_from_args(args, path)?; + ops::init(&opts, config)?; + config.shell().status("Created", format!("{} project", opts.kind))?; + Ok(()) + } + ("install", Some(args)) => { + let mut compile_opts = compile_options_from_args(config, args, CompileMode::Build)?; + compile_opts.release = !args.is_present("debug"); + + let krates = args.values_of("crate").unwrap_or_default().collect::>(); + + let source = if let Some(url) = args.value_of("git") { + let url = url.to_url()?; + let gitref = if let Some(branch) = args.value_of("branch") { + GitReference::Branch(branch.to_string()) + } else if let Some(tag) = args.value_of("tag") { + GitReference::Tag(tag.to_string()) + } else if let Some(rev) = args.value_of("rev") { + GitReference::Rev(rev.to_string()) + } else { + GitReference::Branch("master".to_string()) + }; + SourceId::for_git(&url, gitref)? + } else if let Some(path) = args.value_of("path") { + SourceId::for_path(&config.cwd().join(path))? + } else if krates.is_empty() { + SourceId::for_path(config.cwd())? + } else { + SourceId::crates_io(config)? + }; + + let version = args.value_of("version"); + let root = args.value_of("root"); + + if args.is_present("list") { + ops::install_list(root, config)?; + } else { + ops::install(root, krates, &source, version, &compile_opts, args.is_present("force"))?; + } + Ok(()) + } + ("locate-project", Some(args)) => { + let root = root_manifest_from_args(config, args)?; + + let root = root.to_str() + .ok_or_else(|| format_err!("your project path contains characters \ + not representable in Unicode")) + .map_err(|e| CliError::new(e, 1))? + .to_string(); + + #[derive(Serialize)] + pub struct ProjectLocation { + root: String + } + + let location = ProjectLocation { root }; + + cargo::print_json(&location); + Ok(()) + } + ("login", Some(args)) => { + let registry = registry_from_args(config, args)?; + + let token = match args.value_of("token") { + Some(token) => token.to_string(), + None => { + let host = match registry { + Some(ref _registry) => { + return Err(format_err!("token must be provided when \ + --registry is provided.").into()); + } + None => { + let src = SourceId::crates_io(config)?; + let mut src = RegistrySource::remote(&src, config); + src.update()?; + let config = src.config()?.unwrap(); + args.value_of("host").map(|s| s.to_string()) + .unwrap_or(config.api.unwrap()) + } + }; + println!("please visit {}me and paste the API Token below", host); + let mut line = String::new(); + let input = io::stdin(); + input.lock().read_line(&mut line).chain_err(|| { + "failed to read stdin" + }).map_err(CargoError::from)?; + line.trim().to_string() + } + }; + + ops::registry_login(config, token, registry)?; + Ok(()) + } + ("metadata", Some(args)) => { + let ws = workspace_from_args(config, args)?; + + let version = match args.value_of("format-version") { + None => { + config.shell().warn("\ + please specify `--format-version` flag explicitly \ + to avoid compatibility problems" + )?; + 1 + } + Some(version) => version.parse().unwrap(), + }; + + let options = OutputMetadataOptions { + features: values(args, "features"), + all_features: args.is_present("all-features"), + no_default_features: args.is_present("no-default-features"), + no_deps: args.is_present("no-deps"), + version, + }; + + let result = ops::output_metadata(&ws, &options)?; + cargo::print_json(&result); + Ok(()) + } + ("new", Some(args)) => { + let path = args.value_of("path").unwrap(); + let opts = new_opts_from_args(args, path)?; + ops::new(&opts, config)?; + config.shell().status("Created", format!("{} `{}` project", opts.kind, path))?; + Ok(()) + } + ("owner", Some(args)) => { + let registry = registry_from_args(config, args)?; + let opts = ops::OwnersOptions { + krate: args.value_of("crate").map(|s| s.to_string()), + token: args.value_of("token").map(|s| s.to_string()), + index: args.value_of("index").map(|s| s.to_string()), + to_add: args.values_of("add") + .map(|xs| xs.map(|s| s.to_string()).collect()), + to_remove: args.values_of("remove") + .map(|xs| xs.map(|s| s.to_string()).collect()), + list: args.is_present("list"), + registry, + }; + ops::modify_owners(config, &opts)?; + Ok(()) + } + ("package", Some(args)) => { + let ws = workspace_from_args(config, args)?; + ops::package(&ws, &ops::PackageOpts { + config, + verify: !args.is_present("no-verify"), + list: args.is_present("list"), + check_metadata: !args.is_present("no-metadata"), + allow_dirty: args.is_present("allow-dirty"), + target: args.value_of("target"), + jobs: jobs_from_args(args)?, + registry: None, + })?; + Ok(()) + } + ("pkgid", Some(args)) => { + let ws = workspace_from_args(config, args)?; + let spec = args.value_of("spec").or(args.value_of("package")); + let spec = ops::pkgid(&ws, spec)?; + println!("{}", spec); + Ok(()) + } + ("publish", Some(args)) => { + let registry = registry_from_args(config, args)?; + let ws = workspace_from_args(config, args)?; + let index = index_from_args(config, args)?; + + ops::publish(&ws, &ops::PublishOpts { + config, + token: args.value_of("token").map(|s| s.to_string()), + index, + verify: !args.is_present("no-verify"), + allow_dirty: args.is_present("allow-dirty"), + target: args.value_of("target"), + jobs: jobs_from_args(args)?, + dry_run: args.is_present("dry-run"), + registry, + })?; + Ok(()) + } + ("read-manifest", Some(args)) => { + let root = root_manifest_from_args(config, args)?; + let pkg = Package::for_path(&root, config)?; + cargo::print_json(&pkg); + Ok(()) + } + ("run", Some(args)) => { + let ws = workspace_from_args(config, args)?; + + let mut compile_opts = compile_options_from_args_for_single_package( + config, args, CompileMode::Build, + )?; + if !args.is_present("example") && !args.is_present("bin") { + compile_opts.filter = ops::CompileFilter::Default { + required_features_filterable: false, + }; + }; + match ops::run(&ws, &compile_opts, &values(args, "args"))? { + None => Ok(()), + Some(err) => { + // If we never actually spawned the process then that sounds pretty + // bad and we always want to forward that up. + let exit = match err.exit { + Some(exit) => exit, + None => return Err(CliError::new(err.into(), 101)), + }; + + // If `-q` was passed then we suppress extra error information about + // a failed process, we assume the process itself printed out enough + // information about why it failed so we don't do so as well + let exit_code = exit.code().unwrap_or(101); + Err(if args.is_present("quite") { + CliError::code(exit_code) + } else { + CliError::new(err.into(), exit_code) + }) + } + } + } + ("rustc", Some(args)) => { + let ws = workspace_from_args(config, args)?; + let mode = match args.value_of("profile") { + Some("dev") | None => CompileMode::Build, + Some("test") => CompileMode::Test, + Some("bench") => CompileMode::Bench, + Some("check") => CompileMode::Check { test: false }, + Some(mode) => { + let err = format_err!("unknown profile: `{}`, use dev, + test, or bench", mode); + return Err(CliError::new(err, 101)); + } + }; + let mut compile_opts = compile_options_from_args_for_single_package( + config, args, mode, + )?; + compile_opts.target_rustc_args = Some(values(args, "args")); + ops::compile(&ws, &compile_opts)?; + Ok(()) + } + ("rustdoc", Some(args)) => { + let ws = workspace_from_args(config, args)?; + let mut compile_opts = compile_options_from_args_for_single_package( + config, args, CompileMode::Doc { deps: false }, + )?; + compile_opts.target_rustdoc_args = Some(values(args, "args")); + let doc_opts = ops::DocOptions { + open_result: args.is_present("open"), + compile_opts, + }; + ops::doc(&ws, &doc_opts)?; + Ok(()) + } + ("search", Some(args)) => { + let registry = registry_from_args(config, args)?; + let index = index_from_args(config, args)?; + let limit: Option = args.value_of("limit") + .and_then(|v| v.parse().ok()); //FIXME: validation + let limit = min(100, limit.unwrap_or(10)); + let query: Vec<&str> = args.values_of("query").unwrap_or_default().collect(); + let query: String = query.join("+"); + ops::search(&query, config, index, limit, registry)?; + Ok(()) + } + ("test", Some(args)) => { + let ws = workspace_from_args(config, args)?; + + let mut compile_opts = compile_options_from_args(config, args, CompileMode::Test)?; + let doc = args.is_present("doc"); + if doc { + compile_opts.mode = ops::CompileMode::Doctest; + compile_opts.filter = ops::CompileFilter::new(true, + Vec::new(), false, + Vec::new(), false, + Vec::new(), false, + Vec::new(), false, + false); + } + + let ops = ops::TestOptions { + no_run: args.is_present("no-run"), + no_fail_fast: args.is_present("no-fail-fast"), + only_doc: doc, + compile_opts, + }; + + // TESTNAME is actually an argument of the test binary, but it's + // important so we explicitly mention it and reconfigure + let mut test_args = vec![]; + test_args.extend(args.value_of("TESTNAME").into_iter().map(|s| s.to_string())); + test_args.extend(args.values_of("args").unwrap_or_default().map(|s| s.to_string())); + + let err = ops::run_tests(&ws, &ops, &test_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!("{}", err.hint(&ws)), i), + None => CliError::new(err.into(), 101), + }) + } + }; + } + ("uninstall", Some(args)) => { + let root = args.value_of("root"); + let specs = args.values_of("spec").unwrap_or_default().collect(); + ops::uninstall(root, specs, &values(args, "bin"), config)?; + Ok(()) + } + ("update", Some(args)) => { + let ws = workspace_from_args(config, args)?; + + let update_opts = ops::UpdateOptions { + aggressive: args.is_present("aggressive"), + precise: args.value_of("precise"), + to_update: values(args, "package"), + config, + }; + ops::update_lockfile(&ws, &update_opts)?; + Ok(()) + } + ("verify-project", Some(args)) => { + fn fail(reason: &str, value: &str) -> ! { + let mut h = HashMap::new(); + h.insert(reason.to_string(), value.to_string()); + cargo::print_json(&h); + process::exit(1) + } + + let mut contents = String::new(); + let filename = match root_manifest_from_args(config, args) { + Ok(filename) => filename, + Err(e) => fail("invalid", &e.to_string()), + }; + + let file = File::open(&filename); + match file.and_then(|mut f| f.read_to_string(&mut contents)) { + Ok(_) => {} + Err(e) => fail("invalid", &format!("error reading file: {}", e)) + }; + if contents.parse::().is_err() { + fail("invalid", "invalid-format"); + } + + let mut h = HashMap::new(); + h.insert("success".to_string(), "true".to_string()); + cargo::print_json(&h); + Ok(()) + } + ("version", _) => { + println!("{}", cargo::version()); + Ok(()) + } + ("yank", Some(args)) => { + let registry = registry_from_args(config, args)?; + + ops::yank(config, + args.value_of("crate").map(|s| s.to_string()), + args.value_of("vers").map(|s| s.to_string()), + args.value_of("token").map(|s| s.to_string()), + args.value_of("index").map(|s| s.to_string()), + args.is_present("undo"), + registry)?; + Ok(()) + } + (cmd, Some(args)) => { + if let Some(mut alias) = super::aliased_command(config, cmd)? { + alias.extend(args.values_of("").unwrap_or_default().map(|s| s.to_string())); + let args = cli() + .setting(AppSettings::NoBinaryName) + .get_matches_from_safe(alias)?; + return execute_subcommand(config, args); + } + let mut ext_args: Vec<&str> = vec![cmd]; + ext_args.extend(args.values_of("").unwrap_or_default()); + super::execute_external_subcommand(config, cmd, &ext_args) + } + _ => Ok(()) + } +} + + +fn cli() -> App { + let app = App::new("cargo") + .settings(&[ + AppSettings::DisableVersion, + AppSettings::UnifiedHelpMessage, + AppSettings::DeriveDisplayOrder, + AppSettings::VersionlessSubcommands, + AppSettings::AllowExternalSubcommands, + ]) + .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( + opt("frozen", "Require Cargo.lock and cache are up to date") + .global(true) + ) + .arg( + opt("locked", "Require Cargo.lock is up to date") + .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 ' for more information on a specific command. +") + .subcommands(commands::builtin()) + ; + app +} + + +/// List all runnable commands +pub fn list_commands(config: &Config) -> BTreeSet<(String, Option)> { + let prefix = "cargo-"; + let suffix = env::consts::EXE_SUFFIX; + let mut commands = BTreeSet::new(); + for dir in search_directories(config) { + let entries = match fs::read_dir(dir) { + Ok(entries) => entries, + _ => continue, + }; + for entry in entries.filter_map(|e| e.ok()) { + let path = entry.path(); + let filename = match path.file_name().and_then(|s| s.to_str()) { + Some(filename) => filename, + _ => continue, + }; + if !filename.starts_with(prefix) || !filename.ends_with(suffix) { + continue; + } + if is_executable(entry.path()) { + let end = filename.len() - suffix.len(); + commands.insert( + (filename[prefix.len()..end].to_string(), + Some(path.display().to_string())) + ); + } + } + } + + for cmd in commands::builtin() { + commands.insert((cmd.get_name().to_string(), None)); + } + + commands +} diff --git a/src/bin/cli/bench.rs b/src/bin/cli/bench.rs deleted file mode 100644 index df43b7801..000000000 --- a/src/bin/cli/bench.rs +++ /dev/null @@ -1,67 +0,0 @@ -use command_prelude::*; -use clap::AppSettings; - -pub fn cli() -> App { - subcommand("bench") - .setting(AppSettings::TrailingVarArg) - .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_targets_all( - "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("Build for the target triple") - .arg_manifest_path() - .arg_message_format() - .arg( - opt("no-fail-fast", "Run all benchmarks regardless of failure") - ) - .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. -") -} diff --git a/src/bin/cli/build.rs b/src/bin/cli/build.rs deleted file mode 100644 index 9eddd651b..000000000 --- a/src/bin/cli/build.rs +++ /dev/null @@ -1,44 +0,0 @@ -use command_prelude::*; - -pub fn cli() -> App { - subcommand("build").alias("b") - .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_targets_all( - "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_release("Build artifacts in release mode, with optimizations") - .arg_features() - .arg_target_triple("Build for the target triple") - .arg_manifest_path() - .arg_message_format() - .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. -") - -} diff --git a/src/bin/cli/check.rs b/src/bin/cli/check.rs deleted file mode 100644 index ecf7fe6ce..000000000 --- a/src/bin/cli/check.rs +++ /dev/null @@ -1,50 +0,0 @@ -use command_prelude::*; - -pub fn cli() -> App { - subcommand("check") - .about("Check a local package and all of its dependencies for errors") - .arg_package( - "Package(s) to check", - "Check all packages in the workspace", - "Exclude packages from the check", - ) - .arg_jobs() - .arg_targets_all( - "Check only this package's library", - "Check only the specified binary", - "Check all binaries", - "Check only the specified example", - "Check all examples", - "Check only the specified test target", - "Check all tests", - "Check only the specified bench target", - "Check all benches", - "Check all targets (lib and bin targets by default)", - ) - .arg_release("Check artifacts in release mode, with optimizations") - .arg( - opt("profile", "Profile to build the selected target for") - .value_name("PROFILE") - ) - .arg_features() - .arg_target_triple("Check for the target triple") - .arg_manifest_path() - .arg_message_format() - .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 checked 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. - -The `--profile test` flag can be used to check unit tests with the -`#[cfg(test)]` attribute. -") -} diff --git a/src/bin/cli/clean.rs b/src/bin/cli/clean.rs deleted file mode 100644 index 7852c3c5c..000000000 --- a/src/bin/cli/clean.rs +++ /dev/null @@ -1,19 +0,0 @@ -use command_prelude::*; - -pub fn cli() -> App { - subcommand("clean") - .about("Remove artifacts that cargo has generated in the past") - .arg( - opt("package", "Package to clean artifacts for") - .short("p").value_name("SPEC").multiple(true) - ) - .arg_manifest_path() - .arg_target_triple("Target triple to clean output for (default all)") - .arg_release("Whether or not to clean release artifacts") - .after_help("\ -If the --package argument is given, then SPEC is a package id specification -which indicates which package's artifacts should be cleaned out. If it is not -given, then all packages' artifacts are removed. For more information on SPEC -and its format, see the `cargo help pkgid` command. -") -} diff --git a/src/bin/cli/doc.rs b/src/bin/cli/doc.rs deleted file mode 100644 index bcb709b29..000000000 --- a/src/bin/cli/doc.rs +++ /dev/null @@ -1,41 +0,0 @@ -use command_prelude::*; - -pub fn cli() -> App { - subcommand("doc") - .about("Build a package's documentation") - .arg( - opt("open", "Opens the docs in a browser after the operation") - ) - .arg_package( - "Package to document", - "Document all packages in the workspace", - "Exclude packages from the build", - ) - .arg( - opt("no-deps", "Don't build documentation for dependencies") - ) - .arg_jobs() - .arg_targets_lib_bin( - "Document only this package's library", - "Document only the specified binary", - "Document all binaries", - ) - .arg_release("Build artifacts in release mode, with optimizations") - .arg_features() - .arg_target_triple("Build for the target triple") - .arg_manifest_path() - .arg_message_format() - .after_help("\ -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. - -All packages in the workspace are documented 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. - -If the --package argument is given, then SPEC is a package id specification -which indicates which package should be documented. If it is not given, then the -current package is documented. For more information on SPEC and its format, see -the `cargo help pkgid` command. -") -} diff --git a/src/bin/cli/fetch.rs b/src/bin/cli/fetch.rs deleted file mode 100644 index bb4a946ab..000000000 --- a/src/bin/cli/fetch.rs +++ /dev/null @@ -1,17 +0,0 @@ -use command_prelude::*; - -pub fn cli() -> App { - subcommand("fetch") - .about("Fetch dependencies of a package from the network") - .arg_manifest_path() - .after_help("\ -If a lockfile is available, this command will ensure that all of the git -dependencies and/or registries dependencies are downloaded and locally -available. The network is never touched after a `cargo fetch` unless -the lockfile changes. - -If the lockfile is not available, then this is the equivalent of -`cargo generate-lockfile`. A lockfile is generated and dependencies are also -all updated. -") -} diff --git a/src/bin/cli/generate_lockfile.rs b/src/bin/cli/generate_lockfile.rs deleted file mode 100644 index 56ab283f4..000000000 --- a/src/bin/cli/generate_lockfile.rs +++ /dev/null @@ -1,17 +0,0 @@ -use command_prelude::*; - -pub fn cli() -> App { - subcommand("generate-lockfile") - .about("Generate the lockfile for a project") - .arg_manifest_path() - .after_help("\ -If a lockfile is available, this command will ensure that all of the git -dependencies and/or registries dependencies are downloaded and locally -available. The network is never touched after a `cargo fetch` unless -the lockfile changes. - -If the lockfile is not available, then this is the equivalent of -`cargo generate-lockfile`. A lockfile is generated and dependencies are also -all updated. -") -} diff --git a/src/bin/cli/git_checkout.rs b/src/bin/cli/git_checkout.rs deleted file mode 100644 index 4bbcba133..000000000 --- a/src/bin/cli/git_checkout.rs +++ /dev/null @@ -1,8 +0,0 @@ -use command_prelude::*; - -pub fn cli() -> App { - subcommand("git-checkout") - .about("Checkout a copy of a Git repository") - .arg(Arg::with_name("url").long("url").value_name("URL").required(true)) - .arg(Arg::with_name("reference").long("reference").value_name("REF").required(true)) -} diff --git a/src/bin/cli/init.rs b/src/bin/cli/init.rs deleted file mode 100644 index e9d618b43..000000000 --- a/src/bin/cli/init.rs +++ /dev/null @@ -1,8 +0,0 @@ -use command_prelude::*; - -pub fn cli() -> App { - subcommand("init") - .about("Create a new cargo package in an existing directory") - .arg(Arg::with_name("path")) - .arg_new_opts() -} diff --git a/src/bin/cli/install.rs b/src/bin/cli/install.rs deleted file mode 100644 index ce1834d9d..000000000 --- a/src/bin/cli/install.rs +++ /dev/null @@ -1,86 +0,0 @@ -use command_prelude::*; - -pub fn cli() -> App { - subcommand("install") - .about("Create a new cargo package in an existing directory") - .arg(Arg::with_name("crate").multiple(true)) - - .arg( - opt("version", "Specify a version to install from crates.io") - .alias("vers").value_name("VERSION") - ) - .arg( - opt("git", "Git URL to install the specified crate from") - .value_name("URL") - ) - .arg( - opt("branch", "Branch to use when installing from git") - .value_name("BRANCH") - ) - .arg( - opt("tag", "Tag to use when installing from git") - .value_name("TAG") - ) - .arg( - opt("rev", "Specific commit to use when installing from git") - .value_name("SHA") - ) - .arg( - opt("path", "Filesystem path to local crate to install") - .value_name("PATH") - ) - - .arg(opt("list", "list all installed packages and their versions")) - - .arg_jobs() - .arg( - opt("force", "Force overwriting existing crates or binaries") - .short("f") - ) - .arg_features() - .arg(opt("debug", "Build in debug mode instead of release mode")) - .arg_targets_bins_examples( - "Install only the specified binary", - "Install all binaries", - "Install only the specified example", - "Install all examples", - ) - .arg( - opt("root", "Directory to install packages into") - .value_name("DIR") - ) - .after_help("\ -This command manages Cargo's local set of installed binary crates. Only packages -which have [[bin]] targets can be installed, and all binaries are installed into -the installation root's `bin` folder. The installation root is determined, in -order of precedence, by `--root`, `$CARGO_INSTALL_ROOT`, the `install.root` -configuration key, and finally the home directory (which is either -`$CARGO_HOME` if set or `$HOME/.cargo` by default). - -There are multiple sources from which a crate can be installed. The default -location is crates.io but the `--git` and `--path` flags can change this source. -If the source contains more than one package (such as crates.io or a git -repository with multiple crates) the `` argument is required to indicate -which crate should be installed. - -Crates from crates.io can optionally specify the version they wish to install -via the `--vers` flags, and similarly packages from git repositories can -optionally specify the branch, tag, or revision that should be installed. If a -crate has multiple binaries, the `--bin` argument can selectively install only -one of them, and if you'd rather install examples the `--example` argument can -be used as well. - -By default cargo will refuse to overwrite existing binaries. The `--force` flag -enables overwriting existing binaries. Thus you can reinstall a crate with -`cargo install --force `. - -As a special convenience, omitting the specification entirely will -install the crate in the current directory. That is, `install` is equivalent to -the more explicit `install --path .`. - -If the source is crates.io or `--git` then by default the crate will be built -in a temporary target directory. To avoid this, the target directory can be -specified by setting the `CARGO_TARGET_DIR` environment variable to a relative -path. In particular, this can be useful for caching build artifacts on -continuous integration systems.") -} diff --git a/src/bin/cli/locate_project.rs b/src/bin/cli/locate_project.rs deleted file mode 100644 index 1bddac4c2..000000000 --- a/src/bin/cli/locate_project.rs +++ /dev/null @@ -1,7 +0,0 @@ -use command_prelude::*; - -pub fn cli() -> App { - subcommand("locate-project") - .about("Checkout a copy of a Git repository") - .arg_manifest_path() -} diff --git a/src/bin/cli/login.rs b/src/bin/cli/login.rs deleted file mode 100644 index 045770181..000000000 --- a/src/bin/cli/login.rs +++ /dev/null @@ -1,10 +0,0 @@ -use command_prelude::*; - -pub fn cli() -> App { - subcommand("login") - .about("Save an api token from the registry locally. \ - If token is not specified, it will be read from stdin.") - .arg(Arg::with_name("token")) - .arg(opt("host", "Host to set the token for").value_name("HOST")) - .arg(opt("registry", "Registry to use").value_name("REGISTRY")) -} diff --git a/src/bin/cli/metadata.rs b/src/bin/cli/metadata.rs deleted file mode 100644 index 7f4904c14..000000000 --- a/src/bin/cli/metadata.rs +++ /dev/null @@ -1,18 +0,0 @@ -use command_prelude::*; - -pub fn cli() -> App { - subcommand("metadata") - .about("Output the resolved dependencies of a project, \ - the concrete used versions including overrides, \ - in machine-readable format") - .arg_features() - .arg( - opt("no-deps", "Output information only about the root package \ - and don't fetch dependencies") - ) - .arg_manifest_path() - .arg( - opt("format-version", "Format version") - .value_name("VERSION").possible_value("1") - ) -} diff --git a/src/bin/cli/mod.rs b/src/bin/cli/mod.rs deleted file mode 100644 index 8fb63d35f..000000000 --- a/src/bin/cli/mod.rs +++ /dev/null @@ -1,730 +0,0 @@ -extern crate clap; -#[cfg(never)] -extern crate cargo; - -use std::io::{self, Read, BufRead}; -use std::cmp::min; -use std::fs::File; -use std::collections::HashMap; -use std::process; - -use clap::{AppSettings, Arg, ArgMatches}; -use toml; - -use cargo::{self, Config, CargoError, CliResult, CliError}; -use cargo::core::{Source, SourceId, GitReference, Package}; -use cargo::util::{ToUrl, CargoResultExt}; -use cargo::ops::{self, CompileMode, OutputMetadataOptions}; -use cargo::sources::{GitSource, RegistrySource}; - -use std::collections::BTreeSet; -use std::env; -use std::fs; - -use search_directories; -use is_executable; -use command_prelude::*; - -pub fn do_main(config: &mut Config) -> CliResult { - let args = cli().get_matches_safe()?; - let is_verbose = args.occurrences_of("verbose") > 0; - if args.is_present("version") { - let version = cargo::version(); - println!("{}", version); - if is_verbose { - 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(()); - } - - if let Some(ref code) = args.value_of("explain") { - let mut procss = config.rustc()?.process(); - procss.arg("--explain").arg(code).exec()?; - return Ok(()); - } - - if args.is_present("list") { - println!("Installed Commands:"); - for command in list_commands(config) { - let (command, path) = command; - if is_verbose { - match path { - Some(p) => println!(" {:<20} {}", command, p), - None => println!(" {:<20}", command), - } - } else { - println!(" {}", command); - } - } - return Ok(()); - } - - execute_subcommand(config, args) -} - -fn execute_subcommand(config: &mut Config, args: ArgMatches) -> CliResult { - config_from_args(config, &args)?; - - match args.subcommand() { - ("bench", Some(args)) => { - let ws = workspace_from_args(config, args)?; - let mut compile_opts = compile_options_from_args(config, args, CompileMode::Bench)?; - compile_opts.release = true; - - 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)?; - 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)) => { - let mut ws = workspace_from_args(config, args)?; - if config.cli_unstable().avoid_dev_deps { - ws.set_require_optional_deps(false); - } - let compile_opts = compile_options_from_args(config, args, CompileMode::Build)?; - ops::compile(&ws, &compile_opts)?; - Ok(()) - } - ("check", Some(args)) => { - let ws = workspace_from_args(config, args)?; - let test = match args.value_of("profile") { - Some("test") => true, - None => false, - Some(profile) => { - let err = format_err!("unknown profile: `{}`, only `test` is \ - currently supported", profile); - return Err(CliError::new(err, 101)); - } - }; - let mode = CompileMode::Check { test }; - let compile_opts = compile_options_from_args(config, args, mode)?; - ops::compile(&ws, &compile_opts)?; - Ok(()) - } - ("clean", Some(args)) => { - let ws = workspace_from_args(config, args)?; - let opts = ops::CleanOptions { - config, - spec: values(args, "package"), - target: args.value_of("target"), - release: args.is_present("release"), - }; - ops::clean(&ws, &opts)?; - Ok(()) - } - ("doc", Some(args)) => { - let ws = workspace_from_args(config, args)?; - let mode = ops::CompileMode::Doc { deps: !args.is_present("no-deps") }; - let compile_opts = compile_options_from_args(config, args, mode)?; - let doc_opts = ops::DocOptions { - open_result: args.is_present("open"), - compile_opts, - }; - ops::doc(&ws, &doc_opts)?; - Ok(()) - } - ("fetch", Some(args)) => { - let ws = workspace_from_args(config, args)?; - ops::fetch(&ws)?; - Ok(()) - } - ("generate-lockfile", Some(args)) => { - let ws = workspace_from_args(config, args)?; - ops::generate_lockfile(&ws)?; - Ok(()) - } - ("git-checkout", Some(args)) => { - let url = args.value_of("url").unwrap().to_url()?; - let reference = args.value_of("reference").unwrap(); - - let reference = GitReference::Branch(reference.to_string()); - let source_id = SourceId::for_git(&url, reference)?; - - let mut source = GitSource::new(&source_id, config)?; - - source.update()?; - - Ok(()) - } - ("init", Some(args)) => { - let path = args.value_of("path").unwrap_or("."); - let opts = new_opts_from_args(args, path)?; - ops::init(&opts, config)?; - config.shell().status("Created", format!("{} project", opts.kind))?; - Ok(()) - } - ("install", Some(args)) => { - let mut compile_opts = compile_options_from_args(config, args, CompileMode::Build)?; - compile_opts.release = !args.is_present("debug"); - - let krates = args.values_of("crate").unwrap_or_default().collect::>(); - - let source = if let Some(url) = args.value_of("git") { - let url = url.to_url()?; - let gitref = if let Some(branch) = args.value_of("branch") { - GitReference::Branch(branch.to_string()) - } else if let Some(tag) = args.value_of("tag") { - GitReference::Tag(tag.to_string()) - } else if let Some(rev) = args.value_of("rev") { - GitReference::Rev(rev.to_string()) - } else { - GitReference::Branch("master".to_string()) - }; - SourceId::for_git(&url, gitref)? - } else if let Some(path) = args.value_of("path") { - SourceId::for_path(&config.cwd().join(path))? - } else if krates.is_empty() { - SourceId::for_path(config.cwd())? - } else { - SourceId::crates_io(config)? - }; - - let version = args.value_of("version"); - let root = args.value_of("root"); - - if args.is_present("list") { - ops::install_list(root, config)?; - } else { - ops::install(root, krates, &source, version, &compile_opts, args.is_present("force"))?; - } - Ok(()) - } - ("locate-project", Some(args)) => { - let root = root_manifest_from_args(config, args)?; - - let root = root.to_str() - .ok_or_else(|| format_err!("your project path contains characters \ - not representable in Unicode")) - .map_err(|e| CliError::new(e, 1))? - .to_string(); - - #[derive(Serialize)] - pub struct ProjectLocation { - root: String - } - - let location = ProjectLocation { root }; - - cargo::print_json(&location); - Ok(()) - } - ("login", Some(args)) => { - let registry = registry_from_args(config, args)?; - - let token = match args.value_of("token") { - Some(token) => token.to_string(), - None => { - let host = match registry { - Some(ref _registry) => { - return Err(format_err!("token must be provided when \ - --registry is provided.").into()); - } - None => { - let src = SourceId::crates_io(config)?; - let mut src = RegistrySource::remote(&src, config); - src.update()?; - let config = src.config()?.unwrap(); - args.value_of("host").map(|s| s.to_string()) - .unwrap_or(config.api.unwrap()) - } - }; - println!("please visit {}me and paste the API Token below", host); - let mut line = String::new(); - let input = io::stdin(); - input.lock().read_line(&mut line).chain_err(|| { - "failed to read stdin" - }).map_err(CargoError::from)?; - line.trim().to_string() - } - }; - - ops::registry_login(config, token, registry)?; - Ok(()) - } - ("metadata", Some(args)) => { - let ws = workspace_from_args(config, args)?; - - let version = match args.value_of("format-version") { - None => { - config.shell().warn("\ - please specify `--format-version` flag explicitly \ - to avoid compatibility problems" - )?; - 1 - } - Some(version) => version.parse().unwrap(), - }; - - let options = OutputMetadataOptions { - features: values(args, "features"), - all_features: args.is_present("all-features"), - no_default_features: args.is_present("no-default-features"), - no_deps: args.is_present("no-deps"), - version, - }; - - let result = ops::output_metadata(&ws, &options)?; - cargo::print_json(&result); - Ok(()) - } - ("new", Some(args)) => { - let path = args.value_of("path").unwrap(); - let opts = new_opts_from_args(args, path)?; - ops::new(&opts, config)?; - config.shell().status("Created", format!("{} `{}` project", opts.kind, path))?; - Ok(()) - } - ("owner", Some(args)) => { - let registry = registry_from_args(config, args)?; - let opts = ops::OwnersOptions { - krate: args.value_of("crate").map(|s| s.to_string()), - token: args.value_of("token").map(|s| s.to_string()), - index: args.value_of("index").map(|s| s.to_string()), - to_add: args.values_of("add") - .map(|xs| xs.map(|s| s.to_string()).collect()), - to_remove: args.values_of("remove") - .map(|xs| xs.map(|s| s.to_string()).collect()), - list: args.is_present("list"), - registry, - }; - ops::modify_owners(config, &opts)?; - Ok(()) - } - ("package", Some(args)) => { - let ws = workspace_from_args(config, args)?; - ops::package(&ws, &ops::PackageOpts { - config, - verify: !args.is_present("no-verify"), - list: args.is_present("list"), - check_metadata: !args.is_present("no-metadata"), - allow_dirty: args.is_present("allow-dirty"), - target: args.value_of("target"), - jobs: jobs_from_args(args)?, - registry: None, - })?; - Ok(()) - } - ("pkgid", Some(args)) => { - let ws = workspace_from_args(config, args)?; - let spec = args.value_of("spec").or(args.value_of("package")); - let spec = ops::pkgid(&ws, spec)?; - println!("{}", spec); - Ok(()) - } - ("publish", Some(args)) => { - let registry = registry_from_args(config, args)?; - let ws = workspace_from_args(config, args)?; - let index = index_from_args(config, args)?; - - ops::publish(&ws, &ops::PublishOpts { - config, - token: args.value_of("token").map(|s| s.to_string()), - index, - verify: !args.is_present("no-verify"), - allow_dirty: args.is_present("allow-dirty"), - target: args.value_of("target"), - jobs: jobs_from_args(args)?, - dry_run: args.is_present("dry-run"), - registry, - })?; - Ok(()) - } - ("read-manifest", Some(args)) => { - let root = root_manifest_from_args(config, args)?; - let pkg = Package::for_path(&root, config)?; - cargo::print_json(&pkg); - Ok(()) - } - ("run", Some(args)) => { - let ws = workspace_from_args(config, args)?; - - let mut compile_opts = compile_options_from_args_for_single_package( - config, args, CompileMode::Build, - )?; - if !args.is_present("example") && !args.is_present("bin") { - compile_opts.filter = ops::CompileFilter::Default { - required_features_filterable: false, - }; - }; - match ops::run(&ws, &compile_opts, &values(args, "args"))? { - None => Ok(()), - Some(err) => { - // If we never actually spawned the process then that sounds pretty - // bad and we always want to forward that up. - let exit = match err.exit { - Some(exit) => exit, - None => return Err(CliError::new(err.into(), 101)), - }; - - // If `-q` was passed then we suppress extra error information about - // a failed process, we assume the process itself printed out enough - // information about why it failed so we don't do so as well - let exit_code = exit.code().unwrap_or(101); - Err(if args.is_present("quite") { - CliError::code(exit_code) - } else { - CliError::new(err.into(), exit_code) - }) - } - } - } - ("rustc", Some(args)) => { - let ws = workspace_from_args(config, args)?; - let mode = match args.value_of("profile") { - Some("dev") | None => CompileMode::Build, - Some("test") => CompileMode::Test, - Some("bench") => CompileMode::Bench, - Some("check") => CompileMode::Check { test: false }, - Some(mode) => { - let err = format_err!("unknown profile: `{}`, use dev, - test, or bench", mode); - return Err(CliError::new(err, 101)); - } - }; - let mut compile_opts = compile_options_from_args_for_single_package( - config, args, mode, - )?; - compile_opts.target_rustc_args = Some(values(args, "args")); - ops::compile(&ws, &compile_opts)?; - Ok(()) - } - ("rustdoc", Some(args)) => { - let ws = workspace_from_args(config, args)?; - let mut compile_opts = compile_options_from_args_for_single_package( - config, args, CompileMode::Doc { deps: false }, - )?; - compile_opts.target_rustdoc_args = Some(values(args, "args")); - let doc_opts = ops::DocOptions { - open_result: args.is_present("open"), - compile_opts, - }; - ops::doc(&ws, &doc_opts)?; - Ok(()) - } - ("search", Some(args)) => { - let registry = registry_from_args(config, args)?; - let index = index_from_args(config, args)?; - let limit: Option = args.value_of("limit") - .and_then(|v| v.parse().ok()); //FIXME: validation - let limit = min(100, limit.unwrap_or(10)); - let query: Vec<&str> = args.values_of("query").unwrap_or_default().collect(); - let query: String = query.join("+"); - ops::search(&query, config, index, limit, registry)?; - Ok(()) - } - ("test", Some(args)) => { - let ws = workspace_from_args(config, args)?; - - let mut compile_opts = compile_options_from_args(config, args, CompileMode::Test)?; - let doc = args.is_present("doc"); - if doc { - compile_opts.mode = ops::CompileMode::Doctest; - compile_opts.filter = ops::CompileFilter::new(true, - Vec::new(), false, - Vec::new(), false, - Vec::new(), false, - Vec::new(), false, - false); - } - - let ops = ops::TestOptions { - no_run: args.is_present("no-run"), - no_fail_fast: args.is_present("no-fail-fast"), - only_doc: doc, - compile_opts, - }; - - // TESTNAME is actually an argument of the test binary, but it's - // important so we explicitly mention it and reconfigure - let mut test_args = vec![]; - test_args.extend(args.value_of("TESTNAME").into_iter().map(|s| s.to_string())); - test_args.extend(args.values_of("args").unwrap_or_default().map(|s| s.to_string())); - - let err = ops::run_tests(&ws, &ops, &test_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!("{}", err.hint(&ws)), i), - None => CliError::new(err.into(), 101), - }) - } - }; - } - ("uninstall", Some(args)) => { - let root = args.value_of("root"); - let specs = args.values_of("spec").unwrap_or_default().collect(); - ops::uninstall(root, specs, &values(args, "bin"), config)?; - Ok(()) - } - ("update", Some(args)) => { - let ws = workspace_from_args(config, args)?; - - let update_opts = ops::UpdateOptions { - aggressive: args.is_present("aggressive"), - precise: args.value_of("precise"), - to_update: values(args, "package"), - config, - }; - ops::update_lockfile(&ws, &update_opts)?; - Ok(()) - } - ("verify-project", Some(args)) => { - fn fail(reason: &str, value: &str) -> ! { - let mut h = HashMap::new(); - h.insert(reason.to_string(), value.to_string()); - cargo::print_json(&h); - process::exit(1) - } - - let mut contents = String::new(); - let filename = match root_manifest_from_args(config, args) { - Ok(filename) => filename, - Err(e) => fail("invalid", &e.to_string()), - }; - - let file = File::open(&filename); - match file.and_then(|mut f| f.read_to_string(&mut contents)) { - Ok(_) => {} - Err(e) => fail("invalid", &format!("error reading file: {}", e)) - }; - if contents.parse::().is_err() { - fail("invalid", "invalid-format"); - } - - let mut h = HashMap::new(); - h.insert("success".to_string(), "true".to_string()); - cargo::print_json(&h); - Ok(()) - } - ("version", _) => { - println!("{}", cargo::version()); - Ok(()) - } - ("yank", Some(args)) => { - let registry = registry_from_args(config, args)?; - - ops::yank(config, - args.value_of("crate").map(|s| s.to_string()), - args.value_of("vers").map(|s| s.to_string()), - args.value_of("token").map(|s| s.to_string()), - args.value_of("index").map(|s| s.to_string()), - args.is_present("undo"), - registry)?; - Ok(()) - } - (cmd, Some(args)) => { - if let Some(mut alias) = super::aliased_command(config, cmd)? { - alias.extend(args.values_of("").unwrap_or_default().map(|s| s.to_string())); - let args = cli() - .setting(AppSettings::NoBinaryName) - .get_matches_from_safe(alias)?; - return execute_subcommand(config, args); - } - let mut ext_args: Vec<&str> = vec![cmd]; - ext_args.extend(args.values_of("").unwrap_or_default()); - super::execute_external_subcommand(config, cmd, &ext_args) - } - _ => Ok(()) - } -} - - -fn cli() -> App { - let app = App::new("cargo") - .settings(&[ - AppSettings::DisableVersion, - AppSettings::UnifiedHelpMessage, - AppSettings::DeriveDisplayOrder, - AppSettings::VersionlessSubcommands, - AppSettings::AllowExternalSubcommands, - ]) - .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( - opt("frozen", "Require Cargo.lock and cache are up to date") - .global(true) - ) - .arg( - opt("locked", "Require Cargo.lock is up to date") - .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 ' for more information on a specific command. -") - .subcommands(builtin_subcommands()) - ; - app -} - -fn builtin_subcommands() -> Vec { - vec![ - bench::cli(), - build::cli(), - check::cli(), - clean::cli(), - doc::cli(), - fetch::cli(), - generate_lockfile::cli(), - git_checkout::cli(), - init::cli(), - install::cli(), - locate_project::cli(), - login::cli(), - metadata::cli(), - new::cli(), - owner::cli(), - package::cli(), - pkgid::cli(), - publish::cli(), - read_manifest::cli(), - run::cli(), - rustc::cli(), - rustdoc::cli(), - search::cli(), - test::cli(), - uninstall::cli(), - update::cli(), - verify_project::cli(), - version::cli(), - yank::cli(), - ] -} - -/// List all runnable commands -pub fn list_commands(config: &Config) -> BTreeSet<(String, Option)> { - let prefix = "cargo-"; - let suffix = env::consts::EXE_SUFFIX; - let mut commands = BTreeSet::new(); - for dir in search_directories(config) { - let entries = match fs::read_dir(dir) { - Ok(entries) => entries, - _ => continue, - }; - for entry in entries.filter_map(|e| e.ok()) { - let path = entry.path(); - let filename = match path.file_name().and_then(|s| s.to_str()) { - Some(filename) => filename, - _ => continue, - }; - if !filename.starts_with(prefix) || !filename.ends_with(suffix) { - continue; - } - if is_executable(entry.path()) { - let end = filename.len() - suffix.len(); - commands.insert( - (filename[prefix.len()..end].to_string(), - Some(path.display().to_string())) - ); - } - } - } - - for cmd in builtin_subcommands() { - commands.insert((cmd.get_name().to_string(), None)); - } - - commands -} - - -mod bench; -mod build; -mod check; -mod clean; -mod doc; -mod fetch; -mod generate_lockfile; - -// FIXME: let's just drop this subcommand? -mod git_checkout; - -mod init; -mod install; -mod locate_project; -mod login; -mod metadata; -mod new; -mod owner; -mod package; -mod pkgid; -mod publish; -mod read_manifest; -mod run; -mod rustc; -mod rustdoc; -mod search; -mod test; -mod uninstall; -mod update; -mod verify_project; -mod version; -mod yank; diff --git a/src/bin/cli/new.rs b/src/bin/cli/new.rs deleted file mode 100644 index eb03e37d5..000000000 --- a/src/bin/cli/new.rs +++ /dev/null @@ -1,8 +0,0 @@ -use command_prelude::*; - -pub fn cli() -> App { - subcommand("new") - .about("Create a new cargo package at ") - .arg(Arg::with_name("path").required(true)) - .arg_new_opts() -} diff --git a/src/bin/cli/owner.rs b/src/bin/cli/owner.rs deleted file mode 100644 index dd7c5adf1..000000000 --- a/src/bin/cli/owner.rs +++ /dev/null @@ -1,28 +0,0 @@ -use command_prelude::*; - -pub fn cli() -> App { - subcommand("owner") - .about("Manage the owners of a crate on the registry") - .arg(Arg::with_name("crate")) - .arg( - opt("add", "Name of a user or team to add as an owner") - .short("a").value_name("LOGIN").multiple(true) - ) - .arg( - opt("remove", "Name of a user or team to remove as an owner") - .short("r").value_name("LOGIN").multiple(true) - ) - .arg(opt("list", "List owners of a crate").short("l")) - .arg(opt("index", "Registry index to modify owners for").value_name("INDEX")) - .arg(opt("token", "API token to use when authenticating").value_name("TOKEN")) - .arg(opt("registry", "Registry to use").value_name("REGISTRY")) - .after_help("\ - This command will modify the owners for a package - on the specified registry(or - default).Note that owners of a package can upload new versions, yank old - versions.Explicitly named owners can also modify the set of owners, so take - caution! - - See http://doc.crates.io/crates-io.html#cargo-owner for detailed documentation - and troubleshooting.") -} diff --git a/src/bin/cli/package.rs b/src/bin/cli/package.rs deleted file mode 100644 index 59ba384b7..000000000 --- a/src/bin/cli/package.rs +++ /dev/null @@ -1,13 +0,0 @@ -use command_prelude::*; - -pub fn cli() -> App { - subcommand("package") - .about("Assemble the local package into a distributable tarball") - .arg(opt("list", "Print files included in a package without making one").short("l")) - .arg(opt("no-verify", "Don't verify the contents by building them")) - .arg(opt("no-metadata", "Ignore warnings about a lack of human-usable metadata")) - .arg(opt("allow-dirty", "Allow dirty working directories to be packaged")) - .arg_target_triple("Build for the target triple") - .arg_manifest_path() - .arg_jobs() -} diff --git a/src/bin/cli/pkgid.rs b/src/bin/cli/pkgid.rs deleted file mode 100644 index 26335735a..000000000 --- a/src/bin/cli/pkgid.rs +++ /dev/null @@ -1,29 +0,0 @@ -use command_prelude::*; - -pub fn cli() -> App { - subcommand("pkgid") - .about("Print a fully qualified package specification") - .arg(Arg::with_name("spec")) - .arg_single_package("Argument to get the package id specifier for") - .arg_manifest_path() - .after_help("\ -Given a argument, print out the fully qualified package id specifier. -This command will generate an error if is ambiguous as to which package -it refers to in the dependency graph. If no is given, then the pkgid for -the local package is printed. - -This command requires that a lockfile is available and dependencies have been -fetched. - -Example Package IDs - - pkgid | name | version | url - |-----------------------------|--------|-----------|---------------------| - foo | foo | * | * - foo:1.2.3 | foo | 1.2.3 | * - crates.io/foo | foo | * | *://crates.io/foo - crates.io/foo#1.2.3 | foo | 1.2.3 | *://crates.io/foo - crates.io/bar#foo:1.2.3 | foo | 1.2.3 | *://crates.io/bar - http://crates.io/foo#1.2.3 | foo | 1.2.3 | http://crates.io/foo -") -} diff --git a/src/bin/cli/publish.rs b/src/bin/cli/publish.rs deleted file mode 100644 index fc4ead218..000000000 --- a/src/bin/cli/publish.rs +++ /dev/null @@ -1,17 +0,0 @@ -use command_prelude::*; - -pub fn cli() -> App { - subcommand("publish") - .about("Upload a package to the registry") - .arg_index() - .arg(opt("token", "Token to use when uploading").value_name("TOKEN")) - .arg(opt("no-verify", "Don't verify the contents by building them")) - .arg(opt("allow-dirty", "Allow dirty working directories to be packaged")) - .arg_target_triple("Build for the target triple") - .arg_manifest_path() - .arg_jobs() - .arg( - opt("dry-run", "Perform all checks without uploading") - ) - .arg(opt("registry", "Registry to publish to").value_name("REGISTRY")) -} diff --git a/src/bin/cli/read_manifest.rs b/src/bin/cli/read_manifest.rs deleted file mode 100644 index ec6ffec83..000000000 --- a/src/bin/cli/read_manifest.rs +++ /dev/null @@ -1,8 +0,0 @@ -use command_prelude::*; - -pub fn cli() -> App { - subcommand("read-manifest") - .about("Deprecated, use `cargo metadata --no-deps` instead. -Print a JSON representation of a Cargo.toml manifest.") - .arg_manifest_path() -} diff --git a/src/bin/cli/run.rs b/src/bin/cli/run.rs deleted file mode 100644 index dae6c9de2..000000000 --- a/src/bin/cli/run.rs +++ /dev/null @@ -1,31 +0,0 @@ -use clap::AppSettings; - -use command_prelude::*; - -pub fn cli() -> App { - subcommand("run").alias("r") - .setting(AppSettings::TrailingVarArg) - .about("Run the main binary of the local package (src/main.rs)") - .arg(Arg::with_name("args").multiple(true)) - .arg_targets_bin_example( - "Name of the bin target to run", - "Name of the example target to run", - ) - .arg_single_package("Package with the target to run") - .arg_jobs() - .arg_release("Build artifacts in release mode, with optimizations") - .arg_features() - .arg_target_triple("Build for the target triple") - .arg_manifest_path() - .arg_message_format() - .after_help("\ -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, -and `--example` specifies the example target to run. At most one of `--bin` or -`--example` can be provided. - -All of the trailing arguments are passed to the binary to run. If you're passing -arguments to both Cargo and the binary, the ones after `--` go to the binary, -the ones before go to Cargo. -") -} diff --git a/src/bin/cli/rustc.rs b/src/bin/cli/rustc.rs deleted file mode 100644 index 8074a551e..000000000 --- a/src/bin/cli/rustc.rs +++ /dev/null @@ -1,47 +0,0 @@ -use clap::AppSettings; - -use command_prelude::*; - -pub fn cli() -> App { - subcommand("rustc") - .setting(AppSettings::TrailingVarArg) - .about("Compile a package and all of its dependencies") - .arg(Arg::with_name("args").multiple(true)) - .arg_single_package("Package to build") - .arg_jobs() - .arg_targets_all( - "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_release("Build artifacts in release mode, with optimizations") - .arg( - opt("profile", "Profile to build the selected target for") - .value_name("PROFILE") - ) - .arg_features() - .arg_target_triple("Target triple which compiles will be for") - .arg_manifest_path() - .arg_message_format() - .after_help("\ -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 -... will all be passed to the final compiler invocation, not any of the -dependencies. Note that the compiler will still unconditionally receive -arguments such as -L, --extern, and --crate-type, and the specified ... -will simply be added to the compiler invocation. - -This command requires that only one target is being compiled. If more than one -target is available for the current package the filters of --lib, --bin, etc, -must be used to select which target is compiled. To pass flags to all compiler -processes spawned by Cargo, use the $RUSTFLAGS environment variable or the -`build.rustflags` configuration option. -") -} diff --git a/src/bin/cli/rustdoc.rs b/src/bin/cli/rustdoc.rs deleted file mode 100644 index 5db6ca9dd..000000000 --- a/src/bin/cli/rustdoc.rs +++ /dev/null @@ -1,41 +0,0 @@ -use clap::AppSettings; - -use command_prelude::*; - -pub fn cli() -> App { - subcommand("rustdoc") - .setting(AppSettings::TrailingVarArg) - .about("Build a package's documentation, using specified custom flags.") - .arg(Arg::with_name("args").multiple(true)) - .arg(opt("open", "Opens the docs in a browser after the operation")) - .arg_single_package("Package to document") - .arg_jobs() - .arg_targets_all( - "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 (default)", - ) - .arg_release("Build artifacts in release mode, with optimizations") - .arg_manifest_path() - .arg_message_format() - .after_help("\ -The specified target for the current package (or package specified by SPEC if -provided) will be documented with the specified ... being passed to the -final rustdoc invocation. Dependencies will not be documented as part of this -command. Note that rustdoc will still unconditionally receive arguments such -as -L, --extern, and --crate-type, and the specified ... will simply be -added to the rustdoc invocation. - -If the --package argument is given, then SPEC is a package id specification -which indicates which package should be documented. If it is not given, then the -current package is documented. For more information on SPEC and its format, see -the `cargo help pkgid` command. -") -} diff --git a/src/bin/cli/search.rs b/src/bin/cli/search.rs deleted file mode 100644 index 62d023b0f..000000000 --- a/src/bin/cli/search.rs +++ /dev/null @@ -1,13 +0,0 @@ -use command_prelude::*; - -pub fn cli() -> App { - subcommand("search") - .about("Search packages in crates.io") - .arg(Arg::with_name("query").multiple(true)) - .arg_index() - .arg( - opt("limit", "Limit the number of results (default: 10, max: 100)") - .value_name("LIMIT") - ) - .arg(opt("registry", "Registry to use").value_name("REGISTRY")) -} diff --git a/src/bin/cli/test.rs b/src/bin/cli/test.rs deleted file mode 100644 index 9c0ae57b7..000000000 --- a/src/bin/cli/test.rs +++ /dev/null @@ -1,84 +0,0 @@ -use command_prelude::*; -use clap::AppSettings; - -pub fn cli() -> App { - subcommand("test").alias("t") - .setting(AppSettings::TrailingVarArg) - .about("Execute all unit and integration tests of a local package") - .arg( - Arg::with_name("TESTNAME").help( - "If specified, only run tests containing this string in their names" - ) - ) - .arg( - Arg::with_name("args").help( - "Arguments for the test binary" - ).multiple(true).last(true) - ) - .arg_targets_all( - "Test only this package's library", - "Test only the specified binary", - "Test all binaries", - "Check that the specified examples compile", - "Check that all examples compile", - "Test only the specified test target", - "Test all tests", - "Test only the specified bench target", - "Test all benches", - "Test all targets (default)", - ) - .arg(opt("doc", "Test only this library's documentation")) - .arg( - opt("no-run", "Compile, but don't run tests") - ) - .arg( - opt("no-fail-fast", "Run all tests regardless of failure") - ) - .arg_package( - "Package to run tests for", - "Test all packages in the workspace", - "Exclude packages from the test", - ) - .arg_jobs() - .arg_release("Build artifacts in release mode, with optimizations") - .arg_features() - .arg_target_triple("Build for the target triple") - .arg_manifest_path() - .arg_message_format() - .after_help("\ -All of the trailing arguments are passed to the test binaries generated for -filtering tests and generally providing options configuring how they run. For -example, this will run all tests with the name `foo` in their name: - - cargo test foo - -If the --package argument is given, then SPEC is a package id specification -which indicates which package should be tested. If it is not given, then the -current package is tested. For more information on SPEC and its format, see the -`cargo help pkgid` command. - -All packages in the workspace are tested 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 test executable but does -not affect how many jobs are used when running the tests. The default value -for the --jobs argument is the number of CPUs. If you want to control the -number of simultaneous running test cases, pass the `--test-threads` option -to the test binaries: - - cargo test -- --test-threads=1 - -Compilation can be configured via the `test` profile in the manifest. - -By default the rust test harness hides output from test execution to -keep results readable. Test output can be recovered (e.g. for debugging) -by passing `--nocapture` to the test binaries: - - cargo test -- --nocapture - -To get the list of all options available for the test binaries use this: - - cargo test -- --help -") -} diff --git a/src/bin/cli/uninstall.rs b/src/bin/cli/uninstall.rs deleted file mode 100644 index 5ab7513e5..000000000 --- a/src/bin/cli/uninstall.rs +++ /dev/null @@ -1,21 +0,0 @@ -use command_prelude::*; - -pub fn cli() -> App { - subcommand("uninstall") - .about("Remove a Rust binary") - .arg(Arg::with_name("spec").multiple(true)) - .arg( - opt("bin", "Only uninstall the binary NAME") - .value_name("NAME").multiple(true) - ) - .arg( - opt("root", "Directory to uninstall packages from") - .value_name("DIR") - ) - .after_help("\ -The argument SPEC is a package id specification (see `cargo help pkgid`) to -specify which crate should be uninstalled. By default all binaries are -uninstalled for a crate but the `--bin` and `--example` flags can be used to -only uninstall particular binaries. -") -} diff --git a/src/bin/cli/update.rs b/src/bin/cli/update.rs deleted file mode 100644 index 523051c25..000000000 --- a/src/bin/cli/update.rs +++ /dev/null @@ -1,37 +0,0 @@ -use command_prelude::*; - -pub fn cli() -> App { - subcommand("update") - .about("Update dependencies as recorded in the local lock file") - .arg( - opt("package", "Package to clean artifacts for") - .short("p").value_name("SPEC").multiple(true) - ) - .arg(opt("aggressive", "Force updating all dependencies of as well")) - .arg( - opt("precise", "Update a single dependency to exactly PRECISE") - .value_name("PRECISE") - ) - .arg_manifest_path() - .after_help("\ -This command requires that a `Cargo.lock` already exists as generated by -`cargo build` or related commands. - -If SPEC is given, then a conservative update of the lockfile will be -performed. This means that only the dependency specified by SPEC will be -updated. Its transitive dependencies will be updated only if SPEC cannot be -updated without updating dependencies. All other dependencies will remain -locked at their currently recorded versions. - -If PRECISE is specified, then --aggressive must not also be specified. The -argument PRECISE is a string representing a precise revision that the package -being updated should be updated to. For example, if the package comes from a git -repository, then PRECISE would be the exact revision that the repository should -be updated to. - -If SPEC is not given, then all dependencies will be re-resolved and -updated. - -For more information about package id specifications, see `cargo help pkgid`. -") -} diff --git a/src/bin/cli/verify_project.rs b/src/bin/cli/verify_project.rs deleted file mode 100644 index 926d8014c..000000000 --- a/src/bin/cli/verify_project.rs +++ /dev/null @@ -1,7 +0,0 @@ -use command_prelude::*; - -pub fn cli() -> App { - subcommand("verify-project") - .about("Check correctness of crate manifest") - .arg_manifest_path() -} diff --git a/src/bin/cli/version.rs b/src/bin/cli/version.rs deleted file mode 100644 index 0d7de9a6c..000000000 --- a/src/bin/cli/version.rs +++ /dev/null @@ -1,6 +0,0 @@ -use command_prelude::*; - -pub fn cli() -> App { - subcommand("version") - .about("Show version information") -} diff --git a/src/bin/cli/yank.rs b/src/bin/cli/yank.rs deleted file mode 100644 index 54039a3b1..000000000 --- a/src/bin/cli/yank.rs +++ /dev/null @@ -1,23 +0,0 @@ -use command_prelude::*; - -pub fn cli() -> App { - subcommand("yank") - .about("Remove a pushed crate from the index") - .arg(Arg::with_name("crate")) - .arg( - opt("vers", "The version to yank or un-yank").value_name("VERSION") - ) - .arg(opt("undo", "Undo a yank, putting a version back into the index")) - .arg(opt("index", "Registry index to yank from").value_name("INDEX")) - .arg(opt("token", "API token to use when authenticating").value_name("TOKEN")) - .arg(opt("registry", "Registry to use").value_name("REGISTRY")) - .after_help("\ -The yank command removes a previously pushed crate's version from the server's -index. This command does not delete any data, and the crate will still be -available for download via the registry's download link. - -Note that existing crates locked to a yanked version will still be able to -download the yanked version to use it. Cargo will, however, not allow any new -crates to be locked to any yanked version. -") -} diff --git a/src/bin/command_prelude.rs b/src/bin/command_prelude.rs new file mode 100644 index 000000000..5d10c76be --- /dev/null +++ b/src/bin/command_prelude.rs @@ -0,0 +1,323 @@ +use std::path::PathBuf; + +use clap::{self, SubCommand, AppSettings, ArgMatches}; +use cargo::{Config, CargoResult}; +use cargo::core::Workspace; +use cargo::ops::{CompileMode, CompileOptions, CompileFilter, Packages, MessageFormat, + VersionControl, NewOptions}; +use cargo::util::important_paths::find_root_manifest_for_wd; + +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_single_package(self, package: &'static str) -> Self { + self._arg(opt("package", package).short("p").value_name("SPEC")) + } + + fn arg_jobs(self) -> Self { + self._arg( + opt("jobs", "Number of parallel jobs, defaults to # of CPUs") + .short("j").value_name("N") + ) + } + + fn arg_targets_all( + 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_targets_lib_bin(lib, bin, 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_targets_lib_bin( + self, + lib: &'static str, + bin: &'static str, + bins: &'static str, + ) -> Self { + self._arg(opt("lib", lib)) + ._arg(opt("bin", bin).value_name("NAME").multiple(true)) + ._arg(opt("bins", bins)) + } + + fn arg_targets_bins_examples( + self, + bin: &'static str, + bins: &'static str, + example: &'static str, + examples: &'static str, + ) -> Self { + self._arg(opt("bin", bin).value_name("NAME").multiple(true)) + ._arg(opt("bins", bins)) + ._arg(opt("example", example).value_name("NAME").multiple(true)) + ._arg(opt("examples", examples)) + } + + fn arg_targets_bin_example( + self, + bin: &'static str, + example: &'static str, + ) -> Self { + self._arg(opt("bin", bin).value_name("NAME").multiple(true)) + ._arg(opt("example", example).value_name("NAME").multiple(true)) + } + + fn arg_features(self) -> Self { + self + ._arg( + opt("features", "Space-separated list of features to activate") + .value_name("FEATURES") + ) + ._arg(opt("all-features", "Activate all available features")) + ._arg(opt("no-default-features", "Do not activate the `default` feature")) + } + + fn arg_release(self, release: &'static str) -> Self { + self._arg(opt("release", release)) + } + + fn arg_target_triple(self, target: &'static str) -> Self { + self._arg(opt("target", target).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") + .case_insensitive(true) + .possible_values(&["human", "json"]).default_value("human") + ) + } + + fn arg_new_opts(self) -> Self { + self._arg( + opt("vcs", "\ +Initialize a new repository for the given version \ +control system (git, hg, pijul, or fossil) or do not \ +initialize any version control at all (none), overriding \ +a global configuration.") + .value_name("VCS") + .possible_values(&["git", "hg", "pijul", "fossil", "none"]) + ) + ._arg(opt("bin", "Use a binary (application) template [default]")) + ._arg(opt("lib", "Use a library template")) + ._arg( + opt("name", "Set the resulting package name, defaults to the directory name") + .value_name("NAME") + ) + } + + fn arg_index(self) -> Self { + self + ._arg( + opt("index", "Registry index to upload the package to") + .value_name("INDEX") + ) + ._arg( + opt("host", "DEPRECATED, renamed to '--index'") + .value_name("HOST") + .hidden(true) + ) + } +} + +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::DontCollapseArgsInUsage, + ]) +} + +pub fn values(args: &ArgMatches, name: &str) -> Vec { + args.values_of(name).unwrap_or_default() + .map(|s| s.to_string()) + .collect() +} + + +pub 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(), + ) +} + +pub fn root_manifest_from_args(config: &Config, args: &ArgMatches) -> CargoResult { + let manifest_path = args.value_of("manifest-path").map(|s| s.to_string()); + find_root_manifest_for_wd(manifest_path, config.cwd()) +} + +pub fn workspace_from_args<'a>(config: &'a Config, args: &ArgMatches) -> CargoResult> { + let root = root_manifest_from_args(config, args)?; + Workspace::new(&root, config) +} + +pub fn jobs_from_args(args: &ArgMatches) -> CargoResult> { //FIXME: validation + let jobs = match args.value_of("jobs") { + None => None, + Some(jobs) => Some(jobs.parse::().map_err(|_| { + clap::Error::value_validation_auto( + format!("could not parse `{}` as a number", jobs) + ) + })?) + }; + Ok(jobs) +} + +pub fn compile_options_from_args<'a>( + config: &'a Config, + args: &'a ArgMatches<'a>, + mode: CompileMode, +) -> CargoResult> { + let spec = Packages::from_flags( + args.is_present("all"), + values(args, "exclude"), + values(args, "package"), + )?; + + let message_format = match args.value_of("message-format") { + None => MessageFormat::Human, + Some(f) => { + if f.eq_ignore_ascii_case("json") { + MessageFormat::Json + } else if f.eq_ignore_ascii_case("human") { + MessageFormat::Human + } else { + panic!("Impossible message format: {:?}", f) + } + } + }; + + let opts = CompileOptions { + config, + jobs: jobs_from_args(args)?, + 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: args.is_present("release"), + filter: 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) +} + +pub fn compile_options_from_args_for_single_package<'a>( + config: &'a Config, + args: &'a ArgMatches<'a>, + mode: CompileMode, +) -> CargoResult> { + let mut compile_opts = compile_options_from_args(config, args, mode)?; + compile_opts.spec = Packages::Packages(values(args, "package")); + Ok(compile_opts) +} + +pub fn new_opts_from_args<'a>(args: &'a ArgMatches<'a>, path: &'a str) -> CargoResult> { + let vcs = args.value_of("vcs").map(|vcs| match vcs { + "git" => VersionControl::Git, + "hg" => VersionControl::Hg, + "pijul" => VersionControl::Pijul, + "fossil" => VersionControl::Fossil, + "none" => VersionControl::NoVcs, + vcs => panic!("Impossible vcs: {:?}", vcs), + }); + NewOptions::new(vcs, + args.is_present("bin"), + args.is_present("lib"), + path, + args.value_of("name")) +} + +pub fn registry_from_args(config: &Config, args: &ArgMatches) -> CargoResult> { + match args.value_of("registry") { + Some(registry) => { + if !config.cli_unstable().unstable_options { + return Err(format_err!("registry option is an unstable feature and \ + requires -Zunstable-options to use.").into()); + } + Ok(Some(registry.to_string())) + } + None => Ok(None), + } +} + +pub fn index_from_args(config: &Config, args: &ArgMatches) -> CargoResult> { + // TODO: Deprecated + // remove once it has been decided --host can be removed + // We may instead want to repurpose the host flag, as + // mentioned in this issue + // https://github.com/rust-lang/cargo/issues/4208 + let msg = "The flag '--host' is no longer valid. + +Previous versions of Cargo accepted this flag, but it is being +deprecated. The flag is being renamed to 'index', as the flag +wants the location of the index. Please use '--index' instead. + +This will soon become a hard error, so it's either recommended +to update to a fixed version or contact the upstream maintainer +about this warning."; + + let index = match args.value_of("host") { + Some(host) => { + config.shell().warn(&msg)?; + Some(host.to_string()) + } + None => args.value_of("index").map(|s| s.to_string()) + }; + Ok(index) +} diff --git a/src/bin/commands/bench.rs b/src/bin/commands/bench.rs new file mode 100644 index 000000000..df43b7801 --- /dev/null +++ b/src/bin/commands/bench.rs @@ -0,0 +1,67 @@ +use command_prelude::*; +use clap::AppSettings; + +pub fn cli() -> App { + subcommand("bench") + .setting(AppSettings::TrailingVarArg) + .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_targets_all( + "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("Build for the target triple") + .arg_manifest_path() + .arg_message_format() + .arg( + opt("no-fail-fast", "Run all benchmarks regardless of failure") + ) + .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. +") +} diff --git a/src/bin/commands/build.rs b/src/bin/commands/build.rs new file mode 100644 index 000000000..9eddd651b --- /dev/null +++ b/src/bin/commands/build.rs @@ -0,0 +1,44 @@ +use command_prelude::*; + +pub fn cli() -> App { + subcommand("build").alias("b") + .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_targets_all( + "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_release("Build artifacts in release mode, with optimizations") + .arg_features() + .arg_target_triple("Build for the target triple") + .arg_manifest_path() + .arg_message_format() + .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. +") + +} diff --git a/src/bin/commands/check.rs b/src/bin/commands/check.rs new file mode 100644 index 000000000..ecf7fe6ce --- /dev/null +++ b/src/bin/commands/check.rs @@ -0,0 +1,50 @@ +use command_prelude::*; + +pub fn cli() -> App { + subcommand("check") + .about("Check a local package and all of its dependencies for errors") + .arg_package( + "Package(s) to check", + "Check all packages in the workspace", + "Exclude packages from the check", + ) + .arg_jobs() + .arg_targets_all( + "Check only this package's library", + "Check only the specified binary", + "Check all binaries", + "Check only the specified example", + "Check all examples", + "Check only the specified test target", + "Check all tests", + "Check only the specified bench target", + "Check all benches", + "Check all targets (lib and bin targets by default)", + ) + .arg_release("Check artifacts in release mode, with optimizations") + .arg( + opt("profile", "Profile to build the selected target for") + .value_name("PROFILE") + ) + .arg_features() + .arg_target_triple("Check for the target triple") + .arg_manifest_path() + .arg_message_format() + .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 checked 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. + +The `--profile test` flag can be used to check unit tests with the +`#[cfg(test)]` attribute. +") +} diff --git a/src/bin/commands/clean.rs b/src/bin/commands/clean.rs new file mode 100644 index 000000000..7852c3c5c --- /dev/null +++ b/src/bin/commands/clean.rs @@ -0,0 +1,19 @@ +use command_prelude::*; + +pub fn cli() -> App { + subcommand("clean") + .about("Remove artifacts that cargo has generated in the past") + .arg( + opt("package", "Package to clean artifacts for") + .short("p").value_name("SPEC").multiple(true) + ) + .arg_manifest_path() + .arg_target_triple("Target triple to clean output for (default all)") + .arg_release("Whether or not to clean release artifacts") + .after_help("\ +If the --package argument is given, then SPEC is a package id specification +which indicates which package's artifacts should be cleaned out. If it is not +given, then all packages' artifacts are removed. For more information on SPEC +and its format, see the `cargo help pkgid` command. +") +} diff --git a/src/bin/commands/doc.rs b/src/bin/commands/doc.rs new file mode 100644 index 000000000..bcb709b29 --- /dev/null +++ b/src/bin/commands/doc.rs @@ -0,0 +1,41 @@ +use command_prelude::*; + +pub fn cli() -> App { + subcommand("doc") + .about("Build a package's documentation") + .arg( + opt("open", "Opens the docs in a browser after the operation") + ) + .arg_package( + "Package to document", + "Document all packages in the workspace", + "Exclude packages from the build", + ) + .arg( + opt("no-deps", "Don't build documentation for dependencies") + ) + .arg_jobs() + .arg_targets_lib_bin( + "Document only this package's library", + "Document only the specified binary", + "Document all binaries", + ) + .arg_release("Build artifacts in release mode, with optimizations") + .arg_features() + .arg_target_triple("Build for the target triple") + .arg_manifest_path() + .arg_message_format() + .after_help("\ +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. + +All packages in the workspace are documented 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. + +If the --package argument is given, then SPEC is a package id specification +which indicates which package should be documented. If it is not given, then the +current package is documented. For more information on SPEC and its format, see +the `cargo help pkgid` command. +") +} diff --git a/src/bin/commands/fetch.rs b/src/bin/commands/fetch.rs new file mode 100644 index 000000000..bb4a946ab --- /dev/null +++ b/src/bin/commands/fetch.rs @@ -0,0 +1,17 @@ +use command_prelude::*; + +pub fn cli() -> App { + subcommand("fetch") + .about("Fetch dependencies of a package from the network") + .arg_manifest_path() + .after_help("\ +If a lockfile is available, this command will ensure that all of the git +dependencies and/or registries dependencies are downloaded and locally +available. The network is never touched after a `cargo fetch` unless +the lockfile changes. + +If the lockfile is not available, then this is the equivalent of +`cargo generate-lockfile`. A lockfile is generated and dependencies are also +all updated. +") +} diff --git a/src/bin/commands/generate_lockfile.rs b/src/bin/commands/generate_lockfile.rs new file mode 100644 index 000000000..56ab283f4 --- /dev/null +++ b/src/bin/commands/generate_lockfile.rs @@ -0,0 +1,17 @@ +use command_prelude::*; + +pub fn cli() -> App { + subcommand("generate-lockfile") + .about("Generate the lockfile for a project") + .arg_manifest_path() + .after_help("\ +If a lockfile is available, this command will ensure that all of the git +dependencies and/or registries dependencies are downloaded and locally +available. The network is never touched after a `cargo fetch` unless +the lockfile changes. + +If the lockfile is not available, then this is the equivalent of +`cargo generate-lockfile`. A lockfile is generated and dependencies are also +all updated. +") +} diff --git a/src/bin/commands/git_checkout.rs b/src/bin/commands/git_checkout.rs new file mode 100644 index 000000000..4bbcba133 --- /dev/null +++ b/src/bin/commands/git_checkout.rs @@ -0,0 +1,8 @@ +use command_prelude::*; + +pub fn cli() -> App { + subcommand("git-checkout") + .about("Checkout a copy of a Git repository") + .arg(Arg::with_name("url").long("url").value_name("URL").required(true)) + .arg(Arg::with_name("reference").long("reference").value_name("REF").required(true)) +} diff --git a/src/bin/commands/init.rs b/src/bin/commands/init.rs new file mode 100644 index 000000000..e9d618b43 --- /dev/null +++ b/src/bin/commands/init.rs @@ -0,0 +1,8 @@ +use command_prelude::*; + +pub fn cli() -> App { + subcommand("init") + .about("Create a new cargo package in an existing directory") + .arg(Arg::with_name("path")) + .arg_new_opts() +} diff --git a/src/bin/commands/install.rs b/src/bin/commands/install.rs new file mode 100644 index 000000000..ce1834d9d --- /dev/null +++ b/src/bin/commands/install.rs @@ -0,0 +1,86 @@ +use command_prelude::*; + +pub fn cli() -> App { + subcommand("install") + .about("Create a new cargo package in an existing directory") + .arg(Arg::with_name("crate").multiple(true)) + + .arg( + opt("version", "Specify a version to install from crates.io") + .alias("vers").value_name("VERSION") + ) + .arg( + opt("git", "Git URL to install the specified crate from") + .value_name("URL") + ) + .arg( + opt("branch", "Branch to use when installing from git") + .value_name("BRANCH") + ) + .arg( + opt("tag", "Tag to use when installing from git") + .value_name("TAG") + ) + .arg( + opt("rev", "Specific commit to use when installing from git") + .value_name("SHA") + ) + .arg( + opt("path", "Filesystem path to local crate to install") + .value_name("PATH") + ) + + .arg(opt("list", "list all installed packages and their versions")) + + .arg_jobs() + .arg( + opt("force", "Force overwriting existing crates or binaries") + .short("f") + ) + .arg_features() + .arg(opt("debug", "Build in debug mode instead of release mode")) + .arg_targets_bins_examples( + "Install only the specified binary", + "Install all binaries", + "Install only the specified example", + "Install all examples", + ) + .arg( + opt("root", "Directory to install packages into") + .value_name("DIR") + ) + .after_help("\ +This command manages Cargo's local set of installed binary crates. Only packages +which have [[bin]] targets can be installed, and all binaries are installed into +the installation root's `bin` folder. The installation root is determined, in +order of precedence, by `--root`, `$CARGO_INSTALL_ROOT`, the `install.root` +configuration key, and finally the home directory (which is either +`$CARGO_HOME` if set or `$HOME/.cargo` by default). + +There are multiple sources from which a crate can be installed. The default +location is crates.io but the `--git` and `--path` flags can change this source. +If the source contains more than one package (such as crates.io or a git +repository with multiple crates) the `` argument is required to indicate +which crate should be installed. + +Crates from crates.io can optionally specify the version they wish to install +via the `--vers` flags, and similarly packages from git repositories can +optionally specify the branch, tag, or revision that should be installed. If a +crate has multiple binaries, the `--bin` argument can selectively install only +one of them, and if you'd rather install examples the `--example` argument can +be used as well. + +By default cargo will refuse to overwrite existing binaries. The `--force` flag +enables overwriting existing binaries. Thus you can reinstall a crate with +`cargo install --force `. + +As a special convenience, omitting the specification entirely will +install the crate in the current directory. That is, `install` is equivalent to +the more explicit `install --path .`. + +If the source is crates.io or `--git` then by default the crate will be built +in a temporary target directory. To avoid this, the target directory can be +specified by setting the `CARGO_TARGET_DIR` environment variable to a relative +path. In particular, this can be useful for caching build artifacts on +continuous integration systems.") +} diff --git a/src/bin/commands/locate_project.rs b/src/bin/commands/locate_project.rs new file mode 100644 index 000000000..1bddac4c2 --- /dev/null +++ b/src/bin/commands/locate_project.rs @@ -0,0 +1,7 @@ +use command_prelude::*; + +pub fn cli() -> App { + subcommand("locate-project") + .about("Checkout a copy of a Git repository") + .arg_manifest_path() +} diff --git a/src/bin/commands/login.rs b/src/bin/commands/login.rs new file mode 100644 index 000000000..045770181 --- /dev/null +++ b/src/bin/commands/login.rs @@ -0,0 +1,10 @@ +use command_prelude::*; + +pub fn cli() -> App { + subcommand("login") + .about("Save an api token from the registry locally. \ + If token is not specified, it will be read from stdin.") + .arg(Arg::with_name("token")) + .arg(opt("host", "Host to set the token for").value_name("HOST")) + .arg(opt("registry", "Registry to use").value_name("REGISTRY")) +} diff --git a/src/bin/commands/metadata.rs b/src/bin/commands/metadata.rs new file mode 100644 index 000000000..7f4904c14 --- /dev/null +++ b/src/bin/commands/metadata.rs @@ -0,0 +1,18 @@ +use command_prelude::*; + +pub fn cli() -> App { + subcommand("metadata") + .about("Output the resolved dependencies of a project, \ + the concrete used versions including overrides, \ + in machine-readable format") + .arg_features() + .arg( + opt("no-deps", "Output information only about the root package \ + and don't fetch dependencies") + ) + .arg_manifest_path() + .arg( + opt("format-version", "Format version") + .value_name("VERSION").possible_value("1") + ) +} diff --git a/src/bin/commands/mod.rs b/src/bin/commands/mod.rs new file mode 100644 index 000000000..6dea3eb16 --- /dev/null +++ b/src/bin/commands/mod.rs @@ -0,0 +1,66 @@ +use command_prelude::*; + +pub fn builtin() -> Vec { + vec![ + bench::cli(), + build::cli(), + check::cli(), + clean::cli(), + doc::cli(), + fetch::cli(), + generate_lockfile::cli(), + git_checkout::cli(), + init::cli(), + install::cli(), + locate_project::cli(), + login::cli(), + metadata::cli(), + new::cli(), + owner::cli(), + package::cli(), + pkgid::cli(), + publish::cli(), + read_manifest::cli(), + run::cli(), + rustc::cli(), + rustdoc::cli(), + search::cli(), + test::cli(), + uninstall::cli(), + update::cli(), + verify_project::cli(), + version::cli(), + yank::cli(), + ] +} + + +mod bench; +mod build; +mod check; +mod clean; +mod doc; +mod fetch; +mod generate_lockfile; +mod git_checkout; +mod init; +mod install; +mod locate_project; +mod login; +mod metadata; +mod new; +mod owner; +mod package; +mod pkgid; +mod publish; +mod read_manifest; +mod run; +mod rustc; +mod rustdoc; +mod search; +mod test; +mod uninstall; +mod update; +mod verify_project; +mod version; +mod yank; diff --git a/src/bin/commands/new.rs b/src/bin/commands/new.rs new file mode 100644 index 000000000..eb03e37d5 --- /dev/null +++ b/src/bin/commands/new.rs @@ -0,0 +1,8 @@ +use command_prelude::*; + +pub fn cli() -> App { + subcommand("new") + .about("Create a new cargo package at ") + .arg(Arg::with_name("path").required(true)) + .arg_new_opts() +} diff --git a/src/bin/commands/owner.rs b/src/bin/commands/owner.rs new file mode 100644 index 000000000..dd7c5adf1 --- /dev/null +++ b/src/bin/commands/owner.rs @@ -0,0 +1,28 @@ +use command_prelude::*; + +pub fn cli() -> App { + subcommand("owner") + .about("Manage the owners of a crate on the registry") + .arg(Arg::with_name("crate")) + .arg( + opt("add", "Name of a user or team to add as an owner") + .short("a").value_name("LOGIN").multiple(true) + ) + .arg( + opt("remove", "Name of a user or team to remove as an owner") + .short("r").value_name("LOGIN").multiple(true) + ) + .arg(opt("list", "List owners of a crate").short("l")) + .arg(opt("index", "Registry index to modify owners for").value_name("INDEX")) + .arg(opt("token", "API token to use when authenticating").value_name("TOKEN")) + .arg(opt("registry", "Registry to use").value_name("REGISTRY")) + .after_help("\ + This command will modify the owners for a package + on the specified registry(or + default).Note that owners of a package can upload new versions, yank old + versions.Explicitly named owners can also modify the set of owners, so take + caution! + + See http://doc.crates.io/crates-io.html#cargo-owner for detailed documentation + and troubleshooting.") +} diff --git a/src/bin/commands/package.rs b/src/bin/commands/package.rs new file mode 100644 index 000000000..59ba384b7 --- /dev/null +++ b/src/bin/commands/package.rs @@ -0,0 +1,13 @@ +use command_prelude::*; + +pub fn cli() -> App { + subcommand("package") + .about("Assemble the local package into a distributable tarball") + .arg(opt("list", "Print files included in a package without making one").short("l")) + .arg(opt("no-verify", "Don't verify the contents by building them")) + .arg(opt("no-metadata", "Ignore warnings about a lack of human-usable metadata")) + .arg(opt("allow-dirty", "Allow dirty working directories to be packaged")) + .arg_target_triple("Build for the target triple") + .arg_manifest_path() + .arg_jobs() +} diff --git a/src/bin/commands/pkgid.rs b/src/bin/commands/pkgid.rs new file mode 100644 index 000000000..26335735a --- /dev/null +++ b/src/bin/commands/pkgid.rs @@ -0,0 +1,29 @@ +use command_prelude::*; + +pub fn cli() -> App { + subcommand("pkgid") + .about("Print a fully qualified package specification") + .arg(Arg::with_name("spec")) + .arg_single_package("Argument to get the package id specifier for") + .arg_manifest_path() + .after_help("\ +Given a argument, print out the fully qualified package id specifier. +This command will generate an error if is ambiguous as to which package +it refers to in the dependency graph. If no is given, then the pkgid for +the local package is printed. + +This command requires that a lockfile is available and dependencies have been +fetched. + +Example Package IDs + + pkgid | name | version | url + |-----------------------------|--------|-----------|---------------------| + foo | foo | * | * + foo:1.2.3 | foo | 1.2.3 | * + crates.io/foo | foo | * | *://crates.io/foo + crates.io/foo#1.2.3 | foo | 1.2.3 | *://crates.io/foo + crates.io/bar#foo:1.2.3 | foo | 1.2.3 | *://crates.io/bar + http://crates.io/foo#1.2.3 | foo | 1.2.3 | http://crates.io/foo +") +} diff --git a/src/bin/commands/publish.rs b/src/bin/commands/publish.rs new file mode 100644 index 000000000..fc4ead218 --- /dev/null +++ b/src/bin/commands/publish.rs @@ -0,0 +1,17 @@ +use command_prelude::*; + +pub fn cli() -> App { + subcommand("publish") + .about("Upload a package to the registry") + .arg_index() + .arg(opt("token", "Token to use when uploading").value_name("TOKEN")) + .arg(opt("no-verify", "Don't verify the contents by building them")) + .arg(opt("allow-dirty", "Allow dirty working directories to be packaged")) + .arg_target_triple("Build for the target triple") + .arg_manifest_path() + .arg_jobs() + .arg( + opt("dry-run", "Perform all checks without uploading") + ) + .arg(opt("registry", "Registry to publish to").value_name("REGISTRY")) +} diff --git a/src/bin/commands/read_manifest.rs b/src/bin/commands/read_manifest.rs new file mode 100644 index 000000000..ec6ffec83 --- /dev/null +++ b/src/bin/commands/read_manifest.rs @@ -0,0 +1,8 @@ +use command_prelude::*; + +pub fn cli() -> App { + subcommand("read-manifest") + .about("Deprecated, use `cargo metadata --no-deps` instead. +Print a JSON representation of a Cargo.toml manifest.") + .arg_manifest_path() +} diff --git a/src/bin/commands/run.rs b/src/bin/commands/run.rs new file mode 100644 index 000000000..dae6c9de2 --- /dev/null +++ b/src/bin/commands/run.rs @@ -0,0 +1,31 @@ +use clap::AppSettings; + +use command_prelude::*; + +pub fn cli() -> App { + subcommand("run").alias("r") + .setting(AppSettings::TrailingVarArg) + .about("Run the main binary of the local package (src/main.rs)") + .arg(Arg::with_name("args").multiple(true)) + .arg_targets_bin_example( + "Name of the bin target to run", + "Name of the example target to run", + ) + .arg_single_package("Package with the target to run") + .arg_jobs() + .arg_release("Build artifacts in release mode, with optimizations") + .arg_features() + .arg_target_triple("Build for the target triple") + .arg_manifest_path() + .arg_message_format() + .after_help("\ +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, +and `--example` specifies the example target to run. At most one of `--bin` or +`--example` can be provided. + +All of the trailing arguments are passed to the binary to run. If you're passing +arguments to both Cargo and the binary, the ones after `--` go to the binary, +the ones before go to Cargo. +") +} diff --git a/src/bin/commands/rustc.rs b/src/bin/commands/rustc.rs new file mode 100644 index 000000000..8074a551e --- /dev/null +++ b/src/bin/commands/rustc.rs @@ -0,0 +1,47 @@ +use clap::AppSettings; + +use command_prelude::*; + +pub fn cli() -> App { + subcommand("rustc") + .setting(AppSettings::TrailingVarArg) + .about("Compile a package and all of its dependencies") + .arg(Arg::with_name("args").multiple(true)) + .arg_single_package("Package to build") + .arg_jobs() + .arg_targets_all( + "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_release("Build artifacts in release mode, with optimizations") + .arg( + opt("profile", "Profile to build the selected target for") + .value_name("PROFILE") + ) + .arg_features() + .arg_target_triple("Target triple which compiles will be for") + .arg_manifest_path() + .arg_message_format() + .after_help("\ +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 +... will all be passed to the final compiler invocation, not any of the +dependencies. Note that the compiler will still unconditionally receive +arguments such as -L, --extern, and --crate-type, and the specified ... +will simply be added to the compiler invocation. + +This command requires that only one target is being compiled. If more than one +target is available for the current package the filters of --lib, --bin, etc, +must be used to select which target is compiled. To pass flags to all compiler +processes spawned by Cargo, use the $RUSTFLAGS environment variable or the +`build.rustflags` configuration option. +") +} diff --git a/src/bin/commands/rustdoc.rs b/src/bin/commands/rustdoc.rs new file mode 100644 index 000000000..5db6ca9dd --- /dev/null +++ b/src/bin/commands/rustdoc.rs @@ -0,0 +1,41 @@ +use clap::AppSettings; + +use command_prelude::*; + +pub fn cli() -> App { + subcommand("rustdoc") + .setting(AppSettings::TrailingVarArg) + .about("Build a package's documentation, using specified custom flags.") + .arg(Arg::with_name("args").multiple(true)) + .arg(opt("open", "Opens the docs in a browser after the operation")) + .arg_single_package("Package to document") + .arg_jobs() + .arg_targets_all( + "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 (default)", + ) + .arg_release("Build artifacts in release mode, with optimizations") + .arg_manifest_path() + .arg_message_format() + .after_help("\ +The specified target for the current package (or package specified by SPEC if +provided) will be documented with the specified ... being passed to the +final rustdoc invocation. Dependencies will not be documented as part of this +command. Note that rustdoc will still unconditionally receive arguments such +as -L, --extern, and --crate-type, and the specified ... will simply be +added to the rustdoc invocation. + +If the --package argument is given, then SPEC is a package id specification +which indicates which package should be documented. If it is not given, then the +current package is documented. For more information on SPEC and its format, see +the `cargo help pkgid` command. +") +} diff --git a/src/bin/commands/search.rs b/src/bin/commands/search.rs new file mode 100644 index 000000000..62d023b0f --- /dev/null +++ b/src/bin/commands/search.rs @@ -0,0 +1,13 @@ +use command_prelude::*; + +pub fn cli() -> App { + subcommand("search") + .about("Search packages in crates.io") + .arg(Arg::with_name("query").multiple(true)) + .arg_index() + .arg( + opt("limit", "Limit the number of results (default: 10, max: 100)") + .value_name("LIMIT") + ) + .arg(opt("registry", "Registry to use").value_name("REGISTRY")) +} diff --git a/src/bin/commands/test.rs b/src/bin/commands/test.rs new file mode 100644 index 000000000..9c0ae57b7 --- /dev/null +++ b/src/bin/commands/test.rs @@ -0,0 +1,84 @@ +use command_prelude::*; +use clap::AppSettings; + +pub fn cli() -> App { + subcommand("test").alias("t") + .setting(AppSettings::TrailingVarArg) + .about("Execute all unit and integration tests of a local package") + .arg( + Arg::with_name("TESTNAME").help( + "If specified, only run tests containing this string in their names" + ) + ) + .arg( + Arg::with_name("args").help( + "Arguments for the test binary" + ).multiple(true).last(true) + ) + .arg_targets_all( + "Test only this package's library", + "Test only the specified binary", + "Test all binaries", + "Check that the specified examples compile", + "Check that all examples compile", + "Test only the specified test target", + "Test all tests", + "Test only the specified bench target", + "Test all benches", + "Test all targets (default)", + ) + .arg(opt("doc", "Test only this library's documentation")) + .arg( + opt("no-run", "Compile, but don't run tests") + ) + .arg( + opt("no-fail-fast", "Run all tests regardless of failure") + ) + .arg_package( + "Package to run tests for", + "Test all packages in the workspace", + "Exclude packages from the test", + ) + .arg_jobs() + .arg_release("Build artifacts in release mode, with optimizations") + .arg_features() + .arg_target_triple("Build for the target triple") + .arg_manifest_path() + .arg_message_format() + .after_help("\ +All of the trailing arguments are passed to the test binaries generated for +filtering tests and generally providing options configuring how they run. For +example, this will run all tests with the name `foo` in their name: + + cargo test foo + +If the --package argument is given, then SPEC is a package id specification +which indicates which package should be tested. If it is not given, then the +current package is tested. For more information on SPEC and its format, see the +`cargo help pkgid` command. + +All packages in the workspace are tested 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 test executable but does +not affect how many jobs are used when running the tests. The default value +for the --jobs argument is the number of CPUs. If you want to control the +number of simultaneous running test cases, pass the `--test-threads` option +to the test binaries: + + cargo test -- --test-threads=1 + +Compilation can be configured via the `test` profile in the manifest. + +By default the rust test harness hides output from test execution to +keep results readable. Test output can be recovered (e.g. for debugging) +by passing `--nocapture` to the test binaries: + + cargo test -- --nocapture + +To get the list of all options available for the test binaries use this: + + cargo test -- --help +") +} diff --git a/src/bin/commands/uninstall.rs b/src/bin/commands/uninstall.rs new file mode 100644 index 000000000..5ab7513e5 --- /dev/null +++ b/src/bin/commands/uninstall.rs @@ -0,0 +1,21 @@ +use command_prelude::*; + +pub fn cli() -> App { + subcommand("uninstall") + .about("Remove a Rust binary") + .arg(Arg::with_name("spec").multiple(true)) + .arg( + opt("bin", "Only uninstall the binary NAME") + .value_name("NAME").multiple(true) + ) + .arg( + opt("root", "Directory to uninstall packages from") + .value_name("DIR") + ) + .after_help("\ +The argument SPEC is a package id specification (see `cargo help pkgid`) to +specify which crate should be uninstalled. By default all binaries are +uninstalled for a crate but the `--bin` and `--example` flags can be used to +only uninstall particular binaries. +") +} diff --git a/src/bin/commands/update.rs b/src/bin/commands/update.rs new file mode 100644 index 000000000..523051c25 --- /dev/null +++ b/src/bin/commands/update.rs @@ -0,0 +1,37 @@ +use command_prelude::*; + +pub fn cli() -> App { + subcommand("update") + .about("Update dependencies as recorded in the local lock file") + .arg( + opt("package", "Package to clean artifacts for") + .short("p").value_name("SPEC").multiple(true) + ) + .arg(opt("aggressive", "Force updating all dependencies of as well")) + .arg( + opt("precise", "Update a single dependency to exactly PRECISE") + .value_name("PRECISE") + ) + .arg_manifest_path() + .after_help("\ +This command requires that a `Cargo.lock` already exists as generated by +`cargo build` or related commands. + +If SPEC is given, then a conservative update of the lockfile will be +performed. This means that only the dependency specified by SPEC will be +updated. Its transitive dependencies will be updated only if SPEC cannot be +updated without updating dependencies. All other dependencies will remain +locked at their currently recorded versions. + +If PRECISE is specified, then --aggressive must not also be specified. The +argument PRECISE is a string representing a precise revision that the package +being updated should be updated to. For example, if the package comes from a git +repository, then PRECISE would be the exact revision that the repository should +be updated to. + +If SPEC is not given, then all dependencies will be re-resolved and +updated. + +For more information about package id specifications, see `cargo help pkgid`. +") +} diff --git a/src/bin/commands/verify_project.rs b/src/bin/commands/verify_project.rs new file mode 100644 index 000000000..926d8014c --- /dev/null +++ b/src/bin/commands/verify_project.rs @@ -0,0 +1,7 @@ +use command_prelude::*; + +pub fn cli() -> App { + subcommand("verify-project") + .about("Check correctness of crate manifest") + .arg_manifest_path() +} diff --git a/src/bin/commands/version.rs b/src/bin/commands/version.rs new file mode 100644 index 000000000..0d7de9a6c --- /dev/null +++ b/src/bin/commands/version.rs @@ -0,0 +1,6 @@ +use command_prelude::*; + +pub fn cli() -> App { + subcommand("version") + .about("Show version information") +} diff --git a/src/bin/commands/yank.rs b/src/bin/commands/yank.rs new file mode 100644 index 000000000..54039a3b1 --- /dev/null +++ b/src/bin/commands/yank.rs @@ -0,0 +1,23 @@ +use command_prelude::*; + +pub fn cli() -> App { + subcommand("yank") + .about("Remove a pushed crate from the index") + .arg(Arg::with_name("crate")) + .arg( + opt("vers", "The version to yank or un-yank").value_name("VERSION") + ) + .arg(opt("undo", "Undo a yank, putting a version back into the index")) + .arg(opt("index", "Registry index to yank from").value_name("INDEX")) + .arg(opt("token", "API token to use when authenticating").value_name("TOKEN")) + .arg(opt("registry", "Registry to use").value_name("REGISTRY")) + .after_help("\ +The yank command removes a previously pushed crate's version from the server's +index. This command does not delete any data, and the crate will still be +available for download via the registry's download link. + +Note that existing crates locked to a yanked version will still be able to +download the yanked version to use it. Cargo will, however, not allow any new +crates to be locked to any yanked version. +") +}