mirror of https://github.com/astral-sh/uv
Improve interface
This commit is contained in:
parent
f7a6359663
commit
c5cd30d2bb
|
|
@ -990,7 +990,7 @@ fn parse_find_links(input: &str) -> Result<Maybe<PipFindLinks>, String> {
|
|||
if input.is_empty() {
|
||||
Ok(Maybe::None)
|
||||
} else {
|
||||
IndexUrl::parse_preserving_trailing_slash(input)
|
||||
IndexUrl::parse_find_links(input)
|
||||
.map(Index::from_find_links)
|
||||
.map(|index| Index {
|
||||
origin: Some(Origin::Cli),
|
||||
|
|
|
|||
|
|
@ -222,7 +222,7 @@ impl Index {
|
|||
pub fn relative_to(mut self, root_dir: &Path) -> Result<Self, IndexUrlError> {
|
||||
if let IndexUrl::Path(ref url) = self.url {
|
||||
if let Some(given) = url.given() {
|
||||
self.url = IndexUrl::parse(given, Some(root_dir))?;
|
||||
self.url = IndexUrl::parse_simple_api(given, Some(root_dir))?;
|
||||
}
|
||||
}
|
||||
Ok(self)
|
||||
|
|
|
|||
|
|
@ -34,24 +34,24 @@ pub enum IndexUrl {
|
|||
}
|
||||
|
||||
impl IndexUrl {
|
||||
/// Parse an [`IndexUrl`] from a string, relative to an optional root directory.
|
||||
/// Parse a Simple API [`IndexUrl`] from a string, relative to an optional root directory.
|
||||
///
|
||||
/// If no root directory is provided, relative paths are resolved against the current working
|
||||
/// directory.
|
||||
///
|
||||
/// Normalizes non-file URLs by removing trailing slashes for consistency.
|
||||
pub fn parse(path: &str, root_dir: Option<&Path>) -> Result<Self, IndexUrlError> {
|
||||
Self::parse_with_trailing_slash_policy(path, root_dir, TrailingSlashPolicy::Remove)
|
||||
pub fn parse_simple_api(path: &str, root_dir: Option<&Path>) -> Result<Self, IndexUrlError> {
|
||||
Self::parse(path, root_dir, TrailingSlashPolicy::Remove)
|
||||
}
|
||||
|
||||
/// Parse an [`IndexUrl`] from a string, relative to an optional root directory.
|
||||
/// Parse a find-links [`IndexUrl`] from a string, relative to an optional root directory.
|
||||
///
|
||||
/// If no root directory is provided, relative paths are resolved against the current working
|
||||
/// directory.
|
||||
///
|
||||
/// Preserves trailing slash if present in `path`.
|
||||
pub fn parse_preserving_trailing_slash(path: &str) -> Result<Self, IndexUrlError> {
|
||||
Self::parse_with_trailing_slash_policy(path, None, TrailingSlashPolicy::Preserve)
|
||||
pub fn parse_find_links(path: &str) -> Result<Self, IndexUrlError> {
|
||||
Self::parse(path, None, TrailingSlashPolicy::Preserve)
|
||||
}
|
||||
|
||||
/// Parse an [`IndexUrl`] from a string, relative to an optional root directory.
|
||||
|
|
@ -60,7 +60,7 @@ impl IndexUrl {
|
|||
/// directory.
|
||||
///
|
||||
/// Applies trailing slash policy to non-file URLs.
|
||||
fn parse_with_trailing_slash_policy(
|
||||
fn parse(
|
||||
path: &str,
|
||||
root_dir: Option<&Path>,
|
||||
slash_policy: TrailingSlashPolicy,
|
||||
|
|
@ -91,10 +91,7 @@ impl IndexUrl {
|
|||
}
|
||||
}
|
||||
};
|
||||
Ok(Self::from_verbatim_url_with_trailing_slash_policy(
|
||||
url.with_given(path),
|
||||
slash_policy,
|
||||
))
|
||||
Ok(Self::from_verbatim_url(url.with_given(path), slash_policy))
|
||||
}
|
||||
|
||||
/// Return the root [`Url`] of the index, if applicable.
|
||||
|
|
@ -119,18 +116,21 @@ impl IndexUrl {
|
|||
Some(url)
|
||||
}
|
||||
|
||||
/// Construct an [`IndexUrl`] from a [`VerbatimUrl`], preserving a trailing
|
||||
/// Construct a Simple API [`IndexUrl`] from a [`VerbatimUrl`], removing a trailing
|
||||
/// slash if present.
|
||||
pub fn from_verbatim_url_preserving_trailing_slash(url: VerbatimUrl) -> Self {
|
||||
Self::from_verbatim_url_with_trailing_slash_policy(url, TrailingSlashPolicy::Preserve)
|
||||
pub fn from_simple_api_url(url: VerbatimUrl) -> Self {
|
||||
Self::from_verbatim_url(url, TrailingSlashPolicy::Remove)
|
||||
}
|
||||
|
||||
/// Construct a find-links [`IndexUrl`] from a [`VerbatimUrl`], preserving a trailing
|
||||
/// slash if present.
|
||||
pub fn from_find_links_url(url: VerbatimUrl) -> Self {
|
||||
Self::from_verbatim_url(url, TrailingSlashPolicy::Preserve)
|
||||
}
|
||||
|
||||
/// Construct an [`IndexUrl`] from a [`VerbatimUrl`], applying a [`TrailingSlashPolicy`]
|
||||
/// to non-file URLs.
|
||||
fn from_verbatim_url_with_trailing_slash_policy(
|
||||
mut url: VerbatimUrl,
|
||||
slash_policy: TrailingSlashPolicy,
|
||||
) -> Self {
|
||||
fn from_verbatim_url(mut url: VerbatimUrl, slash_policy: TrailingSlashPolicy) -> Self {
|
||||
if url.scheme() == "file" {
|
||||
return Self::Path(Arc::new(url));
|
||||
}
|
||||
|
|
@ -286,7 +286,7 @@ impl FromStr for IndexUrl {
|
|||
type Err = IndexUrlError;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
Self::parse(s, None)
|
||||
Self::parse_simple_api(s, None)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -322,14 +322,6 @@ impl<'de> serde::de::Deserialize<'de> for IndexUrl {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<VerbatimUrl> for IndexUrl {
|
||||
fn from(url: VerbatimUrl) -> Self {
|
||||
// Remove trailing slashes for consistency. They'll be re-added if necessary when
|
||||
// querying the Simple API.
|
||||
Self::from_verbatim_url_with_trailing_slash_policy(url, TrailingSlashPolicy::Remove)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<IndexUrl> for DisplaySafeUrl {
|
||||
fn from(index: IndexUrl) -> Self {
|
||||
match index {
|
||||
|
|
@ -790,31 +782,25 @@ mod tests {
|
|||
let verbatim_url_without_trailing_slash =
|
||||
VerbatimUrl::from_url(url_without_trailing_slash.clone());
|
||||
|
||||
// Test `From<VerbatimUrl>` implementation.
|
||||
// Test `from_verbatim_url_without_trailing_slash`.
|
||||
// Trailing slash should be removed if present.
|
||||
assert_eq!(
|
||||
IndexUrl::from(verbatim_url_with_trailing_slash.clone()).url(),
|
||||
IndexUrl::from_simple_api_url(verbatim_url_with_trailing_slash.clone()).url(),
|
||||
&url_without_trailing_slash
|
||||
);
|
||||
assert_eq!(
|
||||
IndexUrl::from(verbatim_url_without_trailing_slash.clone()).url(),
|
||||
IndexUrl::from_simple_api_url(verbatim_url_without_trailing_slash.clone()).url(),
|
||||
&url_without_trailing_slash
|
||||
);
|
||||
|
||||
// Test `from_verbatim_url_preserving_trailing_slash`.
|
||||
// Trailing slash should be preserved if present.
|
||||
assert_eq!(
|
||||
IndexUrl::from_verbatim_url_preserving_trailing_slash(
|
||||
verbatim_url_with_trailing_slash.clone()
|
||||
)
|
||||
.url(),
|
||||
IndexUrl::from_find_links_url(verbatim_url_with_trailing_slash.clone()).url(),
|
||||
&url_with_trailing_slash
|
||||
);
|
||||
assert_eq!(
|
||||
IndexUrl::from_verbatim_url_preserving_trailing_slash(
|
||||
verbatim_url_without_trailing_slash.clone()
|
||||
)
|
||||
.url(),
|
||||
IndexUrl::from_find_links_url(verbatim_url_without_trailing_slash.clone()).url(),
|
||||
&url_without_trailing_slash
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -821,8 +821,9 @@ impl TryFrom<RequirementSourceWire> for RequirementSource {
|
|||
conflict,
|
||||
} => Ok(Self::Registry {
|
||||
specifier,
|
||||
index: index
|
||||
.map(|index| IndexMetadata::from(IndexUrl::from(VerbatimUrl::from_url(index)))),
|
||||
index: index.map(|index| {
|
||||
IndexMetadata::from(IndexUrl::from_simple_api_url(VerbatimUrl::from_url(index)))
|
||||
}),
|
||||
conflict,
|
||||
}),
|
||||
RequirementSourceWire::Git { git } => {
|
||||
|
|
|
|||
|
|
@ -196,7 +196,8 @@ mod tests {
|
|||
fn test_decision_default_400() {
|
||||
let strategy = IndexStatusCodeStrategy::Default;
|
||||
let status_code = StatusCode::BAD_REQUEST;
|
||||
let index_url = IndexUrl::parse("https://internal-registry.com/simple", None).unwrap();
|
||||
let index_url =
|
||||
IndexUrl::parse_simple_api("https://internal-registry.com/simple", None).unwrap();
|
||||
let capabilities = IndexCapabilities::default();
|
||||
let decision = strategy.handle_status_code(status_code, &index_url, &capabilities);
|
||||
assert_eq!(
|
||||
|
|
@ -209,7 +210,8 @@ mod tests {
|
|||
fn test_decision_default_401() {
|
||||
let strategy = IndexStatusCodeStrategy::Default;
|
||||
let status_code = StatusCode::UNAUTHORIZED;
|
||||
let index_url = IndexUrl::parse("https://internal-registry.com/simple", None).unwrap();
|
||||
let index_url =
|
||||
IndexUrl::parse_simple_api("https://internal-registry.com/simple", None).unwrap();
|
||||
let capabilities = IndexCapabilities::default();
|
||||
let decision = strategy.handle_status_code(status_code, &index_url, &capabilities);
|
||||
assert_eq!(
|
||||
|
|
@ -224,7 +226,8 @@ mod tests {
|
|||
fn test_decision_default_403() {
|
||||
let strategy = IndexStatusCodeStrategy::Default;
|
||||
let status_code = StatusCode::FORBIDDEN;
|
||||
let index_url = IndexUrl::parse("https://internal-registry.com/simple", None).unwrap();
|
||||
let index_url =
|
||||
IndexUrl::parse_simple_api("https://internal-registry.com/simple", None).unwrap();
|
||||
let capabilities = IndexCapabilities::default();
|
||||
let decision = strategy.handle_status_code(status_code, &index_url, &capabilities);
|
||||
assert_eq!(
|
||||
|
|
@ -239,7 +242,8 @@ mod tests {
|
|||
fn test_decision_default_404() {
|
||||
let strategy = IndexStatusCodeStrategy::Default;
|
||||
let status_code = StatusCode::NOT_FOUND;
|
||||
let index_url = IndexUrl::parse("https://internal-registry.com/simple", None).unwrap();
|
||||
let index_url =
|
||||
IndexUrl::parse_simple_api("https://internal-registry.com/simple", None).unwrap();
|
||||
let capabilities = IndexCapabilities::default();
|
||||
let decision = strategy.handle_status_code(status_code, &index_url, &capabilities);
|
||||
assert_eq!(decision, IndexStatusCodeDecision::Ignore);
|
||||
|
|
@ -249,7 +253,8 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_decision_pytorch() {
|
||||
let index_url = IndexUrl::parse("https://download.pytorch.org/whl/cu118", None).unwrap();
|
||||
let index_url =
|
||||
IndexUrl::parse_simple_api("https://download.pytorch.org/whl/cu118", None).unwrap();
|
||||
let strategy = IndexStatusCodeStrategy::from_index_url(&index_url);
|
||||
let capabilities = IndexCapabilities::default();
|
||||
// Test we continue on 403 for PyTorch registry.
|
||||
|
|
@ -275,7 +280,8 @@ mod tests {
|
|||
let strategy = IndexStatusCodeStrategy::IgnoreErrorCodes {
|
||||
status_codes: status_codes.iter().copied().collect::<FxHashSet<_>>(),
|
||||
};
|
||||
let index_url = IndexUrl::parse("https://internal-registry.com/simple", None).unwrap();
|
||||
let index_url =
|
||||
IndexUrl::parse_simple_api("https://internal-registry.com/simple", None).unwrap();
|
||||
let capabilities = IndexCapabilities::default();
|
||||
// Test each ignored status code
|
||||
for status_code in status_codes {
|
||||
|
|
|
|||
|
|
@ -141,17 +141,19 @@ impl RequirementsSpecification {
|
|||
.map(Requirement::from)
|
||||
.map(NameRequirementSpecification::from)
|
||||
.collect(),
|
||||
index_url: requirements_txt.index_url.map(IndexUrl::from),
|
||||
index_url: requirements_txt
|
||||
.index_url
|
||||
.map(IndexUrl::from_simple_api_url),
|
||||
extra_index_urls: requirements_txt
|
||||
.extra_index_urls
|
||||
.into_iter()
|
||||
.map(IndexUrl::from)
|
||||
.map(IndexUrl::from_simple_api_url)
|
||||
.collect(),
|
||||
no_index: requirements_txt.no_index,
|
||||
find_links: requirements_txt
|
||||
.find_links
|
||||
.into_iter()
|
||||
.map(IndexUrl::from_verbatim_url_preserving_trailing_slash)
|
||||
.map(IndexUrl::from_find_links_url)
|
||||
.collect(),
|
||||
no_binary: requirements_txt.no_binary,
|
||||
no_build: requirements_txt.only_binary,
|
||||
|
|
|
|||
|
|
@ -1346,7 +1346,7 @@ impl PylockTomlWheel {
|
|||
};
|
||||
|
||||
let index = if let Some(index) = index {
|
||||
IndexUrl::from(VerbatimUrl::from_url(index.clone()))
|
||||
IndexUrl::from_simple_api_url(VerbatimUrl::from_url(index.clone()))
|
||||
} else {
|
||||
// Including the index is only a SHOULD in PEP 751. If it's omitted, we treat the
|
||||
// URL (less the filename) as the index. This isn't correct, but it's the best we can
|
||||
|
|
@ -1354,7 +1354,7 @@ impl PylockTomlWheel {
|
|||
// of this URL (since we cache under the hash of the index).
|
||||
let mut index = file_url.to_url().map_err(PylockTomlErrorKind::ToUrl)?;
|
||||
index.path_segments_mut().unwrap().pop();
|
||||
IndexUrl::from(VerbatimUrl::from_url(index))
|
||||
IndexUrl::from_simple_api_url(VerbatimUrl::from_url(index))
|
||||
};
|
||||
|
||||
let file = Box::new(uv_distribution_types::File {
|
||||
|
|
@ -1502,7 +1502,7 @@ impl PylockTomlSdist {
|
|||
};
|
||||
|
||||
let index = if let Some(index) = index {
|
||||
IndexUrl::from(VerbatimUrl::from_url(index.clone()))
|
||||
IndexUrl::from_simple_api_url(VerbatimUrl::from_url(index.clone()))
|
||||
} else {
|
||||
// Including the index is only a SHOULD in PEP 751. If it's omitted, we treat the
|
||||
// URL (less the filename) as the index. This isn't correct, but it's the best we can
|
||||
|
|
@ -1510,7 +1510,7 @@ impl PylockTomlSdist {
|
|||
// of this URL (since we cache under the hash of the index).
|
||||
let mut index = file_url.to_url().map_err(PylockTomlErrorKind::ToUrl)?;
|
||||
index.path_segments_mut().unwrap().pop();
|
||||
IndexUrl::from(VerbatimUrl::from_url(index))
|
||||
IndexUrl::from_simple_api_url(VerbatimUrl::from_url(index))
|
||||
};
|
||||
|
||||
let file = Box::new(uv_distribution_types::File {
|
||||
|
|
|
|||
|
|
@ -2521,7 +2521,7 @@ impl Package {
|
|||
yanked: None,
|
||||
});
|
||||
|
||||
let index = IndexUrl::from(VerbatimUrl::from_url(
|
||||
let index = IndexUrl::from_simple_api_url(VerbatimUrl::from_url(
|
||||
url.to_url().map_err(LockErrorKind::InvalidUrl)?,
|
||||
));
|
||||
|
||||
|
|
@ -2595,7 +2595,7 @@ impl Package {
|
|||
yanked: None,
|
||||
});
|
||||
|
||||
let index = IndexUrl::from(
|
||||
let index = IndexUrl::from_simple_api_url(
|
||||
VerbatimUrl::from_absolute_path(workspace_root.join(path))
|
||||
.map_err(LockErrorKind::RegistryVerbatimUrl)?,
|
||||
);
|
||||
|
|
@ -2808,13 +2808,13 @@ impl Package {
|
|||
pub fn index(&self, root: &Path) -> Result<Option<IndexUrl>, LockError> {
|
||||
match &self.id.source {
|
||||
Source::Registry(RegistrySource::Url(url)) => {
|
||||
let index = IndexUrl::from(VerbatimUrl::from_url(
|
||||
let index = IndexUrl::from_simple_api_url(VerbatimUrl::from_url(
|
||||
url.to_url().map_err(LockErrorKind::InvalidUrl)?,
|
||||
));
|
||||
Ok(Some(index))
|
||||
}
|
||||
Source::Registry(RegistrySource::Path(path)) => {
|
||||
let index = IndexUrl::from(
|
||||
let index = IndexUrl::from_simple_api_url(
|
||||
VerbatimUrl::from_absolute_path(root.join(path))
|
||||
.map_err(LockErrorKind::RegistryVerbatimUrl)?,
|
||||
);
|
||||
|
|
@ -4283,7 +4283,7 @@ impl Wheel {
|
|||
url: file_location,
|
||||
yanked: None,
|
||||
});
|
||||
let index = IndexUrl::from(VerbatimUrl::from_url(
|
||||
let index = IndexUrl::from_simple_api_url(VerbatimUrl::from_url(
|
||||
url.to_url().map_err(LockErrorKind::InvalidUrl)?,
|
||||
));
|
||||
Ok(RegistryBuiltWheel {
|
||||
|
|
@ -4325,7 +4325,7 @@ impl Wheel {
|
|||
url: file_location,
|
||||
yanked: None,
|
||||
});
|
||||
let index = IndexUrl::from(
|
||||
let index = IndexUrl::from_simple_api_url(
|
||||
VerbatimUrl::from_absolute_path(root.join(index_path))
|
||||
.map_err(LockErrorKind::RegistryVerbatimUrl)?,
|
||||
);
|
||||
|
|
@ -4825,7 +4825,9 @@ fn normalize_requirement(
|
|||
index.remove_credentials();
|
||||
index
|
||||
})
|
||||
.map(|index| IndexMetadata::from(IndexUrl::from(VerbatimUrl::from_url(index))));
|
||||
.map(|index| {
|
||||
IndexMetadata::from(IndexUrl::from_simple_api_url(VerbatimUrl::from_url(index)))
|
||||
});
|
||||
Ok(Requirement {
|
||||
name: requirement.name,
|
||||
extras: requirement.extras,
|
||||
|
|
|
|||
|
|
@ -111,7 +111,7 @@ impl Preference {
|
|||
package
|
||||
.index
|
||||
.as_ref()
|
||||
.map(|index| IndexUrl::from(VerbatimUrl::from(index.clone()))),
|
||||
.map(|index| IndexUrl::from_simple_api_url(VerbatimUrl::from(index.clone()))),
|
||||
),
|
||||
// `pylock.toml` doesn't have fork annotations.
|
||||
fork_markers: vec![],
|
||||
|
|
|
|||
Loading…
Reference in New Issue