use std::path::{Path, PathBuf};
use running_process::broker::builders::CacheManifestBuilder;
use running_process::broker::protocol::CacheRootKind;
use crate::core::NormalizedPath;
pub const ZCCACHE_SERVICE_NAME: &str = "zccache";
const SHARED_BROKER_INSTANCE: &str = "shared";
#[must_use]
pub fn build_manifest_builder(cache_dir: &NormalizedPath) -> CacheManifestBuilder {
let index_dir = cache_dir.join("depgraph");
let log_dir = cache_dir.join("logs");
CacheManifestBuilder::new(ZCCACHE_SERVICE_NAME, crate::core::VERSION)
.broker_instance(SHARED_BROKER_INSTANCE)
.root(
CacheRootKind::CacheData,
path_string(&crate::core::config::artifacts_dir_from_cache_dir(cache_dir)),
)
.root(CacheRootKind::CacheIndex, path_string(&index_dir))
.root(CacheRootKind::CacheLogs, path_string(&log_dir))
.root(CacheRootKind::CacheLocks, path_string(cache_dir))
.root(
CacheRootKind::CacheTmp,
path_string(&crate::core::config::tmp_dir_from_cache_dir(cache_dir)),
)
}
pub fn publish_manifest(cache_dir: &NormalizedPath) -> Option<PathBuf> {
if super::running_process_disabled() {
return None;
}
match build_manifest_builder(cache_dir).publish() {
Ok(path) => Some(path),
Err(err) => {
tracing::warn!(error = %err, "failed to publish running-process cache manifest");
None
}
}
}
pub fn publish_manifest_in(
registry_dir: &Path,
cache_dir: &NormalizedPath,
) -> Result<PathBuf, running_process::broker::manifest::ManifestError> {
build_manifest_builder(cache_dir).publish_in(registry_dir)
}
pub fn publish_service_definition(daemon_binary: &Path) -> Option<PathBuf> {
use running_process::broker::builders::ServiceDefinitionBuilder;
use running_process::broker::server::service_definition_dir;
if super::running_process_disabled() {
return None;
}
let binary = match std::fs::canonicalize(daemon_binary) {
Ok(p) => p,
Err(err) => {
tracing::warn!(
daemon_binary = %daemon_binary.display(),
error = %err,
"failed to canonicalize zccache-daemon binary for service-definition install"
);
return None;
}
};
let Some(binary_dir) = binary.parent() else {
tracing::warn!(
binary = %binary.display(),
"zccache-daemon binary has no parent directory; skipping service-definition install"
);
return None;
};
match ServiceDefinitionBuilder::shared_broker(
ZCCACHE_SERVICE_NAME,
binary.display().to_string(),
)
.per_version_binary_dir(binary_dir.display().to_string())
.min_version(crate::core::VERSION)
.allow_version(crate::core::VERSION)
.label("vendor", "zackees")
.label("package", "zccache")
.label("consumer", "zccache")
.label("running-process-tracker", "zackees/running-process#435")
.install_in(&service_definition_dir())
{
Ok(path) => {
tracing::debug!(servicedef = %path.display(), "installed running-process service definition");
Some(path)
}
Err(err) => {
tracing::warn!(error = %err, "failed to install running-process service definition");
None
}
}
}
fn path_string(path: &NormalizedPath) -> String {
path.as_path().display().to_string()
}
#[cfg(test)]
mod tests {
use super::*;
use running_process::broker::manifest::read_manifest;
use running_process::broker::protocol::CacheRoot;
fn roots_by_kind(roots: &[CacheRoot]) -> Vec<(i32, String)> {
roots.iter().map(|r| (r.kind, r.path.clone())).collect()
}
#[test]
fn manifest_records_all_five_cache_roots() {
let cache_dir = NormalizedPath::from("/tmp/zccache-manifest-test");
let manifest = build_manifest_builder(&cache_dir)
.build()
.expect("seal manifest");
assert_eq!(manifest.service_name, "zccache");
assert_eq!(manifest.service_version, crate::core::VERSION);
assert_eq!(manifest.broker_instance, "shared");
let kinds: Vec<i32> = manifest.roots.iter().map(|r| r.kind).collect();
assert!(
kinds.contains(&(CacheRootKind::CacheData as i32)),
"artifact"
);
assert!(kinds.contains(&(CacheRootKind::CacheIndex as i32)), "index");
assert!(kinds.contains(&(CacheRootKind::CacheLogs as i32)), "log");
assert!(kinds.contains(&(CacheRootKind::CacheLocks as i32)), "lock");
assert!(kinds.contains(&(CacheRootKind::CacheTmp as i32)), "temp");
assert_eq!(manifest.roots.len(), 5);
}
#[test]
fn publish_round_trips_through_central_registry() {
let registry = tempfile::tempdir().expect("tempdir");
let cache_dir = NormalizedPath::from("/tmp/zccache-manifest-roundtrip");
let written = publish_manifest_in(registry.path(), &cache_dir).expect("publish manifest");
assert!(written.exists(), "manifest file should exist on disk");
let loaded = read_manifest(&written).expect("read + verify sealed manifest");
assert_eq!(loaded.service_name, "zccache");
let original = roots_by_kind(
&build_manifest_builder(&cache_dir)
.build()
.expect("seal manifest")
.roots,
);
assert_eq!(roots_by_kind(&loaded.roots), original);
}
}