mirror of
https://github.com/astral-sh/uv.git
synced 2025-07-07 13:25:00 +00:00
Add some text decoration to toolchain CLI (#4882)
## Summary
Attempts to make the CLI output a little more consistent with the `pip`
interface. I opted to make the Python versions, requests, and filenames
blue, and the keys green, but open to opinions on that. (We use blue for
filenames elsewhere.)
Closes #4813.
Closes https://github.com/astral-sh/uv/issues/4814.

This commit is contained in:
parent
57cfe1e229
commit
2d651fe264
3 changed files with 48 additions and 46 deletions
|
@ -5,6 +5,7 @@ use anyhow::Result;
|
|||
use fs_err as fs;
|
||||
use futures::StreamExt;
|
||||
use itertools::Itertools;
|
||||
use owo_colors::OwoColorize;
|
||||
use uv_cache::Cache;
|
||||
use uv_client::Connectivity;
|
||||
use uv_configuration::PreviewMode;
|
||||
|
@ -15,7 +16,7 @@ use uv_python::{requests_from_version_file, PythonRequest};
|
|||
use uv_warnings::warn_user_once;
|
||||
|
||||
use crate::commands::reporters::PythonDownloadReporter;
|
||||
use crate::commands::ExitStatus;
|
||||
use crate::commands::{elapsed, ExitStatus};
|
||||
use crate::printer::Printer;
|
||||
|
||||
/// Download and install Python versions.
|
||||
|
@ -62,7 +63,8 @@ pub(crate) async fn install(
|
|||
for (request, download_request) in requests.iter().zip(download_requests) {
|
||||
writeln!(
|
||||
printer.stderr(),
|
||||
"Looking for installation {request} ({download_request})"
|
||||
"Searching for Python versions matching: {}",
|
||||
request.cyan()
|
||||
)?;
|
||||
if let Some(installation) = installed_installations
|
||||
.iter()
|
||||
|
@ -70,14 +72,15 @@ pub(crate) async fn install(
|
|||
{
|
||||
writeln!(
|
||||
printer.stderr(),
|
||||
"Found existing installation `{}` that satisfies {request}",
|
||||
installation.key()
|
||||
"Found existing installation for {}: {}",
|
||||
request.cyan(),
|
||||
installation.key().green(),
|
||||
)?;
|
||||
if force {
|
||||
writeln!(
|
||||
printer.stderr(),
|
||||
"Removing existing installation `{}`",
|
||||
installation.key()
|
||||
"Uninstalling {}",
|
||||
installation.key().green()
|
||||
)?;
|
||||
fs::remove_dir_all(installation.path())?;
|
||||
unfilled_requests.push(download_request);
|
||||
|
@ -94,12 +97,7 @@ pub(crate) async fn install(
|
|||
"Python is already available. Use `uv python install <request>` to install a specific version.",
|
||||
)?;
|
||||
} else if requests.len() > 1 {
|
||||
writeln!(
|
||||
printer.stderr(),
|
||||
"All requested versions already installed."
|
||||
)?;
|
||||
} else {
|
||||
writeln!(printer.stderr(), "Requested versions already installed.")?;
|
||||
writeln!(printer.stderr(), "All requested versions already installed")?;
|
||||
}
|
||||
return Ok(ExitStatus::Success);
|
||||
}
|
||||
|
@ -117,13 +115,6 @@ pub(crate) async fn install(
|
|||
.unique_by(|download| download.key())
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let s = if downloads.len() == 1 { "" } else { "s" };
|
||||
writeln!(
|
||||
printer.stderr(),
|
||||
"Found {} version{s} requiring installation",
|
||||
downloads.len()
|
||||
)?;
|
||||
|
||||
// Construct a client
|
||||
let client = uv_client::BaseClientBuilder::new()
|
||||
.connectivity(connectivity)
|
||||
|
@ -150,8 +141,9 @@ pub(crate) async fn install(
|
|||
DownloadResult::Fetched(path) => {
|
||||
writeln!(
|
||||
printer.stderr(),
|
||||
"Installed Python {version} to {}",
|
||||
path.user_display()
|
||||
"Installed {} to: {}",
|
||||
format!("Python {version}").cyan(),
|
||||
path.user_display().cyan()
|
||||
)?;
|
||||
path
|
||||
}
|
||||
|
@ -165,9 +157,13 @@ pub(crate) async fn install(
|
|||
let s = if downloads.len() == 1 { "" } else { "s" };
|
||||
writeln!(
|
||||
printer.stderr(),
|
||||
"Installed {} version{s} in {}s",
|
||||
downloads.len(),
|
||||
start.elapsed().as_secs()
|
||||
"{}",
|
||||
format!(
|
||||
"Installed {} {}",
|
||||
format!("{} version{s}", downloads.len()).bold(),
|
||||
format!("in {}", elapsed(start.elapsed())).dimmed()
|
||||
)
|
||||
.dimmed()
|
||||
)?;
|
||||
|
||||
Ok(ExitStatus::Success)
|
||||
|
|
|
@ -79,7 +79,7 @@ pub(crate) async fn list(
|
|||
.collect::<Result<Vec<Result<PythonInstallation, PythonNotFound>>, DiscoveryError>>()?
|
||||
.into_iter()
|
||||
// Drop any "missing" installations
|
||||
.filter_map(std::result::Result::ok);
|
||||
.filter_map(Result::ok);
|
||||
|
||||
let mut output = BTreeSet::new();
|
||||
for installation in installed {
|
||||
|
|
|
@ -4,6 +4,7 @@ use std::fmt::Write;
|
|||
use anyhow::Result;
|
||||
use futures::StreamExt;
|
||||
use itertools::Itertools;
|
||||
use owo_colors::OwoColorize;
|
||||
|
||||
use uv_configuration::PreviewMode;
|
||||
use uv_python::downloads::{self, PythonDownloadRequest};
|
||||
|
@ -11,7 +12,7 @@ use uv_python::managed::ManagedPythonInstallations;
|
|||
use uv_python::PythonRequest;
|
||||
use uv_warnings::warn_user_once;
|
||||
|
||||
use crate::commands::ExitStatus;
|
||||
use crate::commands::{elapsed, ExitStatus};
|
||||
use crate::printer::Printer;
|
||||
|
||||
/// Uninstall managed Python versions.
|
||||
|
@ -24,6 +25,8 @@ pub(crate) async fn uninstall(
|
|||
warn_user_once!("`uv python uninstall` is experimental and may change without warning.");
|
||||
}
|
||||
|
||||
let start = std::time::Instant::now();
|
||||
|
||||
let installations = ManagedPythonInstallations::from_settings()?.init()?;
|
||||
let _lock = installations.acquire_lock()?;
|
||||
|
||||
|
@ -43,7 +46,8 @@ pub(crate) async fn uninstall(
|
|||
for (request, download_request) in requests.iter().zip(download_requests) {
|
||||
writeln!(
|
||||
printer.stderr(),
|
||||
"Looking for Python installations matching {request} ({download_request})"
|
||||
"Searching for Python versions matching: {}",
|
||||
request.cyan()
|
||||
)?;
|
||||
let mut found = false;
|
||||
for installation in installed_installations
|
||||
|
@ -54,31 +58,28 @@ pub(crate) async fn uninstall(
|
|||
if matching_installations.insert(installation.clone()) {
|
||||
writeln!(
|
||||
printer.stderr(),
|
||||
"Found installation `{}` that matches {request}",
|
||||
installation.key()
|
||||
"Found existing installation for {}: {}",
|
||||
request.cyan(),
|
||||
installation.key().green(),
|
||||
)?;
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
writeln!(
|
||||
printer.stderr(),
|
||||
"No installations found matching {request}"
|
||||
"No existing installations found for: {}",
|
||||
request.cyan()
|
||||
)?;
|
||||
}
|
||||
}
|
||||
|
||||
if matching_installations.is_empty() {
|
||||
if matches!(requests.as_slice(), [PythonRequest::Any]) {
|
||||
writeln!(printer.stderr(), "No installed installations found")?;
|
||||
writeln!(printer.stderr(), "No Python installations found")?;
|
||||
} else if requests.len() > 1 {
|
||||
writeln!(
|
||||
printer.stderr(),
|
||||
"No installations found matching the requests"
|
||||
)?;
|
||||
} else {
|
||||
writeln!(
|
||||
printer.stderr(),
|
||||
"No installations found matching the request"
|
||||
"No Python installations found matching the requests"
|
||||
)?;
|
||||
}
|
||||
return Ok(ExitStatus::Failure);
|
||||
|
@ -98,18 +99,19 @@ pub(crate) async fn uninstall(
|
|||
for (key, result) in results.iter().sorted_by_key(|(key, _)| key) {
|
||||
if let Err(err) = result {
|
||||
failed = true;
|
||||
writeln!(printer.stderr(), "Failed to uninstall `{key}`: {err}")?;
|
||||
writeln!(
|
||||
printer.stderr(),
|
||||
"Failed to uninstall {}: {err}",
|
||||
key.green()
|
||||
)?;
|
||||
} else {
|
||||
writeln!(printer.stderr(), "Uninstalled `{key}`")?;
|
||||
writeln!(printer.stderr(), "Uninstalled {}", key.green())?;
|
||||
}
|
||||
}
|
||||
|
||||
if failed {
|
||||
if matching_installations.len() > 1 {
|
||||
writeln!(
|
||||
printer.stderr(),
|
||||
"Failed to remove some Python installations"
|
||||
)?;
|
||||
writeln!(printer.stderr(), "Failed to uninstall some Python versions")?;
|
||||
}
|
||||
return Ok(ExitStatus::Failure);
|
||||
}
|
||||
|
@ -119,11 +121,15 @@ pub(crate) async fn uninstall(
|
|||
} else {
|
||||
"s"
|
||||
};
|
||||
|
||||
writeln!(
|
||||
printer.stderr(),
|
||||
"Removed {} Python installation{s}",
|
||||
matching_installations.len()
|
||||
"{}",
|
||||
format!(
|
||||
"Uninstalled {} {}",
|
||||
format!("{} version{s}", matching_installations.len()).bold(),
|
||||
format!("in {}", elapsed(start.elapsed())).dimmed()
|
||||
)
|
||||
.dimmed()
|
||||
)?;
|
||||
|
||||
Ok(ExitStatus::Success)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue