From: Aleksey Kladov Date: Mon, 12 Mar 2018 21:06:04 +0000 (+0300) Subject: File per command X-Git-Tag: archive/raspbian/0.35.0-2+rpi1~3^2^2^2^2^2^2^2~22^2~2^2~47^2 X-Git-Url: https://dgit.raspbian.org/?a=commitdiff_plain;h=6b9c063b422ea8417a3599b8f2aa344a474dab74;p=cargo.git File per command --- diff --git a/src/bin/cli.rs b/src/bin/cli.rs index 1b8b1e4ac..5d21d020c 100644 --- a/src/bin/cli.rs +++ b/src/bin/cli.rs @@ -1,19 +1,8 @@ extern crate clap; -use std::cmp::min; -use std::collections::HashMap; -use std::fs::File; -use std::io::{self, Read, BufRead}; -use std::process; - use clap::{AppSettings, Arg, ArgMatches}; -use toml; -use cargo::{self, Config, CargoError, CliResult, CliError}; -use cargo::core::{Source, SourceId, GitReference, Package, Verbosity}; -use cargo::ops::{self, CompileMode, OutputMetadataOptions}; -use cargo::sources::{GitSource, RegistrySource}; -use cargo::util::{ToUrl, CargoResultExt}; +use cargo::{self, Config, CliResult}; use super::list_commands; use super::commands; @@ -63,8 +52,6 @@ pub fn main(config: &mut Config) -> CliResult { } if args.subcommand_name().is_none() { - cli().print_help()?; - return Ok(()); } execute_subcommand(config, args) @@ -80,481 +67,28 @@ fn execute_subcommand(config: &mut Config, args: ArgMatches) -> CliResult { &args.values_of_lossy("unstable-features").unwrap_or_default(), )?; - match args.subcommand() { - ("bench", Some(args)) => { - let ws = args.workspace(config)?; - let mut compile_opts = args.compile_options(config, 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 = args.workspace(config)?; - let compile_opts = args.compile_options(config, CompileMode::Build)?; - ops::compile(&ws, &compile_opts)?; - Ok(()) - } - ("check", Some(args)) => { - let ws = args.workspace(config)?; - 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 = args.compile_options(config, mode)?; - ops::compile(&ws, &compile_opts)?; - Ok(()) - } - ("clean", Some(args)) => { - let ws = args.workspace(config)?; - let opts = ops::CleanOptions { - config, - spec: values(args, "package"), - target: args.target(), - release: args.is_present("release"), - }; - ops::clean(&ws, &opts)?; - Ok(()) - } - ("doc", Some(args)) => { - let ws = args.workspace(config)?; - let mode = ops::CompileMode::Doc { deps: !args.is_present("no-deps") }; - let compile_opts = args.compile_options(config, 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 = args.workspace(config)?; - ops::fetch(&ws)?; - Ok(()) - } - ("generate-lockfile", Some(args)) => { - let ws = args.workspace(config)?; - 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 opts = args.new_options()?; - ops::init(&opts, config)?; - config.shell().status("Created", format!("{} project", opts.kind))?; - Ok(()) - } - ("install", Some(args)) => { - let mut compile_opts = args.compile_options(config, CompileMode::Build)?; - compile_opts.release = !args.is_present("debug"); - - let krates = args.values_of("crate").unwrap_or_default().collect::>(); - - let source = if let Some(url) = args.value_of("git") { - let url = url.to_url()?; - let gitref = if let Some(branch) = args.value_of("branch") { - GitReference::Branch(branch.to_string()) - } else if let Some(tag) = args.value_of("tag") { - GitReference::Tag(tag.to_string()) - } else if let Some(rev) = args.value_of("rev") { - GitReference::Rev(rev.to_string()) - } else { - GitReference::Branch("master".to_string()) - }; - SourceId::for_git(&url, gitref)? - } else if let Some(path) = args.value_of("path") { - SourceId::for_path(&config.cwd().join(path))? - } else if krates.is_empty() { - SourceId::for_path(config.cwd())? - } else { - SourceId::crates_io(config)? - }; - - let version = args.value_of("version"); - let root = args.value_of("root"); - - if args.is_present("list") { - ops::install_list(root, config)?; - } else { - ops::install(root, krates, &source, version, &compile_opts, args.is_present("force"))?; - } - Ok(()) - } - ("locate-project", Some(args)) => { - let root = args.root_manifest(config)?; - - 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 = args.registry(config)?; - - 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(()) + let (cmd, args) = match args.subcommand() { + (cmd, Some(args)) => (cmd, args), + _ => { + cli().print_help()?; + return Ok(()); } - ("metadata", Some(args)) => { - let ws = args.workspace(config)?; - - 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 opts = args.new_options()?; - ops::new(&opts, config)?; - let path = args.value_of("path").unwrap(); - config.shell().status("Created", format!("{} `{}` project", opts.kind, path))?; - Ok(()) - } - ("owner", Some(args)) => { - let registry = args.registry(config)?; - 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 = args.workspace(config)?; - 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.target(), - jobs: args.jobs()?, - registry: None, - })?; - Ok(()) - } - ("pkgid", Some(args)) => { - let ws = args.workspace(config)?; - 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 = args.registry(config)?; - let ws = args.workspace(config)?; - let index = args.index(config)?; - - 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.target(), - jobs: args.jobs()?, - dry_run: args.is_present("dry-run"), - registry, - })?; - Ok(()) - } - ("read-manifest", Some(args)) => { - let root = args.root_manifest(config)?; - let pkg = Package::for_path(&root, config)?; - cargo::print_json(&pkg); - Ok(()) - } - ("run", Some(args)) => { - let ws = args.workspace(config)?; - - let mut compile_opts = args.compile_options_for_single_package( - config, 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); - let is_quiet = config.shell().verbosity() == Verbosity::Quiet; - Err(if is_quiet { - CliError::code(exit_code) - } else { - CliError::new(err.into(), exit_code) - }) - } - } - } - ("rustc", Some(args)) => { - let ws = args.workspace(config)?; - 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 = args.compile_options_for_single_package( - config, mode, - )?; - compile_opts.target_rustc_args = Some(values(args, "args")); - ops::compile(&ws, &compile_opts)?; - Ok(()) - } - ("rustdoc", Some(args)) => { - let ws = args.workspace(config)?; - let mut compile_opts = args.compile_options_for_single_package( - config, 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 = args.registry(config)?; - let index = args.index(config)?; - let limit = args.value_of_u32("limit")?; - 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 = args.workspace(config)?; - - let mut compile_opts = args.compile_options(config, 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 = args.workspace(config)?; - - 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 args.root_manifest(config) { - Ok(filename) => filename, - Err(e) => fail("invalid", &e.to_string()), - }; - - let file = File::open(&filename); - match file.and_then(|mut f| f.read_to_string(&mut contents)) { - Ok(_) => {} - Err(e) => fail("invalid", &format!("error reading file: {}", e)) - }; - if contents.parse::().is_err() { - fail("invalid", "invalid-format"); - } - - let mut h = HashMap::new(); - h.insert("success".to_string(), "true".to_string()); - cargo::print_json(&h); - Ok(()) - } - ("version", _) => { - println!("{}", cargo::version()); - Ok(()) - } - ("yank", Some(args)) => { - let registry = args.registry(config)?; + if let Some(exec) = commands::builtin_exec(cmd) { + return exec(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(()) + 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) } diff --git a/src/bin/command_prelude.rs b/src/bin/command_prelude.rs index 7f125b151..6f55ac19b 100644 --- a/src/bin/command_prelude.rs +++ b/src/bin/command_prelude.rs @@ -1,13 +1,14 @@ use std::path::PathBuf; -use clap::{self, SubCommand, AppSettings, ArgMatches}; -use cargo::{Config, CargoResult}; +use clap::{self, SubCommand}; +use cargo::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 use clap::{Arg, ArgMatches, AppSettings}; +pub use cargo::{Config, CliResult, CliError}; pub type App = clap::App<'static, 'static>; diff --git a/src/bin/commands/bench.rs b/src/bin/commands/bench.rs index df43b7801..e396e2bc7 100644 --- a/src/bin/commands/bench.rs +++ b/src/bin/commands/bench.rs @@ -1,5 +1,6 @@ use command_prelude::*; -use clap::AppSettings; + +use cargo::ops::{self, CompileMode, TestOptions}; pub fn cli() -> App { subcommand("bench") @@ -65,3 +66,31 @@ not affect how many jobs are used when running the benchmarks. Compilation can be customized with the `bench` profile in the manifest. ") } + +pub fn exec(config: &mut Config, args: &ArgMatches) -> CliResult { + let ws = args.workspace(config)?; + let mut compile_opts = args.compile_options(config, CompileMode::Bench)?; + compile_opts.release = true; + + let 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) + }) + } + } +} diff --git a/src/bin/commands/build.rs b/src/bin/commands/build.rs index 9eddd651b..a7312a033 100644 --- a/src/bin/commands/build.rs +++ b/src/bin/commands/build.rs @@ -1,5 +1,7 @@ use command_prelude::*; +use cargo::ops::{self, CompileMode}; + pub fn cli() -> App { subcommand("build").alias("b") .about("Compile a local package and all of its dependencies") @@ -42,3 +44,10 @@ the --release flag will use the `release` profile instead. ") } + +pub fn exec(config: &mut Config, args: &ArgMatches) -> CliResult { + let ws = args.workspace(config)?; + let compile_opts = args.compile_options(config, CompileMode::Build)?; + ops::compile(&ws, &compile_opts)?; + Ok(()) +} diff --git a/src/bin/commands/check.rs b/src/bin/commands/check.rs index ecf7fe6ce..7b141bb02 100644 --- a/src/bin/commands/check.rs +++ b/src/bin/commands/check.rs @@ -1,5 +1,7 @@ use command_prelude::*; +use cargo::ops::{self, CompileMode}; + pub fn cli() -> App { subcommand("check") .about("Check a local package and all of its dependencies for errors") @@ -48,3 +50,20 @@ The `--profile test` flag can be used to check unit tests with the `#[cfg(test)]` attribute. ") } + +pub fn exec(config: &mut Config, args: &ArgMatches) -> CliResult { + let ws = args.workspace(config)?; + 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 = args.compile_options(config, mode)?; + ops::compile(&ws, &compile_opts)?; + Ok(()) +} diff --git a/src/bin/commands/clean.rs b/src/bin/commands/clean.rs index 7852c3c5c..7159e2dfe 100644 --- a/src/bin/commands/clean.rs +++ b/src/bin/commands/clean.rs @@ -1,5 +1,7 @@ use command_prelude::*; +use cargo::ops::{self, CleanOptions}; + pub fn cli() -> App { subcommand("clean") .about("Remove artifacts that cargo has generated in the past") @@ -17,3 +19,15 @@ given, then all packages' artifacts are removed. For more information on SPEC and its format, see the `cargo help pkgid` command. ") } + +pub fn exec(config: &mut Config, args: &ArgMatches) -> CliResult { + let ws = args.workspace(config)?; + let opts = CleanOptions { + config, + spec: values(args, "package"), + target: args.target(), + release: args.is_present("release"), + }; + ops::clean(&ws, &opts)?; + Ok(()) +} diff --git a/src/bin/commands/doc.rs b/src/bin/commands/doc.rs index bcb709b29..505945732 100644 --- a/src/bin/commands/doc.rs +++ b/src/bin/commands/doc.rs @@ -1,5 +1,7 @@ use command_prelude::*; +use cargo::ops::{self, CompileMode, DocOptions}; + pub fn cli() -> App { subcommand("doc") .about("Build a package's documentation") @@ -39,3 +41,15 @@ current package is documented. For more information on SPEC and its format, see the `cargo help pkgid` command. ") } + +pub fn exec(config: &mut Config, args: &ArgMatches) -> CliResult { + let ws = args.workspace(config)?; + let mode = CompileMode::Doc { deps: !args.is_present("no-deps") }; + let compile_opts = args.compile_options(config, mode)?; + let doc_opts = DocOptions { + open_result: args.is_present("open"), + compile_opts, + }; + ops::doc(&ws, &doc_opts)?; + Ok(()) +} diff --git a/src/bin/commands/fetch.rs b/src/bin/commands/fetch.rs index bb4a946ab..1ccc2893f 100644 --- a/src/bin/commands/fetch.rs +++ b/src/bin/commands/fetch.rs @@ -1,5 +1,7 @@ use command_prelude::*; +use cargo::ops; + pub fn cli() -> App { subcommand("fetch") .about("Fetch dependencies of a package from the network") @@ -15,3 +17,9 @@ If the lockfile is not available, then this is the equivalent of all updated. ") } + +pub fn exec(config: &mut Config, args: &ArgMatches) -> CliResult { + let ws = args.workspace(config)?; + ops::fetch(&ws)?; + Ok(()) +} diff --git a/src/bin/commands/generate_lockfile.rs b/src/bin/commands/generate_lockfile.rs index 56ab283f4..e1ad63bcd 100644 --- a/src/bin/commands/generate_lockfile.rs +++ b/src/bin/commands/generate_lockfile.rs @@ -1,5 +1,7 @@ use command_prelude::*; +use cargo::ops; + pub fn cli() -> App { subcommand("generate-lockfile") .about("Generate the lockfile for a project") @@ -15,3 +17,9 @@ If the lockfile is not available, then this is the equivalent of all updated. ") } + +pub fn exec(config: &mut Config, args: &ArgMatches) -> CliResult { + let ws = args.workspace(config)?; + ops::generate_lockfile(&ws)?; + Ok(()) +} diff --git a/src/bin/commands/git_checkout.rs b/src/bin/commands/git_checkout.rs index 4bbcba133..1125e9b42 100644 --- a/src/bin/commands/git_checkout.rs +++ b/src/bin/commands/git_checkout.rs @@ -1,8 +1,26 @@ use command_prelude::*; +use cargo::core::{GitReference, SourceId, Source}; +use cargo::sources::GitSource; +use cargo::util::ToUrl; + 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)) } + +pub fn exec(config: &mut Config, args: &ArgMatches) -> CliResult { + 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(()) +} diff --git a/src/bin/commands/init.rs b/src/bin/commands/init.rs index 945ab9a74..24929000c 100644 --- a/src/bin/commands/init.rs +++ b/src/bin/commands/init.rs @@ -1,8 +1,17 @@ use command_prelude::*; +use cargo::ops; + pub fn cli() -> App { subcommand("init") .about("Create a new cargo package in an existing directory") .arg(Arg::with_name("path").default_value(".")) .arg_new_opts() } + +pub fn exec(config: &mut Config, args: &ArgMatches) -> CliResult { + let opts = args.new_options()?; + ops::init(&opts, config)?; + config.shell().status("Created", format!("{} project", opts.kind))?; + Ok(()) +} diff --git a/src/bin/commands/install.rs b/src/bin/commands/install.rs index ce1834d9d..813487950 100644 --- a/src/bin/commands/install.rs +++ b/src/bin/commands/install.rs @@ -1,5 +1,9 @@ use command_prelude::*; +use cargo::core::{GitReference, SourceId}; +use cargo::ops::{self, CompileMode}; +use cargo::util::ToUrl; + pub fn cli() -> App { subcommand("install") .about("Create a new cargo package in an existing directory") @@ -84,3 +88,40 @@ 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.") } + +pub fn exec(config: &mut Config, args: &ArgMatches) -> CliResult { + let mut compile_opts = args.compile_options(config, CompileMode::Build)?; + compile_opts.release = !args.is_present("debug"); + + let krates = args.values_of("crate").unwrap_or_default().collect::>(); + + let source = if let Some(url) = args.value_of("git") { + let url = url.to_url()?; + let gitref = if let Some(branch) = args.value_of("branch") { + GitReference::Branch(branch.to_string()) + } else if let Some(tag) = args.value_of("tag") { + GitReference::Tag(tag.to_string()) + } else if let Some(rev) = args.value_of("rev") { + GitReference::Rev(rev.to_string()) + } else { + GitReference::Branch("master".to_string()) + }; + SourceId::for_git(&url, gitref)? + } else if let Some(path) = args.value_of("path") { + SourceId::for_path(&config.cwd().join(path))? + } else if krates.is_empty() { + SourceId::for_path(config.cwd())? + } else { + SourceId::crates_io(config)? + }; + + let version = args.value_of("version"); + let root = args.value_of("root"); + + if args.is_present("list") { + ops::install_list(root, config)?; + } else { + ops::install(root, krates, &source, version, &compile_opts, args.is_present("force"))?; + } + Ok(()) +} diff --git a/src/bin/commands/locate_project.rs b/src/bin/commands/locate_project.rs index 1bddac4c2..b4662930c 100644 --- a/src/bin/commands/locate_project.rs +++ b/src/bin/commands/locate_project.rs @@ -1,7 +1,29 @@ use command_prelude::*; +use cargo::print_json; + pub fn cli() -> App { subcommand("locate-project") .about("Checkout a copy of a Git repository") .arg_manifest_path() } + +#[derive(Serialize)] +pub struct ProjectLocation { + root: String +} + +pub fn exec(config: &mut Config, args: &ArgMatches) -> CliResult { + let root = args.root_manifest(config)?; + + 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(); + + let location = ProjectLocation { root }; + + print_json(&location); + Ok(()) +} diff --git a/src/bin/commands/login.rs b/src/bin/commands/login.rs index 045770181..7f26ea2e8 100644 --- a/src/bin/commands/login.rs +++ b/src/bin/commands/login.rs @@ -1,5 +1,12 @@ use command_prelude::*; +use std::io::{self, BufRead}; + +use cargo::core::{SourceId, Source}; +use cargo::sources::RegistrySource; +use cargo::util::{CargoError, CargoResultExt}; +use cargo::ops; + pub fn cli() -> App { subcommand("login") .about("Save an api token from the registry locally. \ @@ -8,3 +15,37 @@ pub fn cli() -> App { .arg(opt("host", "Host to set the token for").value_name("HOST")) .arg(opt("registry", "Registry to use").value_name("REGISTRY")) } + +pub fn exec(config: &mut Config, args: &ArgMatches) -> CliResult { + let registry = args.registry(config)?; + + 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(()) +} diff --git a/src/bin/commands/metadata.rs b/src/bin/commands/metadata.rs index 7f4904c14..e3ebaff82 100644 --- a/src/bin/commands/metadata.rs +++ b/src/bin/commands/metadata.rs @@ -1,5 +1,8 @@ use command_prelude::*; +use cargo::ops::{self, OutputMetadataOptions}; +use cargo::print_json; + pub fn cli() -> App { subcommand("metadata") .about("Output the resolved dependencies of a project, \ @@ -16,3 +19,30 @@ pub fn cli() -> App { .value_name("VERSION").possible_value("1") ) } + +pub fn exec(config: &mut Config, args: &ArgMatches) -> CliResult { + let ws = args.workspace(config)?; + + 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)?; + print_json(&result); + Ok(()) +} diff --git a/src/bin/commands/mod.rs b/src/bin/commands/mod.rs index 6dea3eb16..6d8cb64a4 100644 --- a/src/bin/commands/mod.rs +++ b/src/bin/commands/mod.rs @@ -34,33 +34,68 @@ pub fn builtin() -> Vec { ] } +pub fn builtin_exec(cmd: & str) -> Option CliResult> { + let f = match cmd { + "bench" => bench::exec, + "build" => build::exec, + "check" => check::exec, + "clean" => clean::exec, + "doc" => doc::exec, + "fetch" => fetch::exec, + "generate-lockfile" => generate_lockfile::exec, + "git-checkout" => git_checkout::exec, + "init" => init::exec, + "install" => install::exec, + "locate-project" => locate_project::exec, + "login" => login::exec, + "metadata" => metadata::exec, + "new" => new::exec, + "owner" => owner::exec, + "package" => package::exec, + "pkgid" => pkgid::exec, + "publish" => publish::exec, + "read-manifest" => read_manifest::exec, + "run" => run::exec, + "rustc" => rustc::exec, + "rustdoc" => rustdoc::exec, + "search" => search::exec, + "test" => test::exec, + "uninstall" => uninstall::exec, + "update" => update::exec, + "verify-project" => verify_project::exec, + "version" => version::exec, + "yank" => yank::exec, + _ => return None, + }; + Some(f) +} -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; +pub mod bench; +pub mod build; +pub mod check; +pub mod clean; +pub mod doc; +pub mod fetch; +pub mod generate_lockfile; +pub mod git_checkout; +pub mod init; +pub mod install; +pub mod locate_project; +pub mod login; +pub mod metadata; +pub mod new; +pub mod owner; +pub mod package; +pub mod pkgid; +pub mod publish; +pub mod read_manifest; +pub mod run; +pub mod rustc; +pub mod rustdoc; +pub mod search; +pub mod test; +pub mod uninstall; +pub mod update; +pub mod verify_project; +pub mod version; +pub mod yank; diff --git a/src/bin/commands/new.rs b/src/bin/commands/new.rs index eb03e37d5..d41f8cce4 100644 --- a/src/bin/commands/new.rs +++ b/src/bin/commands/new.rs @@ -1,8 +1,18 @@ use command_prelude::*; +use cargo::ops; + pub fn cli() -> App { subcommand("new") .about("Create a new cargo package at ") .arg(Arg::with_name("path").required(true)) .arg_new_opts() } + +pub fn exec(config: &mut Config, args: &ArgMatches) -> CliResult { + let opts = args.new_options()?; + ops::new(&opts, config)?; + let path = args.value_of("path").unwrap(); + config.shell().status("Created", format!("{} `{}` project", opts.kind, path))?; + Ok(()) +} diff --git a/src/bin/commands/owner.rs b/src/bin/commands/owner.rs index dd7c5adf1..41823de9e 100644 --- a/src/bin/commands/owner.rs +++ b/src/bin/commands/owner.rs @@ -1,5 +1,7 @@ use command_prelude::*; +use cargo::ops::{self, OwnersOptions}; + pub fn cli() -> App { subcommand("owner") .about("Manage the owners of a crate on the registry") @@ -26,3 +28,20 @@ pub fn cli() -> App { See http://doc.crates.io/crates-io.html#cargo-owner for detailed documentation and troubleshooting.") } + +pub fn exec(config: &mut Config, args: &ArgMatches) -> CliResult { + let registry = args.registry(config)?; + let opts = 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(()) +} diff --git a/src/bin/commands/package.rs b/src/bin/commands/package.rs index 59ba384b7..eb2306192 100644 --- a/src/bin/commands/package.rs +++ b/src/bin/commands/package.rs @@ -1,5 +1,8 @@ use command_prelude::*; +use cargo::ops::{self, PackageOpts}; + + pub fn cli() -> App { subcommand("package") .about("Assemble the local package into a distributable tarball") @@ -11,3 +14,18 @@ pub fn cli() -> App { .arg_manifest_path() .arg_jobs() } + +pub fn exec(config: &mut Config, args: &ArgMatches) -> CliResult { + let ws = args.workspace(config)?; + ops::package(&ws, &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.target(), + jobs: args.jobs()?, + registry: None, + })?; + Ok(()) +} diff --git a/src/bin/commands/pkgid.rs b/src/bin/commands/pkgid.rs index 26335735a..9777915d0 100644 --- a/src/bin/commands/pkgid.rs +++ b/src/bin/commands/pkgid.rs @@ -1,5 +1,7 @@ use command_prelude::*; +use cargo::ops; + pub fn cli() -> App { subcommand("pkgid") .about("Print a fully qualified package specification") @@ -27,3 +29,11 @@ Example Package IDs http://crates.io/foo#1.2.3 | foo | 1.2.3 | http://crates.io/foo ") } + +pub fn exec(config: &mut Config, args: &ArgMatches) -> CliResult { + let ws = args.workspace(config)?; + let spec = args.value_of("spec").or(args.value_of("package")); + let spec = ops::pkgid(&ws, spec)?; + println!("{}", spec); + Ok(()) +} diff --git a/src/bin/commands/publish.rs b/src/bin/commands/publish.rs index fc4ead218..31c7c9522 100644 --- a/src/bin/commands/publish.rs +++ b/src/bin/commands/publish.rs @@ -1,5 +1,7 @@ use command_prelude::*; +use cargo::ops::{self, PublishOpts}; + pub fn cli() -> App { subcommand("publish") .about("Upload a package to the registry") @@ -15,3 +17,22 @@ pub fn cli() -> App { ) .arg(opt("registry", "Registry to publish to").value_name("REGISTRY")) } + +pub fn exec(config: &mut Config, args: &ArgMatches) -> CliResult { + let registry = args.registry(config)?; + let ws = args.workspace(config)?; + let index = args.index(config)?; + + ops::publish(&ws, &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.target(), + jobs: args.jobs()?, + dry_run: args.is_present("dry-run"), + registry, + })?; + Ok(()) +} diff --git a/src/bin/commands/read_manifest.rs b/src/bin/commands/read_manifest.rs index ec6ffec83..d89fe5b7a 100644 --- a/src/bin/commands/read_manifest.rs +++ b/src/bin/commands/read_manifest.rs @@ -1,8 +1,18 @@ use command_prelude::*; +use cargo::core::Package; +use cargo::print_json; + 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() } + +pub fn exec(config: &mut Config, args: &ArgMatches) -> CliResult { + let root = args.root_manifest(config)?; + let pkg = Package::for_path(&root, config)?; + print_json(&pkg); + Ok(()) +} diff --git a/src/bin/commands/run.rs b/src/bin/commands/run.rs index dae6c9de2..535ae5add 100644 --- a/src/bin/commands/run.rs +++ b/src/bin/commands/run.rs @@ -1,7 +1,8 @@ -use clap::AppSettings; - use command_prelude::*; +use cargo::core::Verbosity; +use cargo::ops::{self, CompileMode, CompileFilter}; + pub fn cli() -> App { subcommand("run").alias("r") .setting(AppSettings::TrailingVarArg) @@ -29,3 +30,38 @@ arguments to both Cargo and the binary, the ones after `--` go to the binary, the ones before go to Cargo. ") } + +pub fn exec(config: &mut Config, args: &ArgMatches) -> CliResult { + let ws = args.workspace(config)?; + + let mut compile_opts = args.compile_options_for_single_package( + config, CompileMode::Build, + )?; + if !args.is_present("example") && !args.is_present("bin") { + compile_opts.filter = 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); + let is_quiet = config.shell().verbosity() == Verbosity::Quiet; + Err(if is_quiet { + CliError::code(exit_code) + } else { + CliError::new(err.into(), exit_code) + }) + } + } +} diff --git a/src/bin/commands/rustc.rs b/src/bin/commands/rustc.rs index 8074a551e..ea4c71b61 100644 --- a/src/bin/commands/rustc.rs +++ b/src/bin/commands/rustc.rs @@ -1,7 +1,7 @@ -use clap::AppSettings; - use command_prelude::*; +use cargo::ops::{self, CompileMode}; + pub fn cli() -> App { subcommand("rustc") .setting(AppSettings::TrailingVarArg) @@ -45,3 +45,24 @@ processes spawned by Cargo, use the $RUSTFLAGS environment variable or the `build.rustflags` configuration option. ") } + +pub fn exec(config: &mut Config, args: &ArgMatches) -> CliResult { + let ws = args.workspace(config)?; + 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 = args.compile_options_for_single_package( + config, mode, + )?; + compile_opts.target_rustc_args = Some(values(args, "args")); + ops::compile(&ws, &compile_opts)?; + Ok(()) +} diff --git a/src/bin/commands/rustdoc.rs b/src/bin/commands/rustdoc.rs index 5db6ca9dd..5b4fbd688 100644 --- a/src/bin/commands/rustdoc.rs +++ b/src/bin/commands/rustdoc.rs @@ -1,7 +1,7 @@ -use clap::AppSettings; - use command_prelude::*; +use cargo::ops::{self, CompileMode, DocOptions}; + pub fn cli() -> App { subcommand("rustdoc") .setting(AppSettings::TrailingVarArg) @@ -39,3 +39,17 @@ current package is documented. For more information on SPEC and its format, see the `cargo help pkgid` command. ") } + +pub fn exec(config: &mut Config, args: &ArgMatches) -> CliResult { + let ws = args.workspace(config)?; + let mut compile_opts = args.compile_options_for_single_package( + config, CompileMode::Doc { deps: false }, + )?; + compile_opts.target_rustdoc_args = Some(values(args, "args")); + let doc_opts = DocOptions { + open_result: args.is_present("open"), + compile_opts, + }; + ops::doc(&ws, &doc_opts)?; + Ok(()) +} diff --git a/src/bin/commands/search.rs b/src/bin/commands/search.rs index 62d023b0f..9b28e1f78 100644 --- a/src/bin/commands/search.rs +++ b/src/bin/commands/search.rs @@ -1,5 +1,9 @@ use command_prelude::*; +use std::cmp::min; + +use cargo::ops; + pub fn cli() -> App { subcommand("search") .about("Search packages in crates.io") @@ -11,3 +15,14 @@ pub fn cli() -> App { ) .arg(opt("registry", "Registry to use").value_name("REGISTRY")) } + +pub fn exec(config: &mut Config, args: &ArgMatches) -> CliResult { + let registry = args.registry(config)?; + let index = args.index(config)?; + let limit = args.value_of_u32("limit")?; + 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(()) +} diff --git a/src/bin/commands/test.rs b/src/bin/commands/test.rs index 9c0ae57b7..83be8de24 100644 --- a/src/bin/commands/test.rs +++ b/src/bin/commands/test.rs @@ -1,5 +1,6 @@ use command_prelude::*; -use clap::AppSettings; + +use cargo::ops::{self, CompileMode}; pub fn cli() -> App { subcommand("test").alias("t") @@ -82,3 +83,43 @@ To get the list of all options available for the test binaries use this: cargo test -- --help ") } + +pub fn exec(config: &mut Config, args: &ArgMatches) -> CliResult { + let ws = args.workspace(config)?; + + let mut compile_opts = args.compile_options(config, 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), + }) + } + }; +} diff --git a/src/bin/commands/uninstall.rs b/src/bin/commands/uninstall.rs index 5ab7513e5..cf62c4c79 100644 --- a/src/bin/commands/uninstall.rs +++ b/src/bin/commands/uninstall.rs @@ -1,5 +1,7 @@ use command_prelude::*; +use cargo::ops; + pub fn cli() -> App { subcommand("uninstall") .about("Remove a Rust binary") @@ -19,3 +21,10 @@ uninstalled for a crate but the `--bin` and `--example` flags can be used to only uninstall particular binaries. ") } + +pub fn exec(config: &mut Config, args: &ArgMatches) -> CliResult { + 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(()) +} diff --git a/src/bin/commands/update.rs b/src/bin/commands/update.rs index 523051c25..c857234bf 100644 --- a/src/bin/commands/update.rs +++ b/src/bin/commands/update.rs @@ -1,5 +1,7 @@ use command_prelude::*; +use cargo::ops::{self, UpdateOptions}; + pub fn cli() -> App { subcommand("update") .about("Update dependencies as recorded in the local lock file") @@ -35,3 +37,16 @@ updated. For more information about package id specifications, see `cargo help pkgid`. ") } + +pub fn exec(config: &mut Config, args: &ArgMatches) -> CliResult { + let ws = args.workspace(config)?; + + let update_opts = UpdateOptions { + aggressive: args.is_present("aggressive"), + precise: args.value_of("precise"), + to_update: values(args, "package"), + config, + }; + ops::update_lockfile(&ws, &update_opts)?; + Ok(()) +} diff --git a/src/bin/commands/verify_project.rs b/src/bin/commands/verify_project.rs index 926d8014c..93afa4bef 100644 --- a/src/bin/commands/verify_project.rs +++ b/src/bin/commands/verify_project.rs @@ -1,7 +1,45 @@ use command_prelude::*; +use std::collections::HashMap; +use std::process; +use std::fs::File; +use std::io::Read; + +use toml; + +use cargo::print_json; + pub fn cli() -> App { subcommand("verify-project") .about("Check correctness of crate manifest") .arg_manifest_path() } + +pub fn exec(config: &mut Config, args: &ArgMatches) -> CliResult { + fn fail(reason: &str, value: &str) -> ! { + let mut h = HashMap::new(); + h.insert(reason.to_string(), value.to_string()); + print_json(&h); + process::exit(1) + } + + let mut contents = String::new(); + let filename = match args.root_manifest(config) { + Ok(filename) => filename, + Err(e) => fail("invalid", &e.to_string()), + }; + + let file = File::open(&filename); + match file.and_then(|mut f| f.read_to_string(&mut contents)) { + Ok(_) => {} + Err(e) => fail("invalid", &format!("error reading file: {}", e)) + }; + if contents.parse::().is_err() { + fail("invalid", "invalid-format"); + } + + let mut h = HashMap::new(); + h.insert("success".to_string(), "true".to_string()); + print_json(&h); + Ok(()) +} diff --git a/src/bin/commands/version.rs b/src/bin/commands/version.rs index 0d7de9a6c..9f7538866 100644 --- a/src/bin/commands/version.rs +++ b/src/bin/commands/version.rs @@ -1,6 +1,13 @@ use command_prelude::*; +use cargo; + pub fn cli() -> App { subcommand("version") .about("Show version information") } + +pub fn exec(_config: &mut Config, _args: &ArgMatches) -> CliResult { + println!("{}", cargo::version()); + Ok(()) +} diff --git a/src/bin/commands/yank.rs b/src/bin/commands/yank.rs index 54039a3b1..2defd080c 100644 --- a/src/bin/commands/yank.rs +++ b/src/bin/commands/yank.rs @@ -1,5 +1,7 @@ use command_prelude::*; +use cargo::ops; + pub fn cli() -> App { subcommand("yank") .about("Remove a pushed crate from the index") @@ -21,3 +23,16 @@ download the yanked version to use it. Cargo will, however, not allow any new crates to be locked to any yanked version. ") } + +pub fn exec(config: &mut Config, args: &ArgMatches) -> CliResult { + let registry = args.registry(config)?; + + 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(()) +}