diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6e1c33982943..807e5312e35f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -731,6 +731,7 @@ jobs: ./uvx -v ruff --version eval "$(./uv generate-shell-completion bash)" eval "$(./uvx --generate-shell-completion bash)" + ./uv self uninstall --remove-data smoke-test-macos: timeout-minutes: 10 @@ -755,6 +756,7 @@ jobs: ./uvx -v ruff --version eval "$(./uv generate-shell-completion bash)" eval "$(./uvx --generate-shell-completion bash)" + ./uv self uninstall --remove-data smoke-test-windows-x86_64: timeout-minutes: 10 @@ -775,6 +777,7 @@ jobs: ./uvx -v ruff --version (& ./uv generate-shell-completion powershell) | Out-String | Invoke-Expression (& ./uvx --generate-shell-completion powershell) | Out-String | Invoke-Expression + ./uv self uninstall --remove-data smoke-test-windows-aarch64: timeout-minutes: 10 @@ -798,6 +801,7 @@ jobs: ./uvx -v ruff --version (& ./uv generate-shell-completion powershell) | Out-String | Invoke-Expression (& ./uvx --generate-shell-completion powershell) | Out-String | Invoke-Expression + ./uv self uninstall --remove-data integration-test-conda: timeout-minutes: 10 diff --git a/crates/uv-cli/src/lib.rs b/crates/uv-cli/src/lib.rs index 1a73e634736e..9f0d943e9ff4 100644 --- a/crates/uv-cli/src/lib.rs +++ b/crates/uv-cli/src/lib.rs @@ -510,6 +510,8 @@ pub struct SelfNamespace { pub enum SelfCommand { /// Update uv. Update(SelfUpdateArgs), + /// Uninstall uv. + Uninstall(SelfUninstallArgs), } #[derive(Args, Debug)] @@ -523,6 +525,14 @@ pub struct SelfUpdateArgs { pub token: Option, } +#[derive(Args, Debug)] +pub struct SelfUninstallArgs { + /// true iff should run `uv cache clean` and remove directories pointed to by `uv python dir` + /// and `uv tool dir` + #[arg(long)] + pub remove_data: bool, +} + #[derive(Args)] #[allow(clippy::struct_excessive_bools)] pub struct CacheNamespace { diff --git a/crates/uv/src/commands/mod.rs b/crates/uv/src/commands/mod.rs index 372c6ec70e46..4584f43886f8 100644 --- a/crates/uv/src/commands/mod.rs +++ b/crates/uv/src/commands/mod.rs @@ -37,6 +37,8 @@ pub(crate) use python::list::list as python_list; pub(crate) use python::pin::pin as python_pin; pub(crate) use python::uninstall::uninstall as python_uninstall; #[cfg(feature = "self-update")] +pub(crate) use self_uninstall::self_uninstall; +#[cfg(feature = "self-update")] pub(crate) use self_update::self_update; pub(crate) use tool::dir::dir as tool_dir; pub(crate) use tool::install::install as tool_install; @@ -71,6 +73,8 @@ mod python; pub(crate) mod reporters; mod run; #[cfg(feature = "self-update")] +mod self_uninstall; +#[cfg(feature = "self-update")] mod self_update; mod tool; mod venv; diff --git a/crates/uv/src/commands/self_uninstall.rs b/crates/uv/src/commands/self_uninstall.rs new file mode 100644 index 000000000000..358b9b281d80 --- /dev/null +++ b/crates/uv/src/commands/self_uninstall.rs @@ -0,0 +1,45 @@ +use anyhow::Result; + +use crate::commands::cache_clean; +use crate::commands::ExitStatus; +use crate::printer::Printer; +use std::env; +use uv_cache::rm_rf; +use uv_cache::Cache; +use uv_python::managed::ManagedPythonInstallations; +use uv_tool::InstalledTools; + +pub(crate) fn self_uninstall( + cache: &Cache, + printer: Printer, + remove_data: bool, +) -> Result { + if remove_data { + // uv cache clean + cache_clean(&[], cache, printer)?; + + // rm -r "$(uv python dir)" + let installed_toolchains = ManagedPythonInstallations::from_settings(None)?; + let python_directory = installed_toolchains.root(); + rm_rf(python_directory)?; + + // rm -r "$(uv tool dir)" + let installed_tools = InstalledTools::from_settings()?; + let tools_path = installed_tools.root(); + rm_rf(tools_path)?; + } + + // Remove uv and uvx binaries + // rm ~/.local/bin/uv ~/.local/bin/uvx + + let uv_executable = env::current_exe().unwrap(); + let uv_path = uv_executable.as_path(); + // We assume uvx executable is in same directory as uv executable + let uvx_executable = uv_path.with_file_name(format!("uvx{}", std::env::consts::EXE_SUFFIX)); + let uvx_path = uvx_executable.as_path(); + + rm_rf(uv_path)?; + rm_rf(uvx_path)?; + + Ok(ExitStatus::Success) +} diff --git a/crates/uv/src/lib.rs b/crates/uv/src/lib.rs index e63eee833b00..a9d8e94f3e8d 100644 --- a/crates/uv/src/lib.rs +++ b/crates/uv/src/lib.rs @@ -24,7 +24,7 @@ use uv_cli::{ }; use uv_cli::{PythonCommand, PythonNamespace, ToolCommand, ToolNamespace, TopLevelArgs}; #[cfg(feature = "self-update")] -use uv_cli::{SelfCommand, SelfNamespace, SelfUpdateArgs}; +use uv_cli::{SelfCommand, SelfNamespace, SelfUninstallArgs, SelfUpdateArgs}; use uv_fs::{Simplified, CWD}; use uv_requirements::RequirementsSource; use uv_scripts::{Pep723Error, Pep723Item, Pep723Metadata, Pep723Script}; @@ -910,10 +910,14 @@ async fn run(mut cli: Cli) -> Result { token, }), }) => commands::self_update(target_version, token, printer).await, + #[cfg(feature = "self-update")] + Commands::Self_(SelfNamespace { + command: SelfCommand::Uninstall(SelfUninstallArgs { remove_data }), + }) => commands::self_uninstall(&cache, printer, remove_data), #[cfg(not(feature = "self-update"))] Commands::Self_(_) => { anyhow::bail!( - "uv was installed through an external package manager, and self-update \ + "uv was installed through an external package manager, and self {{update,uninstall}} \ is not available. Please use your package manager to update uv." ); } diff --git a/docs/reference/cli.md b/docs/reference/cli.md index 18f2fb04b3cd..4fc75041bcf8 100644 --- a/docs/reference/cli.md +++ b/docs/reference/cli.md @@ -9102,6 +9102,8 @@ uv self [OPTIONS]
uv self update

Update uv

+
uv self uninstall

Uninstall uv

+
### uv self update @@ -9230,6 +9232,125 @@ uv self update [OPTIONS] [TARGET_VERSION] +### uv self uninstall + +Uninstall uv + +

Usage

+ +``` +uv self uninstall [OPTIONS] +``` + +

Options

+ +
--allow-insecure-host allow-insecure-host

Allow insecure connections to a host.

+ +

Can be provided multiple times.

+ +

Expects to receive either a hostname (e.g., localhost), a host-port pair (e.g., localhost:8080), or a URL (e.g., https://localhost).

+ +

WARNING: Hosts included in this list will not be verified against the system’s certificate store. Only use --allow-insecure-host in a secure network with verified sources, as it bypasses SSL verification and could expose you to MITM attacks.

+ +

May also be set with the UV_INSECURE_HOST environment variable.

+
--cache-dir cache-dir

Path to the cache directory.

+ +

Defaults to $XDG_CACHE_HOME/uv or $HOME/.cache/uv on macOS and Linux, and %LOCALAPPDATA%\uv\cache on Windows.

+ +

To view the location of the cache directory, run uv cache dir.

+ +

May also be set with the UV_CACHE_DIR environment variable.

+
--color color-choice

Control the use of color in output.

+ +

By default, uv will automatically detect support for colors when writing to a terminal.

+ +

Possible values:

+ +
    +
  • auto: Enables colored output only when the output is going to a terminal or TTY with support
  • + +
  • always: Enables colored output regardless of the detected environment
  • + +
  • never: Disables colored output
  • +
+
--config-file config-file

The path to a uv.toml file to use for configuration.

+ +

While uv configuration can be included in a pyproject.toml file, it is not allowed in this context.

+ +

May also be set with the UV_CONFIG_FILE environment variable.

+
--directory directory

Change to the given directory prior to running the command.

+ +

Relative paths are resolved with the given directory as the base.

+ +

See --project to only change the project root directory.

+ +
--help, -h

Display the concise help for this command

+ +
--native-tls

Whether to load TLS certificates from the platform’s native certificate store.

+ +

By default, uv loads certificates from the bundled webpki-roots crate. The webpki-roots are a reliable set of trust roots from Mozilla, and including them in uv improves portability and performance (especially on macOS).

+ +

However, in some cases, you may want to use the platform’s native certificate store, especially if you’re relying on a corporate trust root (e.g., for a mandatory proxy) that’s included in your system’s certificate store.

+ +

May also be set with the UV_NATIVE_TLS environment variable.

+
--no-cache, -n

Avoid reading from or writing to the cache, instead using a temporary directory for the duration of the operation

+ +

May also be set with the UV_NO_CACHE environment variable.

+
--no-config

Avoid discovering configuration files (pyproject.toml, uv.toml).

+ +

Normally, configuration files are discovered in the current directory, parent directories, or user configuration directories.

+ +

May also be set with the UV_NO_CONFIG environment variable.

+
--no-progress

Hide all progress outputs.

+ +

For example, spinners or progress bars.

+ +

May also be set with the UV_NO_PROGRESS environment variable.

+
--no-python-downloads

Disable automatic downloads of Python.

+ +
--offline

Disable network access.

+ +

When disabled, uv will only use locally cached data and locally available files.

+ +

May also be set with the UV_OFFLINE environment variable.

+
--project project

Run the command within the given project directory.

+ +

All pyproject.toml, uv.toml, and .python-version files will be discovered by walking up the directory tree from the project root, as will the project’s virtual environment (.venv).

+ +

Other command-line arguments (such as relative paths) will be resolved relative to the current working directory.

+ +

See --directory to change the working directory entirely.

+ +

This setting has no effect when used in the uv pip interface.

+ +
--python-preference python-preference

Whether to prefer uv-managed or system Python installations.

+ +

By default, uv prefers using Python versions it manages. However, it will use system Python installations if a uv-managed Python is not installed. This option allows prioritizing or ignoring system Python installations.

+ +

May also be set with the UV_PYTHON_PREFERENCE environment variable.

+

Possible values:

+ +
    +
  • only-managed: Only use managed Python installations; never use system Python installations
  • + +
  • managed: Prefer managed Python installations over system Python installations
  • + +
  • system: Prefer system Python installations over managed Python installations
  • + +
  • only-system: Only use system Python installations; never use managed Python installations
  • +
+
--quiet, -q

Do not print any output

+ +
--remove-data

true iff should run uv cache clean and remove directories pointed to by uv python dir and uv tool dir

+ +
--verbose, -v

Use verbose output.

+ +

You can configure fine-grained logging using the RUST_LOG environment variable. (<https://docs.rs/tracing-subscriber/latest/tracing_subscriber/filter/struct.EnvFilter.html#directives>)

+ +
--version, -V

Display the uv version

+ +
+ ## uv version Display uv's version