1use libflate::gzip::Decoder;
2use std::fs::File;
3use std::io::BufReader;
4use std::io::{self, Error, ErrorKind, Read};
5use std::path::Path;
6use std::path::PathBuf;
7use tar::{Archive, EntryType};
8
9use crate::packagemeta::PackageMeta;
10
11pub struct Package {
12 archive: Archive<Decoder<BufReader<File>>>,
13 path: PathBuf,
14 meta: Option<PackageMeta>,
15}
16
17impl Package {
18 pub fn from_path<P: AsRef<Path>>(path: P) -> io::Result<Self> {
19 let file = File::open(&path)?;
20 let decoder = Decoder::new(BufReader::new(file))?;
21
22 let mut ar = Archive::new(decoder);
23 ar.set_preserve_permissions(true);
24 Ok(Package {
25 archive: ar,
26 path: path.as_ref().to_path_buf(),
27 meta: None,
28 })
29 }
30
31 pub fn install<P: AsRef<Path>>(&mut self, dest: P) -> io::Result<()> {
32 self.archive.unpack(dest)?;
33 Ok(())
34 }
35
36 pub fn list(&mut self) -> io::Result<()> {
37 for i in self.archive.entries()? {
38 println!("{}", i?.path()?.display());
39 }
40 Ok(())
41 }
42
43 pub fn archive(&self) -> &Archive<Decoder<BufReader<File>>> {
44 &self.archive
45 }
46
47 pub fn path(&self) -> &Path {
48 &self.path
49 }
50
51 pub fn meta(&mut self) -> io::Result<&PackageMeta> {
52 if self.meta.is_none() {
53 let mut toml = None;
54 for entry in self.archive.entries()? {
55 let mut entry = entry?;
56 if entry.header().entry_type() != EntryType::Directory
57 && entry.path()?.starts_with("pkg")
58 {
59 if toml.is_none() {
60 let mut text = String::new();
61 entry.read_to_string(&mut text)?;
62 toml = Some(text);
63 } else {
64 return Err(Error::new(
65 ErrorKind::Other,
66 "Multiple metadata files in package",
67 ));
68 }
69 }
70 }
71
72 if let Some(toml) = toml {
73 self.meta = Some(
74 PackageMeta::from_toml(&toml).map_err(|e| Error::new(ErrorKind::Other, e))?,
75 );
76 } else {
77 return Err(Error::new(
78 ErrorKind::NotFound,
79 "Package metadata not found",
80 ));
81 }
82 }
83
84 Ok(self.meta.as_ref().unwrap())
85 }
86}