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
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
use tokio::sync::Semaphore;
use tracing::debug;
use uv_client::{MetadataFormat, RegistryClient, VersionFiles};
use uv_distribution_filename::DistFilename;
use uv_distribution_types::{
IndexCapabilities, IndexLocations, IndexMetadataRef, IndexUrl, RequiresPython,
};
use uv_normalize::PackageName;
use uv_platform_tags::Tags;
use uv_resolver::{ExcludeNewer, PrereleaseMode};
use uv_warnings::warn_user_once;
/// A client to fetch the latest version of a package from an index.
///
/// The returned distribution is guaranteed to be compatible with the provided tags and Python
/// requirement (if specified).
#[derive(Debug, Clone)]
pub(crate) struct LatestClient<'env> {
pub(crate) client: &'env RegistryClient,
pub(crate) capabilities: &'env IndexCapabilities,
pub(crate) prerelease: PrereleaseMode,
pub(crate) exclude_newer: &'env ExcludeNewer,
pub(crate) index_locations: &'env IndexLocations,
pub(crate) tags: Option<&'env Tags>,
pub(crate) requires_python: Option<&'env RequiresPython>,
}
impl LatestClient<'_> {
fn effective_exclude_newer(
&self,
package: &PackageName,
index: &IndexUrl,
) -> Option<jiff::Timestamp> {
self.exclude_newer
.exclude_newer_package_for_index(package, self.index_locations.exclude_newer_for(index))
}
/// Find the latest version of a package from an index.
pub(crate) async fn find_latest(
&self,
package: &PackageName,
index: Option<&IndexUrl>,
download_concurrency: &Semaphore,
) -> Result<Option<DistFilename>, uv_client::Error> {
debug!("Fetching latest version of: `{package}`");
let archives = match self
.client
.simple_detail(
package,
index.map(IndexMetadataRef::from),
self.capabilities,
download_concurrency,
)
.await
{
Ok(archives) => archives,
Err(err) => {
return match err.kind() {
uv_client::ErrorKind::RemotePackageNotFound(_) => Ok(None),
uv_client::ErrorKind::NoIndex(_) => Ok(None),
uv_client::ErrorKind::Offline(_) => Ok(None),
_ => Err(err),
};
}
};
let mut latest: Option<DistFilename> = None;
for (index, archive) in archives {
let MetadataFormat::Simple(archive) = archive else {
continue;
};
let exclude_newer = self.effective_exclude_newer(package, index);
for datum in archive.iter().rev() {
// Find the first compatible distribution.
let files = rkyv::deserialize::<VersionFiles, rkyv::rancor::Error>(&datum.files)
.expect("archived version files always deserializes");
// Determine whether there's a compatible wheel and/or source distribution.
let mut best = None;
for (filename, file) in files.all() {
// Skip distributions uploaded after the cutoff.
if let Some(exclude_newer) = &exclude_newer {
match file.upload_time_utc_ms.as_ref() {
Some(&upload_time) if upload_time >= exclude_newer.as_millisecond() => {
continue;
}
None => {
warn_user_once!(
"{} is missing an upload date, but user provided: {}",
file.filename,
exclude_newer
);
}
_ => {}
}
}
// Skip pre-release distributions.
if !filename.version().is_stable() {
if !matches!(self.prerelease, PrereleaseMode::Allow) {
continue;
}
}
// Skip distributions that are yanked.
if file.yanked.is_some_and(|yanked| yanked.is_yanked()) {
continue;
}
// Skip distributions that are incompatible with the Python requirement.
if let Some(requires_python) = self.requires_python {
if file
.requires_python
.as_ref()
.is_some_and(|file_requires_python| {
!requires_python.is_contained_by(file_requires_python)
})
{
continue;
}
}
// Skip distributions that are incompatible with the current platform.
if let DistFilename::WheelFilename(filename) = &filename {
if self
.tags
.is_some_and(|tags| !filename.compatibility(tags).is_compatible())
{
continue;
}
}
match filename {
DistFilename::WheelFilename(_) => {
best = Some(filename);
break;
}
DistFilename::SourceDistFilename(_) => {
if best.is_none() {
best = Some(filename);
}
}
}
}
match (latest.as_ref(), best) {
(Some(current), Some(best)) if best.version() > current.version() => {
latest = Some(best);
}
(None, Some(best)) => {
latest = Some(best);
}
_ => {}
}
}
}
Ok(latest)
}
}