Reorganize subcommands as a separate submodule
authorAleksey Kladov <aleksey.kladov@gmail.com>
Sat, 10 Mar 2018 13:23:05 +0000 (16:23 +0300)
committerAleksey Kladov <aleksey.kladov@gmail.com>
Sat, 10 Mar 2018 13:23:05 +0000 (16:23 +0300)
63 files changed:
src/bin/cargo.rs
src/bin/cli.rs [new file with mode: 0644]
src/bin/cli/bench.rs [deleted file]
src/bin/cli/build.rs [deleted file]
src/bin/cli/check.rs [deleted file]
src/bin/cli/clean.rs [deleted file]
src/bin/cli/doc.rs [deleted file]
src/bin/cli/fetch.rs [deleted file]
src/bin/cli/generate_lockfile.rs [deleted file]
src/bin/cli/git_checkout.rs [deleted file]
src/bin/cli/init.rs [deleted file]
src/bin/cli/install.rs [deleted file]
src/bin/cli/locate_project.rs [deleted file]
src/bin/cli/login.rs [deleted file]
src/bin/cli/metadata.rs [deleted file]
src/bin/cli/mod.rs [deleted file]
src/bin/cli/new.rs [deleted file]
src/bin/cli/owner.rs [deleted file]
src/bin/cli/package.rs [deleted file]
src/bin/cli/pkgid.rs [deleted file]
src/bin/cli/publish.rs [deleted file]
src/bin/cli/read_manifest.rs [deleted file]
src/bin/cli/run.rs [deleted file]
src/bin/cli/rustc.rs [deleted file]
src/bin/cli/rustdoc.rs [deleted file]
src/bin/cli/search.rs [deleted file]
src/bin/cli/test.rs [deleted file]
src/bin/cli/uninstall.rs [deleted file]
src/bin/cli/update.rs [deleted file]
src/bin/cli/verify_project.rs [deleted file]
src/bin/cli/version.rs [deleted file]
src/bin/cli/yank.rs [deleted file]
src/bin/command_prelude.rs [new file with mode: 0644]
src/bin/commands/bench.rs [new file with mode: 0644]
src/bin/commands/build.rs [new file with mode: 0644]
src/bin/commands/check.rs [new file with mode: 0644]
src/bin/commands/clean.rs [new file with mode: 0644]
src/bin/commands/doc.rs [new file with mode: 0644]
src/bin/commands/fetch.rs [new file with mode: 0644]
src/bin/commands/generate_lockfile.rs [new file with mode: 0644]
src/bin/commands/git_checkout.rs [new file with mode: 0644]
src/bin/commands/init.rs [new file with mode: 0644]
src/bin/commands/install.rs [new file with mode: 0644]
src/bin/commands/locate_project.rs [new file with mode: 0644]
src/bin/commands/login.rs [new file with mode: 0644]
src/bin/commands/metadata.rs [new file with mode: 0644]
src/bin/commands/mod.rs [new file with mode: 0644]
src/bin/commands/new.rs [new file with mode: 0644]
src/bin/commands/owner.rs [new file with mode: 0644]
src/bin/commands/package.rs [new file with mode: 0644]
src/bin/commands/pkgid.rs [new file with mode: 0644]
src/bin/commands/publish.rs [new file with mode: 0644]
src/bin/commands/read_manifest.rs [new file with mode: 0644]
src/bin/commands/run.rs [new file with mode: 0644]
src/bin/commands/rustc.rs [new file with mode: 0644]
src/bin/commands/rustdoc.rs [new file with mode: 0644]
src/bin/commands/search.rs [new file with mode: 0644]
src/bin/commands/test.rs [new file with mode: 0644]
src/bin/commands/uninstall.rs [new file with mode: 0644]
src/bin/commands/update.rs [new file with mode: 0644]
src/bin/commands/verify_project.rs [new file with mode: 0644]
src/bin/commands/version.rs [new file with mode: 0644]
src/bin/commands/yank.rs [new file with mode: 0644]

index b7aa9a4125cf8c970bd84a06bd83851ab966c61f..83c0f78cf4a2577448475c79c1cd860388563a0f 100644 (file)
@@ -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 (file)
index 0000000..6894d3b
--- /dev/null
@@ -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::<Vec<_>>();
+
+            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<u8> = 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::<toml::Value>().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 <command>' for more information on a specific command.
+")
+        .subcommands(commands::builtin())
+    ;
+    app
+}
+
+
+/// List all runnable commands
+pub fn list_commands(config: &Config) -> BTreeSet<(String, Option<String>)> {
+    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 (file)
index df43b78..0000000
+++ /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 (file)
index 9eddd65..0000000
+++ /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 (file)
index ecf7fe6..0000000
+++ /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 (file)
index 7852c3c..0000000
+++ /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 (file)
index bcb709b..0000000
+++ /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 (file)
index bb4a946..0000000
+++ /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 (file)
index 56ab283..0000000
+++ /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 (file)
index 4bbcba1..0000000
+++ /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 (file)
index e9d618b..0000000
+++ /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 (file)
index ce1834d..0000000
+++ /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 `<crate>` 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 <crate>`.
-
-As a special convenience, omitting the <crate> 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 (file)
index 1bddac4..0000000
+++ /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 (file)
index 0457701..0000000
+++ /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 (file)
index 7f4904c..0000000
+++ /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 (file)
index 8fb63d3..0000000
+++ /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::<Vec<_>>();
-
-            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<u8> = 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::<toml::Value>().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 <command>' for more information on a specific command.
-")
-        .subcommands(builtin_subcommands())
-    ;
-    app
-}
-
-fn builtin_subcommands() -> Vec<App> {
-    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<String>)> {
-    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 (file)
index eb03e37..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-use command_prelude::*;
-
-pub fn cli() -> App {
-    subcommand("new")
-        .about("Create a new cargo package at <path>")
-        .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 (file)
index dd7c5ad..0000000
+++ /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 (file)
index 59ba384..0000000
+++ /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 (file)
index 2633573..0000000
+++ /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 <spec> argument, print out the fully qualified package id specifier.
-This command will generate an error if <spec> is ambiguous as to which package
-it refers to in the dependency graph. If no <spec> 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 (file)
index fc4ead2..0000000
+++ /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 (file)
index ec6ffec..0000000
+++ /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 (file)
index dae6c9d..0000000
+++ /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 (file)
index 8074a55..0000000
+++ /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
-<args>... 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 <args>...
-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 (file)
index 5db6ca9..0000000
+++ /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 <opts>... 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 <opts>...  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 (file)
index 62d023b..0000000
+++ /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 (file)
index 9c0ae57..0000000
+++ /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 (file)
index 5ab7513..0000000
+++ /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 (file)
index 523051c..0000000
+++ /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 <name> 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 (file)
index 926d801..0000000
+++ /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 (file)
index 0d7de9a..0000000
+++ /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 (file)
index 54039a3..0000000
+++ /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 (file)
index 0000000..5d10c76
--- /dev/null
@@ -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<String> {
+    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<PathBuf> {
+    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<Workspace<'a>> {
+    let root = root_manifest_from_args(config, args)?;
+    Workspace::new(&root, config)
+}
+
+pub fn jobs_from_args(args: &ArgMatches) -> CargoResult<Option<u32>> { //FIXME: validation
+    let jobs = match args.value_of("jobs") {
+        None => None,
+        Some(jobs) => Some(jobs.parse::<u32>().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<CompileOptions<'a>> {
+    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<CompileOptions<'a>> {
+    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<NewOptions<'a>> {
+    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<Option<String>> {
+    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<Option<String>> {
+    // 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 (file)
index 0000000..df43b78
--- /dev/null
@@ -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 (file)
index 0000000..9eddd65
--- /dev/null
@@ -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 (file)
index 0000000..ecf7fe6
--- /dev/null
@@ -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 (file)
index 0000000..7852c3c
--- /dev/null
@@ -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 (file)
index 0000000..bcb709b
--- /dev/null
@@ -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 (file)
index 0000000..bb4a946
--- /dev/null
@@ -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 (file)
index 0000000..56ab283
--- /dev/null
@@ -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 (file)
index 0000000..4bbcba1
--- /dev/null
@@ -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 (file)
index 0000000..e9d618b
--- /dev/null
@@ -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 (file)
index 0000000..ce1834d
--- /dev/null
@@ -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 `<crate>` 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 <crate>`.
+
+As a special convenience, omitting the <crate> 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 (file)
index 0000000..1bddac4
--- /dev/null
@@ -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 (file)
index 0000000..0457701
--- /dev/null
@@ -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 (file)
index 0000000..7f4904c
--- /dev/null
@@ -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 (file)
index 0000000..6dea3eb
--- /dev/null
@@ -0,0 +1,66 @@
+use command_prelude::*;
+
+pub fn builtin() -> Vec<App> {
+    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 (file)
index 0000000..eb03e37
--- /dev/null
@@ -0,0 +1,8 @@
+use command_prelude::*;
+
+pub fn cli() -> App {
+    subcommand("new")
+        .about("Create a new cargo package at <path>")
+        .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 (file)
index 0000000..dd7c5ad
--- /dev/null
@@ -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 (file)
index 0000000..59ba384
--- /dev/null
@@ -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 (file)
index 0000000..2633573
--- /dev/null
@@ -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 <spec> argument, print out the fully qualified package id specifier.
+This command will generate an error if <spec> is ambiguous as to which package
+it refers to in the dependency graph. If no <spec> 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 (file)
index 0000000..fc4ead2
--- /dev/null
@@ -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 (file)
index 0000000..ec6ffec
--- /dev/null
@@ -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 (file)
index 0000000..dae6c9d
--- /dev/null
@@ -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 (file)
index 0000000..8074a55
--- /dev/null
@@ -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
+<args>... 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 <args>...
+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 (file)
index 0000000..5db6ca9
--- /dev/null
@@ -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 <opts>... 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 <opts>...  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 (file)
index 0000000..62d023b
--- /dev/null
@@ -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 (file)
index 0000000..9c0ae57
--- /dev/null
@@ -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 (file)
index 0000000..5ab7513
--- /dev/null
@@ -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 (file)
index 0000000..523051c
--- /dev/null
@@ -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 <name> 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 (file)
index 0000000..926d801
--- /dev/null
@@ -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 (file)
index 0000000..0d7de9a
--- /dev/null
@@ -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 (file)
index 0000000..54039a3
--- /dev/null
@@ -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.
+")
+}