From: Eric Huss Date: Thu, 3 May 2018 16:13:36 +0000 (-0700) Subject: Address autobins warning. X-Git-Tag: archive/raspbian/0.35.0-2+rpi1~3^2^2^2^2^2^2^2~22^2~1^2~19^2 X-Git-Url: https://dgit.raspbian.org/?a=commitdiff_plain;h=795f69b3dd8b2db3345955c0fcd20380cdd48b41;p=cargo.git Address autobins warning. --- diff --git a/src/bin/cargo.rs b/src/bin/cargo.rs deleted file mode 100644 index 7d7c7db6e..000000000 --- a/src/bin/cargo.rs +++ /dev/null @@ -1,212 +0,0 @@ -extern crate cargo; -extern crate clap; -extern crate env_logger; -#[macro_use] -extern crate failure; -extern crate git2_curl; -extern crate log; -#[macro_use] -extern crate serde_derive; -extern crate serde_json; -extern crate toml; - -use std::env; -use std::fs; -use std::path::{Path, PathBuf}; -use std::collections::BTreeSet; - -use cargo::core::shell::Shell; -use cargo::util::{self, lev_distance, CargoResult, CliResult, Config}; -use cargo::util::{CliError, ProcessError}; - -mod cli; -mod command_prelude; -mod commands; - -fn main() { - env_logger::init(); - - let mut config = match Config::default() { - Ok(cfg) => cfg, - Err(e) => { - let mut shell = Shell::new(); - cargo::exit_with_error(e.into(), &mut shell) - } - }; - - let result = { - init_git_transports(&mut config); - let _token = cargo::util::job::setup(); - cli::main(&mut config) - }; - - match result { - Err(e) => cargo::exit_with_error(e, &mut *config.shell()), - Ok(()) => {} - } -} - -fn aliased_command(config: &Config, command: &str) -> CargoResult>> { - let alias_name = format!("alias.{}", command); - let mut result = Ok(None); - match config.get_string(&alias_name) { - Ok(value) => { - if let Some(record) = value { - let alias_commands = record - .val - .split_whitespace() - .map(|s| s.to_string()) - .collect(); - result = Ok(Some(alias_commands)); - } - } - Err(_) => { - let value = config.get_list(&alias_name)?; - if let Some(record) = value { - let alias_commands: Vec = - record.val.iter().map(|s| s.0.to_string()).collect(); - result = Ok(Some(alias_commands)); - } - } - } - result -} - -/// List all runnable commands -fn list_commands(config: &Config) -> BTreeSet<(String, Option)> { - let prefix = "cargo-"; - let suffix = env::consts::EXE_SUFFIX; - let mut commands = BTreeSet::new(); - for dir in search_directories(config) { - let entries = match fs::read_dir(dir) { - Ok(entries) => entries, - _ => continue, - }; - for entry in entries.filter_map(|e| e.ok()) { - let path = entry.path(); - let filename = match path.file_name().and_then(|s| s.to_str()) { - Some(filename) => filename, - _ => continue, - }; - if !filename.starts_with(prefix) || !filename.ends_with(suffix) { - continue; - } - if is_executable(entry.path()) { - let end = filename.len() - suffix.len(); - commands.insert(( - filename[prefix.len()..end].to_string(), - Some(path.display().to_string()), - )); - } - } - } - - for cmd in commands::builtin() { - commands.insert((cmd.get_name().to_string(), None)); - } - - commands -} - -fn find_closest(config: &Config, cmd: &str) -> Option { - let cmds = list_commands(config); - // Only consider candidates with a lev_distance of 3 or less so we don't - // suggest out-of-the-blue options. - let mut filtered = cmds.iter() - .map(|&(ref c, _)| (lev_distance(c, cmd), c)) - .filter(|&(d, _)| d < 4) - .collect::>(); - filtered.sort_by(|a, b| a.0.cmp(&b.0)); - filtered.get(0).map(|slot| slot.1.clone()) -} - -fn execute_external_subcommand(config: &Config, cmd: &str, args: &[&str]) -> CliResult { - let command_exe = format!("cargo-{}{}", cmd, env::consts::EXE_SUFFIX); - let path = search_directories(config) - .iter() - .map(|dir| dir.join(&command_exe)) - .find(|file| is_executable(file)); - let command = match path { - Some(command) => command, - None => { - let err = match find_closest(config, cmd) { - Some(closest) => format_err!( - "no such subcommand: `{}`\n\n\tDid you mean `{}`?\n", - cmd, - closest - ), - None => format_err!("no such subcommand: `{}`", cmd), - }; - return Err(CliError::new(err, 101)); - } - }; - - let cargo_exe = config.cargo_exe()?; - let err = match util::process(&command) - .env(cargo::CARGO_ENV, cargo_exe) - .args(args) - .exec_replace() - { - Ok(()) => return Ok(()), - Err(e) => e, - }; - - if let Some(perr) = err.downcast_ref::() { - if let Some(code) = perr.exit.as_ref().and_then(|c| c.code()) { - return Err(CliError::code(code)); - } - } - Err(CliError::new(err, 101)) -} - -#[cfg(unix)] -fn is_executable>(path: P) -> bool { - use std::os::unix::prelude::*; - fs::metadata(path) - .map(|metadata| metadata.is_file() && metadata.permissions().mode() & 0o111 != 0) - .unwrap_or(false) -} -#[cfg(windows)] -fn is_executable>(path: P) -> bool { - fs::metadata(path) - .map(|metadata| metadata.is_file()) - .unwrap_or(false) -} - -fn search_directories(config: &Config) -> Vec { - let mut dirs = vec![config.home().clone().into_path_unlocked().join("bin")]; - if let Some(val) = env::var_os("PATH") { - dirs.extend(env::split_paths(&val)); - } - dirs -} - -fn init_git_transports(config: &Config) { - // Only use a custom transport if any HTTP options are specified, - // such as proxies or custom certificate authorities. The custom - // transport, however, is not as well battle-tested. - - match cargo::ops::needs_custom_http_transport(config) { - Ok(true) => {} - _ => return, - } - - let handle = match cargo::ops::http_handle(config) { - Ok(handle) => handle, - Err(..) => return, - }; - - // The unsafety of the registration function derives from two aspects: - // - // 1. This call must be synchronized with all other registration calls as - // well as construction of new transports. - // 2. The argument is leaked. - // - // We're clear on point (1) because this is only called at the start of this - // binary (we know what the state of the world looks like) and we're mostly - // clear on point (2) because we'd only free it after everything is done - // anyway - unsafe { - git2_curl::register(handle); - } -} diff --git a/src/bin/cargo/cli.rs b/src/bin/cargo/cli.rs new file mode 100644 index 000000000..9fbd12cbc --- /dev/null +++ b/src/bin/cargo/cli.rs @@ -0,0 +1,214 @@ +extern crate clap; + +use clap::{AppSettings, Arg, ArgMatches}; + +use cargo::{self, CliResult, Config}; + +use super::list_commands; +use super::commands; +use command_prelude::*; + +pub fn main(config: &mut Config) -> CliResult { + let args = cli().get_matches_safe()?; + + if args.value_of("unstable-features") == Some("help") { + println!( + " +Available unstable (nightly-only) flags: + + -Z avoid-dev-deps -- Avoid installing dev-dependencies if possible + -Z minimal-versions -- Install minimal dependency versions instead of maximum + -Z no-index-update -- Do not update the registry, avoids a network request for benchmarking + -Z offline -- Offline mode that does not perform network requests + -Z unstable-options -- Allow the usage of unstable options such as --registry + +Run with 'cargo -Z [FLAG] [SUBCOMMAND]'" + ); + return Ok(()); + } + + 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(None)?.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(()); + } + + let args = expand_aliases(config, args)?; + + execute_subcommand(config, args) +} + +fn expand_aliases( + config: &mut Config, + args: ArgMatches<'static>, +) -> Result, CliError> { + if let (cmd, Some(args)) = args.subcommand() { + match ( + commands::builtin_exec(cmd), + super::aliased_command(config, cmd)?, + ) { + (None, Some(mut alias)) => { + 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 expand_aliases(config, args); + } + (Some(_), Some(_)) => { + config.shell().warn(format!( + "alias `{}` is ignored, because it is shadowed by a built in command", + cmd + ))?; + } + (_, None) => {} + } + }; + Ok(args) +} + +fn execute_subcommand(config: &mut Config, args: ArgMatches) -> CliResult { + let (cmd, subcommand_args) = match args.subcommand() { + (cmd, Some(args)) => (cmd, args), + _ => { + cli().print_help()?; + return Ok(()); + } + }; + + let arg_target_dir = &subcommand_args.value_of_path("target-dir", config); + + config.configure( + args.occurrences_of("verbose") as u32, + if args.is_present("quiet") { + Some(true) + } else { + None + }, + &args.value_of("color").map(|s| s.to_string()), + args.is_present("frozen"), + args.is_present("locked"), + arg_target_dir, + &args.values_of_lossy("unstable-features") + .unwrap_or_default(), + )?; + + if let Some(exec) = commands::builtin_exec(cmd) { + return exec(config, subcommand_args); + } + + let mut ext_args: Vec<&str> = vec![cmd]; + ext_args.extend(subcommand_args.values_of("").unwrap_or_default()); + super::execute_external_subcommand(config, cmd, &ext_args) +} + +fn cli() -> App { + let app = App::new("cargo") + .settings(&[ + AppSettings::UnifiedHelpMessage, + AppSettings::DeriveDisplayOrder, + AppSettings::VersionlessSubcommands, + AppSettings::AllowExternalSubcommands, + ]) + .about("") + .template( + "\ +Rust's package manager + +USAGE: + {usage} + +OPTIONS: +{unified} + +Some common cargo commands are (see all commands with --list): + build Compile the current project + check Analyze the current project and report errors, but don't build object files + clean Remove the target directory + doc Build this project's and its dependencies' documentation + new Create a new cargo project + init Create a new cargo project in an existing directory + run Build and execute src/main.rs + test Run the tests + bench Run the benchmarks + update Update dependencies listed in Cargo.lock + search Search registry for crates + publish Package and upload this project to the registry + install Install a Rust binary + uninstall Uninstall a Rust binary + +See 'cargo help ' for more information on a specific command.\n", + ) + .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("quiet", "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, see 'cargo -Z help' for details") + .short("Z") + .value_name("FLAG") + .multiple(true) + .number_of_values(1) + .global(true), + ) + .subcommands(commands::builtin()); + app +} diff --git a/src/bin/cargo/command_prelude.rs b/src/bin/cargo/command_prelude.rs new file mode 100644 index 000000000..2f6a04624 --- /dev/null +++ b/src/bin/cargo/command_prelude.rs @@ -0,0 +1,402 @@ +use std::path::PathBuf; +use std::fs; + +use clap::{self, SubCommand}; +use cargo::CargoResult; +use cargo::core::Workspace; +use cargo::ops::{CompileFilter, CompileMode, CompileOptions, MessageFormat, NewOptions, Packages, + VersionControl}; +use cargo::util::paths; +use cargo::util::important_paths::find_root_manifest_for_wd; + +pub use clap::{AppSettings, Arg, ArgMatches}; +pub use cargo::{CliError, CliResult, Config}; + +pub type App = clap::App<'static, 'static>; + +pub trait AppExt: Sized { + fn _arg(self, arg: Arg<'static, 'static>) -> Self; + + fn arg_package_spec( + self, + package: &'static str, + all: &'static str, + exclude: &'static str, + ) -> Self { + self.arg_package_spec_simple(package) + ._arg(opt("all", all)) + ._arg(multi_opt("exclude", "SPEC", exclude)) + } + + fn arg_package_spec_simple(self, package: &'static str) -> Self { + self._arg(multi_opt("package", "SPEC", package).short("p")) + } + + fn arg_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, + example: &'static str, + examples: &'static str, + test: &'static str, + tests: &'static str, + bench: &'static str, + benches: &'static str, + all: &'static str, + ) -> Self { + self.arg_targets_lib_bin(lib, bin, bins) + ._arg(multi_opt("example", "NAME", example)) + ._arg(opt("examples", examples)) + ._arg(multi_opt("test", "NAME", test)) + ._arg(opt("tests", tests)) + ._arg(multi_opt("bench", "NAME", bench)) + ._arg(opt("benches", benches)) + ._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(multi_opt("bin", "NAME", bin)) + ._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(multi_opt("bin", "NAME", bin)) + ._arg(opt("bins", bins)) + ._arg(multi_opt("example", "NAME", example)) + ._arg(opt("examples", examples)) + } + + fn arg_targets_bin_example(self, bin: &'static str, example: &'static str) -> Self { + self._arg(multi_opt("bin", "NAME", bin)) + ._arg(multi_opt("example", "NAME", example)) + } + + 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_doc(self, doc: &'static str) -> Self { + self._arg(opt("doc", doc)) + } + + fn arg_target_triple(self, target: &'static str) -> Self { + self._arg(opt("target", target).value_name("TRIPLE")) + } + + fn arg_target_dir(self) -> Self { + self._arg(opt("target-dir", "Directory for all generated artifacts").value_name("DIRECTORY")) + } + + 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 AppExt 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 multi_opt( + name: &'static str, + value_name: &'static str, + help: &'static str, +) -> Arg<'static, 'static> { + // Note that all `.multiple(true)` arguments in Cargo should specify + // `.number_of_values(1)` as well, so that `--foo val1 val2` is + // **not** parsed as `foo` with values ["val1", "val2"]. + // `number_of_values` should become the default in clap 3. + opt(name, help) + .value_name(value_name) + .multiple(true) + .number_of_values(1) +} + +pub fn subcommand(name: &'static str) -> App { + SubCommand::with_name(name).settings(&[ + AppSettings::UnifiedHelpMessage, + AppSettings::DeriveDisplayOrder, + AppSettings::DontCollapseArgsInUsage, + ]) +} + +pub trait ArgMatchesExt { + fn value_of_u32(&self, name: &str) -> CargoResult> { + let arg = match self._value_of(name) { + None => None, + Some(arg) => Some(arg.parse::().map_err(|_| { + clap::Error::value_validation_auto(format!("could not parse `{}` as a number", arg)) + })?), + }; + Ok(arg) + } + + /// Returns value of the `name` command-line argument as an absolute path + fn value_of_path(&self, name: &str, config: &Config) -> Option { + self._value_of(name).map(|path| config.cwd().join(path)) + } + + fn root_manifest(&self, config: &Config) -> CargoResult { + if let Some(path) = self.value_of_path("manifest-path", config) { + // In general, we try to avoid normalizing paths in Cargo, + // but in this particular case we need it to fix #3586. + let path = paths::normalize_path(&path); + if !path.ends_with("Cargo.toml") { + bail!("the manifest-path must be a path to a Cargo.toml file") + } + if !fs::metadata(&path).is_ok() { + bail!( + "manifest path `{}` does not exist", + self._value_of("manifest-path").unwrap() + ) + } + return Ok(path); + } + find_root_manifest_for_wd(config.cwd()) + } + + fn workspace<'a>(&self, config: &'a Config) -> CargoResult> { + let root = self.root_manifest(config)?; + let mut ws = Workspace::new(&root, config)?; + if config.cli_unstable().avoid_dev_deps { + ws.set_require_optional_deps(false); + } + Ok(ws) + } + + fn jobs(&self) -> CargoResult> { + self.value_of_u32("jobs") + } + + fn target(&self) -> Option { + self._value_of("target").map(|s| s.to_string()) + } + + fn compile_options<'a>( + &self, + config: &'a Config, + mode: CompileMode, + ) -> CargoResult> { + let spec = Packages::from_flags( + self._is_present("all"), + self._values_of("exclude"), + self._values_of("package"), + )?; + + let message_format = match self._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: self.jobs()?, + target: self.target(), + features: self._values_of("features"), + all_features: self._is_present("all-features"), + no_default_features: self._is_present("no-default-features"), + spec, + mode, + release: self._is_present("release"), + filter: CompileFilter::new( + self._is_present("lib"), + self._values_of("bin"), + self._is_present("bins"), + self._values_of("test"), + self._is_present("tests"), + self._values_of("example"), + self._is_present("examples"), + self._values_of("bench"), + self._is_present("benches"), + self._is_present("all-targets"), + ), + message_format, + target_rustdoc_args: None, + target_rustc_args: None, + export_dir: None, + }; + Ok(opts) + } + + fn compile_options_for_single_package<'a>( + &self, + config: &'a Config, + mode: CompileMode, + ) -> CargoResult> { + let mut compile_opts = self.compile_options(config, mode)?; + compile_opts.spec = Packages::Packages(self._values_of("package")); + Ok(compile_opts) + } + + fn new_options(&self, config: &Config) -> CargoResult { + let vcs = self._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, + self._is_present("bin"), + self._is_present("lib"), + self.value_of_path("path", config).unwrap(), + self._value_of("name").map(|s| s.to_string()), + ) + } + + fn registry(&self, config: &Config) -> CargoResult> { + match self._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), + } + } + + fn index(&self, config: &Config) -> CargoResult> { + // TODO: Deprecated + // remove once it has been decided --host can be removed + // We may instead want to repurpose the host flag, as + // mentioned in this issue + // https://github.com/rust-lang/cargo/issues/4208 + let msg = "The flag '--host' is no longer valid. + +Previous versions of Cargo accepted this flag, but it is being +deprecated. The flag is being renamed to 'index', as the flag +wants the location of the index. Please use '--index' instead. + +This will soon become a hard error, so it's either recommended +to update to a fixed version or contact the upstream maintainer +about this warning."; + + let index = match self._value_of("host") { + Some(host) => { + config.shell().warn(&msg)?; + Some(host.to_string()) + } + None => self._value_of("index").map(|s| s.to_string()), + }; + Ok(index) + } + + fn _value_of(&self, name: &str) -> Option<&str>; + + fn _values_of(&self, name: &str) -> Vec; + + fn _is_present(&self, name: &str) -> bool; +} + +impl<'a> ArgMatchesExt for ArgMatches<'a> { + fn _value_of(&self, name: &str) -> Option<&str> { + self.value_of(name) + } + + fn _values_of(&self, name: &str) -> Vec { + self.values_of(name) + .unwrap_or_default() + .map(|s| s.to_string()) + .collect() + } + + fn _is_present(&self, name: &str) -> bool { + self.is_present(name) + } +} + +pub fn values(args: &ArgMatches, name: &str) -> Vec { + args.values_of(name) + .unwrap_or_default() + .map(|s| s.to_string()) + .collect() +} diff --git a/src/bin/cargo/commands/bench.rs b/src/bin/cargo/commands/bench.rs new file mode 100644 index 000000000..83e3ab5af --- /dev/null +++ b/src/bin/cargo/commands/bench.rs @@ -0,0 +1,105 @@ +use command_prelude::*; + +use cargo::ops::{self, CompileMode, TestOptions}; + +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_spec( + "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_target_dir() + .arg_manifest_path() + .arg_message_format() + .arg(opt( + "no-fail-fast", + "Run all benchmarks regardless of failure", + )) + .after_help( + "\ +The benchmark filtering argument `BENCHNAME` and all the arguments following the +two dashes (`--`) are passed to the benchmark binaries and thus to libtest +(rustc's built in unit-test and micro-benchmarking framework). If you're +passing arguments to both Cargo and the binary, the ones after `--` go to the +binary, the ones before go to Cargo. For details about libtest's arguments see +the output of `cargo bench -- --help`. + +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. +", + ) +} + +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/cargo/commands/build.rs b/src/bin/cargo/commands/build.rs new file mode 100644 index 000000000..0ab86aa3a --- /dev/null +++ b/src/bin/cargo/commands/build.rs @@ -0,0 +1,63 @@ +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") + .arg_package_spec( + "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_target_dir() + .arg(opt("out-dir", "Copy final artifacts to this directory").value_name("PATH")) + .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. +", + ) +} + +pub fn exec(config: &mut Config, args: &ArgMatches) -> CliResult { + let ws = args.workspace(config)?; + let mut compile_opts = args.compile_options(config, CompileMode::Build)?; + compile_opts.export_dir = args.value_of_path("out-dir", config); + if compile_opts.export_dir.is_some() && !config.cli_unstable().unstable_options { + Err(format_err!( + "`--out-dir` flag is unstable, pass `-Z unstable-options` to enable it" + ))?; + }; + ops::compile(&ws, &compile_opts)?; + Ok(()) +} diff --git a/src/bin/cargo/commands/check.rs b/src/bin/cargo/commands/check.rs new file mode 100644 index 000000000..e4295c5c3 --- /dev/null +++ b/src/bin/cargo/commands/check.rs @@ -0,0 +1,72 @@ +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") + .arg_package_spec( + "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_target_dir() + .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. +", + ) +} + +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/cargo/commands/clean.rs b/src/bin/cargo/commands/clean.rs new file mode 100644 index 000000000..a7606a644 --- /dev/null +++ b/src/bin/cargo/commands/clean.rs @@ -0,0 +1,35 @@ +use command_prelude::*; + +use cargo::ops::{self, CleanOptions}; + +pub fn cli() -> App { + subcommand("clean") + .about("Remove artifacts that cargo has generated in the past") + .arg_package_spec_simple("Package to clean artifacts for") + .arg_manifest_path() + .arg_target_triple("Target triple to clean output for (default all)") + .arg_target_dir() + .arg_release("Whether or not to clean release artifacts") + .arg_doc("Whether or not to clean just the documentation directory") + .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. +", + ) +} + +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"), + doc: args.is_present("doc"), + }; + ops::clean(&ws, &opts)?; + Ok(()) +} diff --git a/src/bin/cargo/commands/doc.rs b/src/bin/cargo/commands/doc.rs new file mode 100644 index 000000000..54ba96797 --- /dev/null +++ b/src/bin/cargo/commands/doc.rs @@ -0,0 +1,59 @@ +use command_prelude::*; + +use cargo::ops::{self, CompileMode, DocOptions}; + +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_spec( + "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_target_dir() + .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. +", + ) +} + +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/cargo/commands/fetch.rs b/src/bin/cargo/commands/fetch.rs new file mode 100644 index 000000000..f69ed256b --- /dev/null +++ b/src/bin/cargo/commands/fetch.rs @@ -0,0 +1,34 @@ +use command_prelude::*; + +use cargo::ops; +use cargo::ops::FetchOptions; + +pub fn cli() -> App { + subcommand("fetch") + .about("Fetch dependencies of a package from the network") + .arg_manifest_path() + .arg_target_triple("Fetch dependencies for the target triple") + .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. +", + ) +} + +pub fn exec(config: &mut Config, args: &ArgMatches) -> CliResult { + let ws = args.workspace(config)?; + + let opts = FetchOptions { + config, + target: args.target(), + }; + ops::fetch(&ws, &opts)?; + Ok(()) +} diff --git a/src/bin/cargo/commands/generate_lockfile.rs b/src/bin/cargo/commands/generate_lockfile.rs new file mode 100644 index 000000000..f730872be --- /dev/null +++ b/src/bin/cargo/commands/generate_lockfile.rs @@ -0,0 +1,27 @@ +use command_prelude::*; + +use cargo::ops; + +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. +", + ) +} + +pub fn exec(config: &mut Config, args: &ArgMatches) -> CliResult { + let ws = args.workspace(config)?; + ops::generate_lockfile(&ws)?; + Ok(()) +} diff --git a/src/bin/cargo/commands/git_checkout.rs b/src/bin/cargo/commands/git_checkout.rs new file mode 100644 index 000000000..a9401f105 --- /dev/null +++ b/src/bin/cargo/commands/git_checkout.rs @@ -0,0 +1,36 @@ +use command_prelude::*; + +use cargo::core::{GitReference, Source, SourceId}; +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/cargo/commands/init.rs b/src/bin/cargo/commands/init.rs new file mode 100644 index 000000000..c32dead4d --- /dev/null +++ b/src/bin/cargo/commands/init.rs @@ -0,0 +1,19 @@ +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(config)?; + ops::init(&opts, config)?; + config + .shell() + .status("Created", format!("{} project", opts.kind))?; + Ok(()) +} diff --git a/src/bin/cargo/commands/install.rs b/src/bin/cargo/commands/install.rs new file mode 100644 index 000000000..0acdd0269 --- /dev/null +++ b/src/bin/cargo/commands/install.rs @@ -0,0 +1,122 @@ +use command_prelude::*; + +use cargo::core::{GitReference, SourceId}; +use cargo::ops::{self, CompileMode}; +use cargo::util::ToUrl; + +pub fn cli() -> App { + subcommand("install") + .about("Install a Rust binary") + .arg(Arg::with_name("crate").empty_values(false).multiple(true)) + .arg( + opt("version", "Specify a version to install from crates.io") + .alias("vers") + .value_name("VERSION"), + ) + .arg(opt("git", "Git URL to install the specified crate from").value_name("URL")) + .arg(opt("branch", "Branch to use when installing from git").value_name("BRANCH")) + .arg(opt("tag", "Tag to use when installing from git").value_name("TAG")) + .arg(opt("rev", "Specific commit to use when installing from git").value_name("SHA")) + .arg(opt("path", "Filesystem path to local crate to install").value_name("PATH")) + .arg(opt( + "list", + "list all installed packages and their versions", + )) + .arg_jobs() + .arg(opt("force", "Force overwriting existing crates or binaries").short("f")) + .arg_features() + .arg(opt("debug", "Build in debug mode instead of release mode")) + .arg_targets_bins_examples( + "Install only the specified binary", + "Install all binaries", + "Install only the specified example", + "Install all examples", + ) + .arg(opt("root", "Directory to install packages into").value_name("DIR")) + .after_help( + "\ +This command manages Cargo's local set of installed binary crates. Only packages +which have [[bin]] targets can be installed, and all binaries are installed into +the installation root's `bin` folder. The installation root is determined, in +order of precedence, by `--root`, `$CARGO_INSTALL_ROOT`, the `install.root` +configuration key, and finally the home directory (which is either +`$CARGO_HOME` if set or `$HOME/.cargo` by default). + +There are multiple sources from which a crate can be installed. The default +location is crates.io but the `--git` and `--path` flags can change this source. +If the source contains more than one package (such as crates.io or a git +repository with multiple crates) the `` argument is required to indicate +which crate should be installed. + +Crates from crates.io can optionally specify the version they wish to install +via the `--vers` flags, and similarly packages from git repositories can +optionally specify the branch, tag, or revision that should be installed. If a +crate has multiple binaries, the `--bin` argument can selectively install only +one of them, and if you'd rather install examples the `--example` argument can +be used as well. + +By default cargo will refuse to overwrite existing binaries. The `--force` flag +enables overwriting existing binaries. Thus you can reinstall a crate with +`cargo install --force `. + +As a special convenience, omitting the specification entirely will +install the crate in the current directory. That is, `install` is equivalent to +the more explicit `install --path .`. + +If the source is crates.io or `--git` then by default the crate will be built +in a temporary target directory. To avoid this, the target directory can be +specified by setting the `CARGO_TARGET_DIR` environment variable to a relative +path. In particular, this can be useful for caching build artifacts on +continuous integration systems.", + ) +} + +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 mut from_cwd = false; + + 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("path", config) { + SourceId::for_path(&path)? + } else if krates.is_empty() { + from_cwd = true; + 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, + from_cwd, + version, + &compile_opts, + args.is_present("force"), + )?; + } + Ok(()) +} diff --git a/src/bin/cargo/commands/locate_project.rs b/src/bin/cargo/commands/locate_project.rs new file mode 100644 index 000000000..2e20ccfb3 --- /dev/null +++ b/src/bin/cargo/commands/locate_project.rs @@ -0,0 +1,33 @@ +use command_prelude::*; + +use cargo::print_json; + +pub fn cli() -> App { + subcommand("locate-project") + .about("Print a JSON representation of a Cargo.toml file's location") + .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/cargo/commands/login.rs b/src/bin/cargo/commands/login.rs new file mode 100644 index 000000000..199951048 --- /dev/null +++ b/src/bin/cargo/commands/login.rs @@ -0,0 +1,58 @@ +use command_prelude::*; + +use std::io::{self, BufRead}; + +use cargo::core::{Source, SourceId}; +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. \ + 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")) +} + +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/cargo/commands/metadata.rs b/src/bin/cargo/commands/metadata.rs new file mode 100644 index 000000000..b701acd61 --- /dev/null +++ b/src/bin/cargo/commands/metadata.rs @@ -0,0 +1,53 @@ +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, \ + 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"), + ) +} + +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/cargo/commands/mod.rs b/src/bin/cargo/commands/mod.rs new file mode 100644 index 000000000..fc829a855 --- /dev/null +++ b/src/bin/cargo/commands/mod.rs @@ -0,0 +1,101 @@ +use command_prelude::*; + +pub fn builtin() -> Vec { + vec![ + bench::cli(), + build::cli(), + check::cli(), + clean::cli(), + doc::cli(), + fetch::cli(), + generate_lockfile::cli(), + git_checkout::cli(), + init::cli(), + install::cli(), + locate_project::cli(), + login::cli(), + metadata::cli(), + new::cli(), + owner::cli(), + package::cli(), + pkgid::cli(), + publish::cli(), + read_manifest::cli(), + run::cli(), + rustc::cli(), + rustdoc::cli(), + search::cli(), + test::cli(), + uninstall::cli(), + update::cli(), + verify_project::cli(), + version::cli(), + yank::cli(), + ] +} + +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) +} + +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/cargo/commands/new.rs b/src/bin/cargo/commands/new.rs new file mode 100644 index 000000000..ff8472209 --- /dev/null +++ b/src/bin/cargo/commands/new.rs @@ -0,0 +1,26 @@ +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(config)?; + + ops::new(&opts, config)?; + let path = args.value_of("path").unwrap(); + let project_name = if let Some(name) = args.value_of("name") { + name + } else { + path + }; + config + .shell() + .status("Created", format!("{} `{}` project", opts.kind, project_name))?; + Ok(()) +} diff --git a/src/bin/cargo/commands/owner.rs b/src/bin/cargo/commands/owner.rs new file mode 100644 index 000000000..f20be31b1 --- /dev/null +++ b/src/bin/cargo/commands/owner.rs @@ -0,0 +1,49 @@ +use command_prelude::*; + +use cargo::ops::{self, OwnersOptions}; + +pub fn cli() -> App { + subcommand("owner") + .about("Manage the owners of a crate on the registry") + .arg(Arg::with_name("crate")) + .arg(multi_opt("add", "LOGIN", "Name of a user or team to add as an owner").short("a")) + .arg( + multi_opt( + "remove", + "LOGIN", + "Name of a user or team to remove as an owner", + ).short("r"), + ) + .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.", + ) +} + +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/cargo/commands/package.rs b/src/bin/cargo/commands/package.rs new file mode 100644 index 000000000..f5e9d9184 --- /dev/null +++ b/src/bin/cargo/commands/package.rs @@ -0,0 +1,48 @@ +use command_prelude::*; + +use cargo::ops::{self, PackageOpts}; + +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_target_dir() + .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/cargo/commands/pkgid.rs b/src/bin/cargo/commands/pkgid.rs new file mode 100644 index 000000000..7010092d6 --- /dev/null +++ b/src/bin/cargo/commands/pkgid.rs @@ -0,0 +1,41 @@ +use command_prelude::*; + +use cargo::ops; + +pub fn cli() -> App { + subcommand("pkgid") + .about("Print a fully qualified package specification") + .arg(Arg::with_name("spec")) + .arg_package("Argument to get the package id specifier for") + .arg_manifest_path() + .after_help( + "\ +Given a argument, print out the fully qualified package id specifier. +This command will generate an error if is ambiguous as to which package +it refers to in the dependency graph. If no is given, then the pkgid for +the local package is printed. + +This command requires that a lockfile is available and dependencies have been +fetched. + +Example Package IDs + + pkgid | name | version | url + |-----------------------------|--------|-----------|---------------------| + foo | foo | * | * + foo:1.2.3 | foo | 1.2.3 | * + crates.io/foo | foo | * | *://crates.io/foo + crates.io/foo#1.2.3 | foo | 1.2.3 | *://crates.io/foo + crates.io/bar#foo:1.2.3 | foo | 1.2.3 | *://crates.io/bar + http://crates.io/foo#1.2.3 | foo | 1.2.3 | http://crates.io/foo +", + ) +} + +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/cargo/commands/publish.rs b/src/bin/cargo/commands/publish.rs new file mode 100644 index 000000000..b50d3619c --- /dev/null +++ b/src/bin/cargo/commands/publish.rs @@ -0,0 +1,46 @@ +use command_prelude::*; + +use cargo::ops::{self, PublishOpts}; + +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_target_dir() + .arg_manifest_path() + .arg_jobs() + .arg(opt("dry-run", "Perform all checks without uploading")) + .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/cargo/commands/read_manifest.rs b/src/bin/cargo/commands/read_manifest.rs new file mode 100644 index 000000000..1e54c79e8 --- /dev/null +++ b/src/bin/cargo/commands/read_manifest.rs @@ -0,0 +1,18 @@ +use command_prelude::*; + +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 ws = args.workspace(config)?; + print_json(&ws.current()?); + Ok(()) +} diff --git a/src/bin/cargo/commands/run.rs b/src/bin/cargo/commands/run.rs new file mode 100644 index 000000000..763263d5a --- /dev/null +++ b/src/bin/cargo/commands/run.rs @@ -0,0 +1,69 @@ +use command_prelude::*; + +use cargo::core::Verbosity; +use cargo::ops::{self, CompileFilter, CompileMode}; + +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_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_target_dir() + .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 the arguments following the two dashes (`--`) 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. +", + ) +} + +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/cargo/commands/rustc.rs b/src/bin/cargo/commands/rustc.rs new file mode 100644 index 000000000..35fb59e8e --- /dev/null +++ b/src/bin/cargo/commands/rustc.rs @@ -0,0 +1,74 @@ +use command_prelude::*; + +use cargo::ops::{self, CompileMode}; + +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_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_target_dir() + .arg_manifest_path() + .arg_message_format() + .after_help( + "\ +The specified target for the current package (or package specified by SPEC if +provided) will be compiled along with all of its dependencies. The specified +... will all be passed to the final compiler invocation, not any of the +dependencies. Note that the compiler will still unconditionally receive +arguments such as -L, --extern, and --crate-type, and the specified ... +will simply be added to the compiler invocation. + +This command requires that only one target is being compiled. If more than one +target is available for the current package the filters of --lib, --bin, etc, +must be used to select which target is compiled. To pass flags to all compiler +processes spawned by Cargo, use the $RUSTFLAGS environment variable or the +`build.rustflags` configuration option. +", + ) +} + +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)?; + let target_args = values(args, "args"); + compile_opts.target_rustc_args = if target_args.is_empty() { + None + } else { + Some(target_args) + }; + ops::compile(&ws, &compile_opts)?; + Ok(()) +} diff --git a/src/bin/cargo/commands/rustdoc.rs b/src/bin/cargo/commands/rustdoc.rs new file mode 100644 index 000000000..301e65449 --- /dev/null +++ b/src/bin/cargo/commands/rustdoc.rs @@ -0,0 +1,66 @@ +use command_prelude::*; + +use cargo::ops::{self, CompileMode, DocOptions}; + +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_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_features() + .arg_target_dir() + .arg_manifest_path() + .arg_message_format() + .after_help( + "\ +The specified target for the current package (or package specified by SPEC if +provided) will be documented with the specified ... being passed to the +final rustdoc invocation. Dependencies will not be documented as part of this +command. Note that rustdoc will still unconditionally receive arguments such +as -L, --extern, and --crate-type, and the specified ... will simply be +added to the rustdoc invocation. + +If the --package argument is given, then SPEC is a package id specification +which indicates which package should be documented. If it is not given, then the +current package is documented. For more information on SPEC and its format, see +the `cargo help pkgid` command. +", + ) +} + +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 })?; + let target_args = values(args, "args"); + compile_opts.target_rustdoc_args = if target_args.is_empty() { + None + } else { + Some(target_args) + }; + let doc_opts = DocOptions { + open_result: args.is_present("open"), + compile_opts, + }; + ops::doc(&ws, &doc_opts)?; + Ok(()) +} diff --git a/src/bin/cargo/commands/search.rs b/src/bin/cargo/commands/search.rs new file mode 100644 index 000000000..0501d8e5f --- /dev/null +++ b/src/bin/cargo/commands/search.rs @@ -0,0 +1,30 @@ +use command_prelude::*; + +use std::cmp::min; + +use cargo::ops; + +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")) +} + +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/cargo/commands/test.rs b/src/bin/cargo/commands/test.rs new file mode 100644 index 000000000..a25f62f8e --- /dev/null +++ b/src/bin/cargo/commands/test.rs @@ -0,0 +1,137 @@ +use command_prelude::*; + +use cargo::ops::{self, CompileMode}; + +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_spec( + "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_target_dir() + .arg_manifest_path() + .arg_message_format() + .after_help( + "\ +The test filtering argument `TESTNAME` and all the arguments following the +two dashes (`--`) are passed to the test binaries and thus to libtest +(rustc's built in unit-test and micro-benchmarking framework). If you're +passing arguments to both Cargo and the binary, the ones after `--` go to the +binary, the ones before go to Cargo. For details about libtest's arguments see +the output of `cargo test -- --help`. As an example, this will run all +tests with `foo` in their name on 3 threads in parallel: + + cargo test foo -- --test-threads 3 + +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 +", + ) +} + +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/cargo/commands/uninstall.rs b/src/bin/cargo/commands/uninstall.rs new file mode 100644 index 000000000..203185119 --- /dev/null +++ b/src/bin/cargo/commands/uninstall.rs @@ -0,0 +1,26 @@ +use command_prelude::*; + +use cargo::ops; + +pub fn cli() -> App { + subcommand("uninstall") + .about("Remove a Rust binary") + .arg(Arg::with_name("spec").multiple(true)) + .arg(multi_opt("bin", "NAME", "Only uninstall the binary NAME")) + .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. +", + ) +} + +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/cargo/commands/update.rs b/src/bin/cargo/commands/update.rs new file mode 100644 index 000000000..c5a992a3d --- /dev/null +++ b/src/bin/cargo/commands/update.rs @@ -0,0 +1,51 @@ +use command_prelude::*; + +use cargo::ops::{self, UpdateOptions}; + +pub fn cli() -> App { + subcommand("update") + .about("Update dependencies as recorded in the local lock file") + .arg_package_spec_simple("Package to update") + .arg(opt( + "aggressive", + "Force updating all dependencies of as well", + )) + .arg(opt("precise", "Update a single dependency to exactly PRECISE").value_name("PRECISE")) + .arg_manifest_path() + .after_help( + "\ +This command requires that a `Cargo.lock` already exists as generated by +`cargo build` or related commands. + +If SPEC is given, then a conservative update of the lockfile will be +performed. This means that only the dependency specified by SPEC will be +updated. Its transitive dependencies will be updated only if SPEC cannot be +updated without updating dependencies. All other dependencies will remain +locked at their currently recorded versions. + +If PRECISE is specified, then --aggressive must not also be specified. The +argument PRECISE is a string representing a precise revision that the package +being updated should be updated to. For example, if the package comes from a git +repository, then PRECISE would be the exact revision that the repository should +be updated to. + +If SPEC is not given, then all dependencies will be re-resolved and +updated. + +For more information about package id specifications, see `cargo help pkgid`. +", + ) +} + +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/cargo/commands/verify_project.rs b/src/bin/cargo/commands/verify_project.rs new file mode 100644 index 000000000..eea65c775 --- /dev/null +++ b/src/bin/cargo/commands/verify_project.rs @@ -0,0 +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/cargo/commands/version.rs b/src/bin/cargo/commands/version.rs new file mode 100644 index 000000000..0e9d5be52 --- /dev/null +++ b/src/bin/cargo/commands/version.rs @@ -0,0 +1,12 @@ +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/cargo/commands/yank.rs b/src/bin/cargo/commands/yank.rs new file mode 100644 index 000000000..150474be8 --- /dev/null +++ b/src/bin/cargo/commands/yank.rs @@ -0,0 +1,43 @@ +use command_prelude::*; + +use cargo::ops; + +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. +", + ) +} + +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(()) +} diff --git a/src/bin/cargo/main.rs b/src/bin/cargo/main.rs new file mode 100644 index 000000000..7d7c7db6e --- /dev/null +++ b/src/bin/cargo/main.rs @@ -0,0 +1,212 @@ +extern crate cargo; +extern crate clap; +extern crate env_logger; +#[macro_use] +extern crate failure; +extern crate git2_curl; +extern crate log; +#[macro_use] +extern crate serde_derive; +extern crate serde_json; +extern crate toml; + +use std::env; +use std::fs; +use std::path::{Path, PathBuf}; +use std::collections::BTreeSet; + +use cargo::core::shell::Shell; +use cargo::util::{self, lev_distance, CargoResult, CliResult, Config}; +use cargo::util::{CliError, ProcessError}; + +mod cli; +mod command_prelude; +mod commands; + +fn main() { + env_logger::init(); + + let mut config = match Config::default() { + Ok(cfg) => cfg, + Err(e) => { + let mut shell = Shell::new(); + cargo::exit_with_error(e.into(), &mut shell) + } + }; + + let result = { + init_git_transports(&mut config); + let _token = cargo::util::job::setup(); + cli::main(&mut config) + }; + + match result { + Err(e) => cargo::exit_with_error(e, &mut *config.shell()), + Ok(()) => {} + } +} + +fn aliased_command(config: &Config, command: &str) -> CargoResult>> { + let alias_name = format!("alias.{}", command); + let mut result = Ok(None); + match config.get_string(&alias_name) { + Ok(value) => { + if let Some(record) = value { + let alias_commands = record + .val + .split_whitespace() + .map(|s| s.to_string()) + .collect(); + result = Ok(Some(alias_commands)); + } + } + Err(_) => { + let value = config.get_list(&alias_name)?; + if let Some(record) = value { + let alias_commands: Vec = + record.val.iter().map(|s| s.0.to_string()).collect(); + result = Ok(Some(alias_commands)); + } + } + } + result +} + +/// List all runnable commands +fn list_commands(config: &Config) -> BTreeSet<(String, Option)> { + let prefix = "cargo-"; + let suffix = env::consts::EXE_SUFFIX; + let mut commands = BTreeSet::new(); + for dir in search_directories(config) { + let entries = match fs::read_dir(dir) { + Ok(entries) => entries, + _ => continue, + }; + for entry in entries.filter_map(|e| e.ok()) { + let path = entry.path(); + let filename = match path.file_name().and_then(|s| s.to_str()) { + Some(filename) => filename, + _ => continue, + }; + if !filename.starts_with(prefix) || !filename.ends_with(suffix) { + continue; + } + if is_executable(entry.path()) { + let end = filename.len() - suffix.len(); + commands.insert(( + filename[prefix.len()..end].to_string(), + Some(path.display().to_string()), + )); + } + } + } + + for cmd in commands::builtin() { + commands.insert((cmd.get_name().to_string(), None)); + } + + commands +} + +fn find_closest(config: &Config, cmd: &str) -> Option { + let cmds = list_commands(config); + // Only consider candidates with a lev_distance of 3 or less so we don't + // suggest out-of-the-blue options. + let mut filtered = cmds.iter() + .map(|&(ref c, _)| (lev_distance(c, cmd), c)) + .filter(|&(d, _)| d < 4) + .collect::>(); + filtered.sort_by(|a, b| a.0.cmp(&b.0)); + filtered.get(0).map(|slot| slot.1.clone()) +} + +fn execute_external_subcommand(config: &Config, cmd: &str, args: &[&str]) -> CliResult { + let command_exe = format!("cargo-{}{}", cmd, env::consts::EXE_SUFFIX); + let path = search_directories(config) + .iter() + .map(|dir| dir.join(&command_exe)) + .find(|file| is_executable(file)); + let command = match path { + Some(command) => command, + None => { + let err = match find_closest(config, cmd) { + Some(closest) => format_err!( + "no such subcommand: `{}`\n\n\tDid you mean `{}`?\n", + cmd, + closest + ), + None => format_err!("no such subcommand: `{}`", cmd), + }; + return Err(CliError::new(err, 101)); + } + }; + + let cargo_exe = config.cargo_exe()?; + let err = match util::process(&command) + .env(cargo::CARGO_ENV, cargo_exe) + .args(args) + .exec_replace() + { + Ok(()) => return Ok(()), + Err(e) => e, + }; + + if let Some(perr) = err.downcast_ref::() { + if let Some(code) = perr.exit.as_ref().and_then(|c| c.code()) { + return Err(CliError::code(code)); + } + } + Err(CliError::new(err, 101)) +} + +#[cfg(unix)] +fn is_executable>(path: P) -> bool { + use std::os::unix::prelude::*; + fs::metadata(path) + .map(|metadata| metadata.is_file() && metadata.permissions().mode() & 0o111 != 0) + .unwrap_or(false) +} +#[cfg(windows)] +fn is_executable>(path: P) -> bool { + fs::metadata(path) + .map(|metadata| metadata.is_file()) + .unwrap_or(false) +} + +fn search_directories(config: &Config) -> Vec { + let mut dirs = vec![config.home().clone().into_path_unlocked().join("bin")]; + if let Some(val) = env::var_os("PATH") { + dirs.extend(env::split_paths(&val)); + } + dirs +} + +fn init_git_transports(config: &Config) { + // Only use a custom transport if any HTTP options are specified, + // such as proxies or custom certificate authorities. The custom + // transport, however, is not as well battle-tested. + + match cargo::ops::needs_custom_http_transport(config) { + Ok(true) => {} + _ => return, + } + + let handle = match cargo::ops::http_handle(config) { + Ok(handle) => handle, + Err(..) => return, + }; + + // The unsafety of the registration function derives from two aspects: + // + // 1. This call must be synchronized with all other registration calls as + // well as construction of new transports. + // 2. The argument is leaked. + // + // We're clear on point (1) because this is only called at the start of this + // binary (we know what the state of the world looks like) and we're mostly + // clear on point (2) because we'd only free it after everything is done + // anyway + unsafe { + git2_curl::register(handle); + } +} diff --git a/src/bin/cli.rs b/src/bin/cli.rs deleted file mode 100644 index 9fbd12cbc..000000000 --- a/src/bin/cli.rs +++ /dev/null @@ -1,214 +0,0 @@ -extern crate clap; - -use clap::{AppSettings, Arg, ArgMatches}; - -use cargo::{self, CliResult, Config}; - -use super::list_commands; -use super::commands; -use command_prelude::*; - -pub fn main(config: &mut Config) -> CliResult { - let args = cli().get_matches_safe()?; - - if args.value_of("unstable-features") == Some("help") { - println!( - " -Available unstable (nightly-only) flags: - - -Z avoid-dev-deps -- Avoid installing dev-dependencies if possible - -Z minimal-versions -- Install minimal dependency versions instead of maximum - -Z no-index-update -- Do not update the registry, avoids a network request for benchmarking - -Z offline -- Offline mode that does not perform network requests - -Z unstable-options -- Allow the usage of unstable options such as --registry - -Run with 'cargo -Z [FLAG] [SUBCOMMAND]'" - ); - return Ok(()); - } - - 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(None)?.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(()); - } - - let args = expand_aliases(config, args)?; - - execute_subcommand(config, args) -} - -fn expand_aliases( - config: &mut Config, - args: ArgMatches<'static>, -) -> Result, CliError> { - if let (cmd, Some(args)) = args.subcommand() { - match ( - commands::builtin_exec(cmd), - super::aliased_command(config, cmd)?, - ) { - (None, Some(mut alias)) => { - 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 expand_aliases(config, args); - } - (Some(_), Some(_)) => { - config.shell().warn(format!( - "alias `{}` is ignored, because it is shadowed by a built in command", - cmd - ))?; - } - (_, None) => {} - } - }; - Ok(args) -} - -fn execute_subcommand(config: &mut Config, args: ArgMatches) -> CliResult { - let (cmd, subcommand_args) = match args.subcommand() { - (cmd, Some(args)) => (cmd, args), - _ => { - cli().print_help()?; - return Ok(()); - } - }; - - let arg_target_dir = &subcommand_args.value_of_path("target-dir", config); - - config.configure( - args.occurrences_of("verbose") as u32, - if args.is_present("quiet") { - Some(true) - } else { - None - }, - &args.value_of("color").map(|s| s.to_string()), - args.is_present("frozen"), - args.is_present("locked"), - arg_target_dir, - &args.values_of_lossy("unstable-features") - .unwrap_or_default(), - )?; - - if let Some(exec) = commands::builtin_exec(cmd) { - return exec(config, subcommand_args); - } - - let mut ext_args: Vec<&str> = vec![cmd]; - ext_args.extend(subcommand_args.values_of("").unwrap_or_default()); - super::execute_external_subcommand(config, cmd, &ext_args) -} - -fn cli() -> App { - let app = App::new("cargo") - .settings(&[ - AppSettings::UnifiedHelpMessage, - AppSettings::DeriveDisplayOrder, - AppSettings::VersionlessSubcommands, - AppSettings::AllowExternalSubcommands, - ]) - .about("") - .template( - "\ -Rust's package manager - -USAGE: - {usage} - -OPTIONS: -{unified} - -Some common cargo commands are (see all commands with --list): - build Compile the current project - check Analyze the current project and report errors, but don't build object files - clean Remove the target directory - doc Build this project's and its dependencies' documentation - new Create a new cargo project - init Create a new cargo project in an existing directory - run Build and execute src/main.rs - test Run the tests - bench Run the benchmarks - update Update dependencies listed in Cargo.lock - search Search registry for crates - publish Package and upload this project to the registry - install Install a Rust binary - uninstall Uninstall a Rust binary - -See 'cargo help ' for more information on a specific command.\n", - ) - .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("quiet", "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, see 'cargo -Z help' for details") - .short("Z") - .value_name("FLAG") - .multiple(true) - .number_of_values(1) - .global(true), - ) - .subcommands(commands::builtin()); - app -} diff --git a/src/bin/command_prelude.rs b/src/bin/command_prelude.rs deleted file mode 100644 index 2f6a04624..000000000 --- a/src/bin/command_prelude.rs +++ /dev/null @@ -1,402 +0,0 @@ -use std::path::PathBuf; -use std::fs; - -use clap::{self, SubCommand}; -use cargo::CargoResult; -use cargo::core::Workspace; -use cargo::ops::{CompileFilter, CompileMode, CompileOptions, MessageFormat, NewOptions, Packages, - VersionControl}; -use cargo::util::paths; -use cargo::util::important_paths::find_root_manifest_for_wd; - -pub use clap::{AppSettings, Arg, ArgMatches}; -pub use cargo::{CliError, CliResult, Config}; - -pub type App = clap::App<'static, 'static>; - -pub trait AppExt: Sized { - fn _arg(self, arg: Arg<'static, 'static>) -> Self; - - fn arg_package_spec( - self, - package: &'static str, - all: &'static str, - exclude: &'static str, - ) -> Self { - self.arg_package_spec_simple(package) - ._arg(opt("all", all)) - ._arg(multi_opt("exclude", "SPEC", exclude)) - } - - fn arg_package_spec_simple(self, package: &'static str) -> Self { - self._arg(multi_opt("package", "SPEC", package).short("p")) - } - - fn arg_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, - example: &'static str, - examples: &'static str, - test: &'static str, - tests: &'static str, - bench: &'static str, - benches: &'static str, - all: &'static str, - ) -> Self { - self.arg_targets_lib_bin(lib, bin, bins) - ._arg(multi_opt("example", "NAME", example)) - ._arg(opt("examples", examples)) - ._arg(multi_opt("test", "NAME", test)) - ._arg(opt("tests", tests)) - ._arg(multi_opt("bench", "NAME", bench)) - ._arg(opt("benches", benches)) - ._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(multi_opt("bin", "NAME", bin)) - ._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(multi_opt("bin", "NAME", bin)) - ._arg(opt("bins", bins)) - ._arg(multi_opt("example", "NAME", example)) - ._arg(opt("examples", examples)) - } - - fn arg_targets_bin_example(self, bin: &'static str, example: &'static str) -> Self { - self._arg(multi_opt("bin", "NAME", bin)) - ._arg(multi_opt("example", "NAME", example)) - } - - 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_doc(self, doc: &'static str) -> Self { - self._arg(opt("doc", doc)) - } - - fn arg_target_triple(self, target: &'static str) -> Self { - self._arg(opt("target", target).value_name("TRIPLE")) - } - - fn arg_target_dir(self) -> Self { - self._arg(opt("target-dir", "Directory for all generated artifacts").value_name("DIRECTORY")) - } - - 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 AppExt 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 multi_opt( - name: &'static str, - value_name: &'static str, - help: &'static str, -) -> Arg<'static, 'static> { - // Note that all `.multiple(true)` arguments in Cargo should specify - // `.number_of_values(1)` as well, so that `--foo val1 val2` is - // **not** parsed as `foo` with values ["val1", "val2"]. - // `number_of_values` should become the default in clap 3. - opt(name, help) - .value_name(value_name) - .multiple(true) - .number_of_values(1) -} - -pub fn subcommand(name: &'static str) -> App { - SubCommand::with_name(name).settings(&[ - AppSettings::UnifiedHelpMessage, - AppSettings::DeriveDisplayOrder, - AppSettings::DontCollapseArgsInUsage, - ]) -} - -pub trait ArgMatchesExt { - fn value_of_u32(&self, name: &str) -> CargoResult> { - let arg = match self._value_of(name) { - None => None, - Some(arg) => Some(arg.parse::().map_err(|_| { - clap::Error::value_validation_auto(format!("could not parse `{}` as a number", arg)) - })?), - }; - Ok(arg) - } - - /// Returns value of the `name` command-line argument as an absolute path - fn value_of_path(&self, name: &str, config: &Config) -> Option { - self._value_of(name).map(|path| config.cwd().join(path)) - } - - fn root_manifest(&self, config: &Config) -> CargoResult { - if let Some(path) = self.value_of_path("manifest-path", config) { - // In general, we try to avoid normalizing paths in Cargo, - // but in this particular case we need it to fix #3586. - let path = paths::normalize_path(&path); - if !path.ends_with("Cargo.toml") { - bail!("the manifest-path must be a path to a Cargo.toml file") - } - if !fs::metadata(&path).is_ok() { - bail!( - "manifest path `{}` does not exist", - self._value_of("manifest-path").unwrap() - ) - } - return Ok(path); - } - find_root_manifest_for_wd(config.cwd()) - } - - fn workspace<'a>(&self, config: &'a Config) -> CargoResult> { - let root = self.root_manifest(config)?; - let mut ws = Workspace::new(&root, config)?; - if config.cli_unstable().avoid_dev_deps { - ws.set_require_optional_deps(false); - } - Ok(ws) - } - - fn jobs(&self) -> CargoResult> { - self.value_of_u32("jobs") - } - - fn target(&self) -> Option { - self._value_of("target").map(|s| s.to_string()) - } - - fn compile_options<'a>( - &self, - config: &'a Config, - mode: CompileMode, - ) -> CargoResult> { - let spec = Packages::from_flags( - self._is_present("all"), - self._values_of("exclude"), - self._values_of("package"), - )?; - - let message_format = match self._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: self.jobs()?, - target: self.target(), - features: self._values_of("features"), - all_features: self._is_present("all-features"), - no_default_features: self._is_present("no-default-features"), - spec, - mode, - release: self._is_present("release"), - filter: CompileFilter::new( - self._is_present("lib"), - self._values_of("bin"), - self._is_present("bins"), - self._values_of("test"), - self._is_present("tests"), - self._values_of("example"), - self._is_present("examples"), - self._values_of("bench"), - self._is_present("benches"), - self._is_present("all-targets"), - ), - message_format, - target_rustdoc_args: None, - target_rustc_args: None, - export_dir: None, - }; - Ok(opts) - } - - fn compile_options_for_single_package<'a>( - &self, - config: &'a Config, - mode: CompileMode, - ) -> CargoResult> { - let mut compile_opts = self.compile_options(config, mode)?; - compile_opts.spec = Packages::Packages(self._values_of("package")); - Ok(compile_opts) - } - - fn new_options(&self, config: &Config) -> CargoResult { - let vcs = self._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, - self._is_present("bin"), - self._is_present("lib"), - self.value_of_path("path", config).unwrap(), - self._value_of("name").map(|s| s.to_string()), - ) - } - - fn registry(&self, config: &Config) -> CargoResult> { - match self._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), - } - } - - fn index(&self, config: &Config) -> CargoResult> { - // TODO: Deprecated - // remove once it has been decided --host can be removed - // We may instead want to repurpose the host flag, as - // mentioned in this issue - // https://github.com/rust-lang/cargo/issues/4208 - let msg = "The flag '--host' is no longer valid. - -Previous versions of Cargo accepted this flag, but it is being -deprecated. The flag is being renamed to 'index', as the flag -wants the location of the index. Please use '--index' instead. - -This will soon become a hard error, so it's either recommended -to update to a fixed version or contact the upstream maintainer -about this warning."; - - let index = match self._value_of("host") { - Some(host) => { - config.shell().warn(&msg)?; - Some(host.to_string()) - } - None => self._value_of("index").map(|s| s.to_string()), - }; - Ok(index) - } - - fn _value_of(&self, name: &str) -> Option<&str>; - - fn _values_of(&self, name: &str) -> Vec; - - fn _is_present(&self, name: &str) -> bool; -} - -impl<'a> ArgMatchesExt for ArgMatches<'a> { - fn _value_of(&self, name: &str) -> Option<&str> { - self.value_of(name) - } - - fn _values_of(&self, name: &str) -> Vec { - self.values_of(name) - .unwrap_or_default() - .map(|s| s.to_string()) - .collect() - } - - fn _is_present(&self, name: &str) -> bool { - self.is_present(name) - } -} - -pub fn values(args: &ArgMatches, name: &str) -> Vec { - args.values_of(name) - .unwrap_or_default() - .map(|s| s.to_string()) - .collect() -} diff --git a/src/bin/commands/bench.rs b/src/bin/commands/bench.rs deleted file mode 100644 index 83e3ab5af..000000000 --- a/src/bin/commands/bench.rs +++ /dev/null @@ -1,105 +0,0 @@ -use command_prelude::*; - -use cargo::ops::{self, CompileMode, TestOptions}; - -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_spec( - "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_target_dir() - .arg_manifest_path() - .arg_message_format() - .arg(opt( - "no-fail-fast", - "Run all benchmarks regardless of failure", - )) - .after_help( - "\ -The benchmark filtering argument `BENCHNAME` and all the arguments following the -two dashes (`--`) are passed to the benchmark binaries and thus to libtest -(rustc's built in unit-test and micro-benchmarking framework). If you're -passing arguments to both Cargo and the binary, the ones after `--` go to the -binary, the ones before go to Cargo. For details about libtest's arguments see -the output of `cargo bench -- --help`. - -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. -", - ) -} - -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 deleted file mode 100644 index 0ab86aa3a..000000000 --- a/src/bin/commands/build.rs +++ /dev/null @@ -1,63 +0,0 @@ -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") - .arg_package_spec( - "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_target_dir() - .arg(opt("out-dir", "Copy final artifacts to this directory").value_name("PATH")) - .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. -", - ) -} - -pub fn exec(config: &mut Config, args: &ArgMatches) -> CliResult { - let ws = args.workspace(config)?; - let mut compile_opts = args.compile_options(config, CompileMode::Build)?; - compile_opts.export_dir = args.value_of_path("out-dir", config); - if compile_opts.export_dir.is_some() && !config.cli_unstable().unstable_options { - Err(format_err!( - "`--out-dir` flag is unstable, pass `-Z unstable-options` to enable it" - ))?; - }; - ops::compile(&ws, &compile_opts)?; - Ok(()) -} diff --git a/src/bin/commands/check.rs b/src/bin/commands/check.rs deleted file mode 100644 index e4295c5c3..000000000 --- a/src/bin/commands/check.rs +++ /dev/null @@ -1,72 +0,0 @@ -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") - .arg_package_spec( - "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_target_dir() - .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. -", - ) -} - -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 deleted file mode 100644 index a7606a644..000000000 --- a/src/bin/commands/clean.rs +++ /dev/null @@ -1,35 +0,0 @@ -use command_prelude::*; - -use cargo::ops::{self, CleanOptions}; - -pub fn cli() -> App { - subcommand("clean") - .about("Remove artifacts that cargo has generated in the past") - .arg_package_spec_simple("Package to clean artifacts for") - .arg_manifest_path() - .arg_target_triple("Target triple to clean output for (default all)") - .arg_target_dir() - .arg_release("Whether or not to clean release artifacts") - .arg_doc("Whether or not to clean just the documentation directory") - .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. -", - ) -} - -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"), - doc: args.is_present("doc"), - }; - ops::clean(&ws, &opts)?; - Ok(()) -} diff --git a/src/bin/commands/doc.rs b/src/bin/commands/doc.rs deleted file mode 100644 index 54ba96797..000000000 --- a/src/bin/commands/doc.rs +++ /dev/null @@ -1,59 +0,0 @@ -use command_prelude::*; - -use cargo::ops::{self, CompileMode, DocOptions}; - -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_spec( - "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_target_dir() - .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. -", - ) -} - -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 deleted file mode 100644 index f69ed256b..000000000 --- a/src/bin/commands/fetch.rs +++ /dev/null @@ -1,34 +0,0 @@ -use command_prelude::*; - -use cargo::ops; -use cargo::ops::FetchOptions; - -pub fn cli() -> App { - subcommand("fetch") - .about("Fetch dependencies of a package from the network") - .arg_manifest_path() - .arg_target_triple("Fetch dependencies for the target triple") - .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. -", - ) -} - -pub fn exec(config: &mut Config, args: &ArgMatches) -> CliResult { - let ws = args.workspace(config)?; - - let opts = FetchOptions { - config, - target: args.target(), - }; - ops::fetch(&ws, &opts)?; - Ok(()) -} diff --git a/src/bin/commands/generate_lockfile.rs b/src/bin/commands/generate_lockfile.rs deleted file mode 100644 index f730872be..000000000 --- a/src/bin/commands/generate_lockfile.rs +++ /dev/null @@ -1,27 +0,0 @@ -use command_prelude::*; - -use cargo::ops; - -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. -", - ) -} - -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 deleted file mode 100644 index a9401f105..000000000 --- a/src/bin/commands/git_checkout.rs +++ /dev/null @@ -1,36 +0,0 @@ -use command_prelude::*; - -use cargo::core::{GitReference, Source, SourceId}; -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 deleted file mode 100644 index c32dead4d..000000000 --- a/src/bin/commands/init.rs +++ /dev/null @@ -1,19 +0,0 @@ -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(config)?; - 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 deleted file mode 100644 index 0acdd0269..000000000 --- a/src/bin/commands/install.rs +++ /dev/null @@ -1,122 +0,0 @@ -use command_prelude::*; - -use cargo::core::{GitReference, SourceId}; -use cargo::ops::{self, CompileMode}; -use cargo::util::ToUrl; - -pub fn cli() -> App { - subcommand("install") - .about("Install a Rust binary") - .arg(Arg::with_name("crate").empty_values(false).multiple(true)) - .arg( - opt("version", "Specify a version to install from crates.io") - .alias("vers") - .value_name("VERSION"), - ) - .arg(opt("git", "Git URL to install the specified crate from").value_name("URL")) - .arg(opt("branch", "Branch to use when installing from git").value_name("BRANCH")) - .arg(opt("tag", "Tag to use when installing from git").value_name("TAG")) - .arg(opt("rev", "Specific commit to use when installing from git").value_name("SHA")) - .arg(opt("path", "Filesystem path to local crate to install").value_name("PATH")) - .arg(opt( - "list", - "list all installed packages and their versions", - )) - .arg_jobs() - .arg(opt("force", "Force overwriting existing crates or binaries").short("f")) - .arg_features() - .arg(opt("debug", "Build in debug mode instead of release mode")) - .arg_targets_bins_examples( - "Install only the specified binary", - "Install all binaries", - "Install only the specified example", - "Install all examples", - ) - .arg(opt("root", "Directory to install packages into").value_name("DIR")) - .after_help( - "\ -This command manages Cargo's local set of installed binary crates. Only packages -which have [[bin]] targets can be installed, and all binaries are installed into -the installation root's `bin` folder. The installation root is determined, in -order of precedence, by `--root`, `$CARGO_INSTALL_ROOT`, the `install.root` -configuration key, and finally the home directory (which is either -`$CARGO_HOME` if set or `$HOME/.cargo` by default). - -There are multiple sources from which a crate can be installed. The default -location is crates.io but the `--git` and `--path` flags can change this source. -If the source contains more than one package (such as crates.io or a git -repository with multiple crates) the `` argument is required to indicate -which crate should be installed. - -Crates from crates.io can optionally specify the version they wish to install -via the `--vers` flags, and similarly packages from git repositories can -optionally specify the branch, tag, or revision that should be installed. If a -crate has multiple binaries, the `--bin` argument can selectively install only -one of them, and if you'd rather install examples the `--example` argument can -be used as well. - -By default cargo will refuse to overwrite existing binaries. The `--force` flag -enables overwriting existing binaries. Thus you can reinstall a crate with -`cargo install --force `. - -As a special convenience, omitting the specification entirely will -install the crate in the current directory. That is, `install` is equivalent to -the more explicit `install --path .`. - -If the source is crates.io or `--git` then by default the crate will be built -in a temporary target directory. To avoid this, the target directory can be -specified by setting the `CARGO_TARGET_DIR` environment variable to a relative -path. In particular, this can be useful for caching build artifacts on -continuous integration systems.", - ) -} - -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 mut from_cwd = false; - - 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("path", config) { - SourceId::for_path(&path)? - } else if krates.is_empty() { - from_cwd = true; - 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, - from_cwd, - version, - &compile_opts, - args.is_present("force"), - )?; - } - Ok(()) -} diff --git a/src/bin/commands/locate_project.rs b/src/bin/commands/locate_project.rs deleted file mode 100644 index 2e20ccfb3..000000000 --- a/src/bin/commands/locate_project.rs +++ /dev/null @@ -1,33 +0,0 @@ -use command_prelude::*; - -use cargo::print_json; - -pub fn cli() -> App { - subcommand("locate-project") - .about("Print a JSON representation of a Cargo.toml file's location") - .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 deleted file mode 100644 index 199951048..000000000 --- a/src/bin/commands/login.rs +++ /dev/null @@ -1,58 +0,0 @@ -use command_prelude::*; - -use std::io::{self, BufRead}; - -use cargo::core::{Source, SourceId}; -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. \ - 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")) -} - -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 deleted file mode 100644 index b701acd61..000000000 --- a/src/bin/commands/metadata.rs +++ /dev/null @@ -1,53 +0,0 @@ -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, \ - 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"), - ) -} - -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 deleted file mode 100644 index fc829a855..000000000 --- a/src/bin/commands/mod.rs +++ /dev/null @@ -1,101 +0,0 @@ -use command_prelude::*; - -pub fn builtin() -> Vec { - vec![ - bench::cli(), - build::cli(), - check::cli(), - clean::cli(), - doc::cli(), - fetch::cli(), - generate_lockfile::cli(), - git_checkout::cli(), - init::cli(), - install::cli(), - locate_project::cli(), - login::cli(), - metadata::cli(), - new::cli(), - owner::cli(), - package::cli(), - pkgid::cli(), - publish::cli(), - read_manifest::cli(), - run::cli(), - rustc::cli(), - rustdoc::cli(), - search::cli(), - test::cli(), - uninstall::cli(), - update::cli(), - verify_project::cli(), - version::cli(), - yank::cli(), - ] -} - -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) -} - -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 deleted file mode 100644 index ff8472209..000000000 --- a/src/bin/commands/new.rs +++ /dev/null @@ -1,26 +0,0 @@ -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(config)?; - - ops::new(&opts, config)?; - let path = args.value_of("path").unwrap(); - let project_name = if let Some(name) = args.value_of("name") { - name - } else { - path - }; - config - .shell() - .status("Created", format!("{} `{}` project", opts.kind, project_name))?; - Ok(()) -} diff --git a/src/bin/commands/owner.rs b/src/bin/commands/owner.rs deleted file mode 100644 index f20be31b1..000000000 --- a/src/bin/commands/owner.rs +++ /dev/null @@ -1,49 +0,0 @@ -use command_prelude::*; - -use cargo::ops::{self, OwnersOptions}; - -pub fn cli() -> App { - subcommand("owner") - .about("Manage the owners of a crate on the registry") - .arg(Arg::with_name("crate")) - .arg(multi_opt("add", "LOGIN", "Name of a user or team to add as an owner").short("a")) - .arg( - multi_opt( - "remove", - "LOGIN", - "Name of a user or team to remove as an owner", - ).short("r"), - ) - .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.", - ) -} - -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 deleted file mode 100644 index f5e9d9184..000000000 --- a/src/bin/commands/package.rs +++ /dev/null @@ -1,48 +0,0 @@ -use command_prelude::*; - -use cargo::ops::{self, PackageOpts}; - -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_target_dir() - .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 deleted file mode 100644 index 7010092d6..000000000 --- a/src/bin/commands/pkgid.rs +++ /dev/null @@ -1,41 +0,0 @@ -use command_prelude::*; - -use cargo::ops; - -pub fn cli() -> App { - subcommand("pkgid") - .about("Print a fully qualified package specification") - .arg(Arg::with_name("spec")) - .arg_package("Argument to get the package id specifier for") - .arg_manifest_path() - .after_help( - "\ -Given a argument, print out the fully qualified package id specifier. -This command will generate an error if is ambiguous as to which package -it refers to in the dependency graph. If no is given, then the pkgid for -the local package is printed. - -This command requires that a lockfile is available and dependencies have been -fetched. - -Example Package IDs - - pkgid | name | version | url - |-----------------------------|--------|-----------|---------------------| - foo | foo | * | * - foo:1.2.3 | foo | 1.2.3 | * - crates.io/foo | foo | * | *://crates.io/foo - crates.io/foo#1.2.3 | foo | 1.2.3 | *://crates.io/foo - crates.io/bar#foo:1.2.3 | foo | 1.2.3 | *://crates.io/bar - http://crates.io/foo#1.2.3 | foo | 1.2.3 | http://crates.io/foo -", - ) -} - -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 deleted file mode 100644 index b50d3619c..000000000 --- a/src/bin/commands/publish.rs +++ /dev/null @@ -1,46 +0,0 @@ -use command_prelude::*; - -use cargo::ops::{self, PublishOpts}; - -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_target_dir() - .arg_manifest_path() - .arg_jobs() - .arg(opt("dry-run", "Perform all checks without uploading")) - .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 deleted file mode 100644 index 1e54c79e8..000000000 --- a/src/bin/commands/read_manifest.rs +++ /dev/null @@ -1,18 +0,0 @@ -use command_prelude::*; - -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 ws = args.workspace(config)?; - print_json(&ws.current()?); - Ok(()) -} diff --git a/src/bin/commands/run.rs b/src/bin/commands/run.rs deleted file mode 100644 index 763263d5a..000000000 --- a/src/bin/commands/run.rs +++ /dev/null @@ -1,69 +0,0 @@ -use command_prelude::*; - -use cargo::core::Verbosity; -use cargo::ops::{self, CompileFilter, CompileMode}; - -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_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_target_dir() - .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 the arguments following the two dashes (`--`) 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. -", - ) -} - -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 deleted file mode 100644 index 35fb59e8e..000000000 --- a/src/bin/commands/rustc.rs +++ /dev/null @@ -1,74 +0,0 @@ -use command_prelude::*; - -use cargo::ops::{self, CompileMode}; - -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_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_target_dir() - .arg_manifest_path() - .arg_message_format() - .after_help( - "\ -The specified target for the current package (or package specified by SPEC if -provided) will be compiled along with all of its dependencies. The specified -... will all be passed to the final compiler invocation, not any of the -dependencies. Note that the compiler will still unconditionally receive -arguments such as -L, --extern, and --crate-type, and the specified ... -will simply be added to the compiler invocation. - -This command requires that only one target is being compiled. If more than one -target is available for the current package the filters of --lib, --bin, etc, -must be used to select which target is compiled. To pass flags to all compiler -processes spawned by Cargo, use the $RUSTFLAGS environment variable or the -`build.rustflags` configuration option. -", - ) -} - -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)?; - let target_args = values(args, "args"); - compile_opts.target_rustc_args = if target_args.is_empty() { - None - } else { - Some(target_args) - }; - ops::compile(&ws, &compile_opts)?; - Ok(()) -} diff --git a/src/bin/commands/rustdoc.rs b/src/bin/commands/rustdoc.rs deleted file mode 100644 index 301e65449..000000000 --- a/src/bin/commands/rustdoc.rs +++ /dev/null @@ -1,66 +0,0 @@ -use command_prelude::*; - -use cargo::ops::{self, CompileMode, DocOptions}; - -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_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_features() - .arg_target_dir() - .arg_manifest_path() - .arg_message_format() - .after_help( - "\ -The specified target for the current package (or package specified by SPEC if -provided) will be documented with the specified ... being passed to the -final rustdoc invocation. Dependencies will not be documented as part of this -command. Note that rustdoc will still unconditionally receive arguments such -as -L, --extern, and --crate-type, and the specified ... will simply be -added to the rustdoc invocation. - -If the --package argument is given, then SPEC is a package id specification -which indicates which package should be documented. If it is not given, then the -current package is documented. For more information on SPEC and its format, see -the `cargo help pkgid` command. -", - ) -} - -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 })?; - let target_args = values(args, "args"); - compile_opts.target_rustdoc_args = if target_args.is_empty() { - None - } else { - Some(target_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 deleted file mode 100644 index 0501d8e5f..000000000 --- a/src/bin/commands/search.rs +++ /dev/null @@ -1,30 +0,0 @@ -use command_prelude::*; - -use std::cmp::min; - -use cargo::ops; - -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")) -} - -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 deleted file mode 100644 index a25f62f8e..000000000 --- a/src/bin/commands/test.rs +++ /dev/null @@ -1,137 +0,0 @@ -use command_prelude::*; - -use cargo::ops::{self, CompileMode}; - -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_spec( - "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_target_dir() - .arg_manifest_path() - .arg_message_format() - .after_help( - "\ -The test filtering argument `TESTNAME` and all the arguments following the -two dashes (`--`) are passed to the test binaries and thus to libtest -(rustc's built in unit-test and micro-benchmarking framework). If you're -passing arguments to both Cargo and the binary, the ones after `--` go to the -binary, the ones before go to Cargo. For details about libtest's arguments see -the output of `cargo test -- --help`. As an example, this will run all -tests with `foo` in their name on 3 threads in parallel: - - cargo test foo -- --test-threads 3 - -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 -", - ) -} - -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 deleted file mode 100644 index 203185119..000000000 --- a/src/bin/commands/uninstall.rs +++ /dev/null @@ -1,26 +0,0 @@ -use command_prelude::*; - -use cargo::ops; - -pub fn cli() -> App { - subcommand("uninstall") - .about("Remove a Rust binary") - .arg(Arg::with_name("spec").multiple(true)) - .arg(multi_opt("bin", "NAME", "Only uninstall the binary NAME")) - .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. -", - ) -} - -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 deleted file mode 100644 index c5a992a3d..000000000 --- a/src/bin/commands/update.rs +++ /dev/null @@ -1,51 +0,0 @@ -use command_prelude::*; - -use cargo::ops::{self, UpdateOptions}; - -pub fn cli() -> App { - subcommand("update") - .about("Update dependencies as recorded in the local lock file") - .arg_package_spec_simple("Package to update") - .arg(opt( - "aggressive", - "Force updating all dependencies of as well", - )) - .arg(opt("precise", "Update a single dependency to exactly PRECISE").value_name("PRECISE")) - .arg_manifest_path() - .after_help( - "\ -This command requires that a `Cargo.lock` already exists as generated by -`cargo build` or related commands. - -If SPEC is given, then a conservative update of the lockfile will be -performed. This means that only the dependency specified by SPEC will be -updated. Its transitive dependencies will be updated only if SPEC cannot be -updated without updating dependencies. All other dependencies will remain -locked at their currently recorded versions. - -If PRECISE is specified, then --aggressive must not also be specified. The -argument PRECISE is a string representing a precise revision that the package -being updated should be updated to. For example, if the package comes from a git -repository, then PRECISE would be the exact revision that the repository should -be updated to. - -If SPEC is not given, then all dependencies will be re-resolved and -updated. - -For more information about package id specifications, see `cargo help pkgid`. -", - ) -} - -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 deleted file mode 100644 index eea65c775..000000000 --- a/src/bin/commands/verify_project.rs +++ /dev/null @@ -1,45 +0,0 @@ -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 deleted file mode 100644 index 0e9d5be52..000000000 --- a/src/bin/commands/version.rs +++ /dev/null @@ -1,12 +0,0 @@ -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 deleted file mode 100644 index 150474be8..000000000 --- a/src/bin/commands/yank.rs +++ /dev/null @@ -1,43 +0,0 @@ -use command_prelude::*; - -use cargo::ops; - -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. -", - ) -} - -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(()) -}