use camino::Utf8PathBuf;
use postgresql_embedded::{Settings, VersionReq};
use tracing::{debug, info, warn};
use super::installation;
use crate::{
TestBootstrapSettings,
cache::{
BinaryCacheConfig,
CacheLock,
CacheLookupResult,
check_cache,
copy_from_cache,
find_matching_cached_version,
populate_cache,
},
observability::LOG_TARGET,
};
fn set_exact_version(settings: &mut Settings, version: &str) {
let exact_version = format!("={version}");
match VersionReq::parse(&exact_version) {
Ok(exact_req) => settings.version = exact_req,
Err(err) => {
debug!(
target: LOG_TARGET,
version = %version,
error = %err,
"failed to parse exact version requirement"
);
}
}
}
#[expect(
clippy::cognitive_complexity,
reason = "error handling branches for UTF-8 validation and copy operation"
)]
fn copy_cached_binaries(
source_dir: &Utf8PathBuf,
version: &str,
settings: &mut Settings,
) -> Option<Utf8PathBuf> {
let Ok(target) = Utf8PathBuf::from_path_buf(settings.installation_dir.clone()) else {
warn!(
target: LOG_TARGET,
"installation_dir is not valid UTF-8, skipping cache"
);
return None;
};
let target_version_dir = target.join(version);
if let Err(err) = copy_from_cache(source_dir, &target_version_dir) {
warn!(
target: LOG_TARGET,
version = %version,
error = %err,
"cache copy failed, falling back to download"
);
return None;
}
settings.installation_dir = target_version_dir.clone().into();
settings.trust_installation_dir = true;
Some(target_version_dir)
}
fn apply_cached_binaries(
source_dir: &Utf8PathBuf,
version: &str,
version_req: &VersionReq,
bootstrap: &mut TestBootstrapSettings,
) -> bool {
let Some(target_version_dir) =
copy_cached_binaries(source_dir, version, &mut bootstrap.settings)
else {
return false;
};
set_exact_version(&mut bootstrap.settings, version);
info!(
target: LOG_TARGET,
version_req = %version_req,
matched_version = %version,
source = %source_dir,
target = %target_version_dir,
"using cached binaries"
);
true
}
fn log_no_matching_version(version_req: &VersionReq) {
debug!(
target: LOG_TARGET,
version_req = %version_req,
"no matching cached version found"
);
}
fn log_lock_acquisition_failed(version: &str) {
debug!(
target: LOG_TARGET,
version = %version,
"failed to acquire cache lock, skipping cache"
);
}
fn log_cache_entry_invalid(version: &str) {
debug!(
target: LOG_TARGET,
version = %version,
"cache entry no longer valid"
);
}
pub(super) fn try_use_binary_cache(
config: &BinaryCacheConfig,
version_req: &VersionReq,
bootstrap: &mut TestBootstrapSettings,
) -> bool {
let Some((version, _source_dir)) = find_matching_cached_version(&config.cache_dir, version_req)
else {
log_no_matching_version(version_req);
return false;
};
let Ok(_lock) = CacheLock::acquire_shared(&config.cache_dir, &version) else {
log_lock_acquisition_failed(&version);
return false;
};
match check_cache(&config.cache_dir, &version) {
CacheLookupResult::Hit { source_dir } => {
apply_cached_binaries(&source_dir, &version, version_req, bootstrap)
}
CacheLookupResult::Miss => {
log_cache_entry_invalid(&version);
false
}
}
}
#[expect(
clippy::cognitive_complexity,
reason = "cache population flow with lock acquisition and double-check is readable as-is"
)]
pub(super) fn try_populate_binary_cache(config: &BinaryCacheConfig, settings: &Settings) {
let Some(installed_dir) = installation::resolve_installed_dir(settings) else {
debug!(
target: LOG_TARGET,
"no installed directory found, skipping cache population"
);
return;
};
let Some(version) = extract_version_from_path(&installed_dir) else {
debug!(
target: LOG_TARGET,
path = %installed_dir.display(),
"could not extract version from path, skipping cache population"
);
return;
};
if matches!(
check_cache(&config.cache_dir, &version),
CacheLookupResult::Hit { .. }
) {
debug!(
target: LOG_TARGET,
version = %version,
"version already cached, skipping population"
);
return;
}
let Ok(_lock) = CacheLock::acquire_exclusive(&config.cache_dir, &version) else {
warn!(
target: LOG_TARGET,
version = %version,
"failed to acquire exclusive cache lock, skipping population"
);
return;
};
if matches!(
check_cache(&config.cache_dir, &version),
CacheLookupResult::Hit { .. }
) {
debug!(
target: LOG_TARGET,
version = %version,
"version cached by another process"
);
return;
}
let Ok(source) = Utf8PathBuf::from_path_buf(installed_dir.clone()) else {
warn!(
target: LOG_TARGET,
"installed directory is not valid UTF-8, skipping cache population"
);
return;
};
if let Err(err) = populate_cache(&source, &config.cache_dir, &version) {
warn!(
target: LOG_TARGET,
error = %err,
version = %version,
"failed to populate cache"
);
} else {
info!(
target: LOG_TARGET,
version = %version,
cache_dir = %config.cache_dir,
"populated binary cache"
);
}
}
fn extract_version_from_path(path: &std::path::Path) -> Option<String> {
let name = path.file_name()?.to_str()?;
postgresql_embedded::Version::parse(name).ok()?;
Some(name.to_owned())
}