mirror of https://github.com/astral-sh/uv
WIP: Dry run flag for pip install
This commit is contained in:
parent
b71ae74943
commit
4d9cdf2758
|
|
@ -1,5 +1,5 @@
|
||||||
use std::process::ExitCode;
|
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
use std::{fmt::Display, process::ExitCode};
|
||||||
|
|
||||||
pub(crate) use clean::clean;
|
pub(crate) use clean::clean;
|
||||||
use distribution_types::InstalledMetadata;
|
use distribution_types::InstalledMetadata;
|
||||||
|
|
@ -8,6 +8,7 @@ pub(crate) use pip_compile::{extra_name_with_clap_error, pip_compile, Upgrade};
|
||||||
pub(crate) use pip_install::pip_install;
|
pub(crate) use pip_install::pip_install;
|
||||||
pub(crate) use pip_sync::pip_sync;
|
pub(crate) use pip_sync::pip_sync;
|
||||||
pub(crate) use pip_uninstall::pip_uninstall;
|
pub(crate) use pip_uninstall::pip_uninstall;
|
||||||
|
use uv_normalize::PackageName;
|
||||||
pub(crate) use venv::venv;
|
pub(crate) use venv::venv;
|
||||||
|
|
||||||
mod clean;
|
mod clean;
|
||||||
|
|
@ -70,3 +71,10 @@ pub(super) struct ChangeEvent<T: InstalledMetadata> {
|
||||||
dist: T,
|
dist: T,
|
||||||
kind: ChangeEventKind,
|
kind: ChangeEventKind,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub(super) struct DryRunEvent<T: Display> {
|
||||||
|
name: PackageName,
|
||||||
|
version: T,
|
||||||
|
kind: ChangeEventKind,
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ use std::collections::HashSet;
|
||||||
use std::fmt::Write;
|
use std::fmt::Write;
|
||||||
|
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
use std::time::Instant;
|
||||||
|
|
||||||
use anstream::eprint;
|
use anstream::eprint;
|
||||||
use anyhow::{anyhow, Context, Result};
|
use anyhow::{anyhow, Context, Result};
|
||||||
|
|
@ -40,7 +41,7 @@ use crate::commands::{elapsed, ChangeEvent, ChangeEventKind, ExitStatus};
|
||||||
use crate::printer::Printer;
|
use crate::printer::Printer;
|
||||||
use crate::requirements::{ExtrasSpecification, RequirementsSource, RequirementsSpecification};
|
use crate::requirements::{ExtrasSpecification, RequirementsSource, RequirementsSpecification};
|
||||||
|
|
||||||
use super::Upgrade;
|
use super::{DryRunEvent, Upgrade};
|
||||||
|
|
||||||
/// Install packages into the current environment.
|
/// Install packages into the current environment.
|
||||||
#[allow(clippy::too_many_arguments)]
|
#[allow(clippy::too_many_arguments)]
|
||||||
|
|
@ -137,6 +138,9 @@ pub(crate) async fn pip_install(
|
||||||
)
|
)
|
||||||
.dimmed()
|
.dimmed()
|
||||||
)?;
|
)?;
|
||||||
|
if dry_run {
|
||||||
|
writeln!(printer, "Would make no changes")?;
|
||||||
|
}
|
||||||
return Ok(ExitStatus::Success);
|
return Ok(ExitStatus::Success);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -503,12 +507,7 @@ async fn install(
|
||||||
.map(ResolvedEditable::Built)
|
.map(ResolvedEditable::Built)
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
let Plan {
|
let plan = Planner::with_requirements(&requirements)
|
||||||
local,
|
|
||||||
remote,
|
|
||||||
reinstalls,
|
|
||||||
extraneous: _,
|
|
||||||
} = Planner::with_requirements(&requirements)
|
|
||||||
.with_editable_requirements(editables)
|
.with_editable_requirements(editables)
|
||||||
.build(
|
.build(
|
||||||
site_packages,
|
site_packages,
|
||||||
|
|
@ -522,71 +521,16 @@ async fn install(
|
||||||
.context("Failed to determine installation plan")?;
|
.context("Failed to determine installation plan")?;
|
||||||
|
|
||||||
if dry_run {
|
if dry_run {
|
||||||
if !remote.is_empty() {
|
return report_dry_run(resolution, plan, start, printer);
|
||||||
writeln!(
|
|
||||||
printer,
|
|
||||||
"{} The following packages would be downloaded:",
|
|
||||||
"DRY RUN".white().bold()
|
|
||||||
)?;
|
|
||||||
for dist in &remote {
|
|
||||||
let version = resolution
|
|
||||||
.get(&dist.name)
|
|
||||||
.map(|r| r.version().map_or(String::new(), |v| format!("=={v}")))
|
|
||||||
.unwrap_or_default();
|
|
||||||
writeln!(
|
|
||||||
printer,
|
|
||||||
" {} {}{}",
|
|
||||||
"~".blue(),
|
|
||||||
dist.name.as_ref().white().bold(),
|
|
||||||
version.dimmed()
|
|
||||||
)?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if !reinstalls.is_empty() {
|
|
||||||
writeln!(
|
|
||||||
printer,
|
|
||||||
"{} The following packages would be reinstalled:",
|
|
||||||
"DRY RUN".white().bold()
|
|
||||||
)?;
|
|
||||||
for dist_info in &reinstalls {
|
|
||||||
let version = resolution
|
|
||||||
.get(dist_info.name())
|
|
||||||
.map(|r| r.version().map_or(String::new(), |v| format!("=={v}")))
|
|
||||||
.unwrap_or_default();
|
|
||||||
writeln!(
|
|
||||||
printer,
|
|
||||||
" {} {}{}",
|
|
||||||
"~".blue(),
|
|
||||||
dist_info.name().white().bold(),
|
|
||||||
version.dimmed()
|
|
||||||
)?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if !local.is_empty() {
|
|
||||||
writeln!(
|
|
||||||
printer,
|
|
||||||
"{} The following packages would be installed from local cache:",
|
|
||||||
"DRY RUN".white().bold()
|
|
||||||
)?;
|
|
||||||
for local_dist in &local {
|
|
||||||
let version = resolution
|
|
||||||
.get(local_dist.name())
|
|
||||||
.map(|r| r.version().map_or(String::new(), |v| format!("=={v}")))
|
|
||||||
.unwrap_or_default();
|
|
||||||
writeln!(
|
|
||||||
printer,
|
|
||||||
" {} {}{}",
|
|
||||||
"~".blue(),
|
|
||||||
local_dist.name().white().bold(),
|
|
||||||
version.dimmed()
|
|
||||||
)?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return Ok(());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let Plan {
|
||||||
|
local,
|
||||||
|
remote,
|
||||||
|
reinstalls,
|
||||||
|
extraneous: _,
|
||||||
|
} = plan;
|
||||||
|
|
||||||
// Nothing to do.
|
// Nothing to do.
|
||||||
if remote.is_empty() && local.is_empty() && reinstalls.is_empty() {
|
if remote.is_empty() && local.is_empty() && reinstalls.is_empty() {
|
||||||
let s = if resolution.len() == 1 { "" } else { "s" };
|
let s = if resolution.len() == 1 { "" } else { "s" };
|
||||||
|
|
@ -600,7 +544,6 @@ async fn install(
|
||||||
)
|
)
|
||||||
.dimmed()
|
.dimmed()
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -750,6 +693,140 @@ async fn install(
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn report_dry_run(
|
||||||
|
resolution: &Resolution,
|
||||||
|
plan: Plan,
|
||||||
|
start: Instant,
|
||||||
|
mut printer: Printer,
|
||||||
|
) -> Result<(), Error> {
|
||||||
|
let Plan {
|
||||||
|
local,
|
||||||
|
remote,
|
||||||
|
reinstalls,
|
||||||
|
extraneous: _,
|
||||||
|
} = plan;
|
||||||
|
|
||||||
|
// Nothing to do.
|
||||||
|
if remote.is_empty() && local.is_empty() && reinstalls.is_empty() {
|
||||||
|
let s = if resolution.len() == 1 { "" } else { "s" };
|
||||||
|
writeln!(
|
||||||
|
printer,
|
||||||
|
"{}",
|
||||||
|
format!(
|
||||||
|
"Audited {} in {}",
|
||||||
|
format!("{} package{}", resolution.len(), s).bold(),
|
||||||
|
elapsed(start.elapsed())
|
||||||
|
)
|
||||||
|
.dimmed()
|
||||||
|
)?;
|
||||||
|
writeln!(printer, "Would make no changes")?;
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Map any registry-based requirements back to those returned by the resolver.
|
||||||
|
let remote = remote
|
||||||
|
.iter()
|
||||||
|
.map(|dist| {
|
||||||
|
resolution
|
||||||
|
.get(&dist.name)
|
||||||
|
.cloned()
|
||||||
|
.expect("Resolution should contain all packages")
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
// Download, build, and unzip any missing distributions.
|
||||||
|
let wheels = if remote.is_empty() {
|
||||||
|
vec![]
|
||||||
|
} else {
|
||||||
|
let s = if remote.len() == 1 { "" } else { "s" };
|
||||||
|
writeln!(
|
||||||
|
printer,
|
||||||
|
"{}",
|
||||||
|
format!(
|
||||||
|
"Would download {}",
|
||||||
|
format!("{} package{}", remote.len(), s).bold(),
|
||||||
|
)
|
||||||
|
.dimmed()
|
||||||
|
)?;
|
||||||
|
remote
|
||||||
|
};
|
||||||
|
|
||||||
|
// Remove any existing installations.
|
||||||
|
if !reinstalls.is_empty() {
|
||||||
|
let s = if reinstalls.len() == 1 { "" } else { "s" };
|
||||||
|
writeln!(
|
||||||
|
printer,
|
||||||
|
"{}",
|
||||||
|
format!(
|
||||||
|
"Would uninstall {}",
|
||||||
|
format!("{} package{}", reinstalls.len(), s).bold(),
|
||||||
|
)
|
||||||
|
.dimmed()
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Install the resolved distributions.
|
||||||
|
let installs = wheels.len() + local.len();
|
||||||
|
|
||||||
|
if installs > 0 {
|
||||||
|
let s = if installs == 1 { "" } else { "s" };
|
||||||
|
writeln!(
|
||||||
|
printer,
|
||||||
|
"{}",
|
||||||
|
format!(
|
||||||
|
"Would install {}",
|
||||||
|
format!("{} package{}", installs, s).bold(),
|
||||||
|
)
|
||||||
|
.dimmed()
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
for event in reinstalls
|
||||||
|
.into_iter()
|
||||||
|
.map(|distribution| DryRunEvent {
|
||||||
|
name: distribution.name().clone(),
|
||||||
|
version: distribution.version().to_string(),
|
||||||
|
kind: ChangeEventKind::Removed,
|
||||||
|
})
|
||||||
|
.chain(wheels.into_iter().map(|distribution| DryRunEvent {
|
||||||
|
name: distribution.name().clone(),
|
||||||
|
version: distribution.version().unwrap().to_string(),
|
||||||
|
kind: ChangeEventKind::Added,
|
||||||
|
}))
|
||||||
|
.chain(local.into_iter().map(|distribution| DryRunEvent {
|
||||||
|
name: distribution.name().clone(),
|
||||||
|
version: distribution.installed_version().to_string(),
|
||||||
|
kind: ChangeEventKind::Added,
|
||||||
|
}))
|
||||||
|
.sorted_unstable_by(|a, b| a.name.cmp(&b.name).then_with(|| a.kind.cmp(&b.kind)))
|
||||||
|
{
|
||||||
|
match event.kind {
|
||||||
|
ChangeEventKind::Added => {
|
||||||
|
writeln!(
|
||||||
|
printer,
|
||||||
|
" {} {}{}{}",
|
||||||
|
"+".green(),
|
||||||
|
event.name.as_ref().bold(),
|
||||||
|
"==".dimmed(),
|
||||||
|
event.version.dimmed()
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
ChangeEventKind::Removed => {
|
||||||
|
writeln!(
|
||||||
|
printer,
|
||||||
|
" {} {}{}{}",
|
||||||
|
"-".red(),
|
||||||
|
event.name.as_ref().bold(),
|
||||||
|
"==".dimmed(),
|
||||||
|
event.version.dimmed()
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
/// Validate the installed packages in the virtual environment.
|
/// Validate the installed packages in the virtual environment.
|
||||||
fn validate(resolution: &Resolution, venv: &Virtualenv, mut printer: Printer) -> Result<(), Error> {
|
fn validate(resolution: &Resolution, venv: &Virtualenv, mut printer: Printer) -> Result<(), Error> {
|
||||||
let site_packages = SitePackages::from_executable(venv)?;
|
let site_packages = SitePackages::from_executable(venv)?;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue