Skip to content

Commit c749923

Browse files
committed
🔧 add --install-dir arg to uv python commands
1 parent 172bff4 commit c749923

File tree

6 files changed

+51
-8
lines changed

6 files changed

+51
-8
lines changed

crates/uv-cli/src/lib.rs

+10
Original file line numberDiff line numberDiff line change
@@ -3559,6 +3559,11 @@ pub struct PythonListArgs {
35593559
#[derive(Args)]
35603560
#[allow(clippy::struct_excessive_bools)]
35613561
pub struct PythonInstallArgs {
3562+
/// The directory where Python will be installed.
3563+
///
3564+
#[arg(long, short, env = "UV_PYTHON_INSTALL_DIR")]
3565+
pub install_dir: Option<PathBuf>,
3566+
35623567
/// The Python version(s) to install.
35633568
///
35643569
/// If not provided, the requested Python version(s) will be read from the
@@ -3580,6 +3585,11 @@ pub struct PythonInstallArgs {
35803585
#[derive(Args)]
35813586
#[allow(clippy::struct_excessive_bools)]
35823587
pub struct PythonUninstallArgs {
3588+
/// The directory where Python is installed.
3589+
///
3590+
#[arg(long, short, env = "UV_PYTHON_INSTALL_DIR")]
3591+
pub install_dir: Option<PathBuf>,
3592+
35833593
/// The Python version(s) to uninstall.
35843594
///
35853595
/// See `uv help python` to view supported request formats.

crates/uv-python/src/managed.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ pub struct ManagedPythonInstallations {
6565

6666
impl ManagedPythonInstallations {
6767
/// A directory for Python installations at `root`.
68-
fn from_path(root: impl Into<PathBuf>) -> Self {
68+
pub fn from_path(root: impl Into<PathBuf>) -> Self {
6969
Self { root: root.into() }
7070
}
7171

crates/uv/src/commands/python/install.rs

+7-1
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ use crate::printer::Printer;
2121
/// Download and install Python versions.
2222
pub(crate) async fn install(
2323
project_dir: &Path,
24+
install_dir: Option<&Path>,
2425
targets: Vec<String>,
2526
reinstall: bool,
2627
python_downloads: PythonDownloads,
@@ -31,7 +32,12 @@ pub(crate) async fn install(
3132
) -> Result<ExitStatus> {
3233
let start = std::time::Instant::now();
3334

34-
let installations = ManagedPythonInstallations::from_settings()?.init()?;
35+
let installations = if let Some(install_dir) = install_dir {
36+
ManagedPythonInstallations::from_path(install_dir)
37+
} else {
38+
ManagedPythonInstallations::from_settings()?
39+
}
40+
.init()?;
3541
let installations_dir = installations.root();
3642
let cache_dir = installations.cache();
3743
let _lock = installations.lock().await?;

crates/uv/src/commands/python/uninstall.rs

+8-1
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,22 @@ use uv_python::PythonRequest;
1414
use crate::commands::python::{ChangeEvent, ChangeEventKind};
1515
use crate::commands::{elapsed, ExitStatus};
1616
use crate::printer::Printer;
17+
use std::path::Path;
1718

1819
/// Uninstall managed Python versions.
1920
pub(crate) async fn uninstall(
21+
install_dir: Option<&Path>,
2022
targets: Vec<String>,
2123
all: bool,
2224

2325
printer: Printer,
2426
) -> Result<ExitStatus> {
25-
let installations = ManagedPythonInstallations::from_settings()?.init()?;
27+
let installations = if let Some(install_dir) = install_dir {
28+
ManagedPythonInstallations::from_path(install_dir)
29+
} else {
30+
ManagedPythonInstallations::from_settings()?.init()?
31+
};
32+
2633
let _lock = installations.lock().await?;
2734

2835
// Perform the uninstallation.

crates/uv/src/lib.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -1016,6 +1016,7 @@ async fn run(cli: Cli) -> Result<ExitStatus> {
10161016

10171017
commands::python_install(
10181018
&project_dir,
1019+
args.install_dir.as_deref(),
10191020
args.targets,
10201021
args.reinstall,
10211022
globals.python_downloads,
@@ -1033,7 +1034,8 @@ async fn run(cli: Cli) -> Result<ExitStatus> {
10331034
let args = settings::PythonUninstallSettings::resolve(args, filesystem);
10341035
show_settings!(args);
10351036

1036-
commands::python_uninstall(args.targets, args.all, printer).await
1037+
commands::python_uninstall(args.install_dir.as_deref(), args.targets, args.all, printer)
1038+
.await
10371039
}
10381040
Commands::Python(PythonNamespace {
10391041
command: PythonCommand::Find(args),

crates/uv/src/settings.rs

+22-4
Original file line numberDiff line numberDiff line change
@@ -585,6 +585,7 @@ impl PythonListSettings {
585585
#[allow(clippy::struct_excessive_bools)]
586586
#[derive(Debug, Clone)]
587587
pub(crate) struct PythonInstallSettings {
588+
pub(crate) install_dir: Option<PathBuf>,
588589
pub(crate) targets: Vec<String>,
589590
pub(crate) reinstall: bool,
590591
}
@@ -593,16 +594,25 @@ impl PythonInstallSettings {
593594
/// Resolve the [`PythonInstallSettings`] from the CLI and filesystem configuration.
594595
#[allow(clippy::needless_pass_by_value)]
595596
pub(crate) fn resolve(args: PythonInstallArgs, _filesystem: Option<FilesystemOptions>) -> Self {
596-
let PythonInstallArgs { targets, reinstall } = args;
597+
let PythonInstallArgs {
598+
install_dir,
599+
targets,
600+
reinstall,
601+
} = args;
597602

598-
Self { targets, reinstall }
603+
Self {
604+
install_dir,
605+
targets,
606+
reinstall,
607+
}
599608
}
600609
}
601610

602611
/// The resolved settings to use for a `python uninstall` invocation.
603612
#[allow(clippy::struct_excessive_bools)]
604613
#[derive(Debug, Clone)]
605614
pub(crate) struct PythonUninstallSettings {
615+
pub(crate) install_dir: Option<PathBuf>,
606616
pub(crate) targets: Vec<String>,
607617
pub(crate) all: bool,
608618
}
@@ -614,9 +624,17 @@ impl PythonUninstallSettings {
614624
args: PythonUninstallArgs,
615625
_filesystem: Option<FilesystemOptions>,
616626
) -> Self {
617-
let PythonUninstallArgs { targets, all } = args;
627+
let PythonUninstallArgs {
628+
install_dir,
629+
targets,
630+
all,
631+
} = args;
618632

619-
Self { targets, all }
633+
Self {
634+
install_dir,
635+
targets,
636+
all,
637+
}
620638
}
621639
}
622640

0 commit comments

Comments
 (0)