Compare prerelease versions correctly for updates
ci / test (push) Waiting to run
ci / fuzz-smoke (push) Waiting to run
ci / windows-client (push) Waiting to run
ci / package-release (linux-x86_64, ubuntu-latest) (push) Waiting to run
ci / package-release (macos-aarch64, macos-14) (push) Waiting to run
ci / package-release (macos-x86_64, macos-13) (push) Waiting to run
ci / package-release (windows-x86_64, windows-latest) (push) Waiting to run
ci / publish-gitea-release (push) Blocked by required conditions
ci / remote-bench (push) Waiting to run
ci / test (push) Waiting to run
ci / fuzz-smoke (push) Waiting to run
ci / windows-client (push) Waiting to run
ci / package-release (linux-x86_64, ubuntu-latest) (push) Waiting to run
ci / package-release (macos-aarch64, macos-14) (push) Waiting to run
ci / package-release (macos-x86_64, macos-13) (push) Waiting to run
ci / package-release (windows-x86_64, windows-latest) (push) Waiting to run
ci / publish-gitea-release (push) Blocked by required conditions
ci / remote-bench (push) Waiting to run
This commit is contained in:
+83
-4
@@ -4135,15 +4135,71 @@ fn update_binary_version_for_installer(local: &str, latest_tag: Option<&str>) ->
|
||||
}
|
||||
|
||||
fn compare_dotted_versions(left: &str, right: &str) -> std::cmp::Ordering {
|
||||
let left = parse_dotted_version(left);
|
||||
let right = parse_dotted_version(right);
|
||||
let width = left.len().max(right.len());
|
||||
let left = parse_comparable_version(left);
|
||||
let right = parse_comparable_version(right);
|
||||
let width = left.core.len().max(right.core.len());
|
||||
for index in 0..width {
|
||||
let ordering = left
|
||||
.core
|
||||
.get(index)
|
||||
.copied()
|
||||
.unwrap_or(0)
|
||||
.cmp(&right.get(index).copied().unwrap_or(0));
|
||||
.cmp(&right.core.get(index).copied().unwrap_or(0));
|
||||
if ordering != std::cmp::Ordering::Equal {
|
||||
return ordering;
|
||||
}
|
||||
}
|
||||
compare_prerelease(left.prerelease.as_deref(), right.prerelease.as_deref())
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
struct ComparableVersion {
|
||||
core: Vec<u64>,
|
||||
prerelease: Option<String>,
|
||||
}
|
||||
|
||||
fn parse_comparable_version(version: &str) -> ComparableVersion {
|
||||
let version = version.strip_prefix('v').unwrap_or(version);
|
||||
let version = version.split_once('+').map_or(version, |(base, _)| base);
|
||||
let (core, prerelease) = version
|
||||
.split_once('-')
|
||||
.map_or((version, None), |(core, pre)| (core, Some(pre)));
|
||||
ComparableVersion {
|
||||
core: parse_dotted_version(core),
|
||||
prerelease: prerelease
|
||||
.filter(|value| !value.is_empty())
|
||||
.map(|value| value.to_ascii_lowercase()),
|
||||
}
|
||||
}
|
||||
|
||||
fn compare_prerelease(left: Option<&str>, right: Option<&str>) -> std::cmp::Ordering {
|
||||
match (left, right) {
|
||||
(None, None) => std::cmp::Ordering::Equal,
|
||||
(None, Some(_)) => std::cmp::Ordering::Greater,
|
||||
(Some(_), None) => std::cmp::Ordering::Less,
|
||||
(Some(left), Some(right)) => compare_prerelease_identifiers(left, right),
|
||||
}
|
||||
}
|
||||
|
||||
fn compare_prerelease_identifiers(left: &str, right: &str) -> std::cmp::Ordering {
|
||||
let left_parts = left.split(['.', '-']).collect::<Vec<_>>();
|
||||
let right_parts = right.split(['.', '-']).collect::<Vec<_>>();
|
||||
let width = left_parts.len().max(right_parts.len());
|
||||
for index in 0..width {
|
||||
let Some(left) = left_parts.get(index).copied() else {
|
||||
return std::cmp::Ordering::Less;
|
||||
};
|
||||
let Some(right) = right_parts.get(index).copied() else {
|
||||
return std::cmp::Ordering::Greater;
|
||||
};
|
||||
let left_number = parse_numeric_identifier(left);
|
||||
let right_number = parse_numeric_identifier(right);
|
||||
let ordering = match (left_number, right_number) {
|
||||
(Some(left), Some(right)) => left.cmp(&right),
|
||||
(Some(_), None) => std::cmp::Ordering::Less,
|
||||
(None, Some(_)) => std::cmp::Ordering::Greater,
|
||||
(None, None) => left.cmp(right),
|
||||
};
|
||||
if ordering != std::cmp::Ordering::Equal {
|
||||
return ordering;
|
||||
}
|
||||
@@ -4151,6 +4207,12 @@ fn compare_dotted_versions(left: &str, right: &str) -> std::cmp::Ordering {
|
||||
std::cmp::Ordering::Equal
|
||||
}
|
||||
|
||||
fn parse_numeric_identifier(value: &str) -> Option<u64> {
|
||||
(!value.is_empty() && value.bytes().all(|byte| byte.is_ascii_digit()))
|
||||
.then(|| value.parse::<u64>().ok())
|
||||
.flatten()
|
||||
}
|
||||
|
||||
fn parse_dotted_version(version: &str) -> Vec<u64> {
|
||||
version
|
||||
.split(|byte: char| !byte.is_ascii_digit())
|
||||
@@ -11226,6 +11288,14 @@ mod tests {
|
||||
update_binary_version_for_installer("1.0.0-rc41", Some("v1.0.0-rc42")),
|
||||
None
|
||||
);
|
||||
assert_eq!(
|
||||
update_binary_version_for_installer("1.0.0", Some("v1.0.0-rc42")).as_deref(),
|
||||
Some("v1.0.0")
|
||||
);
|
||||
assert_eq!(
|
||||
update_binary_version_for_installer("1.0.0-rc42", Some("v1.0.0")),
|
||||
None
|
||||
);
|
||||
let config = ClientConfig::default();
|
||||
let unix = unix_update_script(
|
||||
&config,
|
||||
@@ -11357,6 +11427,15 @@ mod tests {
|
||||
update_version_status("1.0.0-rc40", "1.0.0-rc37"),
|
||||
"local newer than latest release"
|
||||
);
|
||||
assert_eq!(
|
||||
update_version_status("1.0.0-rc42", "1.0.0"),
|
||||
"update available"
|
||||
);
|
||||
assert_eq!(
|
||||
update_version_status("1.0.0", "1.0.0-rc42"),
|
||||
"local newer than latest release"
|
||||
);
|
||||
assert_eq!(update_version_status("1.0.0", "1.0.0+build.7"), "current");
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
Reference in New Issue
Block a user