use std::path::{Path, PathBuf};
#[must_use]
pub fn repo_folder_name(repo_id: &str) -> String {
let mut name = String::from("models");
for segment in repo_id.split('/') {
name.push_str("--");
name.push_str(segment);
}
name
}
#[must_use]
pub fn repo_dir(cache_root: &Path, repo_id: &str) -> PathBuf {
cache_root.join(repo_folder_name(repo_id))
}
#[must_use]
pub fn snapshots_dir(repo_dir: &Path) -> PathBuf {
repo_dir.join("snapshots")
}
#[must_use]
pub fn snapshot_dir(repo_dir: &Path, commit_hash: &str) -> PathBuf {
snapshots_dir(repo_dir).join(commit_hash)
}
#[must_use]
pub fn pointer_path(repo_dir: &Path, commit_hash: &str, filename: &str) -> PathBuf {
snapshot_dir(repo_dir, commit_hash).join(filename)
}
#[must_use]
pub fn blobs_dir(repo_dir: &Path) -> PathBuf {
repo_dir.join("blobs")
}
#[must_use]
pub fn blob_path(repo_dir: &Path, etag: &str) -> PathBuf {
blobs_dir(repo_dir).join(etag)
}
#[must_use]
pub fn temp_blob_path(repo_dir: &Path, etag: &str) -> PathBuf {
let mut name = etag.to_owned();
name.push_str(".chunked.part");
blobs_dir(repo_dir).join(name)
}
#[must_use]
pub fn temp_state_path(repo_dir: &Path, etag: &str) -> PathBuf {
let mut name = etag.to_owned();
name.push_str(".chunked.part.state");
blobs_dir(repo_dir).join(name)
}
#[must_use]
pub fn refs_dir(repo_dir: &Path) -> PathBuf {
repo_dir.join("refs")
}
#[must_use]
pub fn ref_path(repo_dir: &Path, revision: &str) -> PathBuf {
refs_dir(repo_dir).join(revision)
}
#[must_use]
pub fn header_cache_dir(repo_dir: &Path) -> PathBuf {
repo_dir.join(".hf-fm-header-cache")
}
#[must_use]
pub fn header_cache_path(repo_dir: &Path, filename: &str, etag: &str) -> PathBuf {
let mut name = filename.replace(['/', '\\'], "__");
name.push('.');
name.push_str(etag);
name.push_str(".json");
header_cache_dir(repo_dir).join(name)
}
#[cfg(test)]
mod tests {
#![allow(clippy::panic, clippy::unwrap_used, clippy::expect_used)]
use super::*;
#[test]
fn blob_path_joins_repo_dir_and_etag() {
let rd = Path::new("/tmp/models--x--y");
assert_eq!(blob_path(rd, "abc123"), rd.join("blobs").join("abc123"));
}
#[test]
fn temp_blob_path_preserves_periods_in_etag() {
let rd = Path::new("/tmp/models--x--y");
assert_eq!(
temp_blob_path(rd, "abc.def"),
rd.join("blobs").join("abc.def.chunked.part")
);
}
#[test]
fn temp_state_path_lives_next_to_temp_blob() {
let rd = Path::new("/tmp/models--x--y");
let etag = "abc123";
assert_eq!(
temp_state_path(rd, etag),
rd.join("blobs").join("abc123.chunked.part.state")
);
assert_eq!(
temp_blob_path(rd, etag).parent(),
temp_state_path(rd, etag).parent()
);
}
#[test]
fn temp_state_path_preserves_periods_in_etag() {
let rd = Path::new("/tmp/models--x--y");
assert_eq!(
temp_state_path(rd, "abc.def"),
rd.join("blobs").join("abc.def.chunked.part.state")
);
}
#[test]
fn header_cache_path_joins_repo_dir_filename_and_etag() {
let rd = Path::new("/tmp/models--x--y");
assert_eq!(
header_cache_path(rd, "model.gguf", "abc123"),
rd.join(".hf-fm-header-cache")
.join("model.gguf.abc123.json")
);
}
#[test]
fn header_cache_path_sanitizes_nested_filenames() {
let rd = Path::new("/tmp/models--x--y");
assert_eq!(
header_cache_path(rd, "subdir/model.gguf", "abc123"),
rd.join(".hf-fm-header-cache")
.join("subdir__model.gguf.abc123.json")
);
}
#[test]
fn header_cache_path_preserves_periods_in_etag() {
let rd = Path::new("/tmp/models--x--y");
assert_eq!(
header_cache_path(rd, "model.gguf", "abc.def"),
rd.join(".hf-fm-header-cache")
.join("model.gguf.abc.def.json")
);
}
#[test]
fn header_cache_path_lives_under_header_cache_dir() {
let rd = Path::new("/tmp/models--x--y");
assert_eq!(
header_cache_path(rd, "model.gguf", "abc123").parent(),
Some(header_cache_dir(rd).as_path())
);
}
}