use std::path::Path;
use super::config::read_toml_value;
use super::date::parse_relative_days;
use super::detect::get_delay_days;
use super::types::{
mark_unsupported_with_message, missing_status_for_path, CheckStatus, Recommendation,
};
use super::version::{extract_version_str, parse_semver};
pub(crate) const UV_KEY: &str = "exclude-newer";
const UV_MIN_MAJOR: u64 = 0;
const UV_MIN_MINOR: u64 = 9;
const UV_MIN_PATCH: u64 = 17;
fn supports_relative_duration(version: &str) -> bool {
let ver = extract_version_str(version);
parse_semver(ver).is_some_and(|(major, minor, patch)| {
(major, minor, patch) >= (UV_MIN_MAJOR, UV_MIN_MINOR, UV_MIN_PATCH)
})
}
pub fn scan(path: &Path, version: &str) -> Vec<Recommendation> {
let days = get_delay_days();
let ver = extract_version_str(version);
let val = read_toml_value(path, UV_KEY);
let status = match &val {
Some(v) => {
match parse_relative_days(v) {
Some(d) if d == days => CheckStatus::Ok(v.clone()),
_ => CheckStatus::WrongValue(v.clone()),
}
}
None => missing_status_for_path(path),
};
let rec = Recommendation {
key: UV_KEY.into(),
description: format!("Delay new versions by {days} days"),
expected: format!("{days} days"),
status,
};
let rec = if supports_relative_duration(version) {
rec
} else {
let configured_non_relative = val
.as_deref()
.is_some_and(|v| parse_relative_days(v).is_none());
let msg = match val.as_deref() {
Some(v) if configured_non_relative => format!(
"set to {v} — relative durations require uv \u{2265} \
{UV_MIN_MAJOR}.{UV_MIN_MINOR}.{UV_MIN_PATCH} (have {ver})"
),
_ => format!(
"requires uv \u{2265} {UV_MIN_MAJOR}.{UV_MIN_MINOR}.{UV_MIN_PATCH} (have {ver})"
),
};
mark_unsupported_with_message(rec, msg)
};
vec![rec]
}