mirror of
https://github.com/astral-sh/uv.git
synced 2025-08-04 19:08:04 +00:00
Expand environment variables in URLs (#640)
## Summary This PR enables users to express relative dependencies via environment variables. Like pip, PDM, Hatch, Rye, and others, we now allow users to express dependencies like: ```text flask @ file://${PROJECT_ROOT}/flask-3.0.0-py3-none-any.whl ``` In the compiled requirements file, we'll also preserve the unexpanded environment variable. Closes https://github.com/astral-sh/puffin/issues/592.
This commit is contained in:
parent
ed8dfbfcf7
commit
22c7057b35
2 changed files with 99 additions and 2 deletions
|
@ -1,4 +1,8 @@
|
|||
use std::borrow::Cow;
|
||||
use std::ops::Deref;
|
||||
|
||||
use once_cell::sync::Lazy;
|
||||
use regex::Regex;
|
||||
use url::Url;
|
||||
|
||||
/// A wrapper around [`Url`] that preserves the original string.
|
||||
|
@ -14,9 +18,9 @@ pub struct VerbatimUrl {
|
|||
}
|
||||
|
||||
impl VerbatimUrl {
|
||||
/// Parse a URL from a string.
|
||||
/// Parse a URL from a string, expanding any environment variables.
|
||||
pub fn parse(given: String) -> Result<Self, Error> {
|
||||
let url = Url::parse(&given)?;
|
||||
let url = Url::parse(&expand_env_vars(&given))?;
|
||||
Ok(Self {
|
||||
given: Some(given),
|
||||
url,
|
||||
|
@ -73,3 +77,38 @@ pub enum Error {
|
|||
#[error(transparent)]
|
||||
Url(#[from] url::ParseError),
|
||||
}
|
||||
|
||||
/// Expand all available environment variables.
|
||||
///
|
||||
/// This is modeled off of pip's environment variable expansion, which states:
|
||||
///
|
||||
/// The only allowed format for environment variables defined in the
|
||||
/// requirement file is `${MY_VARIABLE_1}` to ensure two things:
|
||||
///
|
||||
/// 1. Strings that contain a `$` aren't accidentally (partially) expanded.
|
||||
/// 2. Ensure consistency across platforms for requirement files.
|
||||
///
|
||||
/// ...
|
||||
///
|
||||
/// Valid characters in variable names follow the `POSIX standard
|
||||
/// <http://pubs.opengroup.org/onlinepubs/9699919799/>`_ and are limited
|
||||
/// to uppercase letter, digits and the `_` (underscore).
|
||||
fn expand_env_vars(s: &str) -> Cow<'_, str> {
|
||||
// Generate a URL-escaped project root, to be used via the `${PROJECT_ROOT}`
|
||||
// environment variable. Ensure that it's URL-escaped.
|
||||
static PROJECT_ROOT_FRAGMENT: Lazy<String> = Lazy::new(|| {
|
||||
let project_root = std::env::current_dir().unwrap();
|
||||
project_root.to_string_lossy().replace(' ', "%20")
|
||||
});
|
||||
|
||||
static RE: Lazy<Regex> =
|
||||
Lazy::new(|| Regex::new(r"(?P<var>\$\{(?P<name>[A-Z0-9_]+)})").unwrap());
|
||||
|
||||
RE.replace_all(s, |caps: ®ex::Captures<'_>| {
|
||||
let name = caps.name("name").unwrap().as_str();
|
||||
std::env::var(name).unwrap_or_else(|_| match name {
|
||||
"PROJECT_ROOT" => PROJECT_ROOT_FRAGMENT.clone(),
|
||||
_ => caps["var"].to_owned(),
|
||||
})
|
||||
})
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue