use std::path::{Path, PathBuf};
use std::process::Command;
use thiserror::Error;
use crate::git_env::scrub_git_env;
const COMPRESSION_LEVEL: i32 = 19;
#[derive(Debug, Error)]
pub enum ArchiveError {
#[error("archive construction failure: {0}")]
Build(#[from] std::io::Error),
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct ArchiveEntry {
pub path: PathBuf,
pub content: String,
}
pub fn build_archive(entries: &[ArchiveEntry]) -> Result<Vec<u8>, ArchiveError> {
let mut sorted: Vec<&ArchiveEntry> = entries.iter().collect();
sorted.sort_by(|first, second| first.path.cmp(&second.path));
let mut builder = tar::Builder::new(Vec::new());
for entry in sorted {
let mut header = tar::Header::new_gnu();
header.set_size(entry.content.len() as u64);
header.set_mode(0o644);
header.set_mtime(0);
header.set_uid(0);
header.set_gid(0);
header.set_entry_type(tar::EntryType::Regular);
builder.append_data(&mut header, &entry.path, entry.content.as_bytes())?;
}
let tar_bytes = builder.into_inner()?;
Ok(zstd::encode_all(tar_bytes.as_slice(), COMPRESSION_LEVEL)?)
}
pub fn gitattributes_covers_lfs(project_root: &Path, path: &Path) -> bool {
let mut command = Command::new("git");
scrub_git_env(&mut command);
let Ok(output) = command
.args(["check-attr", "filter", "--"])
.arg(path)
.current_dir(project_root)
.output()
else {
return false;
};
if !output.status.success() {
return false;
}
String::from_utf8_lossy(&output.stdout)
.lines()
.any(|line| line.ends_with(": filter: lfs"))
}