anyreader-walker 0.1.0

Recursively walk archives and compressed files
Documentation
use crate::entry::FileEntry;
use crate::stack::AnyWalker;
use crate::walkers::ArchiveVisitor;
use std::io::Read;

pub struct TarWalker<T: Read> {
    archive: tar::Archive<T>,
}

impl<T: Read> TarWalker<T> {
    pub fn new(reader: T) -> Self {
        Self {
            archive: tar::Archive::new(reader),
        }
    }
}

impl<'a, T: Read + 'a> ArchiveVisitor<'a> for TarWalker<T> {
    type Item = tar::Entry<'a, T>;

    fn visit<V: AnyWalker>(mut self, visitor: &mut V) -> std::io::Result<()> {
        let mut entries = self.archive.entries()?;
        while let Some(Ok(entry)) = entries.next() {
            if entry.header().entry_type() != tar::EntryType::Regular || entry.size() == 0 {
                continue;
            }
            let size = entry.size();
            let path = entry.path()?.to_path_buf();
            let entry = FileEntry::from_reader(path, size, entry)?;
            visitor.walk(entry)?;
        }
        Ok(())
    }
}

#[cfg(test)]
mod tests {
    use crate::tests::{TestVisitor, TEST_DATA};

    use crate::entry::FileEntry;
    use crate::walkers::ArchiveVisitor;
    use anyreader::test::tar_archive;
    use anyreader::FormatKind;
    use std::path::PathBuf;

    #[test]
    fn test_read_tar() {
        let data = tar_archive([("test", TEST_DATA.to_vec())]);
        let entry = FileEntry::from_bytes(PathBuf::from("test"), data).unwrap();
        let mut visitor = TestVisitor::default();

        entry.visit(&mut visitor).unwrap();

        let found = visitor.into_data();
        assert_eq!(found.len(), 1);
        assert_eq!(
            found,
            vec![(
                FormatKind::Unknown,
                PathBuf::from("test"),
                TEST_DATA.to_vec()
            )]
        )
    }

    #[test]
    fn test_read_tar_nested() {
        let data = tar_archive([
            ("file", TEST_DATA.to_vec()),
            ("nested", tar_archive(vec![("test", TEST_DATA)])),
        ]);
        let entry = FileEntry::from_bytes(PathBuf::from("test"), data).unwrap();
        let mut visitor = TestVisitor::default();
        entry.visit(&mut visitor).unwrap();
        let found = visitor.into_data();

        assert_eq!(found.len(), 2);
        assert_eq!(
            found,
            vec![
                (
                    FormatKind::Unknown,
                    PathBuf::from("file"),
                    TEST_DATA.to_vec()
                ),
                (
                    FormatKind::Unknown,
                    PathBuf::from("test"),
                    TEST_DATA.to_vec()
                )
            ]
        )
    }
}