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))))
|
||||
.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 {
|
||||
|
|
@ -283,38 +263,4 @@ mod tests {
|
|||
);
|
||||
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)
|
||||
}
|
||||
})
|
||||
.collect::<BTreeSet<_>>()
|
||||
.collect::<Vec<_>>()
|
||||
});
|
||||
|
||||
// Add the workspace packages to the queue.
|
||||
|
|
@ -1478,12 +1478,11 @@ impl Lock {
|
|||
if let Source::Registry(index) = &package.id.source {
|
||||
match index {
|
||||
RegistrySource::Url(url) => {
|
||||
// Normalize URL before validating.
|
||||
let url = url.without_trailing_slash();
|
||||
if remotes
|
||||
.as_ref()
|
||||
.is_some_and(|remotes| !remotes.contains(&url))
|
||||
{
|
||||
if remotes.as_ref().is_some_and(|remotes| {
|
||||
!remotes.iter().any(|remote| {
|
||||
matches!(url.as_ref().strip_prefix(remote.as_ref()), Some("" | "/"))
|
||||
})
|
||||
}) {
|
||||
let name = &package.id.name;
|
||||
let version = &package
|
||||
.id
|
||||
|
|
@ -1493,7 +1492,7 @@ impl Lock {
|
|||
return Ok(SatisfiesResult::MissingRemoteIndex(
|
||||
name,
|
||||
version,
|
||||
url.into_owned(),
|
||||
url.clone(),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue