use std::io;
use std::io::Read as _;
use typst::foundations::Bytes;
use typst::syntax::package::PackageSpec;
use typst::syntax::{FileId, Source, VirtualPath};
pub enum File {
Source(Source),
File(FileId, Bytes),
}
pub fn inspect_archive(
spec: PackageSpec,
tar_gz: impl io::Read,
mut inspect: impl FnMut(File),
) -> io::Result<()> {
let tar = flate2::read::GzDecoder::new(tar_gz);
let mut archive = tar::Archive::new(tar);
let entries = archive.entries()?;
for entry in entries {
let mut entry = entry?;
let path = entry.path()?;
let is_source_file = path.extension().is_some_and(|ext| ext == "typ");
let file_id = FileId::new(Some(spec.clone()), VirtualPath::new(path));
let file = if is_source_file {
let mut content = String::new();
entry.read_to_string(&mut content)?;
File::Source(Source::new(file_id, content))
} else {
let mut content = Vec::new();
entry.read_to_end(&mut content)?;
File::File(file_id, Bytes::new(content))
};
inspect(file)
}
Ok(())
}
pub fn read_archive(spec: PackageSpec, tar_gz: impl io::Read) -> io::Result<Vec<File>> {
let mut files = Vec::new();
inspect_archive(spec, tar_gz, |file| files.push(file))?;
Ok(files)
}
impl super::Package {
pub fn inspect_archive(&self, inspect: impl FnMut(File)) -> io::Result<()> {
inspect_archive(self.spec(), self.archive, inspect)
}
pub fn read_archive(&self) -> io::Result<Vec<File>> {
read_archive(self.spec(), self.archive)
}
}