]> git.proxmox.com Git - cargo.git/commitdiff
Move command prelude into main library
authorAndy Caldwell <andrew.caldwell@metaswitch.com>
Mon, 19 Nov 2018 21:41:09 +0000 (21:41 +0000)
committerAndy Caldwell <andrew.caldwell@metaswitch.com>
Mon, 19 Nov 2018 21:41:09 +0000 (21:41 +0000)
src/bin/cargo/command_prelude.rs [deleted file]
src/bin/cargo/main.rs
src/cargo/util/command_prelude.rs [new file with mode: 0644]
src/cargo/util/mod.rs

diff --git a/src/bin/cargo/command_prelude.rs b/src/bin/cargo/command_prelude.rs
deleted file mode 100644 (file)
index c8f2fc8..0000000
+++ /dev/null
@@ -1,453 +0,0 @@
-use std::path::PathBuf;
-use std::fs;
-
-use clap::{self, SubCommand};
-use cargo::CargoResult;
-use cargo::core::Workspace;
-use cargo::core::compiler::{BuildConfig, MessageFormat};
-use cargo::ops::{CompileFilter, CompileOptions, NewOptions, Packages, VersionControl};
-use cargo::sources::CRATES_IO_REGISTRY;
-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 use cargo::core::compiler::CompileMode;
-
-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", "short"])
-                .default_value("human"),
-        )
-    }
-
-    fn arg_build_plan(self) -> Self {
-        self._arg(opt("build-plan", "Output the build plan in JSON"))
-    }
-
-    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("edition", "Edition to set for the crate generated")
-                    .possible_values(&["2015", "2018"])
-                    .value_name("YEAR")
-            )
-            ._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<Option<u32>> {
-        let arg = match self._value_of(name) {
-            None => None,
-            Some(arg) => Some(arg.parse::<u32>().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<PathBuf> {
-        self._value_of(name).map(|path| config.cwd().join(path))
-    }
-
-    fn root_manifest(&self, config: &Config) -> CargoResult<PathBuf> {
-        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_err() {
-                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<Workspace<'a>> {
-        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<Option<u32>> {
-        self.value_of_u32("jobs")
-    }
-
-    fn target(&self) -> Option<String> {
-        self._value_of("target").map(|s| s.to_string())
-    }
-
-    fn compile_options<'a>(
-        &self,
-        config: &'a Config,
-        mode: CompileMode,
-    ) -> CargoResult<CompileOptions<'a>> {
-        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 if f.eq_ignore_ascii_case("short") {
-                    MessageFormat::Short
-                } else {
-                    panic!("Impossible message format: {:?}", f)
-                }
-            }
-        };
-
-        let mut build_config = BuildConfig::new(config, self.jobs()?, &self.target(), mode)?;
-        build_config.message_format = message_format;
-        build_config.release = self._is_present("release");
-        build_config.build_plan = self._is_present("build-plan");
-        if build_config.build_plan && !config.cli_unstable().unstable_options {
-            Err(format_err!(
-                "`--build-plan` flag is unstable, pass `-Z unstable-options` to enable it"
-            ))?;
-        };
-
-        let opts = CompileOptions {
-            config,
-            build_config,
-            features: self._values_of("features"),
-            all_features: self._is_present("all-features"),
-            no_default_features: self._is_present("no-default-features"),
-            spec,
-            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"),
-            ),
-            target_rustdoc_args: None,
-            target_rustc_args: None,
-            local_rustdoc_args: None,
-            export_dir: None,
-        };
-        Ok(opts)
-    }
-
-    fn compile_options_for_single_package<'a>(
-        &self,
-        config: &'a Config,
-        mode: CompileMode,
-    ) -> CargoResult<CompileOptions<'a>> {
-        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<NewOptions> {
-        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()),
-            self._value_of("edition").map(|s| s.to_string()),
-            self.registry(config)?,
-        )
-    }
-
-    fn registry(&self, config: &Config) -> CargoResult<Option<String>> {
-        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."
-                    ));
-                }
-
-                if registry == CRATES_IO_REGISTRY {
-                    // If "crates.io" is specified then we just need to return None
-                    // as that will cause cargo to use crates.io. This is required
-                    // for the case where a default alterative registry is used
-                    // but the user wants to switch back to crates.io for a single
-                    // command.
-                    Ok(None)
-                }
-                else {
-                    Ok(Some(registry.to_string()))                    
-                }
-            }
-            None => {
-                config.default_registry()
-            }
-        }
-    }
-
-    fn index(&self, config: &Config) -> CargoResult<Option<String>> {
-        // TODO: Deprecated
-        // remove once it has been decided --host can be removed
-        // We may instead want to repurpose the host flag, as
-        // mentioned in this issue
-        // https://github.com/rust-lang/cargo/issues/4208
-        let msg = "The flag '--host' is no longer valid.
-
-Previous versions of Cargo accepted this flag, but it is being
-deprecated. The flag is being renamed to 'index', as the flag
-wants the location of the index. Please use '--index' instead.
-
-This will soon become a hard error, so it's either recommended
-to update to a fixed version or contact the upstream maintainer
-about this warning.";
-
-        let index = match 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<String>;
-
-    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<String> {
-        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<String> {
-    args.values_of(name)
-        .unwrap_or_default()
-        .map(|s| s.to_string())
-        .collect()
-}
-
-#[derive(PartialEq, PartialOrd, Eq, Ord)]
-pub enum CommandInfo {
-    BuiltIn { name: String, about: Option<String>, },
-    External { name: String, path: PathBuf },
-}
-
-impl CommandInfo {
-    pub fn name(&self) -> String {
-        match self {
-            CommandInfo::BuiltIn { name, .. } => name.to_string(),
-            CommandInfo::External { name, .. } => name.to_string(),
-        }
-    }
-}
index e0333ee1081558e8a1dac1c0b3a7f3f59e99a69c..979d894942744ef71af2a09c030122f37727784d 100644 (file)
@@ -19,11 +19,10 @@ 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::{self, command_prelude, lev_distance, CargoResult, CliResult, Config};
 use cargo::util::{CliError, ProcessError};
 
 mod cli;
-mod command_prelude;
 mod commands;
 
 use command_prelude::*;
diff --git a/src/cargo/util/command_prelude.rs b/src/cargo/util/command_prelude.rs
new file mode 100644 (file)
index 0000000..774e0fc
--- /dev/null
@@ -0,0 +1,453 @@
+use std::path::PathBuf;
+use std::fs;
+
+use clap::{self, SubCommand};
+use CargoResult;
+use core::Workspace;
+use core::compiler::{BuildConfig, MessageFormat};
+use ops::{CompileFilter, CompileOptions, NewOptions, Packages, VersionControl};
+use sources::CRATES_IO_REGISTRY;
+use util::paths;
+use util::important_paths::find_root_manifest_for_wd;
+
+pub use clap::{AppSettings, Arg, ArgMatches};
+pub use {CliError, CliResult, Config};
+pub use core::compiler::CompileMode;
+
+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", "short"])
+                .default_value("human"),
+        )
+    }
+
+    fn arg_build_plan(self) -> Self {
+        self._arg(opt("build-plan", "Output the build plan in JSON"))
+    }
+
+    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("edition", "Edition to set for the crate generated")
+                    .possible_values(&["2015", "2018"])
+                    .value_name("YEAR")
+            )
+            ._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<Option<u32>> {
+        let arg = match self._value_of(name) {
+            None => None,
+            Some(arg) => Some(arg.parse::<u32>().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<PathBuf> {
+        self._value_of(name).map(|path| config.cwd().join(path))
+    }
+
+    fn root_manifest(&self, config: &Config) -> CargoResult<PathBuf> {
+        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_err() {
+                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<Workspace<'a>> {
+        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<Option<u32>> {
+        self.value_of_u32("jobs")
+    }
+
+    fn target(&self) -> Option<String> {
+        self._value_of("target").map(|s| s.to_string())
+    }
+
+    fn compile_options<'a>(
+        &self,
+        config: &'a Config,
+        mode: CompileMode,
+    ) -> CargoResult<CompileOptions<'a>> {
+        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 if f.eq_ignore_ascii_case("short") {
+                    MessageFormat::Short
+                } else {
+                    panic!("Impossible message format: {:?}", f)
+                }
+            }
+        };
+
+        let mut build_config = BuildConfig::new(config, self.jobs()?, &self.target(), mode)?;
+        build_config.message_format = message_format;
+        build_config.release = self._is_present("release");
+        build_config.build_plan = self._is_present("build-plan");
+        if build_config.build_plan && !config.cli_unstable().unstable_options {
+            Err(format_err!(
+                "`--build-plan` flag is unstable, pass `-Z unstable-options` to enable it"
+            ))?;
+        };
+
+        let opts = CompileOptions {
+            config,
+            build_config,
+            features: self._values_of("features"),
+            all_features: self._is_present("all-features"),
+            no_default_features: self._is_present("no-default-features"),
+            spec,
+            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"),
+            ),
+            target_rustdoc_args: None,
+            target_rustc_args: None,
+            local_rustdoc_args: None,
+            export_dir: None,
+        };
+        Ok(opts)
+    }
+
+    fn compile_options_for_single_package<'a>(
+        &self,
+        config: &'a Config,
+        mode: CompileMode,
+    ) -> CargoResult<CompileOptions<'a>> {
+        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<NewOptions> {
+        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()),
+            self._value_of("edition").map(|s| s.to_string()),
+            self.registry(config)?,
+        )
+    }
+
+    fn registry(&self, config: &Config) -> CargoResult<Option<String>> {
+        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."
+                    ));
+                }
+
+                if registry == CRATES_IO_REGISTRY {
+                    // If "crates.io" is specified then we just need to return None
+                    // as that will cause cargo to use crates.io. This is required
+                    // for the case where a default alterative registry is used
+                    // but the user wants to switch back to crates.io for a single
+                    // command.
+                    Ok(None)
+                }
+                else {
+                    Ok(Some(registry.to_string()))                    
+                }
+            }
+            None => {
+                config.default_registry()
+            }
+        }
+    }
+
+    fn index(&self, config: &Config) -> CargoResult<Option<String>> {
+        // TODO: Deprecated
+        // remove once it has been decided --host can be removed
+        // We may instead want to repurpose the host flag, as
+        // mentioned in this issue
+        // https://github.com/rust-lang/cargo/issues/4208
+        let msg = "The flag '--host' is no longer valid.
+
+Previous versions of Cargo accepted this flag, but it is being
+deprecated. The flag is being renamed to 'index', as the flag
+wants the location of the index. Please use '--index' instead.
+
+This will soon become a hard error, so it's either recommended
+to update to a fixed version or contact the upstream maintainer
+about this warning.";
+
+        let index = match 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<String>;
+
+    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<String> {
+        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<String> {
+    args.values_of(name)
+        .unwrap_or_default()
+        .map(|s| s.to_string())
+        .collect()
+}
+
+#[derive(PartialEq, PartialOrd, Eq, Ord)]
+pub enum CommandInfo {
+    BuiltIn { name: String, about: Option<String>, },
+    External { name: String, path: PathBuf },
+}
+
+impl CommandInfo {
+    pub fn name(&self) -> String {
+        match self {
+            CommandInfo::BuiltIn { name, .. } => name.to_string(),
+            CommandInfo::External { name, .. } => name.to_string(),
+        }
+    }
+}
index c18914954f64b4b5ec7066c2e1591395146db9ba..69f2d0e6852df489b813b81acf4585541366a348 100644 (file)
@@ -38,6 +38,7 @@ pub mod profile;
 pub mod to_semver;
 pub mod to_url;
 pub mod toml;
+pub mod command_prelude;
 mod cfg;
 mod dependency_queue;
 mod rustc;