use std::path::Path;
use crate::config;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct FetchPruneConfig {
pub fetch_recent_refs_days: i64,
pub fetch_recent_refs_include_remotes: bool,
pub fetch_recent_commits_days: i64,
pub fetch_recent_always: bool,
pub prune_offset_days: i64,
pub prune_verify_remote_always: bool,
pub prune_verify_unreachable_always: bool,
pub prune_remote_name: String,
}
impl FetchPruneConfig {
pub fn from_repo(cwd: &Path) -> Self {
Self {
fetch_recent_refs_days: get_int(cwd, "lfs.fetchrecentrefsdays", 7),
fetch_recent_refs_include_remotes: get_bool(cwd, "lfs.fetchrecentremoterefs", true),
fetch_recent_commits_days: get_int(cwd, "lfs.fetchrecentcommitsdays", 0),
fetch_recent_always: get_bool(cwd, "lfs.fetchrecentalways", false),
prune_offset_days: get_int(cwd, "lfs.pruneoffsetdays", 3),
prune_verify_remote_always: get_bool(cwd, "lfs.pruneverifyremotealways", false),
prune_verify_unreachable_always: get_bool(
cwd,
"lfs.pruneverifyunreachablealways",
false,
),
prune_remote_name: get_string(cwd, "lfs.pruneremotetocheck", "origin"),
}
}
}
fn get_int(cwd: &Path, key: &str, default: i64) -> i64 {
config::get_effective(cwd, key)
.ok()
.flatten()
.and_then(|s| s.trim().parse().ok())
.unwrap_or(default)
}
fn get_bool(cwd: &Path, key: &str, default: bool) -> bool {
let Ok(Some(raw)) = config::get_effective(cwd, key) else {
return default;
};
match raw.trim().to_ascii_lowercase().as_str() {
"true" | "yes" | "on" | "1" => true,
"false" | "no" | "off" | "0" | "" => false,
_ => default,
}
}
fn get_string(cwd: &Path, key: &str, default: &str) -> String {
let raw = config::get_effective(cwd, key).ok().flatten();
match raw {
Some(s) if !s.trim().is_empty() => s.trim().to_owned(),
_ => default.to_owned(),
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::tests::commit_helper;
fn set(cwd: &Path, key: &str, value: &str) {
std::process::Command::new("git")
.arg("-C")
.arg(cwd)
.args(["config", key, value])
.status()
.unwrap();
}
#[test]
fn defaults_match_upstream() {
let tmp = commit_helper::init_repo();
let cfg = FetchPruneConfig::from_repo(tmp.path());
assert_eq!(cfg.fetch_recent_refs_days, 7);
assert!(cfg.fetch_recent_refs_include_remotes);
assert_eq!(cfg.fetch_recent_commits_days, 0);
assert!(!cfg.fetch_recent_always);
assert_eq!(cfg.prune_offset_days, 3);
assert!(!cfg.prune_verify_remote_always);
assert!(!cfg.prune_verify_unreachable_always);
assert_eq!(cfg.prune_remote_name, "origin");
}
#[test]
fn reads_overrides() {
let tmp = commit_helper::init_repo();
set(tmp.path(), "lfs.fetchrecentrefsdays", "14");
set(tmp.path(), "lfs.fetchrecentcommitsdays", "30");
set(tmp.path(), "lfs.fetchrecentremoterefs", "false");
set(tmp.path(), "lfs.fetchrecentalways", "yes");
set(tmp.path(), "lfs.pruneoffsetdays", "0");
set(tmp.path(), "lfs.pruneremotetocheck", "upstream");
let cfg = FetchPruneConfig::from_repo(tmp.path());
assert_eq!(cfg.fetch_recent_refs_days, 14);
assert_eq!(cfg.fetch_recent_commits_days, 30);
assert!(!cfg.fetch_recent_refs_include_remotes);
assert!(cfg.fetch_recent_always);
assert_eq!(cfg.prune_offset_days, 0);
assert_eq!(cfg.prune_remote_name, "upstream");
}
#[test]
fn bool_accepts_git_styles() {
let tmp = commit_helper::init_repo();
for (raw, expected) in [
("true", true),
("TRUE", true),
("yes", true),
("On", true),
("1", true),
("false", false),
("no", false),
("OFF", false),
("0", false),
] {
set(tmp.path(), "lfs.fetchrecentalways", raw);
let cfg = FetchPruneConfig::from_repo(tmp.path());
assert_eq!(cfg.fetch_recent_always, expected, "raw={raw:?}");
}
}
}