mirror of https://github.com/astral-sh/uv
During lockfile validation, check for URL match regardless of trailing slash
This commit is contained in:
parent
c5cd30d2bb
commit
08025b0967
|
|
@ -169,26 +169,6 @@ impl UrlString {
|
||||||
.map(|(path, _)| Cow::Owned(UrlString(SmallString::from(path))))
|
.map(|(path, _)| Cow::Owned(UrlString(SmallString::from(path))))
|
||||||
.unwrap_or(Cow::Borrowed(self))
|
.unwrap_or(Cow::Borrowed(self))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return the [`UrlString`] (as a [`Cow`]) with trailing slash removed.
|
|
||||||
///
|
|
||||||
/// This matches the semantics of [`Url::pop_if_empty`], which will not trim a trailing slash if
|
|
||||||
/// it's the only path segment, e.g., `https://example.com/` would be unchanged.
|
|
||||||
#[must_use]
|
|
||||||
pub fn without_trailing_slash(&self) -> Cow<'_, Self> {
|
|
||||||
self.as_ref()
|
|
||||||
.strip_suffix('/')
|
|
||||||
.filter(|path| {
|
|
||||||
// Only strip the trailing slash if there's _another_ trailing slash that isn't a
|
|
||||||
// part of the scheme.
|
|
||||||
path.split_once("://")
|
|
||||||
.map(|(_scheme, rest)| rest)
|
|
||||||
.unwrap_or(path)
|
|
||||||
.contains('/')
|
|
||||||
})
|
|
||||||
.map(|path| Cow::Owned(UrlString(SmallString::from(path))))
|
|
||||||
.unwrap_or(Cow::Borrowed(self))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AsRef<str> for UrlString {
|
impl AsRef<str> for UrlString {
|
||||||
|
|
@ -283,38 +263,4 @@ mod tests {
|
||||||
);
|
);
|
||||||
assert!(matches!(url.without_fragment(), Cow::Owned(_)));
|
assert!(matches!(url.without_fragment(), Cow::Owned(_)));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn without_trailing_slash() {
|
|
||||||
// Borrows a URL without a slash
|
|
||||||
let url = UrlString("https://example.com/path".into());
|
|
||||||
assert_eq!(&*url.without_trailing_slash(), &url);
|
|
||||||
assert!(matches!(url.without_trailing_slash(), Cow::Borrowed(_)));
|
|
||||||
|
|
||||||
// Removes the trailing slash if present on the URL
|
|
||||||
let url = UrlString("https://example.com/path/".into());
|
|
||||||
assert_eq!(
|
|
||||||
&*url.without_trailing_slash(),
|
|
||||||
&UrlString("https://example.com/path".into())
|
|
||||||
);
|
|
||||||
assert!(matches!(url.without_trailing_slash(), Cow::Owned(_)));
|
|
||||||
|
|
||||||
// Does not remove a trailing slash if it's the only path segment
|
|
||||||
let url = UrlString("https://example.com/".into());
|
|
||||||
assert_eq!(&*url.without_trailing_slash(), &url);
|
|
||||||
assert!(matches!(url.without_trailing_slash(), Cow::Borrowed(_)));
|
|
||||||
|
|
||||||
// Does not remove a trailing slash if it's the only path segment with a missing scheme
|
|
||||||
let url = UrlString("example.com/".into());
|
|
||||||
assert_eq!(&*url.without_trailing_slash(), &url);
|
|
||||||
assert!(matches!(url.without_trailing_slash(), Cow::Borrowed(_)));
|
|
||||||
|
|
||||||
// Removes the trailing slash when the scheme is missing
|
|
||||||
let url = UrlString("example.com/path/".into());
|
|
||||||
assert_eq!(
|
|
||||||
&*url.without_trailing_slash(),
|
|
||||||
&UrlString("example.com/path".into())
|
|
||||||
);
|
|
||||||
assert!(matches!(url.without_trailing_slash(), Cow::Owned(_)));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1455,7 +1455,7 @@ impl Lock {
|
||||||
Some(path)
|
Some(path)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.collect::<BTreeSet<_>>()
|
.collect::<Vec<_>>()
|
||||||
});
|
});
|
||||||
|
|
||||||
// Add the workspace packages to the queue.
|
// Add the workspace packages to the queue.
|
||||||
|
|
@ -1478,12 +1478,11 @@ impl Lock {
|
||||||
if let Source::Registry(index) = &package.id.source {
|
if let Source::Registry(index) = &package.id.source {
|
||||||
match index {
|
match index {
|
||||||
RegistrySource::Url(url) => {
|
RegistrySource::Url(url) => {
|
||||||
// Normalize URL before validating.
|
if remotes.as_ref().is_some_and(|remotes| {
|
||||||
let url = url.without_trailing_slash();
|
!remotes.iter().any(|remote| {
|
||||||
if remotes
|
matches!(url.as_ref().strip_prefix(remote.as_ref()), Some("" | "/"))
|
||||||
.as_ref()
|
})
|
||||||
.is_some_and(|remotes| !remotes.contains(&url))
|
}) {
|
||||||
{
|
|
||||||
let name = &package.id.name;
|
let name = &package.id.name;
|
||||||
let version = &package
|
let version = &package
|
||||||
.id
|
.id
|
||||||
|
|
@ -1493,7 +1492,7 @@ impl Lock {
|
||||||
return Ok(SatisfiesResult::MissingRemoteIndex(
|
return Ok(SatisfiesResult::MissingRemoteIndex(
|
||||||
name,
|
name,
|
||||||
version,
|
version,
|
||||||
url.into_owned(),
|
url.clone(),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue