From 3bf530775e17b89a2bbb583fef819e8a9f327abe Mon Sep 17 00:00:00 2001 From: Haydn Evans Date: Fri, 13 Sep 2024 11:15:50 +0200 Subject: [PATCH] add ability to load from .env files before invoking the command --- Cargo.lock | 7 +++++++ Cargo.toml | 1 + crates/uv-cli/src/lib.rs | 6 ++++++ crates/uv/Cargo.toml | 1 + crates/uv/src/commands/project/run.rs | 10 ++++++++++ crates/uv/src/lib.rs | 1 + crates/uv/src/settings.rs | 3 +++ docs/configuration/environment.md | 3 +++ docs/reference/cli.md | 5 +++++ 9 files changed, 37 insertions(+) diff --git a/Cargo.lock b/Cargo.lock index 71edd66e8d69d..d0f94a8f66a9e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1038,6 +1038,12 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10" +[[package]] +name = "dotenvy" +version = "0.15.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b" + [[package]] name = "dunce" version = "1.0.5" @@ -4456,6 +4462,7 @@ dependencies = [ "ctrlc", "distribution-filename", "distribution-types", + "dotenvy", "etcetera", "filetime", "flate2", diff --git a/Cargo.toml b/Cargo.toml index 09163af86cf9b..4115c449fb24f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -85,6 +85,7 @@ directories = { version = "5.0.1" } dirs-sys = { version = "0.4.1" } dunce = { version = "1.0.5" } either = { version = "1.13.0" } +dotenvy = { version = "0.15.7" } encoding_rs_io = { version = "0.1.7" } etcetera = { version = "0.8.0" } flate2 = { version = "1.0.33", default-features = false } diff --git a/crates/uv-cli/src/lib.rs b/crates/uv-cli/src/lib.rs index e9515a9e1262a..8165a87a25559 100644 --- a/crates/uv-cli/src/lib.rs +++ b/crates/uv-cli/src/lib.rs @@ -2527,6 +2527,12 @@ pub struct RunArgs { /// By default, environment modifications are omitted, but enabled under `--verbose`. #[arg(long, env = "UV_SHOW_RESOLUTION", value_parser = clap::builder::BoolishValueParser::new(), hide = true)] pub show_resolution: bool, + + /// Run the command and load environment variables from the `.env` file in the current project. + /// + /// By default, the .env file is not loaded. + #[arg(long, env = "UV_RUN_LOAD_DOTENV")] + pub load_dotenv: bool, } #[derive(Args)] diff --git a/crates/uv/Cargo.toml b/crates/uv/Cargo.toml index b0d49bc402dda..e0e5126a24dbc 100644 --- a/crates/uv/Cargo.toml +++ b/crates/uv/Cargo.toml @@ -52,6 +52,7 @@ anyhow = { workspace = true } axoupdater = { workspace = true, features = ["github_releases", "tokio"], optional = true } clap = { workspace = true, features = ["derive", "string", "wrap_help"] } ctrlc = { workspace = true } +dotenvy = { workspace = true } flate2 = { workspace = true, default-features = false } fs-err = { workspace = true, features = ["tokio"] } futures = { workspace = true } diff --git a/crates/uv/src/commands/project/run.rs b/crates/uv/src/commands/project/run.rs index cbecf373abda3..4ea85ed1a016d 100644 --- a/crates/uv/src/commands/project/run.rs +++ b/crates/uv/src/commands/project/run.rs @@ -43,6 +43,7 @@ use crate::commands::reporters::PythonDownloadReporter; use crate::commands::{project, ExitStatus, SharedState}; use crate::printer::Printer; use crate::settings::ResolverInstallerSettings; +use dotenvy::dotenv_override; /// Run a command. #[allow(clippy::fn_params_excessive_bools)] @@ -63,6 +64,7 @@ pub(crate) async fn run( editable: EditableMode, python: Option, settings: ResolverInstallerSettings, + load_dotenv: bool, python_preference: PythonPreference, python_downloads: PythonDownloads, connectivity: Connectivity, @@ -703,6 +705,14 @@ pub(crate) async fn run( debug!("Running `{command}`"); let mut process = command.as_command(interpreter); + // Load the `.env` into the environment if the flag or ENV is set. + // This is done before setting the PATH or VIRTUAL_ENV environment variables + // to ensure they are not overwritten + if load_dotenv { + debug!("Loading `.env` file"); + dotenv_override().ok(); + }; + // Construct the `PATH` environment variable. let new_path = std::env::join_paths( ephemeral_env diff --git a/crates/uv/src/lib.rs b/crates/uv/src/lib.rs index 80b788ec25782..09b2ab894507b 100644 --- a/crates/uv/src/lib.rs +++ b/crates/uv/src/lib.rs @@ -1168,6 +1168,7 @@ async fn run_project( args.editable, args.python, args.settings, + args.load_dotenv, globals.python_preference, globals.python_downloads, globals.connectivity, diff --git a/crates/uv/src/settings.rs b/crates/uv/src/settings.rs index c7d1eb626825d..75ccc3412d84c 100644 --- a/crates/uv/src/settings.rs +++ b/crates/uv/src/settings.rs @@ -222,6 +222,7 @@ pub(crate) struct RunSettings { pub(crate) python: Option, pub(crate) refresh: Refresh, pub(crate) settings: ResolverInstallerSettings, + pub(crate) load_dotenv: bool, } impl RunSettings { @@ -251,6 +252,7 @@ impl RunSettings { no_project, python, show_resolution, + load_dotenv, } = args; Self { @@ -279,6 +281,7 @@ impl RunSettings { resolver_installer_options(installer, build), filesystem, ), + load_dotenv, } } } diff --git a/docs/configuration/environment.md b/docs/configuration/environment.md index 9cb1142db78cb..a57762ea37f0d 100644 --- a/docs/configuration/environment.md +++ b/docs/configuration/environment.md @@ -63,6 +63,9 @@ uv accepts the following command-line arguments as environment variables: `--no-python-downloads` option. Whether uv should allow Python downloads. - `UV_COMPILE_BYTECODE`: Equivalent to the `--compile-bytecode` command-line argument. If set, uv will compile Python source files to bytecode after installation. +- `UV_RUN_LOAD_DOTENV`: Equivalent to the `--load-dotenv` command-line argument. If set, `uv run` + will load the .env file from the current project directory (if it exists) to load all ENVs into + the current process. In each case, the corresponding command-line argument takes precedence over an environment variable. diff --git a/docs/reference/cli.md b/docs/reference/cli.md index a7ee29fd49826..31f1467845da0 100644 --- a/docs/reference/cli.md +++ b/docs/reference/cli.md @@ -205,6 +205,11 @@ uv run [OPTIONS]
  • symlink: Symbolically link packages from the wheel into the site-packages directory
  • +
    --load-dotenv

    Run the command and load environment variables from the .env file in the current project.

    + +

    By default, the .env file is not loaded.

    + +

    May also be set with the UV_RUN_LOAD_DOTENV environment variable.

    --locked

    Assert that the uv.lock will remain unchanged.

    Requires that the lockfile is up-to-date. If the lockfile is missing or needs to be updated, uv will exit with an error.