mirror of https://github.com/astral-sh/uv
Add a `PubGrubRequirement` struct (#3553)
## Summary Formalize some of the patterns in here. No behavior changes, just moving this method onto a struct.
This commit is contained in:
parent
eb8e733790
commit
10ec48299e
|
|
@ -91,14 +91,16 @@ fn add_requirements(
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add the package, plus any extra variants.
|
// Add the package, plus any extra variants.
|
||||||
for result in std::iter::once(to_pubgrub(requirement, None, urls, locals)).chain(
|
for result in std::iter::once(PubGrubRequirement::from_requirement(
|
||||||
requirement
|
requirement,
|
||||||
.extras
|
None,
|
||||||
.clone()
|
urls,
|
||||||
.into_iter()
|
locals,
|
||||||
.map(|extra| to_pubgrub(requirement, Some(extra), urls, locals)),
|
))
|
||||||
) {
|
.chain(requirement.extras.clone().into_iter().map(|extra| {
|
||||||
let (package, version) = result?;
|
PubGrubRequirement::from_requirement(requirement, Some(extra), urls, locals)
|
||||||
|
})) {
|
||||||
|
let PubGrubRequirement { package, version } = result?;
|
||||||
|
|
||||||
match &package {
|
match &package {
|
||||||
PubGrubPackage::Package(name, ..) => {
|
PubGrubPackage::Package(name, ..) => {
|
||||||
|
|
@ -152,7 +154,8 @@ fn add_requirements(
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add the package.
|
// Add the package.
|
||||||
let (package, version) = to_pubgrub(constraint, None, urls, locals)?;
|
let PubGrubRequirement { package, version } =
|
||||||
|
PubGrubRequirement::from_constraint(constraint, urls, locals)?;
|
||||||
|
|
||||||
// Ignore self-dependencies.
|
// Ignore self-dependencies.
|
||||||
if let PubGrubPackage::Package(name, ..) = &package {
|
if let PubGrubPackage::Package(name, ..) = &package {
|
||||||
|
|
@ -178,106 +181,136 @@ impl From<PubGrubDependencies> for Vec<(PubGrubPackage, Range<Version>)> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Convert a [`Requirement`] to a PubGrub-compatible package and range.
|
/// A PubGrub-compatible package and version range.
|
||||||
fn to_pubgrub(
|
#[derive(Debug, Clone)]
|
||||||
requirement: &Requirement,
|
struct PubGrubRequirement {
|
||||||
extra: Option<ExtraName>,
|
package: PubGrubPackage,
|
||||||
urls: &Urls,
|
version: Range<Version>,
|
||||||
locals: &Locals,
|
}
|
||||||
) -> Result<(PubGrubPackage, Range<Version>), ResolveError> {
|
|
||||||
match &requirement.source {
|
|
||||||
RequirementSource::Registry { specifier, .. } => {
|
|
||||||
// TODO(konsti): We're currently losing the index information here, but we need
|
|
||||||
// either pass it to `PubGrubPackage` or the `ResolverProvider` beforehand.
|
|
||||||
// If the specifier is an exact version, and the user requested a local version that's
|
|
||||||
// more precise than the specifier, use the local version instead.
|
|
||||||
let version = if let Some(expected) = locals.get(&requirement.name) {
|
|
||||||
specifier
|
|
||||||
.iter()
|
|
||||||
.map(|specifier| {
|
|
||||||
Locals::map(expected, specifier)
|
|
||||||
.map_err(ResolveError::InvalidVersion)
|
|
||||||
.and_then(|specifier| PubGrubSpecifier::try_from(&specifier))
|
|
||||||
})
|
|
||||||
.fold_ok(Range::full(), |range, specifier| {
|
|
||||||
range.intersection(&specifier.into())
|
|
||||||
})?
|
|
||||||
} else {
|
|
||||||
specifier
|
|
||||||
.iter()
|
|
||||||
.map(PubGrubSpecifier::try_from)
|
|
||||||
.fold_ok(Range::full(), |range, specifier| {
|
|
||||||
range.intersection(&specifier.into())
|
|
||||||
})?
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok((
|
impl PubGrubRequirement {
|
||||||
PubGrubPackage::from_package(requirement.name.clone(), extra, urls),
|
/// Convert a [`Requirement`] to a PubGrub-compatible package and range.
|
||||||
version,
|
pub(crate) fn from_requirement(
|
||||||
))
|
requirement: &Requirement,
|
||||||
}
|
extra: Option<ExtraName>,
|
||||||
RequirementSource::Url { url, .. } => {
|
urls: &Urls,
|
||||||
let Some(expected) = urls.get(&requirement.name) else {
|
locals: &Locals,
|
||||||
return Err(ResolveError::DisallowedUrl(
|
) -> Result<Self, ResolveError> {
|
||||||
requirement.name.clone(),
|
match &requirement.source {
|
||||||
url.to_string(),
|
RequirementSource::Registry { specifier, .. } => {
|
||||||
));
|
// TODO(konsti): We're currently losing the index information here, but we need
|
||||||
};
|
// either pass it to `PubGrubPackage` or the `ResolverProvider` beforehand.
|
||||||
|
// If the specifier is an exact version, and the user requested a local version that's
|
||||||
|
// more precise than the specifier, use the local version instead.
|
||||||
|
let version = if let Some(expected) = locals.get(&requirement.name) {
|
||||||
|
specifier
|
||||||
|
.iter()
|
||||||
|
.map(|specifier| {
|
||||||
|
Locals::map(expected, specifier)
|
||||||
|
.map_err(ResolveError::InvalidVersion)
|
||||||
|
.and_then(|specifier| PubGrubSpecifier::try_from(&specifier))
|
||||||
|
})
|
||||||
|
.fold_ok(Range::full(), |range, specifier| {
|
||||||
|
range.intersection(&specifier.into())
|
||||||
|
})?
|
||||||
|
} else {
|
||||||
|
specifier
|
||||||
|
.iter()
|
||||||
|
.map(PubGrubSpecifier::try_from)
|
||||||
|
.fold_ok(Range::full(), |range, specifier| {
|
||||||
|
range.intersection(&specifier.into())
|
||||||
|
})?
|
||||||
|
};
|
||||||
|
|
||||||
if !Urls::is_allowed(expected, url) {
|
Ok(Self {
|
||||||
return Err(ResolveError::ConflictingUrlsTransitive(
|
package: PubGrubPackage::from_package(requirement.name.clone(), extra, urls),
|
||||||
requirement.name.clone(),
|
version,
|
||||||
expected.verbatim().to_string(),
|
})
|
||||||
url.verbatim().to_string(),
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
RequirementSource::Url { url, .. } => {
|
||||||
|
let Some(expected) = urls.get(&requirement.name) else {
|
||||||
|
return Err(ResolveError::DisallowedUrl(
|
||||||
|
requirement.name.clone(),
|
||||||
|
url.to_string(),
|
||||||
|
));
|
||||||
|
};
|
||||||
|
|
||||||
Ok((
|
if !Urls::is_allowed(expected, url) {
|
||||||
PubGrubPackage::Package(requirement.name.clone(), extra, Some(expected.clone())),
|
return Err(ResolveError::ConflictingUrlsTransitive(
|
||||||
Range::full(),
|
requirement.name.clone(),
|
||||||
))
|
expected.verbatim().to_string(),
|
||||||
}
|
url.verbatim().to_string(),
|
||||||
RequirementSource::Git { url, .. } => {
|
));
|
||||||
let Some(expected) = urls.get(&requirement.name) else {
|
}
|
||||||
return Err(ResolveError::DisallowedUrl(
|
|
||||||
requirement.name.clone(),
|
|
||||||
url.to_string(),
|
|
||||||
));
|
|
||||||
};
|
|
||||||
|
|
||||||
if !Urls::is_allowed(expected, url) {
|
Ok(Self {
|
||||||
return Err(ResolveError::ConflictingUrlsTransitive(
|
package: PubGrubPackage::Package(
|
||||||
requirement.name.clone(),
|
requirement.name.clone(),
|
||||||
expected.verbatim().to_string(),
|
extra,
|
||||||
url.verbatim().to_string(),
|
Some(expected.clone()),
|
||||||
));
|
),
|
||||||
|
version: Range::full(),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
RequirementSource::Git { url, .. } => {
|
||||||
|
let Some(expected) = urls.get(&requirement.name) else {
|
||||||
|
return Err(ResolveError::DisallowedUrl(
|
||||||
|
requirement.name.clone(),
|
||||||
|
url.to_string(),
|
||||||
|
));
|
||||||
|
};
|
||||||
|
|
||||||
Ok((
|
if !Urls::is_allowed(expected, url) {
|
||||||
PubGrubPackage::Package(requirement.name.clone(), extra, Some(expected.clone())),
|
return Err(ResolveError::ConflictingUrlsTransitive(
|
||||||
Range::full(),
|
requirement.name.clone(),
|
||||||
))
|
expected.verbatim().to_string(),
|
||||||
}
|
url.verbatim().to_string(),
|
||||||
RequirementSource::Path { url, .. } => {
|
));
|
||||||
let Some(expected) = urls.get(&requirement.name) else {
|
}
|
||||||
return Err(ResolveError::DisallowedUrl(
|
|
||||||
requirement.name.clone(),
|
|
||||||
url.to_string(),
|
|
||||||
));
|
|
||||||
};
|
|
||||||
|
|
||||||
if !Urls::is_allowed(expected, url) {
|
Ok(Self {
|
||||||
return Err(ResolveError::ConflictingUrlsTransitive(
|
package: PubGrubPackage::Package(
|
||||||
requirement.name.clone(),
|
requirement.name.clone(),
|
||||||
expected.verbatim().to_string(),
|
extra,
|
||||||
url.verbatim().to_string(),
|
Some(expected.clone()),
|
||||||
));
|
),
|
||||||
|
version: Range::full(),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
RequirementSource::Path { url, .. } => {
|
||||||
|
let Some(expected) = urls.get(&requirement.name) else {
|
||||||
|
return Err(ResolveError::DisallowedUrl(
|
||||||
|
requirement.name.clone(),
|
||||||
|
url.to_string(),
|
||||||
|
));
|
||||||
|
};
|
||||||
|
|
||||||
Ok((
|
if !Urls::is_allowed(expected, url) {
|
||||||
PubGrubPackage::Package(requirement.name.clone(), extra, Some(expected.clone())),
|
return Err(ResolveError::ConflictingUrlsTransitive(
|
||||||
Range::full(),
|
requirement.name.clone(),
|
||||||
))
|
expected.verbatim().to_string(),
|
||||||
|
url.verbatim().to_string(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(Self {
|
||||||
|
package: PubGrubPackage::Package(
|
||||||
|
requirement.name.clone(),
|
||||||
|
extra,
|
||||||
|
Some(expected.clone()),
|
||||||
|
),
|
||||||
|
version: Range::full(),
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Convert a constraint to a PubGrub-compatible package and range.
|
||||||
|
pub(crate) fn from_constraint(
|
||||||
|
constraint: &Requirement,
|
||||||
|
urls: &Urls,
|
||||||
|
locals: &Locals,
|
||||||
|
) -> Result<Self, ResolveError> {
|
||||||
|
Self::from_requirement(constraint, None, urls, locals)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue