Support file://localhost/ schemes (#2657)

## Summary

`uv` was failing to install requirements defined like:

```
file://localhost/Users/crmarsh/Downloads/iniconfig-2.0.0-py3-none-any.whl
```

Closes https://github.com/astral-sh/uv/issues/2652.
This commit is contained in:
Charlie Marsh 2024-03-25 15:23:26 -04:00 committed by GitHub
parent 7a5571fa5c
commit 8587c440fe
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 119 additions and 13 deletions

View file

@ -46,7 +46,7 @@ use uv_fs::normalize_url_path;
// Parity with the crates.io version of pep508_rs
use crate::verbatim_url::VerbatimUrlError;
pub use uv_normalize::{ExtraName, InvalidNameError, PackageName};
pub use verbatim_url::{expand_env_vars, split_scheme, Scheme, VerbatimUrl};
pub use verbatim_url::{expand_env_vars, split_scheme, strip_host, Scheme, VerbatimUrl};
mod marker;
mod verbatim_url;
@ -1018,9 +1018,10 @@ fn preprocess_url(
if let Some((scheme, path)) = split_scheme(&expanded) {
match Scheme::parse(scheme) {
// Ex) `file:///home/ferris/project/scripts/...` or `file:../editable/`.
// Ex) `file:///home/ferris/project/scripts/...`, `file://localhost/home/ferris/project/scripts/...`, or `file:../ferris/`
Some(Scheme::File) => {
let path = path.strip_prefix("//").unwrap_or(path);
// Strip the leading slashes, along with the `localhost` host, if present.
let path = strip_host(path);
// Transform, e.g., `/C:/Users/ferris/wheel-0.42.0.tar.gz` to `C:\Users\ferris\wheel-0.42.0.tar.gz`.
let path = normalize_url_path(path);
@ -1156,9 +1157,10 @@ fn preprocess_unnamed_url(
if let Some((scheme, path)) = split_scheme(&expanded) {
match Scheme::parse(scheme) {
// Ex) `file:///home/ferris/project/scripts/...` or `file:../editable/`.
// Ex) `file:///home/ferris/project/scripts/...`, `file://localhost/home/ferris/project/scripts/...`, or `file:../ferris/`
Some(Scheme::File) => {
let path = path.strip_prefix("//").unwrap_or(path);
// Strip the leading slashes, along with the `localhost` host, if present.
let path = strip_host(path);
// Transform, e.g., `/C:/Users/ferris/wheel-0.42.0.tar.gz` to `C:\Users\ferris\wheel-0.42.0.tar.gz`.
let path = normalize_url_path(path);

View file

@ -264,6 +264,24 @@ pub fn split_scheme(s: &str) -> Option<(&str, &str)> {
Some((scheme, rest))
}
/// Strip the `file://localhost/` host from a file path.
pub fn strip_host(path: &str) -> &str {
// Ex) `file://localhost/...`.
if let Some(path) = path
.strip_prefix("//localhost")
.filter(|path| path.starts_with('/'))
{
return path;
}
// Ex) `file:///...`.
if let Some(path) = path.strip_prefix("//") {
return path;
}
path
}
/// Split the fragment from a URL.
///
/// For example, given `file:///home/ferris/project/scripts#hash=somehash`, returns