use std::fmt::Write;
use anyhow::Result;
use fs_err::File;
use itertools::{Either, Itertools};
use owo_colors::OwoColorize;
use rustc_hash::FxHashMap;
use tracing::debug;
use uv_cache::Cache;
use uv_distribution_types::{DependencyMetadata, Diagnostic, Name};
use uv_fs::Simplified;
use uv_install_wheel::read_record;
use uv_installer::SitePackages;
use uv_normalize::PackageName;
use uv_preview::Preview;
use uv_python::{
EnvironmentPreference, Prefix, PythonEnvironment, PythonPreference, PythonRequest, Target,
};
use crate::commands::ExitStatus;
use crate::commands::pip::operations::report_target_environment;
use crate::printer::Printer;
pub(crate) fn pip_show(
mut packages: Vec<PackageName>,
strict: bool,
dependency_metadata: &DependencyMetadata,
python: Option<&str>,
system: bool,
target: Option<Target>,
prefix: Option<Prefix>,
files: bool,
cache: &Cache,
printer: Printer,
preview: Preview,
) -> Result<ExitStatus> {
if packages.is_empty() {
{
writeln!(
printer.stderr(),
"{}{} Please provide a package name or names.",
"warning".yellow().bold(),
":".bold(),
)?;
}
return Ok(ExitStatus::Failure);
}
let environment = PythonEnvironment::find(
&python.map(PythonRequest::parse).unwrap_or_default(),
EnvironmentPreference::from_system_flag(system, false),
PythonPreference::default().with_system_flag(system),
cache,
preview,
)?;
let environment = if let Some(target) = target {
debug!(
"Using `--target` directory at {}",
target.root().user_display()
);
environment.with_target(target)?
} else if let Some(prefix) = prefix {
debug!(
"Using `--prefix` directory at {}",
prefix.root().user_display()
);
environment.with_prefix(prefix)?
} else {
environment
};
report_target_environment(&environment, cache, printer)?;
let site_packages = SitePackages::from_environment(&environment)?;
let markers = environment.interpreter().resolver_marker_environment();
let tags = environment.interpreter().tags()?;
packages.sort_unstable();
packages.dedup();
let (missing, distributions): (Vec<_>, Vec<_>) = packages.iter().partition_map(|name| {
let installed = site_packages.get_packages(name);
if installed.is_empty() {
Either::Left(name)
} else {
Either::Right(installed)
}
});
if !missing.is_empty() {
writeln!(
printer.stderr(),
"{}{} Package(s) not found for: {}",
"warning".yellow().bold(),
":".bold(),
missing.iter().join(", ").bold()
)?;
}
let distributions = distributions.iter().flatten().collect_vec();
if distributions.is_empty() {
return Ok(ExitStatus::Failure);
}
let mut requires_map = FxHashMap::default();
for dist in &distributions {
if let Ok(metadata) = dist.read_metadata() {
requires_map.insert(
dist.name(),
metadata
.requires_dist
.iter()
.filter(|req| req.evaluate_markers(&markers, &[]))
.map(|req| &req.name)
.sorted_unstable()
.dedup()
.collect_vec(),
);
}
}
if !requires_map.is_empty() {
for installed in site_packages.iter() {
if requires_map.contains_key(installed.name()) {
continue;
}
if let Ok(metadata) = installed.read_metadata() {
let requires = metadata
.requires_dist
.iter()
.filter(|req| req.evaluate_markers(&markers, &[]))
.map(|req| &req.name)
.collect_vec();
if !requires.is_empty() {
requires_map.insert(installed.name(), requires);
}
}
}
}
for (i, distribution) in distributions.iter().enumerate() {
if i > 0 {
writeln!(printer.stdout(), "---")?;
}
writeln!(printer.stdout(), "Name: {}", distribution.name())?;
writeln!(printer.stdout(), "Version: {}", distribution.version())?;
writeln!(
printer.stdout(),
"Location: {}",
distribution
.install_path()
.parent()
.expect("package path is not root")
.simplified_display()
)?;
if let Some(path) = distribution
.as_editable()
.and_then(|url| url.to_file_path().ok())
{
writeln!(
printer.stdout(),
"Editable project location: {}",
path.simplified_display()
)?;
}
if let Some(requires) = requires_map.get(distribution.name()) {
if requires.is_empty() {
writeln!(printer.stdout(), "Requires:")?;
} else {
writeln!(printer.stdout(), "Requires: {}", requires.iter().join(", "))?;
}
let required_by = requires_map
.iter()
.filter(|(name, pkgs)| {
**name != distribution.name()
&& pkgs.iter().any(|pkg| *pkg == distribution.name())
})
.map(|(name, _)| name)
.sorted_unstable()
.dedup()
.collect_vec();
if required_by.is_empty() {
writeln!(printer.stdout(), "Required-by:")?;
} else {
writeln!(
printer.stdout(),
"Required-by: {}",
required_by.into_iter().join(", "),
)?;
}
}
if files {
let path = distribution.install_path().join("RECORD");
let record = read_record(&mut File::open(path)?)?;
writeln!(printer.stdout(), "Files:")?;
for entry in record {
writeln!(printer.stdout(), " {}", entry.path)?;
}
}
}
if strict {
for diagnostic in site_packages.diagnostics(&markers, tags, dependency_metadata)? {
writeln!(
printer.stderr(),
"{}{} {}",
"warning".yellow().bold(),
":".bold(),
diagnostic.message().bold()
)?;
}
}
Ok(ExitStatus::Success)
}