use std::collections::BTreeSet;
use std::path::PathBuf;
use anyhow::{Context, Result};
use crate::git::{self, Repository};
use crate::store::Store;
const INSTALLED_PACKS: &str = "tape/installed-packs";
fn installed_path(repository: &Repository) -> Result<PathBuf> {
Ok(repository.git_dir()?.join(INSTALLED_PACKS))
}
pub fn load_installed(repository: &Repository) -> BTreeSet<String> {
let Ok(path) = installed_path(repository) else {
return BTreeSet::new();
};
let Ok(body) = std::fs::read_to_string(path) else {
return BTreeSet::new();
};
let mut installed = BTreeSet::new();
for line in body.lines() {
if !line.is_empty() {
installed.insert(line.to_string());
}
}
installed
}
pub fn save_installed(repository: &Repository, installed: &BTreeSet<String>) -> Result<()> {
let path = installed_path(repository)?;
if let Some(parent) = path.parent() {
std::fs::create_dir_all(parent).context("create the tape state directory")?;
}
let mut body = String::new();
for key in installed {
body.push_str(key);
body.push('\n');
}
std::fs::write(&path, body).with_context(|| format!("write {}", path.display()))
}
pub async fn fetch(store: &Store, repository: &Repository) -> Result<()> {
let Some((index, _)) = store.read_index().await? else {
return Ok(());
};
let mut installed = load_installed(repository);
let mut fetched = 0u64;
for entry in &index.packs {
let key = store.installed_key(entry.track);
if installed.contains(&key) {
continue;
}
eprintln!("tape: fetching pack {} ({} bytes)", entry.track, entry.size);
let pack = store.read_pack(entry).await?;
if git::pack_object_count(&pack) > 0 {
repository.index_pack(&pack)?;
}
installed.insert(key);
fetched += 1;
}
if fetched > 0 {
save_installed(repository, &installed)?;
}
Ok(())
}