uv/crates/uv-resolver/src/prerelease_mode.rs
Charlie Marsh 295b58ad37
Add uv-workspace crate with settings discovery and deserialization (#3007)
## Summary

This PR adds basic struct definitions along with a "workspace" concept
for discovering settings. (The "workspace" terminology is used to match
Ruff; I did not invent it.)

A few notes:

- We discover any `pyproject.toml` or `uv.toml` file in any parent
directory of the current working directory. (We could adjust this to
look at the directories of the input files.)
- We don't actually do anything with the configuration yet; but those
PRs are large and I want this to be reviewed in isolation.
2024-04-16 13:56:47 -04:00

116 lines
4.3 KiB
Rust

use rustc_hash::FxHashSet;
use pep508_rs::{MarkerEnvironment, VersionOrUrl};
use uv_normalize::PackageName;
use crate::Manifest;
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "clap", derive(clap::ValueEnum))]
#[cfg_attr(feature = "serde", derive(serde::Deserialize))]
pub enum PreReleaseMode {
/// Disallow all pre-release versions.
Disallow,
/// Allow all pre-release versions.
Allow,
/// Allow pre-release versions if all versions of a package are pre-release.
IfNecessary,
/// Allow pre-release versions for first-party packages with explicit pre-release markers in
/// their version requirements.
Explicit,
/// Allow pre-release versions if all versions of a package are pre-release, or if the package
/// has an explicit pre-release marker in its version requirements.
#[default]
IfNecessaryOrExplicit,
}
/// Like [`PreReleaseMode`], but with any additional information required to select a candidate,
/// like the set of direct dependencies.
#[derive(Debug, Clone)]
pub(crate) enum PreReleaseStrategy {
/// Disallow all pre-release versions.
Disallow,
/// Allow all pre-release versions.
Allow,
/// Allow pre-release versions if all versions of a package are pre-release.
IfNecessary,
/// Allow pre-release versions for first-party packages with explicit pre-release markers in
/// their version requirements.
Explicit(FxHashSet<PackageName>),
/// Allow pre-release versions if all versions of a package are pre-release, or if the package
/// has an explicit pre-release marker in its version requirements.
IfNecessaryOrExplicit(FxHashSet<PackageName>),
}
impl PreReleaseStrategy {
pub(crate) fn from_mode(
mode: PreReleaseMode,
manifest: &Manifest,
markers: &MarkerEnvironment,
) -> Self {
match mode {
PreReleaseMode::Disallow => Self::Disallow,
PreReleaseMode::Allow => Self::Allow,
PreReleaseMode::IfNecessary => Self::IfNecessary,
PreReleaseMode::Explicit => Self::Explicit(
manifest
.requirements(markers)
.filter(|requirement| {
let Some(version_or_url) = &requirement.version_or_url else {
return false;
};
let version_specifiers = match version_or_url {
VersionOrUrl::VersionSpecifier(version_specifiers) => {
version_specifiers
}
VersionOrUrl::Url(_) => return false,
};
version_specifiers
.iter()
.any(pep440_rs::VersionSpecifier::any_prerelease)
})
.map(|requirement| requirement.name.clone())
.collect(),
),
PreReleaseMode::IfNecessaryOrExplicit => Self::IfNecessaryOrExplicit(
manifest
.requirements(markers)
.filter(|requirement| {
let Some(version_or_url) = &requirement.version_or_url else {
return false;
};
let version_specifiers = match version_or_url {
VersionOrUrl::VersionSpecifier(version_specifiers) => {
version_specifiers
}
VersionOrUrl::Url(_) => return false,
};
version_specifiers
.iter()
.any(pep440_rs::VersionSpecifier::any_prerelease)
})
.map(|requirement| requirement.name.clone())
.collect(),
),
}
}
/// Returns `true` if a [`PackageName`] is allowed to have pre-release versions.
pub(crate) fn allows(&self, package: &PackageName) -> bool {
match self {
Self::Disallow => false,
Self::Allow => true,
Self::IfNecessary => false,
Self::Explicit(packages) => packages.contains(package),
Self::IfNecessaryOrExplicit(packages) => packages.contains(package),
}
}
}