Add a reusable path-or-URL parser (#14712)

Reviewing #14687, I noticed that we had implemented a
`Url::from_url_or_path`-like function, but it wasn't reusable. This
change `Verbatim::from_url_or_path` so we can use it in other places
too.

The PEP 508 parser is an odd place for this, but that's where
`VerbatimUrl` and `Scheme` are already living.
This commit is contained in:
konsti
2025-07-18 14:08:49 +02:00
committed by GitHub
parent 327c2bcd8a
commit 8f2f43c561
2 changed files with 48 additions and 27 deletions
+2 -27
View File
@@ -39,33 +39,8 @@ impl IndexUrl {
/// If no root directory is provided, relative paths are resolved against the current working
/// directory.
pub fn parse(path: &str, root_dir: Option<&Path>) -> Result<Self, IndexUrlError> {
let url = match split_scheme(path) {
Some((scheme, ..)) => {
match Scheme::parse(scheme) {
Some(_) => {
// Ex) `https://pypi.org/simple`
VerbatimUrl::parse_url(path)?
}
None => {
// Ex) `C:\Users\user\index`
if let Some(root_dir) = root_dir {
VerbatimUrl::from_path(path, root_dir)?
} else {
VerbatimUrl::from_absolute_path(std::path::absolute(path)?)?
}
}
}
}
None => {
// Ex) `/Users/user/index`
if let Some(root_dir) = root_dir {
VerbatimUrl::from_path(path, root_dir)?
} else {
VerbatimUrl::from_absolute_path(std::path::absolute(path)?)?
}
}
};
Ok(Self::from(url.with_given(path)))
let url = VerbatimUrl::from_url_or_path(path, root_dir)?;
Ok(Self::from(url))
}
/// Return the root [`Url`] of the index, if applicable.
+46
View File
@@ -58,6 +58,48 @@ impl VerbatimUrl {
})
}
/// Convert a [`VerbatimUrl`] from a path or a URL.
///
/// If no root directory is provided, relative paths are resolved against the current working
/// directory.
pub fn from_url_or_path(
input: &str,
root_dir: Option<&Path>,
) -> Result<Self, VerbatimUrlError> {
let url = match split_scheme(input) {
Some((scheme, ..)) => {
match Scheme::parse(scheme) {
Some(_) => {
// Ex) `https://pypi.org/simple`
Self::parse_url(input)?
}
None => {
// Ex) `C:\Users\user\index`
if let Some(root_dir) = root_dir {
Self::from_path(input, root_dir)?
} else {
let absolute_path = std::path::absolute(input).map_err(|err| {
VerbatimUrlError::Absolute(input.to_string(), err)
})?;
Self::from_absolute_path(absolute_path)?
}
}
}
}
None => {
// Ex) `/Users/user/index`
if let Some(root_dir) = root_dir {
Self::from_path(input, root_dir)?
} else {
let absolute_path = std::path::absolute(input)
.map_err(|err| VerbatimUrlError::Absolute(input.to_string(), err))?;
Self::from_absolute_path(absolute_path)?
}
}
};
Ok(url.with_given(input))
}
/// Parse a URL from an absolute or relative path.
#[cfg(feature = "non-pep508-extensions")] // PEP 508 arguably only allows absolute file URLs.
pub fn from_path(
@@ -362,6 +404,10 @@ pub enum VerbatimUrlError {
#[error("path could not be normalized: {0}")]
Normalization(PathBuf, #[source] std::io::Error),
/// Received a path that could not be converted to an absolute path.
#[error("path could not be converted to an absolute path: {0}")]
Absolute(String, #[source] std::io::Error),
/// Received a path that could not be normalized.
#[cfg(not(feature = "non-pep508-extensions"))]
#[error("Not a URL (missing scheme): {0}")]