mirror of
https://github.com/astral-sh/uv.git
synced 2025-09-26 12:09:12 +00:00
Add a progress bar to uv tree --outdated
and uv pip list --outdated
(#9284)
## Summary Closes https://github.com/astral-sh/uv/issues/9282.
This commit is contained in:
parent
a0de83001c
commit
b19ccb6b97
3 changed files with 125 additions and 60 deletions
|
@ -27,6 +27,7 @@ use uv_resolver::{ExcludeNewer, PrereleaseMode, RequiresPython};
|
|||
|
||||
use crate::commands::pip::latest::LatestClient;
|
||||
use crate::commands::pip::operations::report_target_environment;
|
||||
use crate::commands::reporters::LatestVersionReporter;
|
||||
use crate::commands::ExitStatus;
|
||||
use crate::printer::Printer;
|
||||
|
||||
|
@ -78,7 +79,7 @@ pub(crate) async fn pip_list(
|
|||
.collect_vec();
|
||||
|
||||
// Determine the latest version for each package.
|
||||
let latest = if outdated {
|
||||
let latest = if outdated && !results.is_empty() {
|
||||
let capabilities = IndexCapabilities::default();
|
||||
|
||||
// Initialize the registry client.
|
||||
|
@ -110,6 +111,8 @@ pub(crate) async fn pip_list(
|
|||
requires_python: &requires_python,
|
||||
};
|
||||
|
||||
let reporter = LatestVersionReporter::from(printer).with_length(results.len() as u64);
|
||||
|
||||
// Fetch the latest version for each package.
|
||||
let mut fetches = futures::stream::iter(&results)
|
||||
.map(|dist| async {
|
||||
|
@ -120,8 +123,14 @@ pub(crate) async fn pip_list(
|
|||
|
||||
let mut map = FxHashMap::default();
|
||||
while let Some((package, version)) = fetches.next().await.transpose()? {
|
||||
if let Some(version) = version.as_ref() {
|
||||
reporter.on_fetch_version(package, version.version());
|
||||
} else {
|
||||
reporter.on_fetch_progress();
|
||||
}
|
||||
map.insert(package, version);
|
||||
}
|
||||
reporter.on_fetch_complete();
|
||||
map
|
||||
} else {
|
||||
FxHashMap::default()
|
||||
|
|
|
@ -24,6 +24,7 @@ use crate::commands::project::lock::{do_safe_lock, LockMode};
|
|||
use crate::commands::project::{
|
||||
default_dependency_groups, DependencyGroupsTarget, ProjectError, ProjectInterpreter,
|
||||
};
|
||||
use crate::commands::reporters::LatestVersionReporter;
|
||||
use crate::commands::{diagnostics, ExitStatus, SharedState};
|
||||
use crate::printer::Printer;
|
||||
use crate::settings::ResolverSettings;
|
||||
|
@ -142,73 +143,89 @@ pub(crate) async fn tree(
|
|||
|
||||
// If necessary, look up the latest version of each package.
|
||||
let latest = if outdated {
|
||||
let ResolverSettings {
|
||||
index_locations: _,
|
||||
index_strategy: _,
|
||||
keyring_provider,
|
||||
resolution: _,
|
||||
prerelease: _,
|
||||
dependency_metadata: _,
|
||||
config_setting: _,
|
||||
no_build_isolation: _,
|
||||
no_build_isolation_package: _,
|
||||
exclude_newer: _,
|
||||
link_mode: _,
|
||||
upgrade: _,
|
||||
build_options: _,
|
||||
sources: _,
|
||||
} = &settings;
|
||||
// Filter to packages that are derived from a registry.
|
||||
let packages = lock
|
||||
.packages()
|
||||
.iter()
|
||||
.filter_map(|package| {
|
||||
let index = match package.index(workspace.install_path()) {
|
||||
Ok(Some(index)) => index,
|
||||
Ok(None) => return None,
|
||||
Err(err) => return Some(Err(err)),
|
||||
};
|
||||
Some(Ok((package, index)))
|
||||
})
|
||||
.collect::<Result<Vec<_>, _>>()?;
|
||||
|
||||
let capabilities = IndexCapabilities::default();
|
||||
if packages.is_empty() {
|
||||
PackageMap::default()
|
||||
} else {
|
||||
let ResolverSettings {
|
||||
index_locations: _,
|
||||
index_strategy: _,
|
||||
keyring_provider,
|
||||
resolution: _,
|
||||
prerelease: _,
|
||||
dependency_metadata: _,
|
||||
config_setting: _,
|
||||
no_build_isolation: _,
|
||||
no_build_isolation_package: _,
|
||||
exclude_newer: _,
|
||||
link_mode: _,
|
||||
upgrade: _,
|
||||
build_options: _,
|
||||
sources: _,
|
||||
} = &settings;
|
||||
|
||||
// Initialize the registry client.
|
||||
let client =
|
||||
RegistryClientBuilder::new(cache.clone().with_refresh(Refresh::All(Timestamp::now())))
|
||||
.native_tls(native_tls)
|
||||
.connectivity(connectivity)
|
||||
.keyring(*keyring_provider)
|
||||
.allow_insecure_host(allow_insecure_host.to_vec())
|
||||
.build();
|
||||
let capabilities = IndexCapabilities::default();
|
||||
|
||||
// Initialize the client to fetch the latest version of each package.
|
||||
let client = LatestClient {
|
||||
client: &client,
|
||||
capabilities: &capabilities,
|
||||
prerelease: lock.prerelease_mode(),
|
||||
exclude_newer: lock.exclude_newer(),
|
||||
requires_python: lock.requires_python(),
|
||||
tags: None,
|
||||
};
|
||||
// Initialize the registry client.
|
||||
let client = RegistryClientBuilder::new(
|
||||
cache.clone().with_refresh(Refresh::All(Timestamp::now())),
|
||||
)
|
||||
.native_tls(native_tls)
|
||||
.connectivity(connectivity)
|
||||
.keyring(*keyring_provider)
|
||||
.allow_insecure_host(allow_insecure_host.to_vec())
|
||||
.build();
|
||||
|
||||
// Fetch the latest version for each package.
|
||||
let mut fetches = futures::stream::iter(lock.packages().iter().filter_map(|package| {
|
||||
// Filter to packages that are derived from a registry.
|
||||
let index = match package.index(workspace.install_path()) {
|
||||
Ok(Some(index)) => index,
|
||||
Ok(None) => return None,
|
||||
Err(err) => return Some(Err(err)),
|
||||
// Initialize the client to fetch the latest version of each package.
|
||||
let client = LatestClient {
|
||||
client: &client,
|
||||
capabilities: &capabilities,
|
||||
prerelease: lock.prerelease_mode(),
|
||||
exclude_newer: lock.exclude_newer(),
|
||||
requires_python: lock.requires_python(),
|
||||
tags: None,
|
||||
};
|
||||
Some(Ok((package, index)))
|
||||
}))
|
||||
.map(|result| async move {
|
||||
let (package, index) = result?;
|
||||
let Some(filename) = client.find_latest(package.name(), Some(&index)).await? else {
|
||||
return Ok(None);
|
||||
};
|
||||
if filename.version() == package.version() {
|
||||
return Ok(None);
|
||||
}
|
||||
Ok::<Option<_>, Error>(Some((package, filename.into_version())))
|
||||
})
|
||||
.buffer_unordered(concurrency.downloads);
|
||||
|
||||
let mut map = PackageMap::default();
|
||||
while let Some(entry) = fetches.next().await.transpose()? {
|
||||
if let Some((package, version)) = entry {
|
||||
map.insert(package.clone(), version);
|
||||
let reporter = LatestVersionReporter::from(printer).with_length(packages.len() as u64);
|
||||
|
||||
// Fetch the latest version for each package.
|
||||
let mut fetches = futures::stream::iter(packages)
|
||||
.map(|(package, index)| async move {
|
||||
let Some(filename) = client.find_latest(package.name(), Some(&index)).await?
|
||||
else {
|
||||
return Ok(None);
|
||||
};
|
||||
Ok::<Option<_>, Error>(Some((package, filename.into_version())))
|
||||
})
|
||||
.buffer_unordered(concurrency.downloads);
|
||||
|
||||
let mut map = PackageMap::default();
|
||||
while let Some(entry) = fetches.next().await.transpose()? {
|
||||
let Some((package, version)) = entry else {
|
||||
reporter.on_fetch_progress();
|
||||
continue;
|
||||
};
|
||||
reporter.on_fetch_version(package.name(), &version);
|
||||
if version > *package.version() {
|
||||
map.insert(package.clone(), version);
|
||||
}
|
||||
}
|
||||
reporter.on_fetch_complete();
|
||||
map
|
||||
}
|
||||
map
|
||||
} else {
|
||||
PackageMap::default()
|
||||
};
|
||||
|
|
|
@ -11,6 +11,7 @@ use uv_distribution_types::{
|
|||
BuildableSource, CachedDist, DistributionMetadata, Name, SourceDist, VersionOrUrlRef,
|
||||
};
|
||||
use uv_normalize::PackageName;
|
||||
use uv_pep440::Version;
|
||||
use uv_python::PythonInstallationKey;
|
||||
use uv_static::EnvVars;
|
||||
|
||||
|
@ -528,6 +529,44 @@ impl uv_publish::Reporter for PublishReporter {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct LatestVersionReporter {
|
||||
progress: ProgressBar,
|
||||
}
|
||||
|
||||
impl From<Printer> for LatestVersionReporter {
|
||||
fn from(printer: Printer) -> Self {
|
||||
let progress = ProgressBar::with_draw_target(None, printer.target());
|
||||
progress.set_style(
|
||||
ProgressStyle::with_template("{bar:20} [{pos}/{len}] {wide_msg:.dim}").unwrap(),
|
||||
);
|
||||
progress.set_message("Fetching latest versions...");
|
||||
Self { progress }
|
||||
}
|
||||
}
|
||||
|
||||
impl LatestVersionReporter {
|
||||
#[must_use]
|
||||
pub(crate) fn with_length(self, length: u64) -> Self {
|
||||
self.progress.set_length(length);
|
||||
self
|
||||
}
|
||||
|
||||
pub(crate) fn on_fetch_progress(&self) {
|
||||
self.progress.inc(1);
|
||||
}
|
||||
|
||||
pub(crate) fn on_fetch_version(&self, name: &PackageName, version: &Version) {
|
||||
self.progress.set_message(format!("{name} v{version}"));
|
||||
self.progress.inc(1);
|
||||
}
|
||||
|
||||
pub(crate) fn on_fetch_complete(&self) {
|
||||
self.progress.set_message("");
|
||||
self.progress.finish_and_clear();
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct CleaningDirectoryReporter {
|
||||
bar: ProgressBar,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue