From c76c8fd9aadff705336d348676d87b15a86b50ce Mon Sep 17 00:00:00 2001
From: Rustin170506 <29879298+hi-rustin@users.noreply.github.com>
Date: Tue, 25 Jun 2024 20:45:33 +0800
Subject: [PATCH 1/4] feat: Add `info` cargo subcommand
---
src/bin/cargo/commands/info.rs | 35 ++
src/bin/cargo/commands/mod.rs | 3 +
src/cargo/ops/mod.rs | 1 +
src/cargo/ops/registry/info/mod.rs | 287 ++++++++++++++++
src/cargo/ops/registry/info/view.rs | 489 ++++++++++++++++++++++++++++
src/cargo/ops/registry/mod.rs | 56 +++-
6 files changed, 870 insertions(+), 1 deletion(-)
create mode 100644 src/bin/cargo/commands/info.rs
create mode 100644 src/cargo/ops/registry/info/mod.rs
create mode 100644 src/cargo/ops/registry/info/view.rs
diff --git a/src/bin/cargo/commands/info.rs b/src/bin/cargo/commands/info.rs
new file mode 100644
index 00000000000..065fcbcd9aa
--- /dev/null
+++ b/src/bin/cargo/commands/info.rs
@@ -0,0 +1,35 @@
+use anyhow::Context;
+use cargo::ops::info;
+use cargo::util::command_prelude::*;
+use cargo_util_schemas::core::PackageIdSpec;
+
+pub fn cli() -> Command {
+ Command::new("info")
+ .about("Display information about a package in the registry")
+ .arg(
+ Arg::new("package")
+ .required(true)
+ .value_name("SPEC")
+ .help_heading(heading::PACKAGE_SELECTION)
+ .help("Package to inspect"),
+ )
+ .arg_index("Registry index URL to search packages in")
+ .arg_registry("Registry to search packages in")
+ .arg_silent_suggestion()
+ .after_help(color_print::cstr!(
+ "Run `cargo help info>` for more detailed information.\n"
+ ))
+}
+
+pub fn exec(gctx: &mut GlobalContext, args: &ArgMatches) -> CliResult {
+ let package = args
+ .get_one::("package")
+ .map(String::as_str)
+ .unwrap();
+ let spec = PackageIdSpec::parse(package)
+ .with_context(|| format!("invalid package ID specification: `{package}`"))?;
+
+ let reg_or_index = args.registry_or_index(gctx)?;
+ info(&spec, gctx, reg_or_index)?;
+ Ok(())
+}
diff --git a/src/bin/cargo/commands/mod.rs b/src/bin/cargo/commands/mod.rs
index 02c3438dc47..b507226f3a9 100644
--- a/src/bin/cargo/commands/mod.rs
+++ b/src/bin/cargo/commands/mod.rs
@@ -14,6 +14,7 @@ pub fn builtin() -> Vec {
generate_lockfile::cli(),
git_checkout::cli(),
help::cli(),
+ info::cli(),
init::cli(),
install::cli(),
locate_project::cli(),
@@ -59,6 +60,7 @@ pub fn builtin_exec(cmd: &str) -> Option {
"generate-lockfile" => generate_lockfile::exec,
"git-checkout" => git_checkout::exec,
"help" => help::exec,
+ "info" => info::exec,
"init" => init::exec,
"install" => install::exec,
"locate-project" => locate_project::exec,
@@ -102,6 +104,7 @@ pub mod fix;
pub mod generate_lockfile;
pub mod git_checkout;
pub mod help;
+pub mod info;
pub mod init;
pub mod install;
pub mod locate_project;
diff --git a/src/cargo/ops/mod.rs b/src/cargo/ops/mod.rs
index b32b2147dc9..0cbf8f92203 100644
--- a/src/cargo/ops/mod.rs
+++ b/src/cargo/ops/mod.rs
@@ -24,6 +24,7 @@ pub use self::cargo_update::write_manifest_upgrades;
pub use self::cargo_update::UpdateOptions;
pub use self::fix::{fix, fix_exec_rustc, fix_get_proxy_lock_addr, FixOptions};
pub use self::lockfile::{load_pkg_lockfile, resolve_to_string, write_pkg_lockfile};
+pub use self::registry::info;
pub use self::registry::modify_owners;
pub use self::registry::publish;
pub use self::registry::registry_login;
diff --git a/src/cargo/ops/registry/info/mod.rs b/src/cargo/ops/registry/info/mod.rs
new file mode 100644
index 00000000000..e4607d0e32a
--- /dev/null
+++ b/src/cargo/ops/registry/info/mod.rs
@@ -0,0 +1,287 @@
+//! Implementation of `cargo info`.
+
+use anyhow::bail;
+use cargo_credential::Operation;
+use cargo_util_schemas::core::{PackageIdSpec, PartialVersion};
+use crates_io::User;
+
+use crate::core::registry::PackageRegistry;
+use crate::core::{Dependency, Package, PackageId, PackageIdSpecQuery, Registry, Workspace};
+use crate::ops::registry::info::view::pretty_view;
+use crate::ops::registry::{get_source_id_with_package_id, RegistryOrIndex, RegistrySourceIds};
+use crate::ops::resolve_ws;
+use crate::sources::source::QueryKind;
+use crate::sources::{IndexSummary, SourceConfigMap};
+use crate::util::auth::AuthorizationErrorReason;
+use crate::util::cache_lock::CacheLockMode;
+use crate::util::command_prelude::root_manifest;
+use crate::{CargoResult, GlobalContext};
+
+mod view;
+
+pub fn info(
+ spec: &PackageIdSpec,
+ gctx: &GlobalContext,
+ reg_or_index: Option,
+) -> CargoResult<()> {
+ let source_config = SourceConfigMap::new(gctx)?;
+ let mut registry = PackageRegistry::new_with_source_config(gctx, source_config)?;
+ // Make sure we get the lock before we download anything.
+ let _lock = gctx.acquire_package_cache_lock(CacheLockMode::DownloadExclusive)?;
+ registry.lock_patches();
+
+ // If we can find it in workspace, use it as a specific version.
+ let nearest_manifest_path = root_manifest(None, gctx).ok();
+ let ws = nearest_manifest_path
+ .as_ref()
+ .and_then(|root| Workspace::new(root, gctx).ok());
+ validate_locked_and_frozen_options(ws.is_some(), gctx)?;
+ let nearest_package = ws.as_ref().and_then(|ws| {
+ nearest_manifest_path
+ .as_ref()
+ .and_then(|path| ws.members().find(|p| p.manifest_path() == path))
+ });
+ let (mut package_id, is_member) = find_pkgid_in_ws(nearest_package, ws.as_ref(), spec);
+ let (use_package_source_id, source_ids) =
+ get_source_id_with_package_id(gctx, package_id, reg_or_index.as_ref())?;
+ // If we don't use the package's source, we need to query the package ID from the specified registry.
+ if !use_package_source_id {
+ package_id = None;
+ }
+
+ let msrv_from_nearest_manifest_path_or_ws =
+ try_get_msrv_from_nearest_manifest_or_ws(nearest_package, ws.as_ref());
+ // If the workspace does not have a specific Rust version,
+ // or if the command is not called within the workspace, then fallback to the global Rust version.
+ let rustc_version = match msrv_from_nearest_manifest_path_or_ws {
+ Some(msrv) => msrv,
+ None => {
+ let current_rustc = gctx.load_global_rustc(ws.as_ref())?.version;
+ // Remove any pre-release identifiers for easier comparison.
+ // Otherwise, the MSRV check will fail if the current Rust version is a nightly or beta version.
+ semver::Version::new(
+ current_rustc.major,
+ current_rustc.minor,
+ current_rustc.patch,
+ )
+ .into()
+ }
+ };
+ // Only suggest cargo tree command when the package is not a workspace member.
+ // For workspace members, `cargo tree --package --invert` is useless. It only prints itself.
+ let suggest_cargo_tree_command = package_id.is_some() && !is_member;
+
+ let summaries = query_summaries(spec, &mut registry, &source_ids)?;
+ let package_id = match package_id {
+ Some(id) => id,
+ None => find_pkgid_in_summaries(&summaries, spec, &rustc_version, &source_ids)?,
+ };
+
+ let package = registry.get(&[package_id])?;
+ let package = package.get_one(package_id)?;
+ let owners = try_list_owners(
+ gctx,
+ &source_ids,
+ reg_or_index.as_ref(),
+ package_id.name().as_str(),
+ )?;
+ pretty_view(
+ package,
+ &summaries,
+ &owners,
+ suggest_cargo_tree_command,
+ gctx,
+ )?;
+
+ Ok(())
+}
+
+fn find_pkgid_in_ws(
+ nearest_package: Option<&Package>,
+ ws: Option<&Workspace<'_>>,
+ spec: &PackageIdSpec,
+) -> (Option, bool) {
+ let Some(ws) = ws else {
+ return (None, false);
+ };
+
+ if let Some(member) = ws.members().find(|p| spec.matches(p.package_id())) {
+ return (Some(member.package_id()), true);
+ }
+
+ let Ok((_, resolve)) = resolve_ws(ws, false) else {
+ return (None, false);
+ };
+
+ if let Some(package_id) = nearest_package
+ .map(|p| p.package_id())
+ .into_iter()
+ .flat_map(|p| resolve.deps(p))
+ .map(|(p, _)| p)
+ .filter(|&p| spec.matches(p))
+ .max_by_key(|&p| p.version())
+ {
+ return (Some(package_id), false);
+ }
+
+ if let Some(package_id) = ws
+ .members()
+ .map(|p| p.package_id())
+ .flat_map(|p| resolve.deps(p))
+ .map(|(p, _)| p)
+ .filter(|&p| spec.matches(p))
+ .max_by_key(|&p| p.version())
+ {
+ return (Some(package_id), false);
+ }
+
+ if let Some(package_id) = resolve
+ .iter()
+ .filter(|&p| spec.matches(p))
+ .max_by_key(|&p| p.version())
+ {
+ return (Some(package_id), false);
+ }
+
+ (None, false)
+}
+
+fn find_pkgid_in_summaries(
+ summaries: &[IndexSummary],
+ spec: &PackageIdSpec,
+ rustc_version: &PartialVersion,
+ source_ids: &RegistrySourceIds,
+) -> CargoResult {
+ let summary = summaries
+ .iter()
+ .filter(|s| spec.matches(s.package_id()))
+ .max_by(|s1, s2| {
+ // Check the MSRV compatibility.
+ let s1_matches = s1
+ .as_summary()
+ .rust_version()
+ .map(|v| v.is_compatible_with(rustc_version))
+ .unwrap_or_else(|| false);
+ let s2_matches = s2
+ .as_summary()
+ .rust_version()
+ .map(|v| v.is_compatible_with(rustc_version))
+ .unwrap_or_else(|| false);
+ // MSRV compatible version is preferred.
+ match (s1_matches, s2_matches) {
+ (true, false) => std::cmp::Ordering::Greater,
+ (false, true) => std::cmp::Ordering::Less,
+ // If both summaries match the current Rust version or neither do, try to
+ // pick the latest version.
+ _ => s1.package_id().version().cmp(s2.package_id().version()),
+ }
+ });
+
+ match summary {
+ Some(summary) => Ok(summary.package_id()),
+ None => {
+ anyhow::bail!(
+ "could not find `{}` in registry `{}`",
+ spec,
+ source_ids.original.url()
+ )
+ }
+ }
+}
+
+fn query_summaries(
+ spec: &PackageIdSpec,
+ registry: &mut PackageRegistry<'_>,
+ source_ids: &RegistrySourceIds,
+) -> CargoResult> {
+ // Query without version requirement to get all index summaries.
+ let dep = Dependency::parse(spec.name(), None, source_ids.original)?;
+ loop {
+ // Exact to avoid returning all for path/git
+ match registry.query_vec(&dep, QueryKind::Exact) {
+ std::task::Poll::Ready(res) => {
+ break res;
+ }
+ std::task::Poll::Pending => registry.block_until_ready()?,
+ }
+ }
+}
+
+// Try to list the login and name of all owners of a crate.
+fn try_list_owners(
+ gctx: &GlobalContext,
+ source_ids: &RegistrySourceIds,
+ reg_or_index: Option<&RegistryOrIndex>,
+ package_name: &str,
+) -> CargoResult>> {
+ // Only remote registries support listing owners.
+ if !source_ids.original.is_remote_registry() {
+ return Ok(None);
+ }
+ match super::registry(
+ gctx,
+ source_ids,
+ None,
+ reg_or_index,
+ false,
+ Some(Operation::Read),
+ ) {
+ Ok(mut registry) => {
+ let owners = registry.list_owners(package_name)?;
+ let names = owners.iter().map(get_username).collect();
+ return Ok(Some(names));
+ }
+ Err(err) => {
+ // If the token is missing, it means the user is not logged in.
+ // We don't want to show an error in this case.
+ if err.to_string().contains(
+ (AuthorizationErrorReason::TokenMissing)
+ .to_string()
+ .as_str(),
+ ) {
+ return Ok(None);
+ }
+ return Err(err);
+ }
+ }
+}
+
+fn get_username(u: &User) -> String {
+ format!(
+ "{}{}",
+ u.login,
+ u.name
+ .as_ref()
+ .map(|name| format!(" ({})", name))
+ .unwrap_or_default(),
+ )
+}
+
+fn validate_locked_and_frozen_options(
+ in_workspace: bool,
+ gctx: &GlobalContext,
+) -> Result<(), anyhow::Error> {
+ // Only in workspace, we can use --frozen or --locked.
+ if !in_workspace {
+ if gctx.locked() {
+ bail!("the option `--locked` can only be used within a workspace");
+ }
+
+ if gctx.frozen() {
+ bail!("the option `--frozen` can only be used within a workspace");
+ }
+ }
+ Ok(())
+}
+
+fn try_get_msrv_from_nearest_manifest_or_ws(
+ nearest_package: Option<&Package>,
+ ws: Option<&Workspace<'_>>,
+) -> Option {
+ // Try to get the MSRV from the nearest manifest.
+ let rust_version = nearest_package.and_then(|p| p.rust_version().map(|v| v.as_partial()));
+ // If the nearest manifest does not have a specific Rust version, try to get it from the workspace.
+ rust_version
+ .or_else(|| ws.and_then(|ws| ws.rust_version().map(|v| v.as_partial())))
+ .cloned()
+}
diff --git a/src/cargo/ops/registry/info/view.rs b/src/cargo/ops/registry/info/view.rs
new file mode 100644
index 00000000000..06ecd5913e2
--- /dev/null
+++ b/src/cargo/ops/registry/info/view.rs
@@ -0,0 +1,489 @@
+use std::collections::HashMap;
+use std::io::Write;
+
+use crate::util::style::{ERROR, HEADER, LITERAL, NOP, NOTE, WARN};
+use crate::{
+ core::{
+ dependency::DepKind, shell::Verbosity, Dependency, FeatureMap, Package, PackageId, SourceId,
+ },
+ sources::IndexSummary,
+ util::interning::InternedString,
+ CargoResult, GlobalContext,
+};
+
+// Pretty print the package information.
+pub(super) fn pretty_view(
+ package: &Package,
+ summaries: &[IndexSummary],
+ owners: &Option>,
+ suggest_cargo_tree_command: bool,
+ gctx: &GlobalContext,
+) -> CargoResult<()> {
+ let summary = package.manifest().summary();
+ let package_id = summary.package_id();
+ let metadata = package.manifest().metadata();
+ let is_package_from_crates_io = summary.source_id().is_crates_io();
+ let header = HEADER;
+ let error = ERROR;
+ let warn = WARN;
+ let note = NOTE;
+
+ let mut shell = gctx.shell();
+ let verbosity = shell.verbosity();
+ write!(shell.out(), "{header}{}{header:#}", package_id.name())?;
+ if !metadata.keywords.is_empty() {
+ let message = if is_package_from_crates_io {
+ metadata
+ .keywords
+ .iter()
+ .map(|keyword| {
+ let link = shell.out_hyperlink(format!("https://crates.io/keywords/{keyword}"));
+ format!("{link}#{keyword}{link:#}")
+ })
+ .collect::>()
+ .join(" ")
+ } else {
+ format!("#{}", metadata.keywords.join(" #"))
+ };
+ write!(shell.out(), " {note}{message}{note:#}")?;
+ }
+
+ let stdout = shell.out();
+ writeln!(stdout)?;
+ if let Some(ref description) = metadata.description {
+ writeln!(stdout, "{}", description.trim_end())?;
+ }
+ write!(
+ stdout,
+ "{header}version:{header:#} {}",
+ package_id.version()
+ )?;
+ // Add a warning message to stdout if the following conditions are met:
+ // 1. The package version is not the latest available version.
+ // 2. The package source is not crates.io.
+ match (
+ summaries.iter().max_by_key(|s| s.as_summary().version()),
+ is_package_from_crates_io,
+ ) {
+ (Some(latest), false) if latest.as_summary().version() != package_id.version() => {
+ write!(
+ stdout,
+ " {warn}(latest {} {warn:#}{note}from {}{note:#}{warn}){warn:#}",
+ latest.as_summary().version(),
+ pretty_source(summary.source_id(), gctx)
+ )?;
+ }
+ (Some(latest), true) if latest.as_summary().version() != package_id.version() => {
+ write!(
+ stdout,
+ " {warn}(latest {}){warn:#}",
+ latest.as_summary().version(),
+ )?;
+ }
+ (_, false) => {
+ write!(
+ stdout,
+ " {note}(from {}){note:#}",
+ pretty_source(summary.source_id(), gctx)
+ )?;
+ }
+ (_, true) => {}
+ }
+ writeln!(stdout)?;
+ writeln!(
+ stdout,
+ "{header}license:{header:#} {}",
+ metadata
+ .license
+ .clone()
+ .unwrap_or_else(|| format!("{error}unknown{error:#}"))
+ )?;
+ // TODO: color MSRV as a warning if newer than either the "workspace" MSRV or `rustc --version`
+ writeln!(
+ stdout,
+ "{header}rust-version:{header:#} {}",
+ metadata
+ .rust_version
+ .as_ref()
+ .map(|v| v.to_string())
+ .unwrap_or_else(|| format!("{warn}unknown{warn:#}"))
+ )?;
+ if let Some(ref link) = metadata.documentation.clone().or_else(|| {
+ is_package_from_crates_io.then(|| {
+ format!(
+ "https://docs.rs/{name}/{version}",
+ name = package_id.name(),
+ version = package_id.version()
+ )
+ })
+ }) {
+ writeln!(stdout, "{header}documentation:{header:#} {link}")?;
+ }
+ if let Some(ref link) = metadata.homepage {
+ writeln!(stdout, "{header}homepage:{header:#} {link}")?;
+ }
+ if let Some(ref link) = metadata.repository {
+ writeln!(stdout, "{header}repository:{header:#} {link}")?;
+ }
+ // Only print the crates.io link if the package is from crates.io.
+ if is_package_from_crates_io {
+ writeln!(
+ stdout,
+ "{header}crates.io:{header:#} https://crates.io/crates/{}/{}",
+ package_id.name(),
+ package_id.version()
+ )?;
+ }
+
+ let activated = &[InternedString::new("default")];
+ let resolved_features = resolve_features(activated, summary.features());
+ pretty_features(
+ resolved_features.clone(),
+ summary.features(),
+ verbosity,
+ stdout,
+ )?;
+
+ pretty_deps(
+ package,
+ &resolved_features,
+ summary.features(),
+ verbosity,
+ stdout,
+ gctx,
+ )?;
+
+ if let Some(owners) = owners {
+ pretty_owners(owners, stdout)?;
+ }
+
+ if suggest_cargo_tree_command {
+ suggest_cargo_tree(package_id, stdout)?;
+ }
+
+ Ok(())
+}
+
+fn pretty_source(source: SourceId, ctx: &GlobalContext) -> String {
+ if let Some(relpath) = source
+ .local_path()
+ .and_then(|path| pathdiff::diff_paths(path, ctx.cwd()))
+ {
+ let path = std::path::Path::new(".").join(relpath);
+ path.display().to_string()
+ } else {
+ source.to_string()
+ }
+}
+
+fn pretty_deps(
+ package: &Package,
+ resolved_features: &[(InternedString, FeatureStatus)],
+ features: &FeatureMap,
+ verbosity: Verbosity,
+ stdout: &mut dyn Write,
+ gctx: &GlobalContext,
+) -> CargoResult<()> {
+ match verbosity {
+ Verbosity::Quiet | Verbosity::Normal => {
+ return Ok(());
+ }
+ Verbosity::Verbose => {}
+ }
+
+ let header = HEADER;
+
+ let dependencies = package
+ .dependencies()
+ .iter()
+ .filter(|d| d.kind() == DepKind::Normal)
+ .collect::>();
+ if !dependencies.is_empty() {
+ writeln!(stdout, "{header}dependencies:{header:#}")?;
+ print_deps(dependencies, resolved_features, features, stdout, gctx)?;
+ }
+
+ let build_dependencies = package
+ .dependencies()
+ .iter()
+ .filter(|d| d.kind() == DepKind::Build)
+ .collect::>();
+ if !build_dependencies.is_empty() {
+ writeln!(stdout, "{header}build-dependencies:{header:#}")?;
+ print_deps(
+ build_dependencies,
+ resolved_features,
+ features,
+ stdout,
+ gctx,
+ )?;
+ }
+
+ Ok(())
+}
+
+fn print_deps(
+ dependencies: Vec<&Dependency>,
+ resolved_features: &[(InternedString, FeatureStatus)],
+ features: &FeatureMap,
+ stdout: &mut dyn Write,
+ gctx: &GlobalContext,
+) -> Result<(), anyhow::Error> {
+ let enabled_by_user = HEADER;
+ let enabled = NOP;
+ let disabled = anstyle::Style::new() | anstyle::Effects::DIMMED;
+
+ let mut dependencies = dependencies
+ .into_iter()
+ .map(|dependency| {
+ let status = if !dependency.is_optional() {
+ FeatureStatus::EnabledByUser
+ } else if resolved_features
+ .iter()
+ .filter(|(_, s)| !s.is_disabled())
+ .filter_map(|(n, _)| features.get(n))
+ .flatten()
+ .filter_map(|f| match f {
+ crate::core::FeatureValue::Feature(_) => None,
+ crate::core::FeatureValue::Dep { dep_name } => Some(dep_name),
+ crate::core::FeatureValue::DepFeature { dep_name, weak, .. } if *weak => {
+ Some(dep_name)
+ }
+ crate::core::FeatureValue::DepFeature { .. } => None,
+ })
+ .any(|dep_name| *dep_name == dependency.name_in_toml())
+ {
+ FeatureStatus::Enabled
+ } else {
+ FeatureStatus::Disabled
+ };
+ (dependency, status)
+ })
+ .collect::>();
+ dependencies.sort_by_key(|(d, s)| (*s, d.package_name()));
+ for (dependency, status) in dependencies {
+ // 1. Only print the version requirement if it is a registry dependency.
+ // 2. Only print the source if it is not a registry dependency.
+ // For example: `bar (./crates/bar)` or `bar@=1.2.3`.
+ let (req, source) = if dependency.source_id().is_registry() {
+ (
+ format!("@{}", pretty_req(dependency.version_req())),
+ String::new(),
+ )
+ } else {
+ (
+ String::new(),
+ format!(" ({})", pretty_source(dependency.source_id(), gctx)),
+ )
+ };
+
+ if status == FeatureStatus::EnabledByUser {
+ write!(stdout, " {enabled_by_user}+{enabled_by_user:#}")?;
+ } else {
+ write!(stdout, " ")?;
+ }
+ let style = match status {
+ FeatureStatus::EnabledByUser | FeatureStatus::Enabled => enabled,
+ FeatureStatus::Disabled => disabled,
+ };
+ writeln!(
+ stdout,
+ "{style}{}{}{}{style:#}",
+ dependency.package_name(),
+ req,
+ source
+ )?;
+ }
+ Ok(())
+}
+
+fn pretty_req(req: &crate::util::OptVersionReq) -> String {
+ let mut rendered = req.to_string();
+ let strip_prefix = match req {
+ crate::util::OptVersionReq::Any => false,
+ crate::util::OptVersionReq::Req(req)
+ | crate::util::OptVersionReq::Locked(_, req)
+ | crate::util::OptVersionReq::Precise(_, req) => {
+ req.comparators.len() == 1 && rendered.starts_with('^')
+ }
+ };
+ if strip_prefix {
+ rendered.remove(0);
+ rendered
+ } else {
+ rendered
+ }
+}
+
+fn pretty_features(
+ resolved_features: Vec<(InternedString, FeatureStatus)>,
+ features: &FeatureMap,
+ verbosity: Verbosity,
+ stdout: &mut dyn Write,
+) -> CargoResult<()> {
+ let header = HEADER;
+ let enabled_by_user = HEADER;
+ let enabled = NOP;
+ let disabled = anstyle::Style::new() | anstyle::Effects::DIMMED;
+ let summary = anstyle::Style::new() | anstyle::Effects::ITALIC;
+
+ // If there are no features, return early.
+ let margin = features
+ .iter()
+ .map(|(name, _)| name.len())
+ .max()
+ .unwrap_or_default();
+ if margin == 0 {
+ return Ok(());
+ }
+
+ writeln!(stdout, "{header}features:{header:#}")?;
+
+ const MAX_FEATURE_PRINTS: usize = 30;
+ let total_activated = resolved_features
+ .iter()
+ .filter(|(_, s)| !s.is_disabled())
+ .count();
+ let total_deactivated = resolved_features
+ .iter()
+ .filter(|(_, s)| s.is_disabled())
+ .count();
+ let show_all = match verbosity {
+ Verbosity::Quiet | Verbosity::Normal => false,
+ Verbosity::Verbose => true,
+ };
+ let show_activated = total_activated <= MAX_FEATURE_PRINTS || show_all;
+ let show_deactivated = (total_activated + total_deactivated) <= MAX_FEATURE_PRINTS || show_all;
+ for (current, status, current_activated) in resolved_features
+ .iter()
+ .map(|(n, s)| (n, s, features.get(n).unwrap()))
+ {
+ if !status.is_disabled() && !show_activated {
+ continue;
+ }
+ if status.is_disabled() && !show_deactivated {
+ continue;
+ }
+ if *status == FeatureStatus::EnabledByUser {
+ write!(stdout, " {enabled_by_user}+{enabled_by_user:#}")?;
+ } else {
+ write!(stdout, " ")?;
+ }
+ let style = match status {
+ FeatureStatus::EnabledByUser | FeatureStatus::Enabled => enabled,
+ FeatureStatus::Disabled => disabled,
+ };
+ writeln!(
+ stdout,
+ "{style}{current: >()
+ .join(", ")
+ )?;
+ }
+ if !show_activated {
+ writeln!(
+ stdout,
+ " {summary}{total_activated} activated features{summary:#}",
+ )?;
+ }
+ if !show_deactivated {
+ writeln!(
+ stdout,
+ " {summary}{total_deactivated} deactivated features{summary:#}",
+ )?;
+ }
+
+ Ok(())
+}
+
+fn pretty_owners(owners: &Vec, stdout: &mut dyn Write) -> CargoResult<()> {
+ let header = HEADER;
+
+ if !owners.is_empty() {
+ writeln!(stdout, "{header}owners:{header:#}",)?;
+ for owner in owners {
+ writeln!(stdout, " {}", owner)?;
+ }
+ }
+
+ Ok(())
+}
+
+// Suggest the cargo tree command to view the dependency tree.
+fn suggest_cargo_tree(package_id: PackageId, stdout: &mut dyn Write) -> CargoResult<()> {
+ let literal = LITERAL;
+
+ note(format_args!(
+ "to see how you depend on {name}, run `{literal}cargo tree --invert --package {name}@{version}{literal:#}`",
+ name = package_id.name(),
+ version = package_id.version(),
+ ), stdout)
+}
+
+pub(super) fn note(msg: impl std::fmt::Display, stdout: &mut dyn Write) -> CargoResult<()> {
+ let note = NOTE;
+ let bold = anstyle::Style::new() | anstyle::Effects::BOLD;
+
+ writeln!(stdout, "{note}note{note:#}{bold}:{bold:#} {msg}",)?;
+
+ Ok(())
+}
+
+#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
+enum FeatureStatus {
+ EnabledByUser,
+ Enabled,
+ Disabled,
+}
+
+impl FeatureStatus {
+ fn is_disabled(&self) -> bool {
+ *self == FeatureStatus::Disabled
+ }
+}
+
+fn resolve_features(
+ explicit: &[InternedString],
+ features: &FeatureMap,
+) -> Vec<(InternedString, FeatureStatus)> {
+ let mut resolved = features
+ .keys()
+ .cloned()
+ .map(|n| {
+ if explicit.contains(&n) {
+ (n, FeatureStatus::EnabledByUser)
+ } else {
+ (n, FeatureStatus::Disabled)
+ }
+ })
+ .collect::>();
+
+ let mut activated_queue = explicit.to_vec();
+
+ while let Some(current) = activated_queue.pop() {
+ let Some(current_activated) = features.get(¤t) else {
+ // `default` isn't always present
+ continue;
+ };
+ for activated in current_activated.iter().rev().filter_map(|f| match f {
+ crate::core::FeatureValue::Feature(name) => Some(name),
+ crate::core::FeatureValue::Dep { .. }
+ | crate::core::FeatureValue::DepFeature { .. } => None,
+ }) {
+ let Some(status) = resolved.get_mut(activated) else {
+ continue;
+ };
+ if status.is_disabled() {
+ *status = FeatureStatus::Enabled;
+ activated_queue.push(*activated);
+ }
+ }
+ }
+
+ let mut resolved: Vec<_> = resolved.into_iter().collect();
+ resolved.sort_by_key(|(name, status)| (*status, *name));
+ resolved
+}
diff --git a/src/cargo/ops/registry/mod.rs b/src/cargo/ops/registry/mod.rs
index f45947566b7..016d4cebb77 100644
--- a/src/cargo/ops/registry/mod.rs
+++ b/src/cargo/ops/registry/mod.rs
@@ -2,6 +2,7 @@
//!
//! [1]: https://doc.rust-lang.org/nightly/cargo/reference/registry-web-api.html
+mod info;
mod login;
mod logout;
mod owner;
@@ -18,7 +19,7 @@ use cargo_credential::{Operation, Secret};
use crates_io::Registry;
use url::Url;
-use crate::core::SourceId;
+use crate::core::{PackageId, SourceId};
use crate::sources::source::Source;
use crate::sources::{RegistrySource, SourceConfigMap};
use crate::util::auth;
@@ -27,6 +28,7 @@ use crate::util::context::{GlobalContext, PathAndArgs};
use crate::util::errors::CargoResult;
use crate::util::network::http::http_handle;
+pub use self::info::info;
pub use self::login::registry_login;
pub use self::logout::registry_logout;
pub use self::owner::modify_owners;
@@ -206,6 +208,47 @@ fn get_source_id(
}
}
+/// Very similar to [`get_source_id`], but is used when the `package_id` is known.
+fn get_source_id_with_package_id(
+ gctx: &GlobalContext,
+ package_id: Option,
+ reg_or_index: Option<&RegistryOrIndex>,
+) -> CargoResult<(bool, RegistrySourceIds)> {
+ let (use_package_source_id, sid) = match (®_or_index, package_id) {
+ (None, Some(package_id)) => (true, package_id.source_id()),
+ (None, None) => (false, SourceId::crates_io(gctx)?),
+ (Some(RegistryOrIndex::Index(url)), None) => (false, SourceId::for_registry(url)?),
+ (Some(RegistryOrIndex::Registry(r)), None) => (false, SourceId::alt_registry(gctx, r)?),
+ (Some(reg_or_index), Some(package_id)) => {
+ let sid = get_initial_source_id_from_registry_or_index(gctx, reg_or_index)?;
+ let package_source_id = package_id.source_id();
+ // 1. Same registry, use the package's source.
+ // 2. Use the package's source if the specified registry is a replacement for the package's source.
+ if sid == package_source_id
+ || is_replacement_for_package_source(gctx, sid, package_source_id)?
+ {
+ (true, package_source_id)
+ } else {
+ (false, sid)
+ }
+ }
+ };
+
+ let (builtin_replacement_sid, replacement_sid) = get_replacement_source_ids(gctx, sid)?;
+
+ if reg_or_index.is_none() && replacement_sid != builtin_replacement_sid {
+ bail!(gen_replacement_error(replacement_sid));
+ } else {
+ Ok((
+ use_package_source_id,
+ RegistrySourceIds {
+ original: sid,
+ replacement: builtin_replacement_sid,
+ },
+ ))
+ }
+}
+
fn get_initial_source_id(
gctx: &GlobalContext,
reg_or_index: Option<&RegistryOrIndex>,
@@ -239,6 +282,17 @@ fn get_replacement_source_ids(
Ok((builtin_replacement_sid, replacement_sid))
}
+fn is_replacement_for_package_source(
+ gctx: &GlobalContext,
+ sid: SourceId,
+ package_source_id: SourceId,
+) -> CargoResult {
+ let pkg_source_replacement_sid = SourceConfigMap::new(gctx)?
+ .load(package_source_id, &HashSet::new())?
+ .replaced_source_id();
+ Ok(pkg_source_replacement_sid == sid)
+}
+
fn gen_replacement_error(replacement_sid: SourceId) -> String {
// Neither --registry nor --index was passed and the user has configured source-replacement.
let error_message = if let Some(replacement_name) = replacement_sid.alt_registry_key() {
From 9d164aa23e248975ef538b3edbdfd6b373558646 Mon Sep 17 00:00:00 2001
From: Rustin170506 <29879298+hi-rustin@users.noreply.github.com>
Date: Wed, 17 Jul 2024 20:50:31 +0800
Subject: [PATCH 2/4] test: migrate all test from cargo-information
---
tests/testsuite/cargo_info/basic/mod.rs | 53 +++
.../cargo_info/basic/stderr.term.svg | 31 ++
.../cargo_info/basic/stdout.term.svg | 51 ++
tests/testsuite/cargo_info/features/mod.rs | 23 +
.../cargo_info/features/stderr.term.svg | 31 ++
.../cargo_info/features/stdout.term.svg | 44 ++
.../features_activated_over_limit/mod.rs | 36 ++
.../stderr.term.svg | 31 ++
.../stdout.term.svg | 43 ++
.../mod.rs | 37 ++
.../stderr.term.svg | 33 ++
.../stdout.term.svg | 441 ++++++++++++++++++
.../features_deactivated_over_limit/mod.rs | 36 ++
.../stderr.term.svg | 31 ++
.../stdout.term.svg | 83 ++++
.../cargo_info/git_dependency/mod.rs | 44 ++
.../cargo_info/git_dependency/stdout.term.svg | 40 ++
tests/testsuite/cargo_info/help/mod.rs | 13 +
.../testsuite/cargo_info/help/stdout.term.svg | 72 +++
tests/testsuite/cargo_info/mod.rs | 38 ++
tests/testsuite/cargo_info/not_found/in | 1 +
tests/testsuite/cargo_info/not_found/mod.rs | 24 +
.../cargo_info/not_found/out/Cargo.lock | 16 +
.../cargo_info/not_found/out/Cargo.toml | 8 +
.../cargo_info/not_found/out/src/lib.rs | 1 +
.../cargo_info/not_found/stderr.term.svg | 30 ++
.../cargo_info/path_dependency/in/Cargo.lock | 14 +
.../cargo_info/path_dependency/in/Cargo.toml | 9 +
.../in/crates/crate1/Cargo.toml | 5 +
.../in/crates/crate1/src/lib.rs | 1 +
.../cargo_info/path_dependency/in/src/lib.rs | 1 +
.../cargo_info/path_dependency/mod.rs | 24 +
.../cargo_info/path_dependency/out/Cargo.lock | 14 +
.../cargo_info/path_dependency/out/Cargo.toml | 9 +
.../out/crates/crate1/Cargo.toml | 5 +
.../out/crates/crate1/src/lib.rs | 1 +
.../cargo_info/path_dependency/out/src/lib.rs | 1 +
.../path_dependency/stdout.term.svg | 40 ++
.../pick_msrv_compatible_package/mod.rs | 24 +
.../stderr.term.svg | 31 ++
.../stdout.term.svg | 36 ++
.../in/Cargo.toml | 2 +
.../in/crate1/Cargo.toml | 5 +
.../in/crate1/src/lib.rs | 0
.../in/crate2/Cargo.toml | 5 +
.../in/crate2/src/lib.rs | 0
.../mod.rs | 32 ++
.../out/Cargo.lock | 10 +
.../out/Cargo.toml | 2 +
.../out/crate1/Cargo.toml | 5 +
.../out/crate1/src/lib.rs | 0
.../out/crate2/Cargo.toml | 5 +
.../out/crate2/src/lib.rs | 0
.../stderr.term.svg | 33 ++
.../stdout.term.svg | 36 ++
.../in/Cargo.toml | 2 +
.../in/crate1/Cargo.toml | 4 +
.../in/crate1/src/lib.rs | 0
.../in/crate2/Cargo.toml | 4 +
.../in/crate2/src/lib.rs | 0
.../mod.rs | 32 ++
.../out/Cargo.lock | 10 +
.../out/Cargo.toml | 2 +
.../out/crate1/Cargo.toml | 4 +
.../out/crate1/src/lib.rs | 0
.../out/crate2/Cargo.toml | 4 +
.../out/crate2/src/lib.rs | 0
.../stderr.term.svg | 33 ++
.../stdout.term.svg | 36 ++
.../specify_empty_version_with_url/mod.rs | 22 +
.../stderr.term.svg | 33 ++
.../specify_version_outside_ws/mod.rs | 20 +
.../stderr.term.svg | 31 ++
.../stdout.term.svg | 36 ++
.../mod.rs | 22 +
.../stderr.term.svg | 30 ++
.../in | 1 +
.../mod.rs | 36 ++
.../out/Cargo.lock | 16 +
.../out/Cargo.toml | 8 +
.../out/src/lib.rs | 1 +
.../stderr.term.svg | 31 ++
.../stdout.term.svg | 36 ++
.../in | 1 +
.../mod.rs | 36 ++
.../out/Cargo.lock | 16 +
.../out/Cargo.toml | 8 +
.../out/src/lib.rs | 1 +
.../stderr.term.svg | 33 ++
.../stdout.term.svg | 42 ++
.../direct1-stderr.term.svg | 29 ++
.../direct1-stdout.term.svg | 42 ++
.../direct2-stdout.term.svg | 42 ++
.../in/Cargo.lock | 85 ++++
.../in/Cargo.toml | 2 +
.../in/crates/direct1/Cargo.toml | 8 +
.../in/crates/direct1/src/lib.rs | 0
.../in/crates/direct2/Cargo.toml | 8 +
.../in/crates/direct2/src/lib.rs | 0
.../in/crates/transitive1/Cargo.toml | 8 +
.../in/crates/transitive1/src/lib.rs | 0
.../in/crates/transitive123/Cargo.toml | 9 +
.../in/crates/transitive123/src/lib.rs | 0
.../in/crates/transitive2/Cargo.toml | 8 +
.../in/crates/transitive2/src/lib.rs | 0
.../in/src/lib.rs | 1 +
.../transitive_dependency_within_ws/mod.rs | 78 ++++
.../out/Cargo.lock | 85 ++++
.../out/Cargo.toml | 2 +
.../out/crates/direct1/Cargo.toml | 8 +
.../out/crates/direct1/src/lib.rs | 0
.../out/crates/direct2/Cargo.toml | 8 +
.../out/crates/direct2/src/lib.rs | 0
.../out/crates/transitive1/Cargo.toml | 8 +
.../out/crates/transitive1/src/lib.rs | 0
.../out/crates/transitive123/Cargo.toml | 9 +
.../out/crates/transitive123/src/lib.rs | 0
.../out/crates/transitive2/Cargo.toml | 8 +
.../out/crates/transitive2/src/lib.rs | 0
.../out/src/lib.rs | 1 +
.../transitive1-stdout.term.svg | 42 ++
.../transitive2-stdout.term.svg | 42 ++
.../ws-stderr.term.svg | 33 ++
.../ws-stdout.term.svg | 42 ++
tests/testsuite/cargo_info/verbose/mod.rs | 53 +++
.../cargo_info/verbose/stderr.term.svg | 33 ++
.../cargo_info/verbose/stdout.term.svg | 59 +++
.../cargo_info/with_frozen_outside_ws/mod.rs | 30 ++
.../with_frozen_outside_ws/stderr.term.svg | 27 ++
.../cargo_info/with_frozen_within_ws/in | 1 +
.../cargo_info/with_frozen_within_ws/mod.rs | 37 ++
.../with_frozen_within_ws/out/Cargo.lock | 16 +
.../with_frozen_within_ws/out/Cargo.toml | 8 +
.../with_frozen_within_ws/out/src/lib.rs | 1 +
.../with_frozen_within_ws/stderr.term.svg | 27 ++
.../cargo_info/with_locked_outside_ws/mod.rs | 30 ++
.../with_locked_outside_ws/stderr.term.svg | 27 ++
.../cargo_info/with_locked_within_ws/in | 1 +
.../cargo_info/with_locked_within_ws/mod.rs | 37 ++
.../with_locked_within_ws/out/Cargo.lock | 16 +
.../with_locked_within_ws/out/Cargo.toml | 8 +
.../with_locked_within_ws/out/src/lib.rs | 1 +
.../with_locked_within_ws/stderr.term.svg | 30 ++
.../in/Cargo.toml | 8 +
.../in/src/lib.rs | 1 +
.../mod.rs | 37 ++
.../out/Cargo.toml | 8 +
.../out/src/lib.rs | 1 +
.../stderr.term.svg | 31 ++
.../stdout.term.svg | 36 ++
.../testsuite/cargo_info/with_offline/mod.rs | 30 ++
.../cargo_info/with_offline/stderr.term.svg | 27 ++
tests/testsuite/cargo_info/with_quiet/mod.rs | 30 ++
.../cargo_info/with_quiet/stdout.term.svg | 36 ++
.../cargo_info/within_workspace.in/Cargo.lock | 16 +
.../cargo_info/within_workspace.in/Cargo.toml | 8 +
.../cargo_info/within_workspace.in/src/lib.rs | 1 +
tests/testsuite/cargo_info/within_ws/in | 1 +
tests/testsuite/cargo_info/within_ws/mod.rs | 36 ++
.../cargo_info/within_ws/out/Cargo.lock | 16 +
.../cargo_info/within_ws/out/Cargo.toml | 8 +
.../cargo_info/within_ws/out/src/lib.rs | 1 +
.../cargo_info/within_ws/stderr.term.svg | 33 ++
.../cargo_info/within_ws/stdout.term.svg | 42 ++
.../in/Cargo.lock | 16 +
.../in/Cargo.toml | 8 +
.../in/src/lib.rs | 1 +
.../within_ws_and_pick_ws_package/mod.rs | 27 ++
.../out/Cargo.lock | 16 +
.../out/Cargo.toml | 8 +
.../out/src/lib.rs | 1 +
.../stdout.term.svg | 36 ++
.../within_ws_with_alternative_registry/in | 1 +
.../mod.rs | 30 ++
.../out/Cargo.lock | 16 +
.../out/Cargo.toml | 8 +
.../out/src/lib.rs | 1 +
.../stderr.term.svg | 33 ++
.../stdout.term.svg | 36 ++
.../within_ws_without_lockfile/in/Cargo.toml | 8 +
.../within_ws_without_lockfile/in/src/lib.rs | 1 +
.../within_ws_without_lockfile/mod.rs | 33 ++
.../within_ws_without_lockfile/out/Cargo.lock | 16 +
.../within_ws_without_lockfile/out/Cargo.toml | 8 +
.../within_ws_without_lockfile/out/src/lib.rs | 1 +
.../stderr.term.svg | 39 ++
.../stdout.term.svg | 42 ++
tests/testsuite/main.rs | 1 +
188 files changed, 4076 insertions(+)
create mode 100644 tests/testsuite/cargo_info/basic/mod.rs
create mode 100644 tests/testsuite/cargo_info/basic/stderr.term.svg
create mode 100644 tests/testsuite/cargo_info/basic/stdout.term.svg
create mode 100644 tests/testsuite/cargo_info/features/mod.rs
create mode 100644 tests/testsuite/cargo_info/features/stderr.term.svg
create mode 100644 tests/testsuite/cargo_info/features/stdout.term.svg
create mode 100644 tests/testsuite/cargo_info/features_activated_over_limit/mod.rs
create mode 100644 tests/testsuite/cargo_info/features_activated_over_limit/stderr.term.svg
create mode 100644 tests/testsuite/cargo_info/features_activated_over_limit/stdout.term.svg
create mode 100644 tests/testsuite/cargo_info/features_activated_over_limit_verbose/mod.rs
create mode 100644 tests/testsuite/cargo_info/features_activated_over_limit_verbose/stderr.term.svg
create mode 100644 tests/testsuite/cargo_info/features_activated_over_limit_verbose/stdout.term.svg
create mode 100644 tests/testsuite/cargo_info/features_deactivated_over_limit/mod.rs
create mode 100644 tests/testsuite/cargo_info/features_deactivated_over_limit/stderr.term.svg
create mode 100644 tests/testsuite/cargo_info/features_deactivated_over_limit/stdout.term.svg
create mode 100644 tests/testsuite/cargo_info/git_dependency/mod.rs
create mode 100644 tests/testsuite/cargo_info/git_dependency/stdout.term.svg
create mode 100644 tests/testsuite/cargo_info/help/mod.rs
create mode 100644 tests/testsuite/cargo_info/help/stdout.term.svg
create mode 100644 tests/testsuite/cargo_info/mod.rs
create mode 120000 tests/testsuite/cargo_info/not_found/in
create mode 100644 tests/testsuite/cargo_info/not_found/mod.rs
create mode 100644 tests/testsuite/cargo_info/not_found/out/Cargo.lock
create mode 100644 tests/testsuite/cargo_info/not_found/out/Cargo.toml
create mode 100644 tests/testsuite/cargo_info/not_found/out/src/lib.rs
create mode 100644 tests/testsuite/cargo_info/not_found/stderr.term.svg
create mode 100644 tests/testsuite/cargo_info/path_dependency/in/Cargo.lock
create mode 100644 tests/testsuite/cargo_info/path_dependency/in/Cargo.toml
create mode 100644 tests/testsuite/cargo_info/path_dependency/in/crates/crate1/Cargo.toml
create mode 100644 tests/testsuite/cargo_info/path_dependency/in/crates/crate1/src/lib.rs
create mode 100644 tests/testsuite/cargo_info/path_dependency/in/src/lib.rs
create mode 100644 tests/testsuite/cargo_info/path_dependency/mod.rs
create mode 100644 tests/testsuite/cargo_info/path_dependency/out/Cargo.lock
create mode 100644 tests/testsuite/cargo_info/path_dependency/out/Cargo.toml
create mode 100644 tests/testsuite/cargo_info/path_dependency/out/crates/crate1/Cargo.toml
create mode 100644 tests/testsuite/cargo_info/path_dependency/out/crates/crate1/src/lib.rs
create mode 100644 tests/testsuite/cargo_info/path_dependency/out/src/lib.rs
create mode 100644 tests/testsuite/cargo_info/path_dependency/stdout.term.svg
create mode 100644 tests/testsuite/cargo_info/pick_msrv_compatible_package/mod.rs
create mode 100644 tests/testsuite/cargo_info/pick_msrv_compatible_package/stderr.term.svg
create mode 100644 tests/testsuite/cargo_info/pick_msrv_compatible_package/stdout.term.svg
create mode 100644 tests/testsuite/cargo_info/pick_msrv_compatible_package_within_ws/in/Cargo.toml
create mode 100644 tests/testsuite/cargo_info/pick_msrv_compatible_package_within_ws/in/crate1/Cargo.toml
create mode 100644 tests/testsuite/cargo_info/pick_msrv_compatible_package_within_ws/in/crate1/src/lib.rs
create mode 100644 tests/testsuite/cargo_info/pick_msrv_compatible_package_within_ws/in/crate2/Cargo.toml
create mode 100644 tests/testsuite/cargo_info/pick_msrv_compatible_package_within_ws/in/crate2/src/lib.rs
create mode 100644 tests/testsuite/cargo_info/pick_msrv_compatible_package_within_ws/mod.rs
create mode 100644 tests/testsuite/cargo_info/pick_msrv_compatible_package_within_ws/out/Cargo.lock
create mode 100644 tests/testsuite/cargo_info/pick_msrv_compatible_package_within_ws/out/Cargo.toml
create mode 100644 tests/testsuite/cargo_info/pick_msrv_compatible_package_within_ws/out/crate1/Cargo.toml
create mode 100644 tests/testsuite/cargo_info/pick_msrv_compatible_package_within_ws/out/crate1/src/lib.rs
create mode 100644 tests/testsuite/cargo_info/pick_msrv_compatible_package_within_ws/out/crate2/Cargo.toml
create mode 100644 tests/testsuite/cargo_info/pick_msrv_compatible_package_within_ws/out/crate2/src/lib.rs
create mode 100644 tests/testsuite/cargo_info/pick_msrv_compatible_package_within_ws/stderr.term.svg
create mode 100644 tests/testsuite/cargo_info/pick_msrv_compatible_package_within_ws/stdout.term.svg
create mode 100644 tests/testsuite/cargo_info/pick_msrv_compatible_package_within_ws_and_use_msrv_from_ws/in/Cargo.toml
create mode 100644 tests/testsuite/cargo_info/pick_msrv_compatible_package_within_ws_and_use_msrv_from_ws/in/crate1/Cargo.toml
create mode 100644 tests/testsuite/cargo_info/pick_msrv_compatible_package_within_ws_and_use_msrv_from_ws/in/crate1/src/lib.rs
create mode 100644 tests/testsuite/cargo_info/pick_msrv_compatible_package_within_ws_and_use_msrv_from_ws/in/crate2/Cargo.toml
create mode 100644 tests/testsuite/cargo_info/pick_msrv_compatible_package_within_ws_and_use_msrv_from_ws/in/crate2/src/lib.rs
create mode 100644 tests/testsuite/cargo_info/pick_msrv_compatible_package_within_ws_and_use_msrv_from_ws/mod.rs
create mode 100644 tests/testsuite/cargo_info/pick_msrv_compatible_package_within_ws_and_use_msrv_from_ws/out/Cargo.lock
create mode 100644 tests/testsuite/cargo_info/pick_msrv_compatible_package_within_ws_and_use_msrv_from_ws/out/Cargo.toml
create mode 100644 tests/testsuite/cargo_info/pick_msrv_compatible_package_within_ws_and_use_msrv_from_ws/out/crate1/Cargo.toml
create mode 100644 tests/testsuite/cargo_info/pick_msrv_compatible_package_within_ws_and_use_msrv_from_ws/out/crate1/src/lib.rs
create mode 100644 tests/testsuite/cargo_info/pick_msrv_compatible_package_within_ws_and_use_msrv_from_ws/out/crate2/Cargo.toml
create mode 100644 tests/testsuite/cargo_info/pick_msrv_compatible_package_within_ws_and_use_msrv_from_ws/out/crate2/src/lib.rs
create mode 100644 tests/testsuite/cargo_info/pick_msrv_compatible_package_within_ws_and_use_msrv_from_ws/stderr.term.svg
create mode 100644 tests/testsuite/cargo_info/pick_msrv_compatible_package_within_ws_and_use_msrv_from_ws/stdout.term.svg
create mode 100644 tests/testsuite/cargo_info/specify_empty_version_with_url/mod.rs
create mode 100644 tests/testsuite/cargo_info/specify_empty_version_with_url/stderr.term.svg
create mode 100644 tests/testsuite/cargo_info/specify_version_outside_ws/mod.rs
create mode 100644 tests/testsuite/cargo_info/specify_version_outside_ws/stderr.term.svg
create mode 100644 tests/testsuite/cargo_info/specify_version_outside_ws/stdout.term.svg
create mode 100644 tests/testsuite/cargo_info/specify_version_with_url_but_registry_is_not_matched/mod.rs
create mode 100644 tests/testsuite/cargo_info/specify_version_with_url_but_registry_is_not_matched/stderr.term.svg
create mode 120000 tests/testsuite/cargo_info/specify_version_within_ws_and_conflict_with_lockfile/in
create mode 100644 tests/testsuite/cargo_info/specify_version_within_ws_and_conflict_with_lockfile/mod.rs
create mode 100644 tests/testsuite/cargo_info/specify_version_within_ws_and_conflict_with_lockfile/out/Cargo.lock
create mode 100644 tests/testsuite/cargo_info/specify_version_within_ws_and_conflict_with_lockfile/out/Cargo.toml
create mode 100644 tests/testsuite/cargo_info/specify_version_within_ws_and_conflict_with_lockfile/out/src/lib.rs
create mode 100644 tests/testsuite/cargo_info/specify_version_within_ws_and_conflict_with_lockfile/stderr.term.svg
create mode 100644 tests/testsuite/cargo_info/specify_version_within_ws_and_conflict_with_lockfile/stdout.term.svg
create mode 120000 tests/testsuite/cargo_info/specify_version_within_ws_and_match_with_lockfile/in
create mode 100644 tests/testsuite/cargo_info/specify_version_within_ws_and_match_with_lockfile/mod.rs
create mode 100644 tests/testsuite/cargo_info/specify_version_within_ws_and_match_with_lockfile/out/Cargo.lock
create mode 100644 tests/testsuite/cargo_info/specify_version_within_ws_and_match_with_lockfile/out/Cargo.toml
create mode 100644 tests/testsuite/cargo_info/specify_version_within_ws_and_match_with_lockfile/out/src/lib.rs
create mode 100644 tests/testsuite/cargo_info/specify_version_within_ws_and_match_with_lockfile/stderr.term.svg
create mode 100644 tests/testsuite/cargo_info/specify_version_within_ws_and_match_with_lockfile/stdout.term.svg
create mode 100644 tests/testsuite/cargo_info/transitive_dependency_within_ws/direct1-stderr.term.svg
create mode 100644 tests/testsuite/cargo_info/transitive_dependency_within_ws/direct1-stdout.term.svg
create mode 100644 tests/testsuite/cargo_info/transitive_dependency_within_ws/direct2-stdout.term.svg
create mode 100644 tests/testsuite/cargo_info/transitive_dependency_within_ws/in/Cargo.lock
create mode 100644 tests/testsuite/cargo_info/transitive_dependency_within_ws/in/Cargo.toml
create mode 100644 tests/testsuite/cargo_info/transitive_dependency_within_ws/in/crates/direct1/Cargo.toml
create mode 100644 tests/testsuite/cargo_info/transitive_dependency_within_ws/in/crates/direct1/src/lib.rs
create mode 100644 tests/testsuite/cargo_info/transitive_dependency_within_ws/in/crates/direct2/Cargo.toml
create mode 100644 tests/testsuite/cargo_info/transitive_dependency_within_ws/in/crates/direct2/src/lib.rs
create mode 100644 tests/testsuite/cargo_info/transitive_dependency_within_ws/in/crates/transitive1/Cargo.toml
create mode 100644 tests/testsuite/cargo_info/transitive_dependency_within_ws/in/crates/transitive1/src/lib.rs
create mode 100644 tests/testsuite/cargo_info/transitive_dependency_within_ws/in/crates/transitive123/Cargo.toml
create mode 100644 tests/testsuite/cargo_info/transitive_dependency_within_ws/in/crates/transitive123/src/lib.rs
create mode 100644 tests/testsuite/cargo_info/transitive_dependency_within_ws/in/crates/transitive2/Cargo.toml
create mode 100644 tests/testsuite/cargo_info/transitive_dependency_within_ws/in/crates/transitive2/src/lib.rs
create mode 100644 tests/testsuite/cargo_info/transitive_dependency_within_ws/in/src/lib.rs
create mode 100644 tests/testsuite/cargo_info/transitive_dependency_within_ws/mod.rs
create mode 100644 tests/testsuite/cargo_info/transitive_dependency_within_ws/out/Cargo.lock
create mode 100644 tests/testsuite/cargo_info/transitive_dependency_within_ws/out/Cargo.toml
create mode 100644 tests/testsuite/cargo_info/transitive_dependency_within_ws/out/crates/direct1/Cargo.toml
create mode 100644 tests/testsuite/cargo_info/transitive_dependency_within_ws/out/crates/direct1/src/lib.rs
create mode 100644 tests/testsuite/cargo_info/transitive_dependency_within_ws/out/crates/direct2/Cargo.toml
create mode 100644 tests/testsuite/cargo_info/transitive_dependency_within_ws/out/crates/direct2/src/lib.rs
create mode 100644 tests/testsuite/cargo_info/transitive_dependency_within_ws/out/crates/transitive1/Cargo.toml
create mode 100644 tests/testsuite/cargo_info/transitive_dependency_within_ws/out/crates/transitive1/src/lib.rs
create mode 100644 tests/testsuite/cargo_info/transitive_dependency_within_ws/out/crates/transitive123/Cargo.toml
create mode 100644 tests/testsuite/cargo_info/transitive_dependency_within_ws/out/crates/transitive123/src/lib.rs
create mode 100644 tests/testsuite/cargo_info/transitive_dependency_within_ws/out/crates/transitive2/Cargo.toml
create mode 100644 tests/testsuite/cargo_info/transitive_dependency_within_ws/out/crates/transitive2/src/lib.rs
create mode 100644 tests/testsuite/cargo_info/transitive_dependency_within_ws/out/src/lib.rs
create mode 100644 tests/testsuite/cargo_info/transitive_dependency_within_ws/transitive1-stdout.term.svg
create mode 100644 tests/testsuite/cargo_info/transitive_dependency_within_ws/transitive2-stdout.term.svg
create mode 100644 tests/testsuite/cargo_info/transitive_dependency_within_ws/ws-stderr.term.svg
create mode 100644 tests/testsuite/cargo_info/transitive_dependency_within_ws/ws-stdout.term.svg
create mode 100644 tests/testsuite/cargo_info/verbose/mod.rs
create mode 100644 tests/testsuite/cargo_info/verbose/stderr.term.svg
create mode 100644 tests/testsuite/cargo_info/verbose/stdout.term.svg
create mode 100644 tests/testsuite/cargo_info/with_frozen_outside_ws/mod.rs
create mode 100644 tests/testsuite/cargo_info/with_frozen_outside_ws/stderr.term.svg
create mode 120000 tests/testsuite/cargo_info/with_frozen_within_ws/in
create mode 100644 tests/testsuite/cargo_info/with_frozen_within_ws/mod.rs
create mode 100644 tests/testsuite/cargo_info/with_frozen_within_ws/out/Cargo.lock
create mode 100644 tests/testsuite/cargo_info/with_frozen_within_ws/out/Cargo.toml
create mode 100644 tests/testsuite/cargo_info/with_frozen_within_ws/out/src/lib.rs
create mode 100644 tests/testsuite/cargo_info/with_frozen_within_ws/stderr.term.svg
create mode 100644 tests/testsuite/cargo_info/with_locked_outside_ws/mod.rs
create mode 100644 tests/testsuite/cargo_info/with_locked_outside_ws/stderr.term.svg
create mode 120000 tests/testsuite/cargo_info/with_locked_within_ws/in
create mode 100644 tests/testsuite/cargo_info/with_locked_within_ws/mod.rs
create mode 100644 tests/testsuite/cargo_info/with_locked_within_ws/out/Cargo.lock
create mode 100644 tests/testsuite/cargo_info/with_locked_within_ws/out/Cargo.toml
create mode 100644 tests/testsuite/cargo_info/with_locked_within_ws/out/src/lib.rs
create mode 100644 tests/testsuite/cargo_info/with_locked_within_ws/stderr.term.svg
create mode 100644 tests/testsuite/cargo_info/with_locked_within_ws_and_pick_the_package/in/Cargo.toml
create mode 100644 tests/testsuite/cargo_info/with_locked_within_ws_and_pick_the_package/in/src/lib.rs
create mode 100644 tests/testsuite/cargo_info/with_locked_within_ws_and_pick_the_package/mod.rs
create mode 100644 tests/testsuite/cargo_info/with_locked_within_ws_and_pick_the_package/out/Cargo.toml
create mode 100644 tests/testsuite/cargo_info/with_locked_within_ws_and_pick_the_package/out/src/lib.rs
create mode 100644 tests/testsuite/cargo_info/with_locked_within_ws_and_pick_the_package/stderr.term.svg
create mode 100644 tests/testsuite/cargo_info/with_locked_within_ws_and_pick_the_package/stdout.term.svg
create mode 100644 tests/testsuite/cargo_info/with_offline/mod.rs
create mode 100644 tests/testsuite/cargo_info/with_offline/stderr.term.svg
create mode 100644 tests/testsuite/cargo_info/with_quiet/mod.rs
create mode 100644 tests/testsuite/cargo_info/with_quiet/stdout.term.svg
create mode 100644 tests/testsuite/cargo_info/within_workspace.in/Cargo.lock
create mode 100644 tests/testsuite/cargo_info/within_workspace.in/Cargo.toml
create mode 100644 tests/testsuite/cargo_info/within_workspace.in/src/lib.rs
create mode 120000 tests/testsuite/cargo_info/within_ws/in
create mode 100644 tests/testsuite/cargo_info/within_ws/mod.rs
create mode 100644 tests/testsuite/cargo_info/within_ws/out/Cargo.lock
create mode 100644 tests/testsuite/cargo_info/within_ws/out/Cargo.toml
create mode 100644 tests/testsuite/cargo_info/within_ws/out/src/lib.rs
create mode 100644 tests/testsuite/cargo_info/within_ws/stderr.term.svg
create mode 100644 tests/testsuite/cargo_info/within_ws/stdout.term.svg
create mode 100644 tests/testsuite/cargo_info/within_ws_and_pick_ws_package/in/Cargo.lock
create mode 100644 tests/testsuite/cargo_info/within_ws_and_pick_ws_package/in/Cargo.toml
create mode 100644 tests/testsuite/cargo_info/within_ws_and_pick_ws_package/in/src/lib.rs
create mode 100644 tests/testsuite/cargo_info/within_ws_and_pick_ws_package/mod.rs
create mode 100644 tests/testsuite/cargo_info/within_ws_and_pick_ws_package/out/Cargo.lock
create mode 100644 tests/testsuite/cargo_info/within_ws_and_pick_ws_package/out/Cargo.toml
create mode 100644 tests/testsuite/cargo_info/within_ws_and_pick_ws_package/out/src/lib.rs
create mode 100644 tests/testsuite/cargo_info/within_ws_and_pick_ws_package/stdout.term.svg
create mode 120000 tests/testsuite/cargo_info/within_ws_with_alternative_registry/in
create mode 100644 tests/testsuite/cargo_info/within_ws_with_alternative_registry/mod.rs
create mode 100644 tests/testsuite/cargo_info/within_ws_with_alternative_registry/out/Cargo.lock
create mode 100644 tests/testsuite/cargo_info/within_ws_with_alternative_registry/out/Cargo.toml
create mode 100644 tests/testsuite/cargo_info/within_ws_with_alternative_registry/out/src/lib.rs
create mode 100644 tests/testsuite/cargo_info/within_ws_with_alternative_registry/stderr.term.svg
create mode 100644 tests/testsuite/cargo_info/within_ws_with_alternative_registry/stdout.term.svg
create mode 100644 tests/testsuite/cargo_info/within_ws_without_lockfile/in/Cargo.toml
create mode 100644 tests/testsuite/cargo_info/within_ws_without_lockfile/in/src/lib.rs
create mode 100644 tests/testsuite/cargo_info/within_ws_without_lockfile/mod.rs
create mode 100644 tests/testsuite/cargo_info/within_ws_without_lockfile/out/Cargo.lock
create mode 100644 tests/testsuite/cargo_info/within_ws_without_lockfile/out/Cargo.toml
create mode 100644 tests/testsuite/cargo_info/within_ws_without_lockfile/out/src/lib.rs
create mode 100644 tests/testsuite/cargo_info/within_ws_without_lockfile/stderr.term.svg
create mode 100644 tests/testsuite/cargo_info/within_ws_without_lockfile/stdout.term.svg
diff --git a/tests/testsuite/cargo_info/basic/mod.rs b/tests/testsuite/cargo_info/basic/mod.rs
new file mode 100644
index 00000000000..dd10058db7c
--- /dev/null
+++ b/tests/testsuite/cargo_info/basic/mod.rs
@@ -0,0 +1,53 @@
+use cargo_test_support::file;
+use cargo_test_support::prelude::*;
+
+use super::init_registry_without_token;
+
+#[cargo_test]
+fn case() {
+ init_registry_without_token();
+ cargo_test_support::registry::Package::new("my-package", "0.1.0")
+ .file(
+ "Cargo.toml",
+ r#"
+ [package]
+ name = "my-package"
+ version = "0.1.0"
+ description = "A package for testing"
+ repository = "https://github.com/hi-rustin/cargo-infromation"
+ documentation = "https://docs.rs/my-package/0.1.0"
+ license = "MIT"
+ edition = "2018"
+ rust-version = "1.50.0"
+ keywords = ["foo", "bar", "baz"]
+
+ [features]
+ default = ["feature1"]
+ feature1 = []
+ feature2 = []
+
+ [dependencies]
+ foo = "0.1.0"
+ bar = "0.2.0"
+ baz = { version = "0.3.0", optional = true }
+
+ [[bin]]
+ name = "my_bin"
+
+ [lib]
+ name = "my_lib"
+ "#,
+ )
+ .file("src/bin/my_bin.rs", "")
+ .file("src/lib.rs", "")
+ .publish();
+
+ snapbox::cmd::Command::cargo_ui()
+ .arg("info")
+ .arg("my-package")
+ .arg("--registry=dummy-registry")
+ .assert()
+ .success()
+ .stdout_eq(file!["stdout.term.svg"])
+ .stderr_eq(file!["stderr.term.svg"]);
+}
diff --git a/tests/testsuite/cargo_info/basic/stderr.term.svg b/tests/testsuite/cargo_info/basic/stderr.term.svg
new file mode 100644
index 00000000000..5d324184d55
--- /dev/null
+++ b/tests/testsuite/cargo_info/basic/stderr.term.svg
@@ -0,0 +1,31 @@
+
+
+
+
+
+
+ Updating `dummy-registry` index
+
+ Downloading crates ...
+
+ Downloaded my-package v0.1.0 (registry `dummy-registry`)
+
+
+
+
+
+
diff --git a/tests/testsuite/cargo_info/basic/stdout.term.svg b/tests/testsuite/cargo_info/basic/stdout.term.svg
new file mode 100644
index 00000000000..d5e381d76bd
--- /dev/null
+++ b/tests/testsuite/cargo_info/basic/stdout.term.svg
@@ -0,0 +1,51 @@
+
+
+
+
+
+
+ my-package #foo #bar #baz
+
+ A package for testing
+
+ version: 0.1.0 (from registry `dummy-registry`)
+
+ license: MIT
+
+ rust-version: 1.50.0
+
+ documentation: https://docs.rs/my-package/0.1.0
+
+ repository: https://github.com/hi-rustin/cargo-infromation
+
+ features:
+
+ + default = [feature1]
+
+ feature1 = []
+
+ baz = [ dep:baz ]
+
+ feature2 = []
+
+
+
+
+
+
diff --git a/tests/testsuite/cargo_info/features/mod.rs b/tests/testsuite/cargo_info/features/mod.rs
new file mode 100644
index 00000000000..303b589a867
--- /dev/null
+++ b/tests/testsuite/cargo_info/features/mod.rs
@@ -0,0 +1,23 @@
+use cargo_test_support::file;
+use cargo_test_support::prelude::*;
+
+use super::init_registry_without_token;
+
+#[cargo_test]
+fn case() {
+ init_registry_without_token();
+ cargo_test_support::registry::Package::new("my-package", "0.1.1")
+ .feature("default", &["feature1", "feature2"])
+ .feature("feature1", &[])
+ .feature("feature2", &[])
+ .publish();
+
+ snapbox::cmd::Command::cargo_ui()
+ .arg("info")
+ .arg("my-package")
+ .arg("--registry=dummy-registry")
+ .assert()
+ .success()
+ .stdout_eq(file!["stdout.term.svg"])
+ .stderr_eq(file!["stderr.term.svg"]);
+}
diff --git a/tests/testsuite/cargo_info/features/stderr.term.svg b/tests/testsuite/cargo_info/features/stderr.term.svg
new file mode 100644
index 00000000000..62667b6f800
--- /dev/null
+++ b/tests/testsuite/cargo_info/features/stderr.term.svg
@@ -0,0 +1,31 @@
+
+
+
+
+
+
+ Updating `dummy-registry` index
+
+ Downloading crates ...
+
+ Downloaded my-package v0.1.1 (registry `dummy-registry`)
+
+
+
+
+
+
diff --git a/tests/testsuite/cargo_info/features/stdout.term.svg b/tests/testsuite/cargo_info/features/stdout.term.svg
new file mode 100644
index 00000000000..c79747b9be0
--- /dev/null
+++ b/tests/testsuite/cargo_info/features/stdout.term.svg
@@ -0,0 +1,44 @@
+
+
+
+
+
+
+ my-package
+
+ version: 0.1.1 (from registry `dummy-registry`)
+
+ license: unknown
+
+ rust-version: unknown
+
+ features:
+
+ + default = [feature1, feature2]
+
+ feature1 = []
+
+ feature2 = []
+
+
+
+
+
+
diff --git a/tests/testsuite/cargo_info/features_activated_over_limit/mod.rs b/tests/testsuite/cargo_info/features_activated_over_limit/mod.rs
new file mode 100644
index 00000000000..49fadef3e9b
--- /dev/null
+++ b/tests/testsuite/cargo_info/features_activated_over_limit/mod.rs
@@ -0,0 +1,36 @@
+use cargo_test_support::file;
+use cargo_test_support::prelude::*;
+
+use super::init_registry_without_token;
+
+#[cargo_test]
+fn case() {
+ const MANY_FEATURES_COUNT: usize = 200;
+ const DEFAULT_FEATURES_COUNT: usize = 100;
+
+ init_registry_without_token();
+ let mut test_package =
+ cargo_test_support::registry::Package::new("your-face", "99999.0.0+my-package");
+ let features = (0..MANY_FEATURES_COUNT)
+ .map(|i| format!("eyes{i:03}"))
+ .collect::>();
+ for name in &features {
+ test_package.feature(name.as_str(), &[]);
+ }
+ let default_features = features
+ .iter()
+ .take(DEFAULT_FEATURES_COUNT)
+ .map(|s| s.as_str())
+ .collect::>();
+ test_package.feature("default", &default_features);
+ test_package.publish();
+
+ snapbox::cmd::Command::cargo_ui()
+ .arg("info")
+ .arg("your-face")
+ .arg("--registry=dummy-registry")
+ .assert()
+ .success()
+ .stdout_eq(file!["stdout.term.svg"])
+ .stderr_eq(file!["stderr.term.svg"]);
+}
diff --git a/tests/testsuite/cargo_info/features_activated_over_limit/stderr.term.svg b/tests/testsuite/cargo_info/features_activated_over_limit/stderr.term.svg
new file mode 100644
index 00000000000..de41e3894c1
--- /dev/null
+++ b/tests/testsuite/cargo_info/features_activated_over_limit/stderr.term.svg
@@ -0,0 +1,31 @@
+
+
+
+
+
+
+ Updating `dummy-registry` index
+
+ Downloading crates ...
+
+ Downloaded your-face v99999.0.0+my-package (registry `dummy-registry`)
+
+
+
+
+
+
diff --git a/tests/testsuite/cargo_info/features_activated_over_limit/stdout.term.svg b/tests/testsuite/cargo_info/features_activated_over_limit/stdout.term.svg
new file mode 100644
index 00000000000..53f0e5a02e5
--- /dev/null
+++ b/tests/testsuite/cargo_info/features_activated_over_limit/stdout.term.svg
@@ -0,0 +1,43 @@
+
+
+
+
+
+
+ your-face
+
+ version: 99999.0.0+my-package (from registry `dummy-registry`)
+
+ license: unknown
+
+ rust-version: unknown
+
+ features:
+
+ 101 activated features
+
+ 100 deactivated features
+
+
+
+
+
+
diff --git a/tests/testsuite/cargo_info/features_activated_over_limit_verbose/mod.rs b/tests/testsuite/cargo_info/features_activated_over_limit_verbose/mod.rs
new file mode 100644
index 00000000000..95b4dfdb76b
--- /dev/null
+++ b/tests/testsuite/cargo_info/features_activated_over_limit_verbose/mod.rs
@@ -0,0 +1,37 @@
+use cargo_test_support::file;
+use cargo_test_support::prelude::*;
+
+use super::init_registry_without_token;
+
+#[cargo_test]
+fn case() {
+ const MANY_FEATURES_COUNT: usize = 200;
+ const DEFAULT_FEATURES_COUNT: usize = 100;
+
+ init_registry_without_token();
+ let mut test_package =
+ cargo_test_support::registry::Package::new("your-face", "99999.0.0+my-package");
+ let features = (0..MANY_FEATURES_COUNT)
+ .map(|i| format!("eyes{i:03}"))
+ .collect::>();
+ for name in &features {
+ test_package.feature(name.as_str(), &[]);
+ }
+ let default_features = features
+ .iter()
+ .take(DEFAULT_FEATURES_COUNT)
+ .map(|s| s.as_str())
+ .collect::>();
+ test_package.feature("default", &default_features);
+ test_package.publish();
+
+ snapbox::cmd::Command::cargo_ui()
+ .arg("info")
+ .arg("your-face")
+ .arg("--verbose")
+ .arg("--registry=dummy-registry")
+ .assert()
+ .success()
+ .stdout_eq(file!["stdout.term.svg"])
+ .stderr_eq(file!["stderr.term.svg"]);
+}
diff --git a/tests/testsuite/cargo_info/features_activated_over_limit_verbose/stderr.term.svg b/tests/testsuite/cargo_info/features_activated_over_limit_verbose/stderr.term.svg
new file mode 100644
index 00000000000..4856382c623
--- /dev/null
+++ b/tests/testsuite/cargo_info/features_activated_over_limit_verbose/stderr.term.svg
@@ -0,0 +1,33 @@
+
+
+
+
+
+
+ Updating `dummy-registry` index
+
+ Downloading crates ...
+
+ Downloaded your-face v99999.0.0+my-package (registry `dummy-registry`)
+
+ Credential cargo:token get dummy-registry
+
+
+
+
+
+
diff --git a/tests/testsuite/cargo_info/features_activated_over_limit_verbose/stdout.term.svg b/tests/testsuite/cargo_info/features_activated_over_limit_verbose/stdout.term.svg
new file mode 100644
index 00000000000..e16531b3249
--- /dev/null
+++ b/tests/testsuite/cargo_info/features_activated_over_limit_verbose/stdout.term.svg
@@ -0,0 +1,441 @@
+
+
+
+
+
+
+ your-face
+
+ version: 99999.0.0+my-package (from registry `dummy-registry`)
+
+ license: unknown
+
+ rust-version: unknown
+
+ features:
+
+ + default = [eyes000, eyes001, eyes002, eyes003, eyes004, eyes005, eyes006, eyes007, eyes008, eyes009, eyes010, eyes011, eyes012, eyes013, eyes014, eyes015, eyes016, eyes017, eyes018, eyes019, eyes020, eyes021, eyes022, eyes023, eyes024, eyes025, eyes026, eyes027, eyes028, eyes029, eyes030, eyes031, eyes032, eyes033, eyes034, eyes035, eyes036, eyes037, eyes038, eyes039, eyes040, eyes041, eyes042, eyes043, eyes044, eyes045, eyes046, eyes047, eyes048, eyes049, eyes050, eyes051, eyes052, eyes053, eyes054, eyes055, eyes056, eyes057, eyes058, eyes059, eyes060, eyes061, eyes062, eyes063, eyes064, eyes065, eyes066, eyes067, eyes068, eyes069, eyes070, eyes071, eyes072, eyes073, eyes074, eyes075, eyes076, eyes077, eyes078, eyes079, eyes080, eyes081, eyes082, eyes083, eyes084, eyes085, eyes086, eyes087, eyes088, eyes089, eyes090, eyes091, eyes092, eyes093, eyes094, eyes095, eyes096, eyes097, eyes098, eyes099]
+
+ eyes000 = []
+
+ eyes001 = []
+
+ eyes002 = []
+
+ eyes003 = []
+
+ eyes004 = []
+
+ eyes005 = []
+
+ eyes006 = []
+
+ eyes007 = []
+
+ eyes008 = []
+
+ eyes009 = []
+
+ eyes010 = []
+
+ eyes011 = []
+
+ eyes012 = []
+
+ eyes013 = []
+
+ eyes014 = []
+
+ eyes015 = []
+
+ eyes016 = []
+
+ eyes017 = []
+
+ eyes018 = []
+
+ eyes019 = []
+
+ eyes020 = []
+
+ eyes021 = []
+
+ eyes022 = []
+
+ eyes023 = []
+
+ eyes024 = []
+
+ eyes025 = []
+
+ eyes026 = []
+
+ eyes027 = []
+
+ eyes028 = []
+
+ eyes029 = []
+
+ eyes030 = []
+
+ eyes031 = []
+
+ eyes032 = []
+
+ eyes033 = []
+
+ eyes034 = []
+
+ eyes035 = []
+
+ eyes036 = []
+
+ eyes037 = []
+
+ eyes038 = []
+
+ eyes039 = []
+
+ eyes040 = []
+
+ eyes041 = []
+
+ eyes042 = []
+
+ eyes043 = []
+
+ eyes044 = []
+
+ eyes045 = []
+
+ eyes046 = []
+
+ eyes047 = []
+
+ eyes048 = []
+
+ eyes049 = []
+
+ eyes050 = []
+
+ eyes051 = []
+
+ eyes052 = []
+
+ eyes053 = []
+
+ eyes054 = []
+
+ eyes055 = []
+
+ eyes056 = []
+
+ eyes057 = []
+
+ eyes058 = []
+
+ eyes059 = []
+
+ eyes060 = []
+
+ eyes061 = []
+
+ eyes062 = []
+
+ eyes063 = []
+
+ eyes064 = []
+
+ eyes065 = []
+
+ eyes066 = []
+
+ eyes067 = []
+
+ eyes068 = []
+
+ eyes069 = []
+
+ eyes070 = []
+
+ eyes071 = []
+
+ eyes072 = []
+
+ eyes073 = []
+
+ eyes074 = []
+
+ eyes075 = []
+
+ eyes076 = []
+
+ eyes077 = []
+
+ eyes078 = []
+
+ eyes079 = []
+
+ eyes080 = []
+
+ eyes081 = []
+
+ eyes082 = []
+
+ eyes083 = []
+
+ eyes084 = []
+
+ eyes085 = []
+
+ eyes086 = []
+
+ eyes087 = []
+
+ eyes088 = []
+
+ eyes089 = []
+
+ eyes090 = []
+
+ eyes091 = []
+
+ eyes092 = []
+
+ eyes093 = []
+
+ eyes094 = []
+
+ eyes095 = []
+
+ eyes096 = []
+
+ eyes097 = []
+
+ eyes098 = []
+
+ eyes099 = []
+
+ eyes100 = []
+
+ eyes101 = []
+
+ eyes102 = []
+
+ eyes103 = []
+
+ eyes104 = []
+
+ eyes105 = []
+
+ eyes106 = []
+
+ eyes107 = []
+
+ eyes108 = []
+
+ eyes109 = []
+
+ eyes110 = []
+
+ eyes111 = []
+
+ eyes112 = []
+
+ eyes113 = []
+
+ eyes114 = []
+
+ eyes115 = []
+
+ eyes116 = []
+
+ eyes117 = []
+
+ eyes118 = []
+
+ eyes119 = []
+
+ eyes120 = []
+
+ eyes121 = []
+
+ eyes122 = []
+
+ eyes123 = []
+
+ eyes124 = []
+
+ eyes125 = []
+
+ eyes126 = []
+
+ eyes127 = []
+
+ eyes128 = []
+
+ eyes129 = []
+
+ eyes130 = []
+
+ eyes131 = []
+
+ eyes132 = []
+
+ eyes133 = []
+
+ eyes134 = []
+
+ eyes135 = []
+
+ eyes136 = []
+
+ eyes137 = []
+
+ eyes138 = []
+
+ eyes139 = []
+
+ eyes140 = []
+
+ eyes141 = []
+
+ eyes142 = []
+
+ eyes143 = []
+
+ eyes144 = []
+
+ eyes145 = []
+
+ eyes146 = []
+
+ eyes147 = []
+
+ eyes148 = []
+
+ eyes149 = []
+
+ eyes150 = []
+
+ eyes151 = []
+
+ eyes152 = []
+
+ eyes153 = []
+
+ eyes154 = []
+
+ eyes155 = []
+
+ eyes156 = []
+
+ eyes157 = []
+
+ eyes158 = []
+
+ eyes159 = []
+
+ eyes160 = []
+
+ eyes161 = []
+
+ eyes162 = []
+
+ eyes163 = []
+
+ eyes164 = []
+
+ eyes165 = []
+
+ eyes166 = []
+
+ eyes167 = []
+
+ eyes168 = []
+
+ eyes169 = []
+
+ eyes170 = []
+
+ eyes171 = []
+
+ eyes172 = []
+
+ eyes173 = []
+
+ eyes174 = []
+
+ eyes175 = []
+
+ eyes176 = []
+
+ eyes177 = []
+
+ eyes178 = []
+
+ eyes179 = []
+
+ eyes180 = []
+
+ eyes181 = []
+
+ eyes182 = []
+
+ eyes183 = []
+
+ eyes184 = []
+
+ eyes185 = []
+
+ eyes186 = []
+
+ eyes187 = []
+
+ eyes188 = []
+
+ eyes189 = []
+
+ eyes190 = []
+
+ eyes191 = []
+
+ eyes192 = []
+
+ eyes193 = []
+
+ eyes194 = []
+
+ eyes195 = []
+
+ eyes196 = []
+
+ eyes197 = []
+
+ eyes198 = []
+
+ eyes199 = []
+
+
+
+
+
+
diff --git a/tests/testsuite/cargo_info/features_deactivated_over_limit/mod.rs b/tests/testsuite/cargo_info/features_deactivated_over_limit/mod.rs
new file mode 100644
index 00000000000..ad6bfa03c3f
--- /dev/null
+++ b/tests/testsuite/cargo_info/features_deactivated_over_limit/mod.rs
@@ -0,0 +1,36 @@
+use cargo_test_support::file;
+use cargo_test_support::prelude::*;
+
+use super::init_registry_without_token;
+
+#[cargo_test]
+fn case() {
+ const MANY_FEATURES_COUNT: usize = 200;
+ const DEFAULT_FEATURES_COUNT: usize = 20;
+
+ init_registry_without_token();
+ let mut test_package =
+ cargo_test_support::registry::Package::new("your-face", "99999.0.0+my-package");
+ let features = (0..MANY_FEATURES_COUNT)
+ .map(|i| format!("eyes{i:03}"))
+ .collect::>();
+ for name in &features {
+ test_package.feature(name.as_str(), &[]);
+ }
+ let default_features = features
+ .iter()
+ .take(DEFAULT_FEATURES_COUNT)
+ .map(|s| s.as_str())
+ .collect::>();
+ test_package.feature("default", &default_features);
+ test_package.publish();
+
+ snapbox::cmd::Command::cargo_ui()
+ .arg("info")
+ .arg("your-face")
+ .arg("--registry=dummy-registry")
+ .assert()
+ .success()
+ .stdout_eq(file!["stdout.term.svg"])
+ .stderr_eq(file!["stderr.term.svg"]);
+}
diff --git a/tests/testsuite/cargo_info/features_deactivated_over_limit/stderr.term.svg b/tests/testsuite/cargo_info/features_deactivated_over_limit/stderr.term.svg
new file mode 100644
index 00000000000..de41e3894c1
--- /dev/null
+++ b/tests/testsuite/cargo_info/features_deactivated_over_limit/stderr.term.svg
@@ -0,0 +1,31 @@
+
+
+
+
+
+
+ Updating `dummy-registry` index
+
+ Downloading crates ...
+
+ Downloaded your-face v99999.0.0+my-package (registry `dummy-registry`)
+
+
+
+
+
+
diff --git a/tests/testsuite/cargo_info/features_deactivated_over_limit/stdout.term.svg b/tests/testsuite/cargo_info/features_deactivated_over_limit/stdout.term.svg
new file mode 100644
index 00000000000..cfadcd506ec
--- /dev/null
+++ b/tests/testsuite/cargo_info/features_deactivated_over_limit/stdout.term.svg
@@ -0,0 +1,83 @@
+
+
+
+
+
+
+ your-face
+
+ version: 99999.0.0+my-package (from registry `dummy-registry`)
+
+ license: unknown
+
+ rust-version: unknown
+
+ features:
+
+ + default = [eyes000, eyes001, eyes002, eyes003, eyes004, eyes005, eyes006, eyes007, eyes008, eyes009, eyes010, eyes011, eyes012, eyes013, eyes014, eyes015, eyes016, eyes017, eyes018, eyes019]
+
+ eyes000 = []
+
+ eyes001 = []
+
+ eyes002 = []
+
+ eyes003 = []
+
+ eyes004 = []
+
+ eyes005 = []
+
+ eyes006 = []
+
+ eyes007 = []
+
+ eyes008 = []
+
+ eyes009 = []
+
+ eyes010 = []
+
+ eyes011 = []
+
+ eyes012 = []
+
+ eyes013 = []
+
+ eyes014 = []
+
+ eyes015 = []
+
+ eyes016 = []
+
+ eyes017 = []
+
+ eyes018 = []
+
+ eyes019 = []
+
+ 180 deactivated features
+
+
+
+
+
+
diff --git a/tests/testsuite/cargo_info/git_dependency/mod.rs b/tests/testsuite/cargo_info/git_dependency/mod.rs
new file mode 100644
index 00000000000..5872aee3070
--- /dev/null
+++ b/tests/testsuite/cargo_info/git_dependency/mod.rs
@@ -0,0 +1,44 @@
+use cargo_test_support::prelude::*;
+use cargo_test_support::{basic_manifest, file, git, project};
+
+use super::init_registry_without_token;
+
+#[cargo_test]
+fn case() {
+ init_registry_without_token();
+ let baz = git::new("baz", |project| {
+ project
+ .file("Cargo.toml", &basic_manifest("baz", "0.1.0"))
+ .file("src/lib.rs", "")
+ });
+
+ let foo = project()
+ .file(
+ "Cargo.toml",
+ &format!(
+ r#"
+ [package]
+ name = "foo"
+ version = "0.1.0"
+
+ [dependencies]
+ baz = {{ git = '{}' }}
+ "#,
+ baz.url()
+ ),
+ )
+ .file("src/lib.rs", "")
+ .build();
+
+ let project_root = foo.root();
+ let cwd = &project_root;
+
+ snapbox::cmd::Command::cargo_ui()
+ .arg("info")
+ .arg_line("--verbose foo")
+ .current_dir(cwd)
+ .assert()
+ .success()
+ .stdout_eq(file!["stdout.term.svg"])
+ .stderr_eq("");
+}
diff --git a/tests/testsuite/cargo_info/git_dependency/stdout.term.svg b/tests/testsuite/cargo_info/git_dependency/stdout.term.svg
new file mode 100644
index 00000000000..ded341482ad
--- /dev/null
+++ b/tests/testsuite/cargo_info/git_dependency/stdout.term.svg
@@ -0,0 +1,40 @@
+
+
+
+
+
+
+ foo
+
+ version: 0.1.0 (from ./)
+
+ license: unknown
+
+ rust-version: unknown
+
+ dependencies:
+
+ + baz ([ROOTURL]/baz)
+
+
+
+
+
+
diff --git a/tests/testsuite/cargo_info/help/mod.rs b/tests/testsuite/cargo_info/help/mod.rs
new file mode 100644
index 00000000000..edaa377d522
--- /dev/null
+++ b/tests/testsuite/cargo_info/help/mod.rs
@@ -0,0 +1,13 @@
+use cargo_test_support::file;
+use cargo_test_support::prelude::*;
+
+#[cargo_test]
+fn case() {
+ snapbox::cmd::Command::cargo_ui()
+ .arg("info")
+ .arg("--help")
+ .assert()
+ .success()
+ .stdout_eq(file!["stdout.term.svg"])
+ .stderr_eq("");
+}
diff --git a/tests/testsuite/cargo_info/help/stdout.term.svg b/tests/testsuite/cargo_info/help/stdout.term.svg
new file mode 100644
index 00000000000..8cefda8b1f2
--- /dev/null
+++ b/tests/testsuite/cargo_info/help/stdout.term.svg
@@ -0,0 +1,72 @@
+
+
+
+
+
+
+ Display information about a package in the registry
+
+
+
+ Usage: cargo[EXE] info [OPTIONS] <SPEC>
+
+
+
+ Options:
+
+ --index <INDEX> Registry index URL to search packages in
+
+ --registry <REGISTRY> Registry to search packages in
+
+ -v , --verbose ... Use verbose output (-vv very verbose/build.rs output)
+
+ -q , --quiet Do not print cargo log messages
+
+ --color <WHEN> Coloring: auto, always, never
+
+ --config <KEY=VALUE> Override a configuration value
+
+ -Z <FLAG> Unstable (nightly-only) flags to Cargo, see 'cargo -Z help' for details
+
+ -h , --help Print help
+
+
+
+ Package Selection:
+
+ <SPEC> Package to inspect
+
+
+
+ Manifest Options:
+
+ --locked Assert that `Cargo.lock` will remain unchanged
+
+ --offline Run without accessing the network
+
+ --frozen Equivalent to specifying both --locked and --offline
+
+
+
+ Run ` cargo help info ` for more detailed information.
+
+
+
+
+
+
diff --git a/tests/testsuite/cargo_info/mod.rs b/tests/testsuite/cargo_info/mod.rs
new file mode 100644
index 00000000000..4e8f48e161f
--- /dev/null
+++ b/tests/testsuite/cargo_info/mod.rs
@@ -0,0 +1,38 @@
+mod basic;
+mod features;
+mod features_activated_over_limit;
+mod features_activated_over_limit_verbose;
+mod features_deactivated_over_limit;
+mod git_dependency;
+mod help;
+mod not_found;
+mod path_dependency;
+mod pick_msrv_compatible_package;
+mod pick_msrv_compatible_package_within_ws;
+mod pick_msrv_compatible_package_within_ws_and_use_msrv_from_ws;
+mod specify_empty_version_with_url;
+mod specify_version_outside_ws;
+mod specify_version_with_url_but_registry_is_not_matched;
+mod specify_version_within_ws_and_conflict_with_lockfile;
+mod specify_version_within_ws_and_match_with_lockfile;
+mod transitive_dependency_within_ws;
+mod verbose;
+mod with_frozen_outside_ws;
+mod with_frozen_within_ws;
+mod with_locked_outside_ws;
+mod with_locked_within_ws;
+mod with_locked_within_ws_and_pick_the_package;
+mod with_offline;
+mod with_quiet;
+mod within_ws;
+mod within_ws_and_pick_ws_package;
+mod within_ws_with_alternative_registry;
+mod within_ws_without_lockfile;
+
+// Initialize the registry without a token.
+// Otherwise, it will try to list owners of the crate and fail.
+pub(crate) fn init_registry_without_token() {
+ let _reg = cargo_test_support::registry::RegistryBuilder::new()
+ .no_configure_token()
+ .build();
+}
diff --git a/tests/testsuite/cargo_info/not_found/in b/tests/testsuite/cargo_info/not_found/in
new file mode 120000
index 00000000000..e9fe1ca7b01
--- /dev/null
+++ b/tests/testsuite/cargo_info/not_found/in
@@ -0,0 +1 @@
+../within_workspace.in
\ No newline at end of file
diff --git a/tests/testsuite/cargo_info/not_found/mod.rs b/tests/testsuite/cargo_info/not_found/mod.rs
new file mode 100644
index 00000000000..bccfe0345e5
--- /dev/null
+++ b/tests/testsuite/cargo_info/not_found/mod.rs
@@ -0,0 +1,24 @@
+use cargo_test_support::prelude::*;
+use cargo_test_support::{compare::assert_ui, current_dir, file, Project};
+
+use super::init_registry_without_token;
+
+#[cargo_test]
+fn case() {
+ init_registry_without_token();
+ let project = Project::from_template(current_dir!().join("in"));
+ let project_root = project.root();
+ let cwd = &project_root;
+
+ snapbox::cmd::Command::cargo_ui()
+ .arg("info")
+ .arg("unknown")
+ .arg("--registry=dummy-registry")
+ .current_dir(cwd)
+ .assert()
+ .failure()
+ .stdout_eq("")
+ .stderr_eq(file!["stderr.term.svg"]);
+
+ assert_ui().subset_matches(current_dir!().join("out"), &project_root);
+}
diff --git a/tests/testsuite/cargo_info/not_found/out/Cargo.lock b/tests/testsuite/cargo_info/not_found/out/Cargo.lock
new file mode 100644
index 00000000000..e9ede42b3cb
--- /dev/null
+++ b/tests/testsuite/cargo_info/not_found/out/Cargo.lock
@@ -0,0 +1,16 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 3
+
+[[package]]
+name = "cargo-list-test-fixture"
+version = "0.0.0"
+dependencies = [
+ "my-package",
+]
+
+[[package]]
+name = "my-package"
+version = "0.1.1+my-package"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "21c0013931e013e890da011e601d9e8514359837da12125e7e89157d9349dcb7"
diff --git a/tests/testsuite/cargo_info/not_found/out/Cargo.toml b/tests/testsuite/cargo_info/not_found/out/Cargo.toml
new file mode 100644
index 00000000000..a200a736b98
--- /dev/null
+++ b/tests/testsuite/cargo_info/not_found/out/Cargo.toml
@@ -0,0 +1,8 @@
+[workspace]
+
+[package]
+name = "cargo-list-test-fixture"
+version = "0.0.0"
+
+[dependencies]
+my-package = "0.1"
diff --git a/tests/testsuite/cargo_info/not_found/out/src/lib.rs b/tests/testsuite/cargo_info/not_found/out/src/lib.rs
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/testsuite/cargo_info/not_found/out/src/lib.rs
@@ -0,0 +1 @@
+
diff --git a/tests/testsuite/cargo_info/not_found/stderr.term.svg b/tests/testsuite/cargo_info/not_found/stderr.term.svg
new file mode 100644
index 00000000000..7ce41f4a41f
--- /dev/null
+++ b/tests/testsuite/cargo_info/not_found/stderr.term.svg
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+ Updating `dummy-registry` index
+
+ error : could not find `unknown` in registry `[ROOTURL]/registry`
+
+
+
+
+
+
diff --git a/tests/testsuite/cargo_info/path_dependency/in/Cargo.lock b/tests/testsuite/cargo_info/path_dependency/in/Cargo.lock
new file mode 100644
index 00000000000..378b02cf7b7
--- /dev/null
+++ b/tests/testsuite/cargo_info/path_dependency/in/Cargo.lock
@@ -0,0 +1,14 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 3
+
+[[package]]
+name = "crate1"
+version = "0.0.0"
+
+[[package]]
+name = "foo"
+version = "0.0.0"
+dependencies = [
+ "crate1",
+]
diff --git a/tests/testsuite/cargo_info/path_dependency/in/Cargo.toml b/tests/testsuite/cargo_info/path_dependency/in/Cargo.toml
new file mode 100644
index 00000000000..be36b12df49
--- /dev/null
+++ b/tests/testsuite/cargo_info/path_dependency/in/Cargo.toml
@@ -0,0 +1,9 @@
+[workspace]
+members = ["crates/*"]
+
+[package]
+name = "foo"
+version = "0.0.0"
+
+[dependencies]
+crate1 = { path = "./crates/crate1" }
diff --git a/tests/testsuite/cargo_info/path_dependency/in/crates/crate1/Cargo.toml b/tests/testsuite/cargo_info/path_dependency/in/crates/crate1/Cargo.toml
new file mode 100644
index 00000000000..7a87e72a96e
--- /dev/null
+++ b/tests/testsuite/cargo_info/path_dependency/in/crates/crate1/Cargo.toml
@@ -0,0 +1,5 @@
+[package]
+name = "crate1"
+version = "0.0.0"
+
+[dependencies]
diff --git a/tests/testsuite/cargo_info/path_dependency/in/crates/crate1/src/lib.rs b/tests/testsuite/cargo_info/path_dependency/in/crates/crate1/src/lib.rs
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/testsuite/cargo_info/path_dependency/in/crates/crate1/src/lib.rs
@@ -0,0 +1 @@
+
diff --git a/tests/testsuite/cargo_info/path_dependency/in/src/lib.rs b/tests/testsuite/cargo_info/path_dependency/in/src/lib.rs
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/testsuite/cargo_info/path_dependency/in/src/lib.rs
@@ -0,0 +1 @@
+
diff --git a/tests/testsuite/cargo_info/path_dependency/mod.rs b/tests/testsuite/cargo_info/path_dependency/mod.rs
new file mode 100644
index 00000000000..3c086895362
--- /dev/null
+++ b/tests/testsuite/cargo_info/path_dependency/mod.rs
@@ -0,0 +1,24 @@
+use cargo_test_support::prelude::*;
+use cargo_test_support::{compare::assert_ui, current_dir, file, Project};
+
+use super::init_registry_without_token;
+
+#[cargo_test]
+fn case() {
+ init_registry_without_token();
+
+ let project = Project::from_template(current_dir!().join("in"));
+ let project_root = project.root();
+ let cwd = &project_root;
+
+ snapbox::cmd::Command::cargo_ui()
+ .arg("info")
+ .arg_line("--verbose foo")
+ .current_dir(cwd)
+ .assert()
+ .success()
+ .stdout_eq(file!["stdout.term.svg"])
+ .stderr_eq("");
+
+ assert_ui().subset_matches(current_dir!().join("out"), &project_root);
+}
diff --git a/tests/testsuite/cargo_info/path_dependency/out/Cargo.lock b/tests/testsuite/cargo_info/path_dependency/out/Cargo.lock
new file mode 100644
index 00000000000..378b02cf7b7
--- /dev/null
+++ b/tests/testsuite/cargo_info/path_dependency/out/Cargo.lock
@@ -0,0 +1,14 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 3
+
+[[package]]
+name = "crate1"
+version = "0.0.0"
+
+[[package]]
+name = "foo"
+version = "0.0.0"
+dependencies = [
+ "crate1",
+]
diff --git a/tests/testsuite/cargo_info/path_dependency/out/Cargo.toml b/tests/testsuite/cargo_info/path_dependency/out/Cargo.toml
new file mode 100644
index 00000000000..be36b12df49
--- /dev/null
+++ b/tests/testsuite/cargo_info/path_dependency/out/Cargo.toml
@@ -0,0 +1,9 @@
+[workspace]
+members = ["crates/*"]
+
+[package]
+name = "foo"
+version = "0.0.0"
+
+[dependencies]
+crate1 = { path = "./crates/crate1" }
diff --git a/tests/testsuite/cargo_info/path_dependency/out/crates/crate1/Cargo.toml b/tests/testsuite/cargo_info/path_dependency/out/crates/crate1/Cargo.toml
new file mode 100644
index 00000000000..7a87e72a96e
--- /dev/null
+++ b/tests/testsuite/cargo_info/path_dependency/out/crates/crate1/Cargo.toml
@@ -0,0 +1,5 @@
+[package]
+name = "crate1"
+version = "0.0.0"
+
+[dependencies]
diff --git a/tests/testsuite/cargo_info/path_dependency/out/crates/crate1/src/lib.rs b/tests/testsuite/cargo_info/path_dependency/out/crates/crate1/src/lib.rs
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/testsuite/cargo_info/path_dependency/out/crates/crate1/src/lib.rs
@@ -0,0 +1 @@
+
diff --git a/tests/testsuite/cargo_info/path_dependency/out/src/lib.rs b/tests/testsuite/cargo_info/path_dependency/out/src/lib.rs
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/testsuite/cargo_info/path_dependency/out/src/lib.rs
@@ -0,0 +1 @@
+
diff --git a/tests/testsuite/cargo_info/path_dependency/stdout.term.svg b/tests/testsuite/cargo_info/path_dependency/stdout.term.svg
new file mode 100644
index 00000000000..426c2aa388b
--- /dev/null
+++ b/tests/testsuite/cargo_info/path_dependency/stdout.term.svg
@@ -0,0 +1,40 @@
+
+
+
+
+
+
+ foo
+
+ version: 0.0.0 (from ./)
+
+ license: unknown
+
+ rust-version: unknown
+
+ dependencies:
+
+ + crate1 (./crates/crate1)
+
+
+
+
+
+
diff --git a/tests/testsuite/cargo_info/pick_msrv_compatible_package/mod.rs b/tests/testsuite/cargo_info/pick_msrv_compatible_package/mod.rs
new file mode 100644
index 00000000000..87f9f2aa4c7
--- /dev/null
+++ b/tests/testsuite/cargo_info/pick_msrv_compatible_package/mod.rs
@@ -0,0 +1,24 @@
+use cargo_test_support::file;
+use cargo_test_support::prelude::*;
+
+use super::init_registry_without_token;
+
+#[cargo_test]
+fn case() {
+ init_registry_without_token();
+ cargo_test_support::registry::Package::new("my-package", "0.1.1+my-package")
+ .rust_version("1.0.0")
+ .publish();
+ cargo_test_support::registry::Package::new("my-package", "0.2.0+my-package")
+ .rust_version("1.9876.0")
+ .publish();
+
+ snapbox::cmd::Command::cargo_ui()
+ .arg("info")
+ .arg("my-package")
+ .arg("--registry=dummy-registry")
+ .assert()
+ .success()
+ .stdout_eq(file!["stdout.term.svg"])
+ .stderr_eq(file!["stderr.term.svg"]);
+}
diff --git a/tests/testsuite/cargo_info/pick_msrv_compatible_package/stderr.term.svg b/tests/testsuite/cargo_info/pick_msrv_compatible_package/stderr.term.svg
new file mode 100644
index 00000000000..51426fe9046
--- /dev/null
+++ b/tests/testsuite/cargo_info/pick_msrv_compatible_package/stderr.term.svg
@@ -0,0 +1,31 @@
+
+
+
+
+
+
+ Updating `dummy-registry` index
+
+ Downloading crates ...
+
+ Downloaded my-package v0.1.1+my-package (registry `dummy-registry`)
+
+
+
+
+
+
diff --git a/tests/testsuite/cargo_info/pick_msrv_compatible_package/stdout.term.svg b/tests/testsuite/cargo_info/pick_msrv_compatible_package/stdout.term.svg
new file mode 100644
index 00000000000..51b4f54fdf8
--- /dev/null
+++ b/tests/testsuite/cargo_info/pick_msrv_compatible_package/stdout.term.svg
@@ -0,0 +1,36 @@
+
+
+
+
+
+
+ my-package
+
+ version: 0.1.1+my-package (latest 0.2.0+my-package from registry `dummy-registry` )
+
+ license: unknown
+
+ rust-version: 1.0.0
+
+
+
+
+
+
diff --git a/tests/testsuite/cargo_info/pick_msrv_compatible_package_within_ws/in/Cargo.toml b/tests/testsuite/cargo_info/pick_msrv_compatible_package_within_ws/in/Cargo.toml
new file mode 100644
index 00000000000..792cd9914d7
--- /dev/null
+++ b/tests/testsuite/cargo_info/pick_msrv_compatible_package_within_ws/in/Cargo.toml
@@ -0,0 +1,2 @@
+[workspace]
+members = ["crate*"]
diff --git a/tests/testsuite/cargo_info/pick_msrv_compatible_package_within_ws/in/crate1/Cargo.toml b/tests/testsuite/cargo_info/pick_msrv_compatible_package_within_ws/in/crate1/Cargo.toml
new file mode 100644
index 00000000000..e64842dc4ea
--- /dev/null
+++ b/tests/testsuite/cargo_info/pick_msrv_compatible_package_within_ws/in/crate1/Cargo.toml
@@ -0,0 +1,5 @@
+[package]
+name = "crate1"
+version = "0.0.0"
+rust-version = "1.0.0"
+
diff --git a/tests/testsuite/cargo_info/pick_msrv_compatible_package_within_ws/in/crate1/src/lib.rs b/tests/testsuite/cargo_info/pick_msrv_compatible_package_within_ws/in/crate1/src/lib.rs
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/tests/testsuite/cargo_info/pick_msrv_compatible_package_within_ws/in/crate2/Cargo.toml b/tests/testsuite/cargo_info/pick_msrv_compatible_package_within_ws/in/crate2/Cargo.toml
new file mode 100644
index 00000000000..308a2b91037
--- /dev/null
+++ b/tests/testsuite/cargo_info/pick_msrv_compatible_package_within_ws/in/crate2/Cargo.toml
@@ -0,0 +1,5 @@
+[package]
+name = "crate2"
+version = "0.0.0"
+rust-version = "1.0.0"
+
diff --git a/tests/testsuite/cargo_info/pick_msrv_compatible_package_within_ws/in/crate2/src/lib.rs b/tests/testsuite/cargo_info/pick_msrv_compatible_package_within_ws/in/crate2/src/lib.rs
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/tests/testsuite/cargo_info/pick_msrv_compatible_package_within_ws/mod.rs b/tests/testsuite/cargo_info/pick_msrv_compatible_package_within_ws/mod.rs
new file mode 100644
index 00000000000..b662a8fd5fe
--- /dev/null
+++ b/tests/testsuite/cargo_info/pick_msrv_compatible_package_within_ws/mod.rs
@@ -0,0 +1,32 @@
+use cargo_test_support::prelude::*;
+use cargo_test_support::{compare::assert_ui, current_dir, file, Project};
+
+use super::init_registry_without_token;
+
+#[cargo_test]
+fn case() {
+ init_registry_without_token();
+ cargo_test_support::registry::Package::new("my-package", "0.1.0").publish();
+ cargo_test_support::registry::Package::new("my-package", "0.2.0")
+ .rust_version("1.0.0")
+ .publish();
+ cargo_test_support::registry::Package::new("my-package", "0.2.1")
+ .rust_version("1.9876.0")
+ .publish();
+
+ let project = Project::from_template(current_dir!().join("in"));
+ let project_root = project.root();
+ let cwd = &project_root.join("crate1");
+
+ snapbox::cmd::Command::cargo_ui()
+ .arg("info")
+ .arg("my-package")
+ .arg("--registry=dummy-registry")
+ .current_dir(cwd)
+ .assert()
+ .success()
+ .stdout_eq(file!["stdout.term.svg"])
+ .stderr_eq(file!["stderr.term.svg"]);
+
+ assert_ui().subset_matches(current_dir!().join("out"), &project_root);
+}
diff --git a/tests/testsuite/cargo_info/pick_msrv_compatible_package_within_ws/out/Cargo.lock b/tests/testsuite/cargo_info/pick_msrv_compatible_package_within_ws/out/Cargo.lock
new file mode 100644
index 00000000000..6934c7f24bf
--- /dev/null
+++ b/tests/testsuite/cargo_info/pick_msrv_compatible_package_within_ws/out/Cargo.lock
@@ -0,0 +1,10 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+[[package]]
+name = "crate1"
+version = "0.0.0"
+
+[[package]]
+name = "crate2"
+version = "0.0.0"
+
diff --git a/tests/testsuite/cargo_info/pick_msrv_compatible_package_within_ws/out/Cargo.toml b/tests/testsuite/cargo_info/pick_msrv_compatible_package_within_ws/out/Cargo.toml
new file mode 100644
index 00000000000..792cd9914d7
--- /dev/null
+++ b/tests/testsuite/cargo_info/pick_msrv_compatible_package_within_ws/out/Cargo.toml
@@ -0,0 +1,2 @@
+[workspace]
+members = ["crate*"]
diff --git a/tests/testsuite/cargo_info/pick_msrv_compatible_package_within_ws/out/crate1/Cargo.toml b/tests/testsuite/cargo_info/pick_msrv_compatible_package_within_ws/out/crate1/Cargo.toml
new file mode 100644
index 00000000000..e64842dc4ea
--- /dev/null
+++ b/tests/testsuite/cargo_info/pick_msrv_compatible_package_within_ws/out/crate1/Cargo.toml
@@ -0,0 +1,5 @@
+[package]
+name = "crate1"
+version = "0.0.0"
+rust-version = "1.0.0"
+
diff --git a/tests/testsuite/cargo_info/pick_msrv_compatible_package_within_ws/out/crate1/src/lib.rs b/tests/testsuite/cargo_info/pick_msrv_compatible_package_within_ws/out/crate1/src/lib.rs
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/tests/testsuite/cargo_info/pick_msrv_compatible_package_within_ws/out/crate2/Cargo.toml b/tests/testsuite/cargo_info/pick_msrv_compatible_package_within_ws/out/crate2/Cargo.toml
new file mode 100644
index 00000000000..308a2b91037
--- /dev/null
+++ b/tests/testsuite/cargo_info/pick_msrv_compatible_package_within_ws/out/crate2/Cargo.toml
@@ -0,0 +1,5 @@
+[package]
+name = "crate2"
+version = "0.0.0"
+rust-version = "1.0.0"
+
diff --git a/tests/testsuite/cargo_info/pick_msrv_compatible_package_within_ws/out/crate2/src/lib.rs b/tests/testsuite/cargo_info/pick_msrv_compatible_package_within_ws/out/crate2/src/lib.rs
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/tests/testsuite/cargo_info/pick_msrv_compatible_package_within_ws/stderr.term.svg b/tests/testsuite/cargo_info/pick_msrv_compatible_package_within_ws/stderr.term.svg
new file mode 100644
index 00000000000..fa6295303b4
--- /dev/null
+++ b/tests/testsuite/cargo_info/pick_msrv_compatible_package_within_ws/stderr.term.svg
@@ -0,0 +1,33 @@
+
+
+
+
+
+
+ Locking 2 packages to latest compatible versions
+
+ Updating `dummy-registry` index
+
+ Downloading crates ...
+
+ Downloaded my-package v0.2.0 (registry `dummy-registry`)
+
+
+
+
+
+
diff --git a/tests/testsuite/cargo_info/pick_msrv_compatible_package_within_ws/stdout.term.svg b/tests/testsuite/cargo_info/pick_msrv_compatible_package_within_ws/stdout.term.svg
new file mode 100644
index 00000000000..2c521f36a13
--- /dev/null
+++ b/tests/testsuite/cargo_info/pick_msrv_compatible_package_within_ws/stdout.term.svg
@@ -0,0 +1,36 @@
+
+
+
+
+
+
+ my-package
+
+ version: 0.2.0 (latest 0.2.1 from registry `dummy-registry` )
+
+ license: unknown
+
+ rust-version: 1.0.0
+
+
+
+
+
+
diff --git a/tests/testsuite/cargo_info/pick_msrv_compatible_package_within_ws_and_use_msrv_from_ws/in/Cargo.toml b/tests/testsuite/cargo_info/pick_msrv_compatible_package_within_ws_and_use_msrv_from_ws/in/Cargo.toml
new file mode 100644
index 00000000000..792cd9914d7
--- /dev/null
+++ b/tests/testsuite/cargo_info/pick_msrv_compatible_package_within_ws_and_use_msrv_from_ws/in/Cargo.toml
@@ -0,0 +1,2 @@
+[workspace]
+members = ["crate*"]
diff --git a/tests/testsuite/cargo_info/pick_msrv_compatible_package_within_ws_and_use_msrv_from_ws/in/crate1/Cargo.toml b/tests/testsuite/cargo_info/pick_msrv_compatible_package_within_ws_and_use_msrv_from_ws/in/crate1/Cargo.toml
new file mode 100644
index 00000000000..60422fea1e4
--- /dev/null
+++ b/tests/testsuite/cargo_info/pick_msrv_compatible_package_within_ws_and_use_msrv_from_ws/in/crate1/Cargo.toml
@@ -0,0 +1,4 @@
+[package]
+name = "crate1"
+version = "0.0.0"
+
diff --git a/tests/testsuite/cargo_info/pick_msrv_compatible_package_within_ws_and_use_msrv_from_ws/in/crate1/src/lib.rs b/tests/testsuite/cargo_info/pick_msrv_compatible_package_within_ws_and_use_msrv_from_ws/in/crate1/src/lib.rs
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/tests/testsuite/cargo_info/pick_msrv_compatible_package_within_ws_and_use_msrv_from_ws/in/crate2/Cargo.toml b/tests/testsuite/cargo_info/pick_msrv_compatible_package_within_ws_and_use_msrv_from_ws/in/crate2/Cargo.toml
new file mode 100644
index 00000000000..e1d2a463576
--- /dev/null
+++ b/tests/testsuite/cargo_info/pick_msrv_compatible_package_within_ws_and_use_msrv_from_ws/in/crate2/Cargo.toml
@@ -0,0 +1,4 @@
+[package]
+name = "crate2"
+version = "0.0.0"
+rust-version = "1.0.0"
diff --git a/tests/testsuite/cargo_info/pick_msrv_compatible_package_within_ws_and_use_msrv_from_ws/in/crate2/src/lib.rs b/tests/testsuite/cargo_info/pick_msrv_compatible_package_within_ws_and_use_msrv_from_ws/in/crate2/src/lib.rs
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/tests/testsuite/cargo_info/pick_msrv_compatible_package_within_ws_and_use_msrv_from_ws/mod.rs b/tests/testsuite/cargo_info/pick_msrv_compatible_package_within_ws_and_use_msrv_from_ws/mod.rs
new file mode 100644
index 00000000000..0a57bb3954f
--- /dev/null
+++ b/tests/testsuite/cargo_info/pick_msrv_compatible_package_within_ws_and_use_msrv_from_ws/mod.rs
@@ -0,0 +1,32 @@
+use cargo_test_support::prelude::*;
+use cargo_test_support::{compare::assert_ui, current_dir, file, Project};
+
+use super::init_registry_without_token;
+
+#[cargo_test]
+fn case() {
+ init_registry_without_token();
+ cargo_test_support::registry::Package::new("my-package", "0.1.0").publish();
+ cargo_test_support::registry::Package::new("my-package", "0.2.0")
+ .rust_version("1.0.0")
+ .publish();
+ cargo_test_support::registry::Package::new("my-package", "0.2.1")
+ .rust_version("1.70.0")
+ .publish();
+
+ let project = Project::from_template(current_dir!().join("in"));
+ let project_root = project.root();
+ let cwd = &project_root.join("crate1");
+
+ snapbox::cmd::Command::cargo_ui()
+ .arg("info")
+ .arg("my-package")
+ .arg("--registry=dummy-registry")
+ .current_dir(cwd)
+ .assert()
+ .success()
+ .stdout_eq(file!["stdout.term.svg"])
+ .stderr_eq(file!["stderr.term.svg"]);
+
+ assert_ui().subset_matches(current_dir!().join("out"), &project_root);
+}
diff --git a/tests/testsuite/cargo_info/pick_msrv_compatible_package_within_ws_and_use_msrv_from_ws/out/Cargo.lock b/tests/testsuite/cargo_info/pick_msrv_compatible_package_within_ws_and_use_msrv_from_ws/out/Cargo.lock
new file mode 100644
index 00000000000..6934c7f24bf
--- /dev/null
+++ b/tests/testsuite/cargo_info/pick_msrv_compatible_package_within_ws_and_use_msrv_from_ws/out/Cargo.lock
@@ -0,0 +1,10 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+[[package]]
+name = "crate1"
+version = "0.0.0"
+
+[[package]]
+name = "crate2"
+version = "0.0.0"
+
diff --git a/tests/testsuite/cargo_info/pick_msrv_compatible_package_within_ws_and_use_msrv_from_ws/out/Cargo.toml b/tests/testsuite/cargo_info/pick_msrv_compatible_package_within_ws_and_use_msrv_from_ws/out/Cargo.toml
new file mode 100644
index 00000000000..792cd9914d7
--- /dev/null
+++ b/tests/testsuite/cargo_info/pick_msrv_compatible_package_within_ws_and_use_msrv_from_ws/out/Cargo.toml
@@ -0,0 +1,2 @@
+[workspace]
+members = ["crate*"]
diff --git a/tests/testsuite/cargo_info/pick_msrv_compatible_package_within_ws_and_use_msrv_from_ws/out/crate1/Cargo.toml b/tests/testsuite/cargo_info/pick_msrv_compatible_package_within_ws_and_use_msrv_from_ws/out/crate1/Cargo.toml
new file mode 100644
index 00000000000..60422fea1e4
--- /dev/null
+++ b/tests/testsuite/cargo_info/pick_msrv_compatible_package_within_ws_and_use_msrv_from_ws/out/crate1/Cargo.toml
@@ -0,0 +1,4 @@
+[package]
+name = "crate1"
+version = "0.0.0"
+
diff --git a/tests/testsuite/cargo_info/pick_msrv_compatible_package_within_ws_and_use_msrv_from_ws/out/crate1/src/lib.rs b/tests/testsuite/cargo_info/pick_msrv_compatible_package_within_ws_and_use_msrv_from_ws/out/crate1/src/lib.rs
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/tests/testsuite/cargo_info/pick_msrv_compatible_package_within_ws_and_use_msrv_from_ws/out/crate2/Cargo.toml b/tests/testsuite/cargo_info/pick_msrv_compatible_package_within_ws_and_use_msrv_from_ws/out/crate2/Cargo.toml
new file mode 100644
index 00000000000..e1d2a463576
--- /dev/null
+++ b/tests/testsuite/cargo_info/pick_msrv_compatible_package_within_ws_and_use_msrv_from_ws/out/crate2/Cargo.toml
@@ -0,0 +1,4 @@
+[package]
+name = "crate2"
+version = "0.0.0"
+rust-version = "1.0.0"
diff --git a/tests/testsuite/cargo_info/pick_msrv_compatible_package_within_ws_and_use_msrv_from_ws/out/crate2/src/lib.rs b/tests/testsuite/cargo_info/pick_msrv_compatible_package_within_ws_and_use_msrv_from_ws/out/crate2/src/lib.rs
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/tests/testsuite/cargo_info/pick_msrv_compatible_package_within_ws_and_use_msrv_from_ws/stderr.term.svg b/tests/testsuite/cargo_info/pick_msrv_compatible_package_within_ws_and_use_msrv_from_ws/stderr.term.svg
new file mode 100644
index 00000000000..fa6295303b4
--- /dev/null
+++ b/tests/testsuite/cargo_info/pick_msrv_compatible_package_within_ws_and_use_msrv_from_ws/stderr.term.svg
@@ -0,0 +1,33 @@
+
+
+
+
+
+
+ Locking 2 packages to latest compatible versions
+
+ Updating `dummy-registry` index
+
+ Downloading crates ...
+
+ Downloaded my-package v0.2.0 (registry `dummy-registry`)
+
+
+
+
+
+
diff --git a/tests/testsuite/cargo_info/pick_msrv_compatible_package_within_ws_and_use_msrv_from_ws/stdout.term.svg b/tests/testsuite/cargo_info/pick_msrv_compatible_package_within_ws_and_use_msrv_from_ws/stdout.term.svg
new file mode 100644
index 00000000000..2c521f36a13
--- /dev/null
+++ b/tests/testsuite/cargo_info/pick_msrv_compatible_package_within_ws_and_use_msrv_from_ws/stdout.term.svg
@@ -0,0 +1,36 @@
+
+
+
+
+
+
+ my-package
+
+ version: 0.2.0 (latest 0.2.1 from registry `dummy-registry` )
+
+ license: unknown
+
+ rust-version: 1.0.0
+
+
+
+
+
+
diff --git a/tests/testsuite/cargo_info/specify_empty_version_with_url/mod.rs b/tests/testsuite/cargo_info/specify_empty_version_with_url/mod.rs
new file mode 100644
index 00000000000..ee6c90ec275
--- /dev/null
+++ b/tests/testsuite/cargo_info/specify_empty_version_with_url/mod.rs
@@ -0,0 +1,22 @@
+use cargo_test_support::prelude::*;
+use cargo_test_support::{file, registry::RegistryBuilder};
+
+#[cargo_test]
+fn case() {
+ let _ = RegistryBuilder::new()
+ .alternative()
+ .no_configure_token()
+ .build();
+ cargo_test_support::registry::Package::new("my-package", "99999.0.0-alpha.1+my-package")
+ .alternative(true)
+ .publish();
+
+ snapbox::cmd::Command::cargo_ui()
+ .arg("info")
+ .arg("https://crates.io")
+ .arg("--registry=alternative")
+ .assert()
+ .failure()
+ .stdout_eq("")
+ .stderr_eq(file!["stderr.term.svg"]);
+}
diff --git a/tests/testsuite/cargo_info/specify_empty_version_with_url/stderr.term.svg b/tests/testsuite/cargo_info/specify_empty_version_with_url/stderr.term.svg
new file mode 100644
index 00000000000..9893f1e611b
--- /dev/null
+++ b/tests/testsuite/cargo_info/specify_empty_version_with_url/stderr.term.svg
@@ -0,0 +1,33 @@
+
+
+
+
+
+
+ error : invalid package ID specification: `https://crates.io`
+
+
+
+ Caused by:
+
+ package name cannot be empty
+
+
+
+
+
+
diff --git a/tests/testsuite/cargo_info/specify_version_outside_ws/mod.rs b/tests/testsuite/cargo_info/specify_version_outside_ws/mod.rs
new file mode 100644
index 00000000000..bfc36dfd7fd
--- /dev/null
+++ b/tests/testsuite/cargo_info/specify_version_outside_ws/mod.rs
@@ -0,0 +1,20 @@
+use cargo_test_support::file;
+use cargo_test_support::prelude::*;
+
+use super::init_registry_without_token;
+
+#[cargo_test]
+fn case() {
+ init_registry_without_token();
+ for ver in ["0.1.1+my-package", "0.2.0+my-package", "0.2.3+my-package"] {
+ cargo_test_support::registry::Package::new("my-package", ver).publish();
+ }
+ snapbox::cmd::Command::cargo_ui()
+ .arg("info")
+ .arg("my-package@0.2")
+ .arg("--registry=dummy-registry")
+ .assert()
+ .success()
+ .stdout_eq(file!["stdout.term.svg"])
+ .stderr_eq(file!["stderr.term.svg"]);
+}
diff --git a/tests/testsuite/cargo_info/specify_version_outside_ws/stderr.term.svg b/tests/testsuite/cargo_info/specify_version_outside_ws/stderr.term.svg
new file mode 100644
index 00000000000..d607725e42c
--- /dev/null
+++ b/tests/testsuite/cargo_info/specify_version_outside_ws/stderr.term.svg
@@ -0,0 +1,31 @@
+
+
+
+
+
+
+ Updating `dummy-registry` index
+
+ Downloading crates ...
+
+ Downloaded my-package v0.2.3+my-package (registry `dummy-registry`)
+
+
+
+
+
+
diff --git a/tests/testsuite/cargo_info/specify_version_outside_ws/stdout.term.svg b/tests/testsuite/cargo_info/specify_version_outside_ws/stdout.term.svg
new file mode 100644
index 00000000000..31a21fb5ecd
--- /dev/null
+++ b/tests/testsuite/cargo_info/specify_version_outside_ws/stdout.term.svg
@@ -0,0 +1,36 @@
+
+
+
+
+
+
+ my-package
+
+ version: 0.2.3+my-package (from registry `dummy-registry`)
+
+ license: unknown
+
+ rust-version: unknown
+
+
+
+
+
+
diff --git a/tests/testsuite/cargo_info/specify_version_with_url_but_registry_is_not_matched/mod.rs b/tests/testsuite/cargo_info/specify_version_with_url_but_registry_is_not_matched/mod.rs
new file mode 100644
index 00000000000..3d460ccf495
--- /dev/null
+++ b/tests/testsuite/cargo_info/specify_version_with_url_but_registry_is_not_matched/mod.rs
@@ -0,0 +1,22 @@
+use cargo_test_support::prelude::*;
+use cargo_test_support::{file, registry::RegistryBuilder};
+
+#[cargo_test]
+fn case() {
+ let _ = RegistryBuilder::new()
+ .alternative()
+ .no_configure_token()
+ .build();
+ cargo_test_support::registry::Package::new("my-package", "99999.0.0-alpha.1+my-package")
+ .alternative(true)
+ .publish();
+
+ snapbox::cmd::Command::cargo_ui()
+ .arg("info")
+ .arg("https://crates.io/my-package")
+ .arg("--registry=alternative")
+ .assert()
+ .failure()
+ .stdout_eq("")
+ .stderr_eq(file!["stderr.term.svg"]);
+}
diff --git a/tests/testsuite/cargo_info/specify_version_with_url_but_registry_is_not_matched/stderr.term.svg b/tests/testsuite/cargo_info/specify_version_with_url_but_registry_is_not_matched/stderr.term.svg
new file mode 100644
index 00000000000..319478675f9
--- /dev/null
+++ b/tests/testsuite/cargo_info/specify_version_with_url_but_registry_is_not_matched/stderr.term.svg
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+ Updating `alternative` index
+
+ error : could not find `https://crates.io/my-package` in registry `[ROOTURL]/alternative-registry`
+
+
+
+
+
+
diff --git a/tests/testsuite/cargo_info/specify_version_within_ws_and_conflict_with_lockfile/in b/tests/testsuite/cargo_info/specify_version_within_ws_and_conflict_with_lockfile/in
new file mode 120000
index 00000000000..e9fe1ca7b01
--- /dev/null
+++ b/tests/testsuite/cargo_info/specify_version_within_ws_and_conflict_with_lockfile/in
@@ -0,0 +1 @@
+../within_workspace.in
\ No newline at end of file
diff --git a/tests/testsuite/cargo_info/specify_version_within_ws_and_conflict_with_lockfile/mod.rs b/tests/testsuite/cargo_info/specify_version_within_ws_and_conflict_with_lockfile/mod.rs
new file mode 100644
index 00000000000..a433b78e63c
--- /dev/null
+++ b/tests/testsuite/cargo_info/specify_version_within_ws_and_conflict_with_lockfile/mod.rs
@@ -0,0 +1,36 @@
+use cargo_test_support::prelude::*;
+use cargo_test_support::{compare::assert_ui, current_dir, file, Project};
+
+use super::init_registry_without_token;
+
+#[cargo_test]
+fn case() {
+ init_registry_without_token();
+ for ver in [
+ "0.1.1+my-package",
+ "0.2.0+my-package",
+ "0.2.3+my-package",
+ "0.4.1+my-package",
+ "20.0.0+my-package",
+ "99999.0.0+my-package",
+ "99999.0.0-alpha.1+my-package",
+ ] {
+ cargo_test_support::registry::Package::new("my-package", ver).publish();
+ }
+
+ let project = Project::from_template(current_dir!().join("in"));
+ let project_root = project.root();
+ let cwd = &project_root;
+
+ snapbox::cmd::Command::cargo_ui()
+ .arg("info")
+ .arg("my-package@0.4")
+ .arg("--registry=dummy-registry")
+ .current_dir(cwd)
+ .assert()
+ .success()
+ .stdout_eq(file!["stdout.term.svg"])
+ .stderr_eq(file!["stderr.term.svg"]);
+
+ assert_ui().subset_matches(current_dir!().join("out"), &project_root);
+}
diff --git a/tests/testsuite/cargo_info/specify_version_within_ws_and_conflict_with_lockfile/out/Cargo.lock b/tests/testsuite/cargo_info/specify_version_within_ws_and_conflict_with_lockfile/out/Cargo.lock
new file mode 100644
index 00000000000..e9ede42b3cb
--- /dev/null
+++ b/tests/testsuite/cargo_info/specify_version_within_ws_and_conflict_with_lockfile/out/Cargo.lock
@@ -0,0 +1,16 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 3
+
+[[package]]
+name = "cargo-list-test-fixture"
+version = "0.0.0"
+dependencies = [
+ "my-package",
+]
+
+[[package]]
+name = "my-package"
+version = "0.1.1+my-package"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "21c0013931e013e890da011e601d9e8514359837da12125e7e89157d9349dcb7"
diff --git a/tests/testsuite/cargo_info/specify_version_within_ws_and_conflict_with_lockfile/out/Cargo.toml b/tests/testsuite/cargo_info/specify_version_within_ws_and_conflict_with_lockfile/out/Cargo.toml
new file mode 100644
index 00000000000..a200a736b98
--- /dev/null
+++ b/tests/testsuite/cargo_info/specify_version_within_ws_and_conflict_with_lockfile/out/Cargo.toml
@@ -0,0 +1,8 @@
+[workspace]
+
+[package]
+name = "cargo-list-test-fixture"
+version = "0.0.0"
+
+[dependencies]
+my-package = "0.1"
diff --git a/tests/testsuite/cargo_info/specify_version_within_ws_and_conflict_with_lockfile/out/src/lib.rs b/tests/testsuite/cargo_info/specify_version_within_ws_and_conflict_with_lockfile/out/src/lib.rs
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/testsuite/cargo_info/specify_version_within_ws_and_conflict_with_lockfile/out/src/lib.rs
@@ -0,0 +1 @@
+
diff --git a/tests/testsuite/cargo_info/specify_version_within_ws_and_conflict_with_lockfile/stderr.term.svg b/tests/testsuite/cargo_info/specify_version_within_ws_and_conflict_with_lockfile/stderr.term.svg
new file mode 100644
index 00000000000..c7cd6790414
--- /dev/null
+++ b/tests/testsuite/cargo_info/specify_version_within_ws_and_conflict_with_lockfile/stderr.term.svg
@@ -0,0 +1,31 @@
+
+
+
+
+
+
+ Updating `dummy-registry` index
+
+ Downloading crates ...
+
+ Downloaded my-package v0.4.1+my-package (registry `dummy-registry`)
+
+
+
+
+
+
diff --git a/tests/testsuite/cargo_info/specify_version_within_ws_and_conflict_with_lockfile/stdout.term.svg b/tests/testsuite/cargo_info/specify_version_within_ws_and_conflict_with_lockfile/stdout.term.svg
new file mode 100644
index 00000000000..78c9f57e0c7
--- /dev/null
+++ b/tests/testsuite/cargo_info/specify_version_within_ws_and_conflict_with_lockfile/stdout.term.svg
@@ -0,0 +1,36 @@
+
+
+
+
+
+
+ my-package
+
+ version: 0.4.1+my-package (latest 99999.0.0+my-package from registry `dummy-registry` )
+
+ license: unknown
+
+ rust-version: unknown
+
+
+
+
+
+
diff --git a/tests/testsuite/cargo_info/specify_version_within_ws_and_match_with_lockfile/in b/tests/testsuite/cargo_info/specify_version_within_ws_and_match_with_lockfile/in
new file mode 120000
index 00000000000..e9fe1ca7b01
--- /dev/null
+++ b/tests/testsuite/cargo_info/specify_version_within_ws_and_match_with_lockfile/in
@@ -0,0 +1 @@
+../within_workspace.in
\ No newline at end of file
diff --git a/tests/testsuite/cargo_info/specify_version_within_ws_and_match_with_lockfile/mod.rs b/tests/testsuite/cargo_info/specify_version_within_ws_and_match_with_lockfile/mod.rs
new file mode 100644
index 00000000000..736a9928627
--- /dev/null
+++ b/tests/testsuite/cargo_info/specify_version_within_ws_and_match_with_lockfile/mod.rs
@@ -0,0 +1,36 @@
+use cargo_test_support::prelude::*;
+use cargo_test_support::{compare::assert_ui, current_dir, file, Project};
+
+use super::init_registry_without_token;
+
+#[cargo_test]
+fn case() {
+ init_registry_without_token();
+ for ver in [
+ "0.1.1+my-package",
+ "0.2.0+my-package",
+ "0.2.3+my-package",
+ "0.4.1+my-package",
+ "20.0.0+my-package",
+ "99999.0.0+my-package",
+ "99999.0.0-alpha.1+my-package",
+ ] {
+ cargo_test_support::registry::Package::new("my-package", ver).publish();
+ }
+
+ let project = Project::from_template(current_dir!().join("in"));
+ let project_root = project.root();
+ let cwd = &project_root;
+
+ snapbox::cmd::Command::cargo_ui()
+ .arg("info")
+ .arg("my-package@0.1")
+ .arg("--registry=dummy-registry")
+ .current_dir(cwd)
+ .assert()
+ .success()
+ .stdout_eq(file!["stdout.term.svg"])
+ .stderr_eq(file!["stderr.term.svg"]);
+
+ assert_ui().subset_matches(current_dir!().join("out"), &project_root);
+}
diff --git a/tests/testsuite/cargo_info/specify_version_within_ws_and_match_with_lockfile/out/Cargo.lock b/tests/testsuite/cargo_info/specify_version_within_ws_and_match_with_lockfile/out/Cargo.lock
new file mode 100644
index 00000000000..e9ede42b3cb
--- /dev/null
+++ b/tests/testsuite/cargo_info/specify_version_within_ws_and_match_with_lockfile/out/Cargo.lock
@@ -0,0 +1,16 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 3
+
+[[package]]
+name = "cargo-list-test-fixture"
+version = "0.0.0"
+dependencies = [
+ "my-package",
+]
+
+[[package]]
+name = "my-package"
+version = "0.1.1+my-package"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "21c0013931e013e890da011e601d9e8514359837da12125e7e89157d9349dcb7"
diff --git a/tests/testsuite/cargo_info/specify_version_within_ws_and_match_with_lockfile/out/Cargo.toml b/tests/testsuite/cargo_info/specify_version_within_ws_and_match_with_lockfile/out/Cargo.toml
new file mode 100644
index 00000000000..a200a736b98
--- /dev/null
+++ b/tests/testsuite/cargo_info/specify_version_within_ws_and_match_with_lockfile/out/Cargo.toml
@@ -0,0 +1,8 @@
+[workspace]
+
+[package]
+name = "cargo-list-test-fixture"
+version = "0.0.0"
+
+[dependencies]
+my-package = "0.1"
diff --git a/tests/testsuite/cargo_info/specify_version_within_ws_and_match_with_lockfile/out/src/lib.rs b/tests/testsuite/cargo_info/specify_version_within_ws_and_match_with_lockfile/out/src/lib.rs
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/testsuite/cargo_info/specify_version_within_ws_and_match_with_lockfile/out/src/lib.rs
@@ -0,0 +1 @@
+
diff --git a/tests/testsuite/cargo_info/specify_version_within_ws_and_match_with_lockfile/stderr.term.svg b/tests/testsuite/cargo_info/specify_version_within_ws_and_match_with_lockfile/stderr.term.svg
new file mode 100644
index 00000000000..4514d2f7765
--- /dev/null
+++ b/tests/testsuite/cargo_info/specify_version_within_ws_and_match_with_lockfile/stderr.term.svg
@@ -0,0 +1,33 @@
+
+
+
+
+
+
+ Updating `dummy-registry` index
+
+ Downloading crates ...
+
+ Downloaded my-package v0.1.1+my-package (registry `dummy-registry`)
+
+ Updating crates.io index
+
+
+
+
+
+
diff --git a/tests/testsuite/cargo_info/specify_version_within_ws_and_match_with_lockfile/stdout.term.svg b/tests/testsuite/cargo_info/specify_version_within_ws_and_match_with_lockfile/stdout.term.svg
new file mode 100644
index 00000000000..711160ec528
--- /dev/null
+++ b/tests/testsuite/cargo_info/specify_version_within_ws_and_match_with_lockfile/stdout.term.svg
@@ -0,0 +1,42 @@
+
+
+
+
+
+
+ my-package
+
+ version: 0.1.1+my-package (latest 99999.0.0+my-package)
+
+ license: unknown
+
+ rust-version: unknown
+
+ documentation: https://docs.rs/my-package/0.1.1+my-package
+
+ crates.io: https://crates.io/crates/my-package/0.1.1+my-package
+
+ note : to see how you depend on my-package, run ` cargo tree --invert --package my-package@0.1.1+my-package `
+
+
+
+
+
+
diff --git a/tests/testsuite/cargo_info/transitive_dependency_within_ws/direct1-stderr.term.svg b/tests/testsuite/cargo_info/transitive_dependency_within_ws/direct1-stderr.term.svg
new file mode 100644
index 00000000000..5e89a97034e
--- /dev/null
+++ b/tests/testsuite/cargo_info/transitive_dependency_within_ws/direct1-stderr.term.svg
@@ -0,0 +1,29 @@
+
+
+
+
+
+
+ Downloading crates ...
+
+ Downloaded my-package v1.0.0 (registry `dummy-registry`)
+
+
+
+
+
+
diff --git a/tests/testsuite/cargo_info/transitive_dependency_within_ws/direct1-stdout.term.svg b/tests/testsuite/cargo_info/transitive_dependency_within_ws/direct1-stdout.term.svg
new file mode 100644
index 00000000000..f6033862451
--- /dev/null
+++ b/tests/testsuite/cargo_info/transitive_dependency_within_ws/direct1-stdout.term.svg
@@ -0,0 +1,42 @@
+
+
+
+
+
+
+ my-package
+
+ version: 1.0.0 (latest 99.0.0)
+
+ license: unknown
+
+ rust-version: unknown
+
+ documentation: https://docs.rs/my-package/1.0.0
+
+ crates.io: https://crates.io/crates/my-package/1.0.0
+
+ note : to see how you depend on my-package, run ` cargo tree --invert --package my-package@1.0.0 `
+
+
+
+
+
+
diff --git a/tests/testsuite/cargo_info/transitive_dependency_within_ws/direct2-stdout.term.svg b/tests/testsuite/cargo_info/transitive_dependency_within_ws/direct2-stdout.term.svg
new file mode 100644
index 00000000000..dac150a5ac5
--- /dev/null
+++ b/tests/testsuite/cargo_info/transitive_dependency_within_ws/direct2-stdout.term.svg
@@ -0,0 +1,42 @@
+
+
+
+
+
+
+ my-package
+
+ version: 2.0.0 (latest 99.0.0)
+
+ license: unknown
+
+ rust-version: unknown
+
+ documentation: https://docs.rs/my-package/2.0.0
+
+ crates.io: https://crates.io/crates/my-package/2.0.0
+
+ note : to see how you depend on my-package, run ` cargo tree --invert --package my-package@2.0.0 `
+
+
+
+
+
+
diff --git a/tests/testsuite/cargo_info/transitive_dependency_within_ws/in/Cargo.lock b/tests/testsuite/cargo_info/transitive_dependency_within_ws/in/Cargo.lock
new file mode 100644
index 00000000000..b0b918f897f
--- /dev/null
+++ b/tests/testsuite/cargo_info/transitive_dependency_within_ws/in/Cargo.lock
@@ -0,0 +1,85 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+[[package]]
+name = "dep1"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "my-package 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "dep2"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "my-package 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "dep3"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "my-package 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "direct1"
+version = "0.0.0"
+dependencies = [
+ "my-package 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "direct2"
+version = "0.0.0"
+dependencies = [
+ "my-package 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "my-package"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "my-package"
+version = "2.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "my-package"
+version = "3.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "transitive1"
+version = "0.0.0"
+dependencies = [
+ "dep1 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "transitive123"
+version = "0.0.0"
+dependencies = [
+ "dep1 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "dep2 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "dep3 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "transitive2"
+version = "0.0.0"
+dependencies = [
+ "dep2 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[metadata]
+"checksum dep1 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ad5d1a0cb2ca0bb8c8ed7623c0309c3b25092b11cb2d578e35ec8e5d280faa5c"
+"checksum dep2 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ed104779d80bde57bdbefd4bcd27e6948caab7f0b8ded30a5cb125a8cba814c8"
+"checksum dep3 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "15fd0baaa7ffd9dd001841b029542f4744180449bc01fff2c40a6d2fd974457e"
+"checksum my-package 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3325a560d0542c9d7bc4a0737e74ea3734fd756a707fd50bea8bc0e5ad1ae74f"
+"checksum my-package 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "597285c86228731859f5b5f08b11731cc5cb150d0a5373572522ff726cb97411"
+"checksum my-package 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3beee062f199bc0f6afc7e97e1518710462b921272773202d8636a59a12a791a"
diff --git a/tests/testsuite/cargo_info/transitive_dependency_within_ws/in/Cargo.toml b/tests/testsuite/cargo_info/transitive_dependency_within_ws/in/Cargo.toml
new file mode 100644
index 00000000000..c66a4d73cae
--- /dev/null
+++ b/tests/testsuite/cargo_info/transitive_dependency_within_ws/in/Cargo.toml
@@ -0,0 +1,2 @@
+[workspace]
+members = ["crates/*"]
diff --git a/tests/testsuite/cargo_info/transitive_dependency_within_ws/in/crates/direct1/Cargo.toml b/tests/testsuite/cargo_info/transitive_dependency_within_ws/in/crates/direct1/Cargo.toml
new file mode 100644
index 00000000000..3890a357430
--- /dev/null
+++ b/tests/testsuite/cargo_info/transitive_dependency_within_ws/in/crates/direct1/Cargo.toml
@@ -0,0 +1,8 @@
+[package]
+name = "direct1"
+version = "0.0.0"
+rust-version = "1.0.0"
+
+
+[dependencies]
+my-package = "1"
diff --git a/tests/testsuite/cargo_info/transitive_dependency_within_ws/in/crates/direct1/src/lib.rs b/tests/testsuite/cargo_info/transitive_dependency_within_ws/in/crates/direct1/src/lib.rs
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/tests/testsuite/cargo_info/transitive_dependency_within_ws/in/crates/direct2/Cargo.toml b/tests/testsuite/cargo_info/transitive_dependency_within_ws/in/crates/direct2/Cargo.toml
new file mode 100644
index 00000000000..a2c34bd6786
--- /dev/null
+++ b/tests/testsuite/cargo_info/transitive_dependency_within_ws/in/crates/direct2/Cargo.toml
@@ -0,0 +1,8 @@
+[package]
+name = "direct2"
+version = "0.0.0"
+rust-version = "1.0.0"
+
+
+[dependencies]
+my-package = "2"
diff --git a/tests/testsuite/cargo_info/transitive_dependency_within_ws/in/crates/direct2/src/lib.rs b/tests/testsuite/cargo_info/transitive_dependency_within_ws/in/crates/direct2/src/lib.rs
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/tests/testsuite/cargo_info/transitive_dependency_within_ws/in/crates/transitive1/Cargo.toml b/tests/testsuite/cargo_info/transitive_dependency_within_ws/in/crates/transitive1/Cargo.toml
new file mode 100644
index 00000000000..c22a9f9c0e8
--- /dev/null
+++ b/tests/testsuite/cargo_info/transitive_dependency_within_ws/in/crates/transitive1/Cargo.toml
@@ -0,0 +1,8 @@
+[package]
+name = "transitive1"
+version = "0.0.0"
+rust-version = "1.0.0"
+
+
+[dependencies]
+dep1 = "1"
diff --git a/tests/testsuite/cargo_info/transitive_dependency_within_ws/in/crates/transitive1/src/lib.rs b/tests/testsuite/cargo_info/transitive_dependency_within_ws/in/crates/transitive1/src/lib.rs
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/tests/testsuite/cargo_info/transitive_dependency_within_ws/in/crates/transitive123/Cargo.toml b/tests/testsuite/cargo_info/transitive_dependency_within_ws/in/crates/transitive123/Cargo.toml
new file mode 100644
index 00000000000..f08bf5faabb
--- /dev/null
+++ b/tests/testsuite/cargo_info/transitive_dependency_within_ws/in/crates/transitive123/Cargo.toml
@@ -0,0 +1,9 @@
+[package]
+name = "transitive123"
+version = "0.0.0"
+rust-version = "1.0.0"
+
+[dependencies]
+dep1 = "1"
+dep2 = "1"
+dep3 = "1"
diff --git a/tests/testsuite/cargo_info/transitive_dependency_within_ws/in/crates/transitive123/src/lib.rs b/tests/testsuite/cargo_info/transitive_dependency_within_ws/in/crates/transitive123/src/lib.rs
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/tests/testsuite/cargo_info/transitive_dependency_within_ws/in/crates/transitive2/Cargo.toml b/tests/testsuite/cargo_info/transitive_dependency_within_ws/in/crates/transitive2/Cargo.toml
new file mode 100644
index 00000000000..0e25fd0008d
--- /dev/null
+++ b/tests/testsuite/cargo_info/transitive_dependency_within_ws/in/crates/transitive2/Cargo.toml
@@ -0,0 +1,8 @@
+[package]
+name = "transitive2"
+version = "0.0.0"
+rust-version = "1.0.0"
+
+
+[dependencies]
+dep2 = "1"
diff --git a/tests/testsuite/cargo_info/transitive_dependency_within_ws/in/crates/transitive2/src/lib.rs b/tests/testsuite/cargo_info/transitive_dependency_within_ws/in/crates/transitive2/src/lib.rs
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/tests/testsuite/cargo_info/transitive_dependency_within_ws/in/src/lib.rs b/tests/testsuite/cargo_info/transitive_dependency_within_ws/in/src/lib.rs
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/testsuite/cargo_info/transitive_dependency_within_ws/in/src/lib.rs
@@ -0,0 +1 @@
+
diff --git a/tests/testsuite/cargo_info/transitive_dependency_within_ws/mod.rs b/tests/testsuite/cargo_info/transitive_dependency_within_ws/mod.rs
new file mode 100644
index 00000000000..9e553b36c6c
--- /dev/null
+++ b/tests/testsuite/cargo_info/transitive_dependency_within_ws/mod.rs
@@ -0,0 +1,78 @@
+use cargo_test_support::prelude::*;
+use cargo_test_support::{compare::assert_ui, current_dir, file, Project};
+
+use super::init_registry_without_token;
+
+#[cargo_test]
+fn case() {
+ init_registry_without_token();
+ // 99.0.0 is unused
+ for ver in ["1.0.0", "2.0.0", "3.0.0", "99.0.0"] {
+ cargo_test_support::registry::Package::new("my-package", ver).publish();
+ }
+ // Dep1 depends on 3.0.0, Dep2 depends on 2.0.0, Dep3 depends on 1.0.0
+ cargo_test_support::registry::Package::new("dep1", "1.0.0")
+ .dep("my-package", "1.0.0")
+ .publish();
+ cargo_test_support::registry::Package::new("dep2", "1.0.0")
+ .dep("my-package", "2.0.0")
+ .publish();
+ cargo_test_support::registry::Package::new("dep3", "1.0.0")
+ .dep("my-package", "3.0.0")
+ .publish();
+
+ let project = Project::from_template(current_dir!().join("in"));
+ let project_root = project.root();
+ let transitive1_root = project_root.join("crates/transitive1");
+ let transitive2_root = project_root.join("crates/transitive2");
+ let direct1_root = project_root.join("crates/direct1");
+ let direct2_root = project_root.join("crates/direct2");
+ let ws_directory = &project_root;
+ let transitive1_directory = &transitive1_root;
+ let transitive2_directory = &transitive2_root;
+ let direct1_directory = &direct1_root;
+ let direct2_directory = &direct2_root;
+
+ snapbox::cmd::Command::cargo_ui()
+ .arg("info")
+ .arg("my-package")
+ .arg("--registry=dummy-registry")
+ .current_dir(ws_directory)
+ .assert()
+ .stdout_eq(file!["ws-stdout.term.svg"])
+ .stderr_eq(file!["ws-stderr.term.svg"]);
+ snapbox::cmd::Command::cargo_ui()
+ .arg("info")
+ .arg("my-package")
+ .arg("--registry=dummy-registry")
+ .current_dir(transitive1_directory)
+ .assert()
+ .stdout_eq(file!["transitive1-stdout.term.svg"])
+ .stderr_eq("");
+ snapbox::cmd::Command::cargo_ui()
+ .arg("info")
+ .arg("my-package")
+ .arg("--registry=dummy-registry")
+ .current_dir(transitive2_directory)
+ .assert()
+ .stdout_eq(file!["transitive2-stdout.term.svg"])
+ .stderr_eq("");
+ snapbox::cmd::Command::cargo_ui()
+ .arg("info")
+ .arg("my-package")
+ .arg("--registry=dummy-registry")
+ .current_dir(direct1_directory)
+ .assert()
+ .stdout_eq(file!["direct1-stdout.term.svg"])
+ .stderr_eq(file!["direct1-stderr.term.svg"]);
+ snapbox::cmd::Command::cargo_ui()
+ .arg("info")
+ .arg("my-package")
+ .arg("--registry=dummy-registry")
+ .current_dir(direct2_directory)
+ .assert()
+ .stdout_eq(file!["direct2-stdout.term.svg"])
+ .stderr_eq("");
+
+ assert_ui().subset_matches(current_dir!().join("out"), &project_root);
+}
diff --git a/tests/testsuite/cargo_info/transitive_dependency_within_ws/out/Cargo.lock b/tests/testsuite/cargo_info/transitive_dependency_within_ws/out/Cargo.lock
new file mode 100644
index 00000000000..b0b918f897f
--- /dev/null
+++ b/tests/testsuite/cargo_info/transitive_dependency_within_ws/out/Cargo.lock
@@ -0,0 +1,85 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+[[package]]
+name = "dep1"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "my-package 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "dep2"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "my-package 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "dep3"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "my-package 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "direct1"
+version = "0.0.0"
+dependencies = [
+ "my-package 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "direct2"
+version = "0.0.0"
+dependencies = [
+ "my-package 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "my-package"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "my-package"
+version = "2.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "my-package"
+version = "3.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "transitive1"
+version = "0.0.0"
+dependencies = [
+ "dep1 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "transitive123"
+version = "0.0.0"
+dependencies = [
+ "dep1 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "dep2 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "dep3 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "transitive2"
+version = "0.0.0"
+dependencies = [
+ "dep2 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[metadata]
+"checksum dep1 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ad5d1a0cb2ca0bb8c8ed7623c0309c3b25092b11cb2d578e35ec8e5d280faa5c"
+"checksum dep2 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ed104779d80bde57bdbefd4bcd27e6948caab7f0b8ded30a5cb125a8cba814c8"
+"checksum dep3 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "15fd0baaa7ffd9dd001841b029542f4744180449bc01fff2c40a6d2fd974457e"
+"checksum my-package 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3325a560d0542c9d7bc4a0737e74ea3734fd756a707fd50bea8bc0e5ad1ae74f"
+"checksum my-package 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "597285c86228731859f5b5f08b11731cc5cb150d0a5373572522ff726cb97411"
+"checksum my-package 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3beee062f199bc0f6afc7e97e1518710462b921272773202d8636a59a12a791a"
diff --git a/tests/testsuite/cargo_info/transitive_dependency_within_ws/out/Cargo.toml b/tests/testsuite/cargo_info/transitive_dependency_within_ws/out/Cargo.toml
new file mode 100644
index 00000000000..c66a4d73cae
--- /dev/null
+++ b/tests/testsuite/cargo_info/transitive_dependency_within_ws/out/Cargo.toml
@@ -0,0 +1,2 @@
+[workspace]
+members = ["crates/*"]
diff --git a/tests/testsuite/cargo_info/transitive_dependency_within_ws/out/crates/direct1/Cargo.toml b/tests/testsuite/cargo_info/transitive_dependency_within_ws/out/crates/direct1/Cargo.toml
new file mode 100644
index 00000000000..3890a357430
--- /dev/null
+++ b/tests/testsuite/cargo_info/transitive_dependency_within_ws/out/crates/direct1/Cargo.toml
@@ -0,0 +1,8 @@
+[package]
+name = "direct1"
+version = "0.0.0"
+rust-version = "1.0.0"
+
+
+[dependencies]
+my-package = "1"
diff --git a/tests/testsuite/cargo_info/transitive_dependency_within_ws/out/crates/direct1/src/lib.rs b/tests/testsuite/cargo_info/transitive_dependency_within_ws/out/crates/direct1/src/lib.rs
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/tests/testsuite/cargo_info/transitive_dependency_within_ws/out/crates/direct2/Cargo.toml b/tests/testsuite/cargo_info/transitive_dependency_within_ws/out/crates/direct2/Cargo.toml
new file mode 100644
index 00000000000..a2c34bd6786
--- /dev/null
+++ b/tests/testsuite/cargo_info/transitive_dependency_within_ws/out/crates/direct2/Cargo.toml
@@ -0,0 +1,8 @@
+[package]
+name = "direct2"
+version = "0.0.0"
+rust-version = "1.0.0"
+
+
+[dependencies]
+my-package = "2"
diff --git a/tests/testsuite/cargo_info/transitive_dependency_within_ws/out/crates/direct2/src/lib.rs b/tests/testsuite/cargo_info/transitive_dependency_within_ws/out/crates/direct2/src/lib.rs
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/tests/testsuite/cargo_info/transitive_dependency_within_ws/out/crates/transitive1/Cargo.toml b/tests/testsuite/cargo_info/transitive_dependency_within_ws/out/crates/transitive1/Cargo.toml
new file mode 100644
index 00000000000..c22a9f9c0e8
--- /dev/null
+++ b/tests/testsuite/cargo_info/transitive_dependency_within_ws/out/crates/transitive1/Cargo.toml
@@ -0,0 +1,8 @@
+[package]
+name = "transitive1"
+version = "0.0.0"
+rust-version = "1.0.0"
+
+
+[dependencies]
+dep1 = "1"
diff --git a/tests/testsuite/cargo_info/transitive_dependency_within_ws/out/crates/transitive1/src/lib.rs b/tests/testsuite/cargo_info/transitive_dependency_within_ws/out/crates/transitive1/src/lib.rs
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/tests/testsuite/cargo_info/transitive_dependency_within_ws/out/crates/transitive123/Cargo.toml b/tests/testsuite/cargo_info/transitive_dependency_within_ws/out/crates/transitive123/Cargo.toml
new file mode 100644
index 00000000000..f08bf5faabb
--- /dev/null
+++ b/tests/testsuite/cargo_info/transitive_dependency_within_ws/out/crates/transitive123/Cargo.toml
@@ -0,0 +1,9 @@
+[package]
+name = "transitive123"
+version = "0.0.0"
+rust-version = "1.0.0"
+
+[dependencies]
+dep1 = "1"
+dep2 = "1"
+dep3 = "1"
diff --git a/tests/testsuite/cargo_info/transitive_dependency_within_ws/out/crates/transitive123/src/lib.rs b/tests/testsuite/cargo_info/transitive_dependency_within_ws/out/crates/transitive123/src/lib.rs
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/tests/testsuite/cargo_info/transitive_dependency_within_ws/out/crates/transitive2/Cargo.toml b/tests/testsuite/cargo_info/transitive_dependency_within_ws/out/crates/transitive2/Cargo.toml
new file mode 100644
index 00000000000..0e25fd0008d
--- /dev/null
+++ b/tests/testsuite/cargo_info/transitive_dependency_within_ws/out/crates/transitive2/Cargo.toml
@@ -0,0 +1,8 @@
+[package]
+name = "transitive2"
+version = "0.0.0"
+rust-version = "1.0.0"
+
+
+[dependencies]
+dep2 = "1"
diff --git a/tests/testsuite/cargo_info/transitive_dependency_within_ws/out/crates/transitive2/src/lib.rs b/tests/testsuite/cargo_info/transitive_dependency_within_ws/out/crates/transitive2/src/lib.rs
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/tests/testsuite/cargo_info/transitive_dependency_within_ws/out/src/lib.rs b/tests/testsuite/cargo_info/transitive_dependency_within_ws/out/src/lib.rs
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/testsuite/cargo_info/transitive_dependency_within_ws/out/src/lib.rs
@@ -0,0 +1 @@
+
diff --git a/tests/testsuite/cargo_info/transitive_dependency_within_ws/transitive1-stdout.term.svg b/tests/testsuite/cargo_info/transitive_dependency_within_ws/transitive1-stdout.term.svg
new file mode 100644
index 00000000000..dac150a5ac5
--- /dev/null
+++ b/tests/testsuite/cargo_info/transitive_dependency_within_ws/transitive1-stdout.term.svg
@@ -0,0 +1,42 @@
+
+
+
+
+
+
+ my-package
+
+ version: 2.0.0 (latest 99.0.0)
+
+ license: unknown
+
+ rust-version: unknown
+
+ documentation: https://docs.rs/my-package/2.0.0
+
+ crates.io: https://crates.io/crates/my-package/2.0.0
+
+ note : to see how you depend on my-package, run ` cargo tree --invert --package my-package@2.0.0 `
+
+
+
+
+
+
diff --git a/tests/testsuite/cargo_info/transitive_dependency_within_ws/transitive2-stdout.term.svg b/tests/testsuite/cargo_info/transitive_dependency_within_ws/transitive2-stdout.term.svg
new file mode 100644
index 00000000000..dac150a5ac5
--- /dev/null
+++ b/tests/testsuite/cargo_info/transitive_dependency_within_ws/transitive2-stdout.term.svg
@@ -0,0 +1,42 @@
+
+
+
+
+
+
+ my-package
+
+ version: 2.0.0 (latest 99.0.0)
+
+ license: unknown
+
+ rust-version: unknown
+
+ documentation: https://docs.rs/my-package/2.0.0
+
+ crates.io: https://crates.io/crates/my-package/2.0.0
+
+ note : to see how you depend on my-package, run ` cargo tree --invert --package my-package@2.0.0 `
+
+
+
+
+
+
diff --git a/tests/testsuite/cargo_info/transitive_dependency_within_ws/ws-stderr.term.svg b/tests/testsuite/cargo_info/transitive_dependency_within_ws/ws-stderr.term.svg
new file mode 100644
index 00000000000..b64062c8142
--- /dev/null
+++ b/tests/testsuite/cargo_info/transitive_dependency_within_ws/ws-stderr.term.svg
@@ -0,0 +1,33 @@
+
+
+
+
+
+
+ Updating `dummy-registry` index
+
+ Downloading crates ...
+
+ Downloaded my-package v2.0.0 (registry `dummy-registry`)
+
+ Updating crates.io index
+
+
+
+
+
+
diff --git a/tests/testsuite/cargo_info/transitive_dependency_within_ws/ws-stdout.term.svg b/tests/testsuite/cargo_info/transitive_dependency_within_ws/ws-stdout.term.svg
new file mode 100644
index 00000000000..dac150a5ac5
--- /dev/null
+++ b/tests/testsuite/cargo_info/transitive_dependency_within_ws/ws-stdout.term.svg
@@ -0,0 +1,42 @@
+
+
+
+
+
+
+ my-package
+
+ version: 2.0.0 (latest 99.0.0)
+
+ license: unknown
+
+ rust-version: unknown
+
+ documentation: https://docs.rs/my-package/2.0.0
+
+ crates.io: https://crates.io/crates/my-package/2.0.0
+
+ note : to see how you depend on my-package, run ` cargo tree --invert --package my-package@2.0.0 `
+
+
+
+
+
+
diff --git a/tests/testsuite/cargo_info/verbose/mod.rs b/tests/testsuite/cargo_info/verbose/mod.rs
new file mode 100644
index 00000000000..2afb5c19975
--- /dev/null
+++ b/tests/testsuite/cargo_info/verbose/mod.rs
@@ -0,0 +1,53 @@
+use cargo_test_support::file;
+use cargo_test_support::prelude::*;
+
+use super::init_registry_without_token;
+
+#[cargo_test]
+fn case() {
+ init_registry_without_token();
+ cargo_test_support::registry::Package::new("my-package", "0.1.0")
+ .file(
+ "Cargo.toml",
+ r#"
+ [package]
+ name = "my-package"
+ version = "0.1.0"
+ description = "A package for testing"
+ repository = "https://github.com/hi-rustin/cargo-infromation"
+ documentation = "https://docs.rs/my-package/0.1.0"
+ license = "MIT"
+ edition = "2018"
+ rust-version = "1.50.0"
+ keywords = ["foo", "bar", "baz"]
+
+ [features]
+ default = ["feature1"]
+ feature1 = []
+ feature2 = []
+
+ [dependencies]
+ foo = "0.1.0"
+ bar = "0.2.0"
+ baz = { version = "0.3.0", optional = true }
+
+ [[bin]]
+ name = "my_bin"
+
+ [lib]
+ name = "my_lib"
+ "#,
+ )
+ .file("src/bin/my_bin.rs", "")
+ .file("src/lib.rs", "")
+ .publish();
+ snapbox::cmd::Command::cargo_ui()
+ .arg("info")
+ .arg("my-package")
+ .arg("--verbose")
+ .arg("--registry=dummy-registry")
+ .assert()
+ .success()
+ .stdout_eq(file!["stdout.term.svg"])
+ .stderr_eq(file!["stderr.term.svg"]);
+}
diff --git a/tests/testsuite/cargo_info/verbose/stderr.term.svg b/tests/testsuite/cargo_info/verbose/stderr.term.svg
new file mode 100644
index 00000000000..dc88c4285a5
--- /dev/null
+++ b/tests/testsuite/cargo_info/verbose/stderr.term.svg
@@ -0,0 +1,33 @@
+
+
+
+
+
+
+ Updating `dummy-registry` index
+
+ Downloading crates ...
+
+ Downloaded my-package v0.1.0 (registry `dummy-registry`)
+
+ Credential cargo:token get dummy-registry
+
+
+
+
+
+
diff --git a/tests/testsuite/cargo_info/verbose/stdout.term.svg b/tests/testsuite/cargo_info/verbose/stdout.term.svg
new file mode 100644
index 00000000000..9b03148d9b3
--- /dev/null
+++ b/tests/testsuite/cargo_info/verbose/stdout.term.svg
@@ -0,0 +1,59 @@
+
+
+
+
+
+
+ my-package #foo #bar #baz
+
+ A package for testing
+
+ version: 0.1.0 (from registry `dummy-registry`)
+
+ license: MIT
+
+ rust-version: 1.50.0
+
+ documentation: https://docs.rs/my-package/0.1.0
+
+ repository: https://github.com/hi-rustin/cargo-infromation
+
+ features:
+
+ + default = [feature1]
+
+ feature1 = []
+
+ baz = [ dep:baz ]
+
+ feature2 = []
+
+ dependencies:
+
+ + bar@0.2.0
+
+ + foo@0.1.0
+
+ baz@0.3.0
+
+
+
+
+
+
diff --git a/tests/testsuite/cargo_info/with_frozen_outside_ws/mod.rs b/tests/testsuite/cargo_info/with_frozen_outside_ws/mod.rs
new file mode 100644
index 00000000000..c04f6934ed3
--- /dev/null
+++ b/tests/testsuite/cargo_info/with_frozen_outside_ws/mod.rs
@@ -0,0 +1,30 @@
+use cargo_test_support::file;
+use cargo_test_support::prelude::*;
+
+use super::init_registry_without_token;
+
+#[cargo_test]
+fn case() {
+ init_registry_without_token();
+ for ver in [
+ "0.1.1+my-package",
+ "0.2.0+my-package",
+ "0.2.3+my-package",
+ "0.4.1+my-package",
+ "20.0.0+my-package",
+ "99999.0.0+my-package",
+ "99999.0.0-alpha.1+my-package",
+ ] {
+ cargo_test_support::registry::Package::new("my-package", ver).publish();
+ }
+
+ snapbox::cmd::Command::cargo_ui()
+ .arg("info")
+ .arg("my-package")
+ .arg("--frozen")
+ .arg("--registry=dummy-registry")
+ .assert()
+ .failure()
+ .stdout_eq("")
+ .stderr_eq(file!["stderr.term.svg"]);
+}
diff --git a/tests/testsuite/cargo_info/with_frozen_outside_ws/stderr.term.svg b/tests/testsuite/cargo_info/with_frozen_outside_ws/stderr.term.svg
new file mode 100644
index 00000000000..e695bb9fb59
--- /dev/null
+++ b/tests/testsuite/cargo_info/with_frozen_outside_ws/stderr.term.svg
@@ -0,0 +1,27 @@
+
+
+
+
+
+
+ error : the option `--frozen` can only be used within a workspace
+
+
+
+
+
+
diff --git a/tests/testsuite/cargo_info/with_frozen_within_ws/in b/tests/testsuite/cargo_info/with_frozen_within_ws/in
new file mode 120000
index 00000000000..e9fe1ca7b01
--- /dev/null
+++ b/tests/testsuite/cargo_info/with_frozen_within_ws/in
@@ -0,0 +1 @@
+../within_workspace.in
\ No newline at end of file
diff --git a/tests/testsuite/cargo_info/with_frozen_within_ws/mod.rs b/tests/testsuite/cargo_info/with_frozen_within_ws/mod.rs
new file mode 100644
index 00000000000..3881f64a880
--- /dev/null
+++ b/tests/testsuite/cargo_info/with_frozen_within_ws/mod.rs
@@ -0,0 +1,37 @@
+use cargo_test_support::prelude::*;
+use cargo_test_support::{compare::assert_ui, current_dir, file, Project};
+
+use super::init_registry_without_token;
+
+#[cargo_test]
+fn case() {
+ init_registry_without_token();
+ for ver in [
+ "0.1.1+my-package",
+ "0.2.0+my-package",
+ "0.2.3+my-package",
+ "0.4.1+my-package",
+ "20.0.0+my-package",
+ "99999.0.0+my-package",
+ "99999.0.0-alpha.1+my-package",
+ ] {
+ cargo_test_support::registry::Package::new("my-package", ver).publish();
+ }
+
+ let project = Project::from_template(current_dir!().join("in"));
+ let project_root = project.root();
+ let cwd = &project_root;
+
+ snapbox::cmd::Command::cargo_ui()
+ .arg("info")
+ .arg("unknown")
+ .arg("--frozen")
+ .arg("--registry=dummy-registry")
+ .current_dir(cwd)
+ .assert()
+ .failure()
+ .stdout_eq("")
+ .stderr_eq(file!["stderr.term.svg"]);
+
+ assert_ui().subset_matches(current_dir!().join("out"), &project_root);
+}
diff --git a/tests/testsuite/cargo_info/with_frozen_within_ws/out/Cargo.lock b/tests/testsuite/cargo_info/with_frozen_within_ws/out/Cargo.lock
new file mode 100644
index 00000000000..e9ede42b3cb
--- /dev/null
+++ b/tests/testsuite/cargo_info/with_frozen_within_ws/out/Cargo.lock
@@ -0,0 +1,16 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 3
+
+[[package]]
+name = "cargo-list-test-fixture"
+version = "0.0.0"
+dependencies = [
+ "my-package",
+]
+
+[[package]]
+name = "my-package"
+version = "0.1.1+my-package"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "21c0013931e013e890da011e601d9e8514359837da12125e7e89157d9349dcb7"
diff --git a/tests/testsuite/cargo_info/with_frozen_within_ws/out/Cargo.toml b/tests/testsuite/cargo_info/with_frozen_within_ws/out/Cargo.toml
new file mode 100644
index 00000000000..a200a736b98
--- /dev/null
+++ b/tests/testsuite/cargo_info/with_frozen_within_ws/out/Cargo.toml
@@ -0,0 +1,8 @@
+[workspace]
+
+[package]
+name = "cargo-list-test-fixture"
+version = "0.0.0"
+
+[dependencies]
+my-package = "0.1"
diff --git a/tests/testsuite/cargo_info/with_frozen_within_ws/out/src/lib.rs b/tests/testsuite/cargo_info/with_frozen_within_ws/out/src/lib.rs
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/testsuite/cargo_info/with_frozen_within_ws/out/src/lib.rs
@@ -0,0 +1 @@
+
diff --git a/tests/testsuite/cargo_info/with_frozen_within_ws/stderr.term.svg b/tests/testsuite/cargo_info/with_frozen_within_ws/stderr.term.svg
new file mode 100644
index 00000000000..5d329b55ad1
--- /dev/null
+++ b/tests/testsuite/cargo_info/with_frozen_within_ws/stderr.term.svg
@@ -0,0 +1,27 @@
+
+
+
+
+
+
+ error : could not find `unknown` in registry `[ROOTURL]/registry`
+
+
+
+
+
+
diff --git a/tests/testsuite/cargo_info/with_locked_outside_ws/mod.rs b/tests/testsuite/cargo_info/with_locked_outside_ws/mod.rs
new file mode 100644
index 00000000000..6678ac7a380
--- /dev/null
+++ b/tests/testsuite/cargo_info/with_locked_outside_ws/mod.rs
@@ -0,0 +1,30 @@
+use cargo_test_support::file;
+use cargo_test_support::prelude::*;
+
+use super::init_registry_without_token;
+
+#[cargo_test]
+fn case() {
+ init_registry_without_token();
+ for ver in [
+ "0.1.1+my-package",
+ "0.2.0+my-package",
+ "0.2.3+my-package",
+ "0.4.1+my-package",
+ "20.0.0+my-package",
+ "99999.0.0+my-package",
+ "99999.0.0-alpha.1+my-package",
+ ] {
+ cargo_test_support::registry::Package::new("my-package", ver).publish();
+ }
+
+ snapbox::cmd::Command::cargo_ui()
+ .arg("info")
+ .arg("my-package")
+ .arg("--locked")
+ .arg("--registry=dummy-registry")
+ .assert()
+ .failure()
+ .stdout_eq("")
+ .stderr_eq(file!["stderr.term.svg"]);
+}
diff --git a/tests/testsuite/cargo_info/with_locked_outside_ws/stderr.term.svg b/tests/testsuite/cargo_info/with_locked_outside_ws/stderr.term.svg
new file mode 100644
index 00000000000..2d9641b8ecf
--- /dev/null
+++ b/tests/testsuite/cargo_info/with_locked_outside_ws/stderr.term.svg
@@ -0,0 +1,27 @@
+
+
+
+
+
+
+ error : the option `--locked` can only be used within a workspace
+
+
+
+
+
+
diff --git a/tests/testsuite/cargo_info/with_locked_within_ws/in b/tests/testsuite/cargo_info/with_locked_within_ws/in
new file mode 120000
index 00000000000..e9fe1ca7b01
--- /dev/null
+++ b/tests/testsuite/cargo_info/with_locked_within_ws/in
@@ -0,0 +1 @@
+../within_workspace.in
\ No newline at end of file
diff --git a/tests/testsuite/cargo_info/with_locked_within_ws/mod.rs b/tests/testsuite/cargo_info/with_locked_within_ws/mod.rs
new file mode 100644
index 00000000000..4f958d75eef
--- /dev/null
+++ b/tests/testsuite/cargo_info/with_locked_within_ws/mod.rs
@@ -0,0 +1,37 @@
+use cargo_test_support::prelude::*;
+use cargo_test_support::{compare::assert_ui, current_dir, file, Project};
+
+use super::init_registry_without_token;
+
+#[cargo_test]
+fn case() {
+ init_registry_without_token();
+ for ver in [
+ "0.1.1+my-package",
+ "0.2.0+my-package",
+ "0.2.3+my-package",
+ "0.4.1+my-package",
+ "20.0.0+my-package",
+ "99999.0.0+my-package",
+ "99999.0.0-alpha.1+my-package",
+ ] {
+ cargo_test_support::registry::Package::new("my-package", ver).publish();
+ }
+
+ let project = Project::from_template(current_dir!().join("in"));
+ let project_root = project.root();
+ let cwd = &project_root;
+
+ snapbox::cmd::Command::cargo_ui()
+ .arg("info")
+ .arg("unknown")
+ .arg("--locked")
+ .arg("--registry=dummy-registry")
+ .current_dir(cwd)
+ .assert()
+ .failure()
+ .stdout_eq("")
+ .stderr_eq(file!["stderr.term.svg"]);
+
+ assert_ui().subset_matches(current_dir!().join("out"), &project_root);
+}
diff --git a/tests/testsuite/cargo_info/with_locked_within_ws/out/Cargo.lock b/tests/testsuite/cargo_info/with_locked_within_ws/out/Cargo.lock
new file mode 100644
index 00000000000..e9ede42b3cb
--- /dev/null
+++ b/tests/testsuite/cargo_info/with_locked_within_ws/out/Cargo.lock
@@ -0,0 +1,16 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 3
+
+[[package]]
+name = "cargo-list-test-fixture"
+version = "0.0.0"
+dependencies = [
+ "my-package",
+]
+
+[[package]]
+name = "my-package"
+version = "0.1.1+my-package"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "21c0013931e013e890da011e601d9e8514359837da12125e7e89157d9349dcb7"
diff --git a/tests/testsuite/cargo_info/with_locked_within_ws/out/Cargo.toml b/tests/testsuite/cargo_info/with_locked_within_ws/out/Cargo.toml
new file mode 100644
index 00000000000..a200a736b98
--- /dev/null
+++ b/tests/testsuite/cargo_info/with_locked_within_ws/out/Cargo.toml
@@ -0,0 +1,8 @@
+[workspace]
+
+[package]
+name = "cargo-list-test-fixture"
+version = "0.0.0"
+
+[dependencies]
+my-package = "0.1"
diff --git a/tests/testsuite/cargo_info/with_locked_within_ws/out/src/lib.rs b/tests/testsuite/cargo_info/with_locked_within_ws/out/src/lib.rs
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/testsuite/cargo_info/with_locked_within_ws/out/src/lib.rs
@@ -0,0 +1 @@
+
diff --git a/tests/testsuite/cargo_info/with_locked_within_ws/stderr.term.svg b/tests/testsuite/cargo_info/with_locked_within_ws/stderr.term.svg
new file mode 100644
index 00000000000..12b850a2837
--- /dev/null
+++ b/tests/testsuite/cargo_info/with_locked_within_ws/stderr.term.svg
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+ Updating `dummy-registry` index
+
+ error : could not find `unknown` in registry `[ROOTURL]/registry`
+
+
+
+
+
+
diff --git a/tests/testsuite/cargo_info/with_locked_within_ws_and_pick_the_package/in/Cargo.toml b/tests/testsuite/cargo_info/with_locked_within_ws_and_pick_the_package/in/Cargo.toml
new file mode 100644
index 00000000000..a200a736b98
--- /dev/null
+++ b/tests/testsuite/cargo_info/with_locked_within_ws_and_pick_the_package/in/Cargo.toml
@@ -0,0 +1,8 @@
+[workspace]
+
+[package]
+name = "cargo-list-test-fixture"
+version = "0.0.0"
+
+[dependencies]
+my-package = "0.1"
diff --git a/tests/testsuite/cargo_info/with_locked_within_ws_and_pick_the_package/in/src/lib.rs b/tests/testsuite/cargo_info/with_locked_within_ws_and_pick_the_package/in/src/lib.rs
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/testsuite/cargo_info/with_locked_within_ws_and_pick_the_package/in/src/lib.rs
@@ -0,0 +1 @@
+
diff --git a/tests/testsuite/cargo_info/with_locked_within_ws_and_pick_the_package/mod.rs b/tests/testsuite/cargo_info/with_locked_within_ws_and_pick_the_package/mod.rs
new file mode 100644
index 00000000000..a04d9ec0150
--- /dev/null
+++ b/tests/testsuite/cargo_info/with_locked_within_ws_and_pick_the_package/mod.rs
@@ -0,0 +1,37 @@
+use cargo_test_support::prelude::*;
+use cargo_test_support::{compare::assert_ui, current_dir, file, Project};
+
+use super::init_registry_without_token;
+
+#[cargo_test]
+fn case() {
+ init_registry_without_token();
+ for ver in [
+ "0.1.1+my-package",
+ "0.2.0+my-package",
+ "0.2.3+my-package",
+ "0.4.1+my-package",
+ "20.0.0+my-package",
+ "99999.0.0+my-package",
+ "99999.0.0-alpha.1+my-package",
+ ] {
+ cargo_test_support::registry::Package::new("my-package", ver).publish();
+ }
+
+ let project = Project::from_template(current_dir!().join("in"));
+ let project_root = project.root();
+ let cwd = &project_root;
+
+ snapbox::cmd::Command::cargo_ui()
+ .arg("info")
+ .arg("my-package")
+ .arg("--locked")
+ .arg("--registry=dummy-registry")
+ .current_dir(cwd)
+ .assert()
+ .success()
+ .stdout_eq(file!["stdout.term.svg"])
+ .stderr_eq(file!["stderr.term.svg"]);
+
+ assert_ui().subset_matches(current_dir!().join("out"), &project_root);
+}
diff --git a/tests/testsuite/cargo_info/with_locked_within_ws_and_pick_the_package/out/Cargo.toml b/tests/testsuite/cargo_info/with_locked_within_ws_and_pick_the_package/out/Cargo.toml
new file mode 100644
index 00000000000..a200a736b98
--- /dev/null
+++ b/tests/testsuite/cargo_info/with_locked_within_ws_and_pick_the_package/out/Cargo.toml
@@ -0,0 +1,8 @@
+[workspace]
+
+[package]
+name = "cargo-list-test-fixture"
+version = "0.0.0"
+
+[dependencies]
+my-package = "0.1"
diff --git a/tests/testsuite/cargo_info/with_locked_within_ws_and_pick_the_package/out/src/lib.rs b/tests/testsuite/cargo_info/with_locked_within_ws_and_pick_the_package/out/src/lib.rs
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/testsuite/cargo_info/with_locked_within_ws_and_pick_the_package/out/src/lib.rs
@@ -0,0 +1 @@
+
diff --git a/tests/testsuite/cargo_info/with_locked_within_ws_and_pick_the_package/stderr.term.svg b/tests/testsuite/cargo_info/with_locked_within_ws_and_pick_the_package/stderr.term.svg
new file mode 100644
index 00000000000..094f2f61c76
--- /dev/null
+++ b/tests/testsuite/cargo_info/with_locked_within_ws_and_pick_the_package/stderr.term.svg
@@ -0,0 +1,31 @@
+
+
+
+
+
+
+ Updating `dummy-registry` index
+
+ Downloading crates ...
+
+ Downloaded my-package v99999.0.0+my-package (registry `dummy-registry`)
+
+
+
+
+
+
diff --git a/tests/testsuite/cargo_info/with_locked_within_ws_and_pick_the_package/stdout.term.svg b/tests/testsuite/cargo_info/with_locked_within_ws_and_pick_the_package/stdout.term.svg
new file mode 100644
index 00000000000..6024659dc97
--- /dev/null
+++ b/tests/testsuite/cargo_info/with_locked_within_ws_and_pick_the_package/stdout.term.svg
@@ -0,0 +1,36 @@
+
+
+
+
+
+
+ my-package
+
+ version: 99999.0.0+my-package (from registry `dummy-registry`)
+
+ license: unknown
+
+ rust-version: unknown
+
+
+
+
+
+
diff --git a/tests/testsuite/cargo_info/with_offline/mod.rs b/tests/testsuite/cargo_info/with_offline/mod.rs
new file mode 100644
index 00000000000..1b0b71610f7
--- /dev/null
+++ b/tests/testsuite/cargo_info/with_offline/mod.rs
@@ -0,0 +1,30 @@
+use cargo_test_support::file;
+use cargo_test_support::prelude::*;
+
+use super::init_registry_without_token;
+
+#[cargo_test]
+fn case() {
+ init_registry_without_token();
+ for ver in [
+ "0.1.1+my-package",
+ "0.2.0+my-package",
+ "0.2.3+my-package",
+ "0.4.1+my-package",
+ "20.0.0+my-package",
+ "99999.0.0+my-package",
+ "99999.0.0-alpha.1+my-package",
+ ] {
+ cargo_test_support::registry::Package::new("my-package", ver).publish();
+ }
+
+ snapbox::cmd::Command::cargo_ui()
+ .arg("info")
+ .arg("my-package")
+ .arg("--offline")
+ .arg("--registry=dummy-registry")
+ .assert()
+ .failure()
+ .stdout_eq("")
+ .stderr_eq(file!["stderr.term.svg"]);
+}
diff --git a/tests/testsuite/cargo_info/with_offline/stderr.term.svg b/tests/testsuite/cargo_info/with_offline/stderr.term.svg
new file mode 100644
index 00000000000..d811fbcd069
--- /dev/null
+++ b/tests/testsuite/cargo_info/with_offline/stderr.term.svg
@@ -0,0 +1,27 @@
+
+
+
+
+
+
+ error : could not find `my-package` in registry `[ROOTURL]/registry`
+
+
+
+
+
+
diff --git a/tests/testsuite/cargo_info/with_quiet/mod.rs b/tests/testsuite/cargo_info/with_quiet/mod.rs
new file mode 100644
index 00000000000..9c5d0cdb9a2
--- /dev/null
+++ b/tests/testsuite/cargo_info/with_quiet/mod.rs
@@ -0,0 +1,30 @@
+use cargo_test_support::file;
+use cargo_test_support::prelude::*;
+
+use super::init_registry_without_token;
+
+#[cargo_test]
+fn case() {
+ init_registry_without_token();
+ for ver in [
+ "0.1.1+my-package",
+ "0.2.0+my-package",
+ "0.2.3+my-package",
+ "0.4.1+my-package",
+ "20.0.0+my-package",
+ "99999.0.0+my-package",
+ "99999.0.0-alpha.1+my-package",
+ ] {
+ cargo_test_support::registry::Package::new("my-package", ver).publish();
+ }
+
+ snapbox::cmd::Command::cargo_ui()
+ .arg("info")
+ .arg("my-package")
+ .arg("--quiet")
+ .arg("--registry=dummy-registry")
+ .assert()
+ .success()
+ .stdout_eq(file!["stdout.term.svg"])
+ .stderr_eq("");
+}
diff --git a/tests/testsuite/cargo_info/with_quiet/stdout.term.svg b/tests/testsuite/cargo_info/with_quiet/stdout.term.svg
new file mode 100644
index 00000000000..6024659dc97
--- /dev/null
+++ b/tests/testsuite/cargo_info/with_quiet/stdout.term.svg
@@ -0,0 +1,36 @@
+
+
+
+
+
+
+ my-package
+
+ version: 99999.0.0+my-package (from registry `dummy-registry`)
+
+ license: unknown
+
+ rust-version: unknown
+
+
+
+
+
+
diff --git a/tests/testsuite/cargo_info/within_workspace.in/Cargo.lock b/tests/testsuite/cargo_info/within_workspace.in/Cargo.lock
new file mode 100644
index 00000000000..e9ede42b3cb
--- /dev/null
+++ b/tests/testsuite/cargo_info/within_workspace.in/Cargo.lock
@@ -0,0 +1,16 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 3
+
+[[package]]
+name = "cargo-list-test-fixture"
+version = "0.0.0"
+dependencies = [
+ "my-package",
+]
+
+[[package]]
+name = "my-package"
+version = "0.1.1+my-package"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "21c0013931e013e890da011e601d9e8514359837da12125e7e89157d9349dcb7"
diff --git a/tests/testsuite/cargo_info/within_workspace.in/Cargo.toml b/tests/testsuite/cargo_info/within_workspace.in/Cargo.toml
new file mode 100644
index 00000000000..a200a736b98
--- /dev/null
+++ b/tests/testsuite/cargo_info/within_workspace.in/Cargo.toml
@@ -0,0 +1,8 @@
+[workspace]
+
+[package]
+name = "cargo-list-test-fixture"
+version = "0.0.0"
+
+[dependencies]
+my-package = "0.1"
diff --git a/tests/testsuite/cargo_info/within_workspace.in/src/lib.rs b/tests/testsuite/cargo_info/within_workspace.in/src/lib.rs
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/testsuite/cargo_info/within_workspace.in/src/lib.rs
@@ -0,0 +1 @@
+
diff --git a/tests/testsuite/cargo_info/within_ws/in b/tests/testsuite/cargo_info/within_ws/in
new file mode 120000
index 00000000000..e9fe1ca7b01
--- /dev/null
+++ b/tests/testsuite/cargo_info/within_ws/in
@@ -0,0 +1 @@
+../within_workspace.in
\ No newline at end of file
diff --git a/tests/testsuite/cargo_info/within_ws/mod.rs b/tests/testsuite/cargo_info/within_ws/mod.rs
new file mode 100644
index 00000000000..f057b582179
--- /dev/null
+++ b/tests/testsuite/cargo_info/within_ws/mod.rs
@@ -0,0 +1,36 @@
+use cargo_test_support::prelude::*;
+use cargo_test_support::{compare::assert_ui, current_dir, file, Project};
+
+use super::init_registry_without_token;
+
+#[cargo_test]
+fn case() {
+ init_registry_without_token();
+ for ver in [
+ "0.1.1+my-package",
+ "0.2.0+my-package",
+ "0.2.3+my-package",
+ "0.4.1+my-package",
+ "20.0.0+my-package",
+ "99999.0.0+my-package",
+ "99999.0.0-alpha.1+my-package",
+ ] {
+ cargo_test_support::registry::Package::new("my-package", ver).publish();
+ }
+
+ let project = Project::from_template(current_dir!().join("in"));
+ let project_root = project.root();
+ let cwd = &project_root;
+
+ snapbox::cmd::Command::cargo_ui()
+ .arg("info")
+ .arg("my-package")
+ .arg("--registry=dummy-registry")
+ .current_dir(cwd)
+ .assert()
+ .success()
+ .stdout_eq(file!["stdout.term.svg"])
+ .stderr_eq(file!["stderr.term.svg"]);
+
+ assert_ui().subset_matches(current_dir!().join("out"), &project_root);
+}
diff --git a/tests/testsuite/cargo_info/within_ws/out/Cargo.lock b/tests/testsuite/cargo_info/within_ws/out/Cargo.lock
new file mode 100644
index 00000000000..e9ede42b3cb
--- /dev/null
+++ b/tests/testsuite/cargo_info/within_ws/out/Cargo.lock
@@ -0,0 +1,16 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 3
+
+[[package]]
+name = "cargo-list-test-fixture"
+version = "0.0.0"
+dependencies = [
+ "my-package",
+]
+
+[[package]]
+name = "my-package"
+version = "0.1.1+my-package"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "21c0013931e013e890da011e601d9e8514359837da12125e7e89157d9349dcb7"
diff --git a/tests/testsuite/cargo_info/within_ws/out/Cargo.toml b/tests/testsuite/cargo_info/within_ws/out/Cargo.toml
new file mode 100644
index 00000000000..a200a736b98
--- /dev/null
+++ b/tests/testsuite/cargo_info/within_ws/out/Cargo.toml
@@ -0,0 +1,8 @@
+[workspace]
+
+[package]
+name = "cargo-list-test-fixture"
+version = "0.0.0"
+
+[dependencies]
+my-package = "0.1"
diff --git a/tests/testsuite/cargo_info/within_ws/out/src/lib.rs b/tests/testsuite/cargo_info/within_ws/out/src/lib.rs
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/testsuite/cargo_info/within_ws/out/src/lib.rs
@@ -0,0 +1 @@
+
diff --git a/tests/testsuite/cargo_info/within_ws/stderr.term.svg b/tests/testsuite/cargo_info/within_ws/stderr.term.svg
new file mode 100644
index 00000000000..4514d2f7765
--- /dev/null
+++ b/tests/testsuite/cargo_info/within_ws/stderr.term.svg
@@ -0,0 +1,33 @@
+
+
+
+
+
+
+ Updating `dummy-registry` index
+
+ Downloading crates ...
+
+ Downloaded my-package v0.1.1+my-package (registry `dummy-registry`)
+
+ Updating crates.io index
+
+
+
+
+
+
diff --git a/tests/testsuite/cargo_info/within_ws/stdout.term.svg b/tests/testsuite/cargo_info/within_ws/stdout.term.svg
new file mode 100644
index 00000000000..711160ec528
--- /dev/null
+++ b/tests/testsuite/cargo_info/within_ws/stdout.term.svg
@@ -0,0 +1,42 @@
+
+
+
+
+
+
+ my-package
+
+ version: 0.1.1+my-package (latest 99999.0.0+my-package)
+
+ license: unknown
+
+ rust-version: unknown
+
+ documentation: https://docs.rs/my-package/0.1.1+my-package
+
+ crates.io: https://crates.io/crates/my-package/0.1.1+my-package
+
+ note : to see how you depend on my-package, run ` cargo tree --invert --package my-package@0.1.1+my-package `
+
+
+
+
+
+
diff --git a/tests/testsuite/cargo_info/within_ws_and_pick_ws_package/in/Cargo.lock b/tests/testsuite/cargo_info/within_ws_and_pick_ws_package/in/Cargo.lock
new file mode 100644
index 00000000000..cf3fed84f81
--- /dev/null
+++ b/tests/testsuite/cargo_info/within_ws_and_pick_ws_package/in/Cargo.lock
@@ -0,0 +1,16 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 3
+
+[[package]]
+name = "cargo-list-test-fixture"
+version = "0.2.0"
+dependencies = [
+ "my-package",
+]
+
+[[package]]
+name = "my-package"
+version = "0.1.1+my-package"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "61758fedb08b81e9c6967f0661a54feb83fb38eb4bde3614119fbc1d03c1cedf"
diff --git a/tests/testsuite/cargo_info/within_ws_and_pick_ws_package/in/Cargo.toml b/tests/testsuite/cargo_info/within_ws_and_pick_ws_package/in/Cargo.toml
new file mode 100644
index 00000000000..443359c3980
--- /dev/null
+++ b/tests/testsuite/cargo_info/within_ws_and_pick_ws_package/in/Cargo.toml
@@ -0,0 +1,8 @@
+[workspace]
+
+[package]
+name = "cargo-list-test-fixture"
+version = "0.2.0"
+
+[dependencies]
+my-package = "0.1"
diff --git a/tests/testsuite/cargo_info/within_ws_and_pick_ws_package/in/src/lib.rs b/tests/testsuite/cargo_info/within_ws_and_pick_ws_package/in/src/lib.rs
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/testsuite/cargo_info/within_ws_and_pick_ws_package/in/src/lib.rs
@@ -0,0 +1 @@
+
diff --git a/tests/testsuite/cargo_info/within_ws_and_pick_ws_package/mod.rs b/tests/testsuite/cargo_info/within_ws_and_pick_ws_package/mod.rs
new file mode 100644
index 00000000000..cc93e23f627
--- /dev/null
+++ b/tests/testsuite/cargo_info/within_ws_and_pick_ws_package/mod.rs
@@ -0,0 +1,27 @@
+use cargo_test_support::prelude::*;
+use cargo_test_support::{compare::assert_ui, current_dir, file, Project};
+
+use super::init_registry_without_token;
+
+#[cargo_test]
+fn case() {
+ init_registry_without_token();
+ cargo_test_support::registry::Package::new("my-package", "0.1.1+my-package").publish();
+ cargo_test_support::registry::Package::new("cargo-list-test-fixture", "0.1.1+my-package")
+ .publish();
+
+ let project = Project::from_template(current_dir!().join("in"));
+ let project_root = project.root();
+ let cwd = &project_root;
+
+ snapbox::cmd::Command::cargo_ui()
+ .arg("info")
+ .arg("cargo-list-test-fixture")
+ .current_dir(cwd)
+ .assert()
+ .success()
+ .stdout_eq(file!["stdout.term.svg"])
+ .stderr_eq("");
+
+ assert_ui().subset_matches(current_dir!().join("out"), &project_root);
+}
diff --git a/tests/testsuite/cargo_info/within_ws_and_pick_ws_package/out/Cargo.lock b/tests/testsuite/cargo_info/within_ws_and_pick_ws_package/out/Cargo.lock
new file mode 100644
index 00000000000..cf3fed84f81
--- /dev/null
+++ b/tests/testsuite/cargo_info/within_ws_and_pick_ws_package/out/Cargo.lock
@@ -0,0 +1,16 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 3
+
+[[package]]
+name = "cargo-list-test-fixture"
+version = "0.2.0"
+dependencies = [
+ "my-package",
+]
+
+[[package]]
+name = "my-package"
+version = "0.1.1+my-package"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "61758fedb08b81e9c6967f0661a54feb83fb38eb4bde3614119fbc1d03c1cedf"
diff --git a/tests/testsuite/cargo_info/within_ws_and_pick_ws_package/out/Cargo.toml b/tests/testsuite/cargo_info/within_ws_and_pick_ws_package/out/Cargo.toml
new file mode 100644
index 00000000000..443359c3980
--- /dev/null
+++ b/tests/testsuite/cargo_info/within_ws_and_pick_ws_package/out/Cargo.toml
@@ -0,0 +1,8 @@
+[workspace]
+
+[package]
+name = "cargo-list-test-fixture"
+version = "0.2.0"
+
+[dependencies]
+my-package = "0.1"
diff --git a/tests/testsuite/cargo_info/within_ws_and_pick_ws_package/out/src/lib.rs b/tests/testsuite/cargo_info/within_ws_and_pick_ws_package/out/src/lib.rs
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/testsuite/cargo_info/within_ws_and_pick_ws_package/out/src/lib.rs
@@ -0,0 +1 @@
+
diff --git a/tests/testsuite/cargo_info/within_ws_and_pick_ws_package/stdout.term.svg b/tests/testsuite/cargo_info/within_ws_and_pick_ws_package/stdout.term.svg
new file mode 100644
index 00000000000..c83baf47563
--- /dev/null
+++ b/tests/testsuite/cargo_info/within_ws_and_pick_ws_package/stdout.term.svg
@@ -0,0 +1,36 @@
+
+
+
+
+
+
+ cargo-list-test-fixture
+
+ version: 0.2.0 (from ./)
+
+ license: unknown
+
+ rust-version: unknown
+
+
+
+
+
+
diff --git a/tests/testsuite/cargo_info/within_ws_with_alternative_registry/in b/tests/testsuite/cargo_info/within_ws_with_alternative_registry/in
new file mode 120000
index 00000000000..e9fe1ca7b01
--- /dev/null
+++ b/tests/testsuite/cargo_info/within_ws_with_alternative_registry/in
@@ -0,0 +1 @@
+../within_workspace.in
\ No newline at end of file
diff --git a/tests/testsuite/cargo_info/within_ws_with_alternative_registry/mod.rs b/tests/testsuite/cargo_info/within_ws_with_alternative_registry/mod.rs
new file mode 100644
index 00000000000..21579d68194
--- /dev/null
+++ b/tests/testsuite/cargo_info/within_ws_with_alternative_registry/mod.rs
@@ -0,0 +1,30 @@
+use cargo_test_support::prelude::*;
+use cargo_test_support::{compare::assert_ui, registry::RegistryBuilder, Project};
+use cargo_test_support::{current_dir, file};
+
+#[cargo_test]
+fn case() {
+ let _ = RegistryBuilder::new()
+ .alternative()
+ .no_configure_token()
+ .build();
+ cargo_test_support::registry::Package::new("my-package", "99999.0.0-alpha.1+my-package")
+ .alternative(true)
+ .publish();
+
+ let project = Project::from_template(current_dir!().join("in"));
+ let project_root = project.root();
+ let cwd = &project_root;
+
+ snapbox::cmd::Command::cargo_ui()
+ .arg("info")
+ .arg("my-package")
+ .arg("--registry=alternative")
+ .current_dir(cwd)
+ .assert()
+ .success()
+ .stdout_eq(file!["stdout.term.svg"])
+ .stderr_eq(file!["stderr.term.svg"]);
+
+ assert_ui().subset_matches(current_dir!().join("out"), &project_root);
+}
diff --git a/tests/testsuite/cargo_info/within_ws_with_alternative_registry/out/Cargo.lock b/tests/testsuite/cargo_info/within_ws_with_alternative_registry/out/Cargo.lock
new file mode 100644
index 00000000000..e9ede42b3cb
--- /dev/null
+++ b/tests/testsuite/cargo_info/within_ws_with_alternative_registry/out/Cargo.lock
@@ -0,0 +1,16 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 3
+
+[[package]]
+name = "cargo-list-test-fixture"
+version = "0.0.0"
+dependencies = [
+ "my-package",
+]
+
+[[package]]
+name = "my-package"
+version = "0.1.1+my-package"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "21c0013931e013e890da011e601d9e8514359837da12125e7e89157d9349dcb7"
diff --git a/tests/testsuite/cargo_info/within_ws_with_alternative_registry/out/Cargo.toml b/tests/testsuite/cargo_info/within_ws_with_alternative_registry/out/Cargo.toml
new file mode 100644
index 00000000000..a200a736b98
--- /dev/null
+++ b/tests/testsuite/cargo_info/within_ws_with_alternative_registry/out/Cargo.toml
@@ -0,0 +1,8 @@
+[workspace]
+
+[package]
+name = "cargo-list-test-fixture"
+version = "0.0.0"
+
+[dependencies]
+my-package = "0.1"
diff --git a/tests/testsuite/cargo_info/within_ws_with_alternative_registry/out/src/lib.rs b/tests/testsuite/cargo_info/within_ws_with_alternative_registry/out/src/lib.rs
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/testsuite/cargo_info/within_ws_with_alternative_registry/out/src/lib.rs
@@ -0,0 +1 @@
+
diff --git a/tests/testsuite/cargo_info/within_ws_with_alternative_registry/stderr.term.svg b/tests/testsuite/cargo_info/within_ws_with_alternative_registry/stderr.term.svg
new file mode 100644
index 00000000000..69ddaf3115c
--- /dev/null
+++ b/tests/testsuite/cargo_info/within_ws_with_alternative_registry/stderr.term.svg
@@ -0,0 +1,33 @@
+
+
+
+
+
+
+ Updating crates.io index
+
+ Updating `alternative` index
+
+ Downloading crates ...
+
+ Downloaded my-package v99999.0.0-alpha.1+my-package (registry `alternative`)
+
+
+
+
+
+
diff --git a/tests/testsuite/cargo_info/within_ws_with_alternative_registry/stdout.term.svg b/tests/testsuite/cargo_info/within_ws_with_alternative_registry/stdout.term.svg
new file mode 100644
index 00000000000..30bf52d0cc8
--- /dev/null
+++ b/tests/testsuite/cargo_info/within_ws_with_alternative_registry/stdout.term.svg
@@ -0,0 +1,36 @@
+
+
+
+
+
+
+ my-package
+
+ version: 99999.0.0-alpha.1+my-package (from registry `alternative`)
+
+ license: unknown
+
+ rust-version: unknown
+
+
+
+
+
+
diff --git a/tests/testsuite/cargo_info/within_ws_without_lockfile/in/Cargo.toml b/tests/testsuite/cargo_info/within_ws_without_lockfile/in/Cargo.toml
new file mode 100644
index 00000000000..75b2d3d13b8
--- /dev/null
+++ b/tests/testsuite/cargo_info/within_ws_without_lockfile/in/Cargo.toml
@@ -0,0 +1,8 @@
+[workspace]
+
+[package]
+name = "cargo-list-test-fixture"
+version = "0.0.0"
+
+[dependencies]
+my-package = "0.2"
diff --git a/tests/testsuite/cargo_info/within_ws_without_lockfile/in/src/lib.rs b/tests/testsuite/cargo_info/within_ws_without_lockfile/in/src/lib.rs
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/testsuite/cargo_info/within_ws_without_lockfile/in/src/lib.rs
@@ -0,0 +1 @@
+
diff --git a/tests/testsuite/cargo_info/within_ws_without_lockfile/mod.rs b/tests/testsuite/cargo_info/within_ws_without_lockfile/mod.rs
new file mode 100644
index 00000000000..6236c449540
--- /dev/null
+++ b/tests/testsuite/cargo_info/within_ws_without_lockfile/mod.rs
@@ -0,0 +1,33 @@
+use cargo_test_support::prelude::*;
+use cargo_test_support::{compare::assert_ui, current_dir, file, Project};
+
+use super::init_registry_without_token;
+
+#[cargo_test]
+fn case() {
+ init_registry_without_token();
+ for ver in [
+ "0.1.1+my-package",
+ "0.2.0+my-package",
+ "0.2.3+my-package",
+ "0.4.1+my-package",
+ ] {
+ cargo_test_support::registry::Package::new("my-package", ver).publish();
+ }
+
+ let project = Project::from_template(current_dir!().join("in"));
+ let project_root = project.root();
+ let cwd = &project_root;
+
+ snapbox::cmd::Command::cargo_ui()
+ .arg("info")
+ .arg("my-package")
+ .arg("--registry=dummy-registry")
+ .current_dir(cwd)
+ .assert()
+ .success()
+ .stdout_eq(file!["stdout.term.svg"])
+ .stderr_eq(file!["stderr.term.svg"]);
+
+ assert_ui().subset_matches(current_dir!().join("out"), &project_root);
+}
diff --git a/tests/testsuite/cargo_info/within_ws_without_lockfile/out/Cargo.lock b/tests/testsuite/cargo_info/within_ws_without_lockfile/out/Cargo.lock
new file mode 100644
index 00000000000..3d372c49933
--- /dev/null
+++ b/tests/testsuite/cargo_info/within_ws_without_lockfile/out/Cargo.lock
@@ -0,0 +1,16 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 3
+
+[[package]]
+name = "cargo-list-test-fixture"
+version = "0.0.0"
+dependencies = [
+ "my-package",
+]
+
+[[package]]
+name = "my-package"
+version = "0.2.3+my-package"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5da91d4048b3b4623431ca790831b8b334ef87b6c1b0338889029a9b199f08a8"
diff --git a/tests/testsuite/cargo_info/within_ws_without_lockfile/out/Cargo.toml b/tests/testsuite/cargo_info/within_ws_without_lockfile/out/Cargo.toml
new file mode 100644
index 00000000000..75b2d3d13b8
--- /dev/null
+++ b/tests/testsuite/cargo_info/within_ws_without_lockfile/out/Cargo.toml
@@ -0,0 +1,8 @@
+[workspace]
+
+[package]
+name = "cargo-list-test-fixture"
+version = "0.0.0"
+
+[dependencies]
+my-package = "0.2"
diff --git a/tests/testsuite/cargo_info/within_ws_without_lockfile/out/src/lib.rs b/tests/testsuite/cargo_info/within_ws_without_lockfile/out/src/lib.rs
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/testsuite/cargo_info/within_ws_without_lockfile/out/src/lib.rs
@@ -0,0 +1 @@
+
diff --git a/tests/testsuite/cargo_info/within_ws_without_lockfile/stderr.term.svg b/tests/testsuite/cargo_info/within_ws_without_lockfile/stderr.term.svg
new file mode 100644
index 00000000000..a81aeeae5cf
--- /dev/null
+++ b/tests/testsuite/cargo_info/within_ws_without_lockfile/stderr.term.svg
@@ -0,0 +1,39 @@
+
+
+
+
+
+
+ Updating `dummy-registry` index
+
+ Locking 2 packages to latest compatible versions
+
+ Adding my-package v0.2.3+my-package (latest: v0.4.1+my-package)
+
+ Downloading crates ...
+
+ Downloaded my-package v0.2.3+my-package (registry `dummy-registry`)
+
+ Updating crates.io index
+
+
+
+
+
+
diff --git a/tests/testsuite/cargo_info/within_ws_without_lockfile/stdout.term.svg b/tests/testsuite/cargo_info/within_ws_without_lockfile/stdout.term.svg
new file mode 100644
index 00000000000..22479c200f3
--- /dev/null
+++ b/tests/testsuite/cargo_info/within_ws_without_lockfile/stdout.term.svg
@@ -0,0 +1,42 @@
+
+
+
+
+
+
+ my-package
+
+ version: 0.2.3+my-package (latest 0.4.1+my-package)
+
+ license: unknown
+
+ rust-version: unknown
+
+ documentation: https://docs.rs/my-package/0.2.3+my-package
+
+ crates.io: https://crates.io/crates/my-package/0.2.3+my-package
+
+ note : to see how you depend on my-package, run ` cargo tree --invert --package my-package@0.2.3+my-package `
+
+
+
+
+
+
diff --git a/tests/testsuite/main.rs b/tests/testsuite/main.rs
index 271d333e2ef..d8f85d16fd4 100644
--- a/tests/testsuite/main.rs
+++ b/tests/testsuite/main.rs
@@ -34,6 +34,7 @@ mod cargo_fix;
mod cargo_generate_lockfile;
mod cargo_git_checkout;
mod cargo_help;
+mod cargo_info;
mod cargo_init;
mod cargo_install;
mod cargo_locate_project;
From 24ef77a0fba9b07b791ba9ce2904473a1b5c5441 Mon Sep 17 00:00:00 2001
From: Rustin170506 <29879298+hi-rustin@users.noreply.github.com>
Date: Sun, 21 Jul 2024 17:14:42 +0800
Subject: [PATCH 3/4] docs: add cargo-info subcommand and add man page
---
src/doc/man/cargo-info.md | 67 ++++++++
src/doc/man/cargo.md | 4 +
src/doc/man/generated_txt/cargo-info.txt | 156 +++++++++++++++++
src/doc/man/generated_txt/cargo.txt | 4 +
src/doc/src/SUMMARY.md | 1 +
src/doc/src/commands/cargo-info.md | 168 ++++++++++++++++++
src/doc/src/commands/cargo.md | 4 +
src/doc/src/commands/manifest-commands.md | 2 +
src/etc/man/cargo-info.1 | 201 ++++++++++++++++++++++
src/etc/man/cargo.1 | 4 +
10 files changed, 611 insertions(+)
create mode 100644 src/doc/man/cargo-info.md
create mode 100644 src/doc/man/generated_txt/cargo-info.txt
create mode 100644 src/doc/src/commands/cargo-info.md
create mode 100644 src/etc/man/cargo-info.1
diff --git a/src/doc/man/cargo-info.md b/src/doc/man/cargo-info.md
new file mode 100644
index 00000000000..d501a2c89d1
--- /dev/null
+++ b/src/doc/man/cargo-info.md
@@ -0,0 +1,67 @@
+# cargo-info(1)
+
+## NAME
+
+cargo-info --- Display information about a package in the registry. Default registry is crates.io
+
+## SYNOPSIS
+
+`cargo info` [_options_] _spec_
+
+## DESCRIPTION
+
+This command displays information about a package in the registry. It fetches data from the package's Cargo.toml file
+and presents it in a human-readable format.
+
+## OPTIONS
+
+### Info Options
+
+{{#options}}
+
+{{#option "_spec_" }}
+
+Fetch information about the specified package. The _spec_ can be a package ID, see {{man "cargo-pkgid" 1}} for the SPEC
+format.
+If the specified package is part of the current workspace, information from the local Cargo.toml file will be displayed.
+If the `Cargo.lock` file does not exist, it will be created. If no version is specified, the appropriate version will be
+selected based on the Minimum Supported Rust Version (MSRV).
+
+{{/option}}
+{{> options-index }}
+{{> options-registry }}
+{{/options}}
+
+### Display Options
+
+{{#options}}
+{{> options-display }}
+{{/options}}
+
+### Manifest Options
+
+{{#options}}
+{{> options-locked }}
+{{/options}}
+
+{{> section-options-common }}
+
+{{> section-environment }}
+
+{{> section-exit-status }}
+
+## EXAMPLES
+
+1. Inspect the `serde` package from crates.io:
+
+ cargo info serde
+2. Inspect the `serde` package with version `1.0.0`:
+
+ cargo info serde@1.0.0
+3. Inspect the `serde` package form the local registry:
+
+ cargo info serde --registry my-registry
+
+## SEE ALSO
+
+{{man "cargo" 1}}, {{man "cargo-search" 1}}
diff --git a/src/doc/man/cargo.md b/src/doc/man/cargo.md
index fa3d8bd3bc7..c67b33770af 100644
--- a/src/doc/man/cargo.md
+++ b/src/doc/man/cargo.md
@@ -62,6 +62,9 @@ available at .
{{man "cargo-generate-lockfile" 1}}\
Generate `Cargo.lock` for a project.
+{{man "cargo-info" 1}}\
+ Display information about a package in the registry. Default registry is crates.io.
+
{{man "cargo-locate-project" 1}}\
Print a JSON representation of a `Cargo.toml` file's location.
@@ -241,4 +244,5 @@ stable yet and may be subject to change.
See for issues.
## SEE ALSO
+
{{man "rustc" 1}}, {{man "rustdoc" 1}}
diff --git a/src/doc/man/generated_txt/cargo-info.txt b/src/doc/man/generated_txt/cargo-info.txt
new file mode 100644
index 00000000000..28a949bdedf
--- /dev/null
+++ b/src/doc/man/generated_txt/cargo-info.txt
@@ -0,0 +1,156 @@
+CARGO-INFO(1)
+
+NAME
+ cargo-info — Display information about a package in the registry.
+ Default registry is crates.io
+
+SYNOPSIS
+ cargo info [options] spec
+
+DESCRIPTION
+ This command displays information about a package in the registry. It
+ fetches data from the package’s Cargo.toml file and presents it in a
+ human-readable format.
+
+OPTIONS
+ Info Options
+ spec
+ Fetch information about the specified package. The spec can be a
+ package ID, see cargo-pkgid(1) for the SPEC format. If the specified
+ package is part of the current workspace, information from the local
+ Cargo.toml file will be displayed. If the Cargo.lock file does not
+ exist, it will be created. If no version is specified, the
+ appropriate version will be selected based on the Minimum Supported
+ Rust Version (MSRV).
+
+ --index index
+ The URL of the registry index to use.
+
+ --registry registry
+ Name of the registry to use. Registry names are defined in Cargo
+ config files
+ . If not
+ specified, the default registry is used, which is defined by the
+ registry.default config key which defaults to crates-io.
+
+ Display Options
+ -v, --verbose
+ Use verbose output. May be specified twice for “very verbose”
+ output which includes extra output such as dependency warnings and
+ build script output. May also be specified with the term.verbose
+ config value
+ .
+
+ -q, --quiet
+ Do not print cargo log messages. May also be specified with the
+ term.quiet config value
+ .
+
+ --color when
+ Control when colored output is used. Valid values:
+
+ o auto (default): Automatically detect if color support is
+ available on the terminal.
+
+ o always: Always display colors.
+
+ o never: Never display colors.
+
+ May also be specified with the term.color config value
+ .
+
+ Manifest Options
+ --locked
+ Asserts that the exact same dependencies and versions are used as
+ when the existing Cargo.lock file was originally generated. Cargo
+ will exit with an error when either of the following scenarios
+ arises:
+
+ o The lock file is missing.
+
+ o Cargo attempted to change the lock file due to a different
+ dependency resolution.
+
+ It may be used in environments where deterministic builds are
+ desired, such as in CI pipelines.
+
+ --offline
+ Prevents Cargo from accessing the network for any reason. Without
+ this flag, Cargo will stop with an error if it needs to access the
+ network and the network is not available. With this flag, Cargo will
+ attempt to proceed without the network if possible.
+
+ Beware that this may result in different dependency resolution than
+ online mode. Cargo will restrict itself to crates that are
+ downloaded locally, even if there might be a newer version as
+ indicated in the local copy of the index. See the cargo-fetch(1)
+ command to download dependencies before going offline.
+
+ May also be specified with the net.offline config value
+ .
+
+ --frozen
+ Equivalent to specifying both --locked and --offline.
+
+ Common Options
+ +toolchain
+ If Cargo has been installed with rustup, and the first argument to
+ cargo begins with +, it will be interpreted as a rustup toolchain
+ name (such as +stable or +nightly). See the rustup documentation
+ for more
+ information about how toolchain overrides work.
+
+ --config KEY=VALUE or PATH
+ Overrides a Cargo configuration value. The argument should be in
+ TOML syntax of KEY=VALUE, or provided as a path to an extra
+ configuration file. This flag may be specified multiple times. See
+ the command-line overrides section
+
+ for more information.
+
+ -C PATH
+ Changes the current working directory before executing any specified
+ operations. This affects things like where cargo looks by default
+ for the project manifest (Cargo.toml), as well as the directories
+ searched for discovering .cargo/config.toml, for example. This
+ option must appear before the command name, for example cargo -C
+ path/to/my-project build.
+
+ This option is only available on the nightly channel
+ and
+ requires the -Z unstable-options flag to enable (see #10098
+ ).
+
+ -h, --help
+ Prints help information.
+
+ -Z flag
+ Unstable (nightly-only) flags to Cargo. Run cargo -Z help for
+ details.
+
+ENVIRONMENT
+ See the reference
+
+ for details on environment variables that Cargo reads.
+
+EXIT STATUS
+ o 0: Cargo succeeded.
+
+ o 101: Cargo failed to complete.
+
+EXAMPLES
+ 1. Inspect the serde package from crates.io:
+
+ cargo info serde
+
+ 2. Inspect the serde package with version 1.0.0:
+
+ cargo info serde@1.0.0
+
+ 3. Inspect the serde package form the local registry:
+
+ cargo info serde --registry my-registry
+
+SEE ALSO
+ cargo(1), cargo-search(1)
+
diff --git a/src/doc/man/generated_txt/cargo.txt b/src/doc/man/generated_txt/cargo.txt
index d9a1d1fd7af..b010d94e5b3 100644
--- a/src/doc/man/generated_txt/cargo.txt
+++ b/src/doc/man/generated_txt/cargo.txt
@@ -56,6 +56,10 @@ COMMANDS
cargo-generate-lockfile(1)
Generate Cargo.lock for a project.
+ cargo-info(1)
+ Display information about a package in the registry. Default
+ registry is crates.io.
+
cargo-locate-project(1)
Print a JSON representation of a Cargo.toml file’s location.
diff --git a/src/doc/src/SUMMARY.md b/src/doc/src/SUMMARY.md
index b18e69111e5..e726318844a 100644
--- a/src/doc/src/SUMMARY.md
+++ b/src/doc/src/SUMMARY.md
@@ -69,6 +69,7 @@
* [Manifest Commands](commands/manifest-commands.md)
* [cargo add](commands/cargo-add.md)
* [cargo generate-lockfile](commands/cargo-generate-lockfile.md)
+ * [cargo info](commands/cargo-info.md)
* [cargo locate-project](commands/cargo-locate-project.md)
* [cargo metadata](commands/cargo-metadata.md)
* [cargo pkgid](commands/cargo-pkgid.md)
diff --git a/src/doc/src/commands/cargo-info.md b/src/doc/src/commands/cargo-info.md
new file mode 100644
index 00000000000..3584eebd75a
--- /dev/null
+++ b/src/doc/src/commands/cargo-info.md
@@ -0,0 +1,168 @@
+# cargo-info(1)
+
+## NAME
+
+cargo-info --- Display information about a package in the registry. Default registry is crates.io
+
+## SYNOPSIS
+
+`cargo info` [_options_] _spec_
+
+## DESCRIPTION
+
+This command displays information about a package in the registry. It fetches data from the package's Cargo.toml file
+and presents it in a human-readable format.
+
+## OPTIONS
+
+### Info Options
+
+
+
+spec
+Fetch information about the specified package. The spec can be a package ID, see cargo-pkgid(1) for the SPEC
+format.
+If the specified package is part of the current workspace, information from the local Cargo.toml file will be displayed.
+If the Cargo.lock
file does not exist, it will be created. If no version is specified, the appropriate version will be
+selected based on the Minimum Supported Rust Version (MSRV).
+
+--index
index
+The URL of the registry index to use.
+
+--registry
registry
+Name of the registry to use. Registry names are defined in Cargo config
+files . If not specified, the default registry is used,
+which is defined by the registry.default
config key which defaults to
+crates-io
.
+
+
+
+### Display Options
+
+
+-v
+--verbose
+Use verbose output. May be specified twice for “very verbose” output which
+includes extra output such as dependency warnings and build script output.
+May also be specified with the term.verbose
+config value .
+
+
+-q
+--quiet
+Do not print cargo log messages.
+May also be specified with the term.quiet
+config value .
+
+
+--color
when
+Control when colored output is used. Valid values:
+
+auto
(default): Automatically detect if color support is available on the
+terminal.
+always
: Always display colors.
+never
: Never display colors.
+
+May also be specified with the term.color
+config value .
+
+
+
+### Manifest Options
+
+
+--locked
+Asserts that the exact same dependencies and versions are used as when the
+existing Cargo.lock
file was originally generated. Cargo will exit with an
+error when either of the following scenarios arises:
+
+The lock file is missing.
+Cargo attempted to change the lock file due to a different dependency resolution.
+
+It may be used in environments where deterministic builds are desired,
+such as in CI pipelines.
+
+
+--offline
+Prevents Cargo from accessing the network for any reason. Without this
+flag, Cargo will stop with an error if it needs to access the network and
+the network is not available. With this flag, Cargo will attempt to
+proceed without the network if possible.
+Beware that this may result in different dependency resolution than online
+mode. Cargo will restrict itself to crates that are downloaded locally, even
+if there might be a newer version as indicated in the local copy of the index.
+See the cargo-fetch(1) command to download dependencies before going
+offline.
+May also be specified with the net.offline
config value .
+
+
+--frozen
+Equivalent to specifying both --locked
and --offline
.
+
+
+
+### Common Options
+
+
+
++
toolchain
+If Cargo has been installed with rustup, and the first argument to cargo
+begins with +
, it will be interpreted as a rustup toolchain name (such
+as +stable
or +nightly
).
+See the rustup documentation
+for more information about how toolchain overrides work.
+
+
+--config
KEY=VALUE or PATH
+Overrides a Cargo configuration value. The argument should be in TOML syntax of KEY=VALUE
,
+or provided as a path to an extra configuration file. This flag may be specified multiple times.
+See the command-line overrides section for more information.
+
+
+-C
PATH
+Changes the current working directory before executing any specified operations. This affects
+things like where cargo looks by default for the project manifest (Cargo.toml
), as well as
+the directories searched for discovering .cargo/config.toml
, for example. This option must
+appear before the command name, for example cargo -C path/to/my-project build
.
+This option is only available on the nightly
+channel and
+requires the -Z unstable-options
flag to enable (see
+#10098 ).
+
+
+-h
+--help
+Prints help information.
+
+
+-Z
flag
+Unstable (nightly-only) flags to Cargo. Run cargo -Z help
for details.
+
+
+
+
+## ENVIRONMENT
+
+See [the reference](../reference/environment-variables.html) for
+details on environment variables that Cargo reads.
+
+## EXIT STATUS
+
+* `0`: Cargo succeeded.
+* `101`: Cargo failed to complete.
+
+## EXAMPLES
+
+1. Inspect the `serde` package from crates.io:
+
+ cargo info serde
+2. Inspect the `serde` package with version `1.0.0`:
+
+ cargo info serde@1.0.0
+3. Inspect the `serde` package form the local registry:
+
+ cargo info serde --registry my-registry
+
+## SEE ALSO
+
+[cargo(1)](cargo.html), [cargo-search(1)](cargo-search.html)
diff --git a/src/doc/src/commands/cargo.md b/src/doc/src/commands/cargo.md
index ccba5dc446b..f6d7fc599fc 100644
--- a/src/doc/src/commands/cargo.md
+++ b/src/doc/src/commands/cargo.md
@@ -62,6 +62,9 @@ available at .
[cargo-generate-lockfile(1)](cargo-generate-lockfile.html)\
Generate `Cargo.lock` for a project.
+[cargo-info(1)](cargo-info.html)\
+ Display information about a package in the registry. Default registry is crates.io.
+
[cargo-locate-project(1)](cargo-locate-project.html)\
Print a JSON representation of a `Cargo.toml` file's location.
@@ -338,4 +341,5 @@ stable yet and may be subject to change.
See for issues.
## SEE ALSO
+
[rustc(1)](https://doc.rust-lang.org/rustc/index.html), [rustdoc(1)](https://doc.rust-lang.org/rustdoc/index.html)
diff --git a/src/doc/src/commands/manifest-commands.md b/src/doc/src/commands/manifest-commands.md
index 98a82d8aa0b..b83e7b93044 100644
--- a/src/doc/src/commands/manifest-commands.md
+++ b/src/doc/src/commands/manifest-commands.md
@@ -1,5 +1,7 @@
# Manifest Commands
+
* [cargo add](cargo-add.md)
+* [cargo_info](cargo-info.md)
* [cargo generate-lockfile](cargo-generate-lockfile.md)
* [cargo locate-project](cargo-locate-project.md)
* [cargo metadata](cargo-metadata.md)
diff --git a/src/etc/man/cargo-info.1 b/src/etc/man/cargo-info.1
new file mode 100644
index 00000000000..9c6ea85eb0d
--- /dev/null
+++ b/src/etc/man/cargo-info.1
@@ -0,0 +1,201 @@
+'\" t
+.TH "CARGO\-INFO" "1"
+.nh
+.ad l
+.ss \n[.ss] 0
+.SH "NAME"
+cargo\-info \[em] Display information about a package in the registry. Default registry is crates.io
+.SH "SYNOPSIS"
+\fBcargo info\fR [\fIoptions\fR] \fIspec\fR
+.SH "DESCRIPTION"
+This command displays information about a package in the registry. It fetches data from the package\[cq]s Cargo.toml file
+and presents it in a human\-readable format.
+.SH "OPTIONS"
+.SS "Info Options"
+.sp
+\fIspec\fR
+.RS 4
+Fetch information about the specified package. The \fIspec\fR can be a package ID, see \fBcargo\-pkgid\fR(1) for the SPEC
+format.
+If the specified package is part of the current workspace, information from the local Cargo.toml file will be displayed.
+If the \fBCargo.lock\fR file does not exist, it will be created. If no version is specified, the appropriate version will be
+selected based on the Minimum Supported Rust Version (MSRV).
+.RE
+.sp
+\fB\-\-index\fR \fIindex\fR
+.RS 4
+The URL of the registry index to use.
+.RE
+.sp
+\fB\-\-registry\fR \fIregistry\fR
+.RS 4
+Name of the registry to use. Registry names are defined in \fICargo config
+files\fR \&. If not specified, the default registry is used,
+which is defined by the \fBregistry.default\fR config key which defaults to
+\fBcrates\-io\fR\&.
+.RE
+.SS "Display Options"
+.sp
+\fB\-v\fR,
+\fB\-\-verbose\fR
+.RS 4
+Use verbose output. May be specified twice for \[lq]very verbose\[rq] output which
+includes extra output such as dependency warnings and build script output.
+May also be specified with the \fBterm.verbose\fR
+\fIconfig value\fR \&.
+.RE
+.sp
+\fB\-q\fR,
+\fB\-\-quiet\fR
+.RS 4
+Do not print cargo log messages.
+May also be specified with the \fBterm.quiet\fR
+\fIconfig value\fR \&.
+.RE
+.sp
+\fB\-\-color\fR \fIwhen\fR
+.RS 4
+Control when colored output is used. Valid values:
+.sp
+.RS 4
+\h'-04'\(bu\h'+02'\fBauto\fR (default): Automatically detect if color support is available on the
+terminal.
+.RE
+.sp
+.RS 4
+\h'-04'\(bu\h'+02'\fBalways\fR: Always display colors.
+.RE
+.sp
+.RS 4
+\h'-04'\(bu\h'+02'\fBnever\fR: Never display colors.
+.RE
+.sp
+May also be specified with the \fBterm.color\fR
+\fIconfig value\fR \&.
+.RE
+.SS "Manifest Options"
+.sp
+\fB\-\-locked\fR
+.RS 4
+Asserts that the exact same dependencies and versions are used as when the
+existing \fBCargo.lock\fR file was originally generated. Cargo will exit with an
+error when either of the following scenarios arises:
+.sp
+.RS 4
+\h'-04'\(bu\h'+02'The lock file is missing.
+.RE
+.sp
+.RS 4
+\h'-04'\(bu\h'+02'Cargo attempted to change the lock file due to a different dependency resolution.
+.RE
+.sp
+It may be used in environments where deterministic builds are desired,
+such as in CI pipelines.
+.RE
+.sp
+\fB\-\-offline\fR
+.RS 4
+Prevents Cargo from accessing the network for any reason. Without this
+flag, Cargo will stop with an error if it needs to access the network and
+the network is not available. With this flag, Cargo will attempt to
+proceed without the network if possible.
+.sp
+Beware that this may result in different dependency resolution than online
+mode. Cargo will restrict itself to crates that are downloaded locally, even
+if there might be a newer version as indicated in the local copy of the index.
+See the \fBcargo\-fetch\fR(1) command to download dependencies before going
+offline.
+.sp
+May also be specified with the \fBnet.offline\fR \fIconfig value\fR \&.
+.RE
+.sp
+\fB\-\-frozen\fR
+.RS 4
+Equivalent to specifying both \fB\-\-locked\fR and \fB\-\-offline\fR\&.
+.RE
+.SS "Common Options"
+.sp
+\fB+\fR\fItoolchain\fR
+.RS 4
+If Cargo has been installed with rustup, and the first argument to \fBcargo\fR
+begins with \fB+\fR, it will be interpreted as a rustup toolchain name (such
+as \fB+stable\fR or \fB+nightly\fR).
+See the \fIrustup documentation\fR
+for more information about how toolchain overrides work.
+.RE
+.sp
+\fB\-\-config\fR \fIKEY=VALUE\fR or \fIPATH\fR
+.RS 4
+Overrides a Cargo configuration value. The argument should be in TOML syntax of \fBKEY=VALUE\fR,
+or provided as a path to an extra configuration file. This flag may be specified multiple times.
+See the \fIcommand\-line overrides section\fR for more information.
+.RE
+.sp
+\fB\-C\fR \fIPATH\fR
+.RS 4
+Changes the current working directory before executing any specified operations. This affects
+things like where cargo looks by default for the project manifest (\fBCargo.toml\fR), as well as
+the directories searched for discovering \fB\&.cargo/config.toml\fR, for example. This option must
+appear before the command name, for example \fBcargo \-C path/to/my\-project build\fR\&.
+.sp
+This option is only available on the \fInightly
+channel\fR and
+requires the \fB\-Z unstable\-options\fR flag to enable (see
+\fI#10098\fR ).
+.RE
+.sp
+\fB\-h\fR,
+\fB\-\-help\fR
+.RS 4
+Prints help information.
+.RE
+.sp
+\fB\-Z\fR \fIflag\fR
+.RS 4
+Unstable (nightly\-only) flags to Cargo. Run \fBcargo \-Z help\fR for details.
+.RE
+.SH "ENVIRONMENT"
+See \fIthe reference\fR for
+details on environment variables that Cargo reads.
+.SH "EXIT STATUS"
+.sp
+.RS 4
+\h'-04'\(bu\h'+02'\fB0\fR: Cargo succeeded.
+.RE
+.sp
+.RS 4
+\h'-04'\(bu\h'+02'\fB101\fR: Cargo failed to complete.
+.RE
+.SH "EXAMPLES"
+.sp
+.RS 4
+\h'-04' 1.\h'+01'Inspect the \fBserde\fR package from crates.io:
+.sp
+.RS 4
+.nf
+ cargo info serde
+.fi
+.RE
+.RE
+.sp
+.RS 4
+\h'-04' 2.\h'+01'Inspect the \fBserde\fR package with version \fB1.0.0\fR:
+.sp
+.RS 4
+.nf
+ cargo info serde@1.0.0
+.fi
+.RE
+.RE
+.sp
+.RS 4
+\h'-04' 3.\h'+01'Inspect the \fBserde\fR package form the local registry:
+.sp
+.RS 4
+.nf
+ cargo info serde \-\-registry my\-registry
+.fi
+.RE
+.RE
+.SH "SEE ALSO"
+\fBcargo\fR(1), \fBcargo\-search\fR(1)
diff --git a/src/etc/man/cargo.1 b/src/etc/man/cargo.1
index eebcf89e43d..b285d67bd12 100644
--- a/src/etc/man/cargo.1
+++ b/src/etc/man/cargo.1
@@ -72,6 +72,10 @@ available at \&.
.br
\ \ \ \ Generate \fBCargo.lock\fR for a project.
.sp
+\fBcargo\-info\fR(1)
+.br
+\ \ \ \ Display information about a package in the registry. Default registry is crates.io.
+.sp
\fBcargo\-locate\-project\fR(1)
.br
\ \ \ \ Print a JSON representation of a \fBCargo.toml\fR file\[cq]s location.
From ba0721501484b2cfd9a2820a37be158083c38a7d Mon Sep 17 00:00:00 2001
From: Rustin170506 <29879298+hi-rustin@users.noreply.github.com>
Date: Sun, 21 Jul 2024 18:09:07 +0800
Subject: [PATCH 4/4] docs: add completions for bash and zsh
---
src/etc/_cargo | 5 +++++
src/etc/cargo.bashcomp.sh | 1 +
2 files changed, 6 insertions(+)
diff --git a/src/etc/_cargo b/src/etc/_cargo
index 0158f6bd85c..b564f5bb0e9 100644
--- a/src/etc/_cargo
+++ b/src/etc/_cargo
@@ -163,6 +163,11 @@ _cargo() {
help)
_cargo_cmds
;;
+ info)
+ _arguments -s -A "^--" $common $registry \
+ '--index=[specify registry index]:index' \
+ '*: :_guard "^-*" "crate"'
+ ;;
init)
_arguments -s -S $common $registry \
diff --git a/src/etc/cargo.bashcomp.sh b/src/etc/cargo.bashcomp.sh
index 5219b8b66ea..10212f92b90 100644
--- a/src/etc/cargo.bashcomp.sh
+++ b/src/etc/cargo.bashcomp.sh
@@ -63,6 +63,7 @@ _cargo()
local opt__fix="$opt_common $opt_pkg_spec $opt_feat $opt_mani $opt_parallel $opt_targets $opt_lock --release --target --message-format --broken-code --edition --edition-idioms --allow-no-vcs --allow-dirty --allow-staged --profile --target-dir --ignore-rust-version"
local opt__generate_lockfile="$opt_common $opt_mani $opt_lock"
local opt__help="$opt_help"
+ local opt__info="$opt_common $opt_lock --registry --index"
local opt__init="$opt_common $opt_lock --bin --lib --name --vcs --edition --registry"
local opt__install="$opt_common $opt_feat $opt_parallel $opt_lock $opt_force --bin --bins --branch --debug --example --examples --git --list --path --rev --root --tag --version --registry --target --profile --no-track --ignore-rust-version"
local opt__locate_project="$opt_common $opt_mani $opt_lock --message-format --workspace"