1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
use uv_distribution_types::RequirementSource;
use uv_normalize::PackageName;
use uv_pep440::Operator;
use crate::resolver::ForkSet;
use crate::{DependencyMode, Manifest, ResolverEnvironment};
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
#[serde(deny_unknown_fields, rename_all = "kebab-case")]
#[cfg_attr(feature = "clap", derive(clap::ValueEnum))]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
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,
}
impl std::fmt::Display for PrereleaseMode {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Disallow => write!(f, "disallow"),
Self::Allow => write!(f, "allow"),
Self::IfNecessary => write!(f, "if-necessary"),
Self::Explicit => write!(f, "explicit"),
Self::IfNecessaryOrExplicit => write!(f, "if-necessary-or-explicit"),
}
}
}
/// 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(ForkSet),
/// 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(ForkSet),
}
impl PrereleaseStrategy {
pub(crate) fn from_mode(
mode: PrereleaseMode,
manifest: &Manifest,
env: &ResolverEnvironment,
dependencies: DependencyMode,
) -> Self {
let mut packages = ForkSet::default();
match mode {
PrereleaseMode::Disallow => Self::Disallow,
PrereleaseMode::Allow => Self::Allow,
PrereleaseMode::IfNecessary => Self::IfNecessary,
_ => {
for requirement in manifest.requirements(env, dependencies) {
let RequirementSource::Registry { specifier, .. } = &requirement.source else {
continue;
};
if specifier
.iter()
.filter(|spec| {
!matches!(spec.operator(), Operator::NotEqual | Operator::NotEqualStar)
})
.any(uv_pep440::VersionSpecifier::any_prerelease)
{
packages.add(&requirement, ());
}
}
match mode {
PrereleaseMode::Explicit => Self::Explicit(packages),
PrereleaseMode::IfNecessaryOrExplicit => Self::IfNecessaryOrExplicit(packages),
_ => unreachable!(),
}
}
}
}
/// Returns `true` if a [`PackageName`] is allowed to have pre-release versions.
pub(crate) fn allows(
&self,
package_name: &PackageName,
env: &ResolverEnvironment,
) -> AllowPrerelease {
match self {
Self::Disallow => AllowPrerelease::No,
Self::Allow => AllowPrerelease::Yes,
Self::IfNecessary => AllowPrerelease::IfNecessary,
Self::Explicit(packages) => {
if packages.contains(package_name, env) {
AllowPrerelease::Yes
} else {
AllowPrerelease::No
}
}
Self::IfNecessaryOrExplicit(packages) => {
if packages.contains(package_name, env) {
AllowPrerelease::Yes
} else {
AllowPrerelease::IfNecessary
}
}
}
}
}
/// The pre-release strategy for a given package.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub(crate) enum AllowPrerelease {
/// Allow all pre-release versions.
Yes,
/// Disallow all pre-release versions.
No,
/// Allow pre-release versions if all versions of this package are pre-release.
IfNecessary,
}