diff --git a/crates/uv/src/commands/tool/install.rs b/crates/uv/src/commands/tool/install.rs index a2a3338e2..26f3d981b 100644 --- a/crates/uv/src/commands/tool/install.rs +++ b/crates/uv/src/commands/tool/install.rs @@ -200,6 +200,13 @@ pub(crate) async fn install( }) .collect::>(); + if target_entry_points.is_empty() { + // Clean up the environment we just created + installed_tools.remove_environment(&name)?; + + bail!("No entry points found for tool `{name}`"); + } + // Check if they exist, before installing let mut existing_entry_points = target_entry_points .iter() @@ -232,7 +239,6 @@ pub(crate) async fn install( ) } - // TODO(zanieb): Handle the case where there are no entrypoints for (name, source_path, target_path) in &target_entry_points { debug!("Installing `{name}`"); #[cfg(unix)] @@ -250,7 +256,7 @@ pub(crate) async fn install( .join(", ") )?; - debug!("Adding receipt for tool `{name}`",); + debug!("Adding receipt for tool `{name}`"); let installed_tools = installed_tools.init()?; let tool = Tool::new( requirements, diff --git a/crates/uv/tests/tool_install.rs b/crates/uv/tests/tool_install.rs index db663b885..8989d28d2 100644 --- a/crates/uv/tests/tool_install.rs +++ b/crates/uv/tests/tool_install.rs @@ -858,3 +858,28 @@ fn tool_install_xdg_bin_home() { .child(format!("black{}", std::env::consts::EXE_SUFFIX)) .assert(predicate::path::exists()); } + +/// Test installing a tool that lacks entrypoints +#[test] +fn tool_install_no_entrypoints() { + let context = TestContext::new("3.12").with_filtered_exe_suffix(); + let tool_dir = context.temp_dir.child("tools"); + let bin_dir = context.temp_dir.child("bin"); + + uv_snapshot!(context.filters(), context.tool_install() + .arg("iniconfig") + .env("UV_TOOL_DIR", tool_dir.as_os_str()) + .env("XDG_BIN_HOME", bin_dir.as_os_str()), @r###" + success: false + exit_code: 2 + ----- stdout ----- + + ----- stderr ----- + warning: `uv tool install` is experimental and may change without warning. + Resolved 1 package in [TIME] + Prepared 1 package in [TIME] + Installed 1 package in [TIME] + + iniconfig==2.0.0 + error: No entry points found for tool `iniconfig` + "###); +}