use libflate::gzip::Decoder;
use std::fs::File;
use std::io::BufReader;
use std::io::{self, Error, ErrorKind, Read};
use std::path::Path;
use std::path::PathBuf;
use tar::{Archive, EntryType};
use crate::packagemeta::PackageMeta;
pub struct Package {
archive: Archive<Decoder<BufReader<File>>>,
path: PathBuf,
meta: Option<PackageMeta>,
}
impl Package {
pub fn from_path<P: AsRef<Path>>(path: P) -> io::Result<Self> {
let file = File::open(&path)?;
let decoder = Decoder::new(BufReader::new(file))?;
let mut ar = Archive::new(decoder);
ar.set_preserve_permissions(true);
Ok(Package {
archive: ar,
path: path.as_ref().to_path_buf(),
meta: None,
})
}
pub fn install<P: AsRef<Path>>(&mut self, dest: P) -> io::Result<()> {
self.archive.unpack(dest)?;
Ok(())
}
pub fn list(&mut self) -> io::Result<()> {
for i in self.archive.entries()? {
println!("{}", i?.path()?.display());
}
Ok(())
}
pub fn archive(&self) -> &Archive<Decoder<BufReader<File>>> {
&self.archive
}
pub fn path(&self) -> &Path {
&self.path
}
pub fn meta(&mut self) -> io::Result<&PackageMeta> {
if self.meta.is_none() {
let mut toml = None;
for entry in self.archive.entries()? {
let mut entry = entry?;
if entry.header().entry_type() != EntryType::Directory
&& entry.path()?.starts_with("pkg")
{
if toml.is_none() {
let mut text = String::new();
entry.read_to_string(&mut text)?;
toml = Some(text);
} else {
return Err(Error::new(
ErrorKind::Other,
"Multiple metadata files in package",
));
}
}
}
if let Some(toml) = toml {
self.meta = Some(
PackageMeta::from_toml(&toml).map_err(|e| Error::new(ErrorKind::Other, e))?,
);
} else {
return Err(Error::new(
ErrorKind::NotFound,
"Package metadata not found",
));
}
}
Ok(self.meta.as_ref().unwrap())
}
}