arch_pkg_db/text/archive/
tar.rs

1use super::{LoadArchiveError, LoadUncompressedArchiveError};
2use crate::{MultiTextCollection, TextCollection, value::RepositoryName};
3use derive_more::{Display, Error};
4use pipe_trait::Pipe;
5use std::{
6    ffi::OsStr,
7    io::{self, Read},
8};
9
10/// Error when trying to load data from a tar archive.
11#[derive(Debug, Display, Error)]
12#[display("Failed to read the tar archive: {_0}")]
13pub struct LoadTarError(io::Error);
14
15impl TextCollection {
16    /// Traverse a tar archive and add contents from `desc` files to the text collection.
17    pub fn extend_from_tar<Bytes: Read>(&mut self, bytes: Bytes) -> Result<(), LoadTarError> {
18        let mut tar = tar::Archive::new(bytes);
19        let entries = tar.entries().map_err(LoadTarError)?;
20
21        for entry in entries {
22            let mut entry = entry.map_err(LoadTarError)?;
23            let path = entry.path().map_err(LoadTarError)?;
24            let file_name = path.file_name().and_then(OsStr::to_str);
25            if file_name != Some("desc") {
26                continue;
27            }
28            let mut text = entry
29                .header()
30                .size()
31                .unwrap_or(0)
32                .pipe(usize::try_from)
33                .unwrap_or(0)
34                .pipe(String::with_capacity);
35            entry.read_to_string(&mut text).map_err(LoadTarError)?;
36            self.insert(text.into());
37        }
38
39        Ok(())
40    }
41
42    /// Traverse a tar archive and add contents from `desc` files to the text collection.
43    pub fn add_tar<Bytes: Read>(mut self, bytes: Bytes) -> Result<Self, LoadTarError> {
44        self.extend_from_tar(bytes)?;
45        Ok(self)
46    }
47
48    /// Traverse a tar archive and add contents from `desc` files to the text collection.
49    pub fn from_tar<Bytes: Read>(bytes: Bytes) -> Result<Self, LoadTarError> {
50        TextCollection::new().add_tar(bytes)
51    }
52}
53
54impl<'a> MultiTextCollection<'a> {
55    /// Extract a tar archive and add contents from its `desc` files to the multi-collection.
56    pub fn extend_from_tar<Bytes: Read>(
57        &mut self,
58        repository: RepositoryName<'a>,
59        bytes: Bytes,
60    ) -> Result<(), LoadArchiveError> {
61        let collection = TextCollection::from_tar(bytes)?;
62        self.insert(repository, collection);
63        Ok(())
64    }
65
66    /// Extract a tar archive and add contents from its `desc` files to the multi-collection.
67    pub fn add_tar<Bytes: Read>(
68        mut self,
69        repository: RepositoryName<'a>,
70        bytes: Bytes,
71    ) -> Result<Self, LoadArchiveError> {
72        self.extend_from_tar(repository, bytes)?;
73        Ok(self)
74    }
75
76    /// Extract a tar archive and add contents from its `desc` files to the multi-collection.
77    pub fn from_tar<Bytes: Read>(
78        repository: RepositoryName<'a>,
79        bytes: Bytes,
80    ) -> Result<Self, LoadArchiveError> {
81        MultiTextCollection::with_capacity(1).add_tar(repository, bytes)
82    }
83}
84
85impl From<LoadTarError> for LoadUncompressedArchiveError {
86    fn from(value: LoadTarError) -> Self {
87        LoadUncompressedArchiveError::Tar(value)
88    }
89}
90
91impl From<LoadTarError> for LoadArchiveError {
92    fn from(value: LoadTarError) -> Self {
93        LoadArchiveError::Tar(value)
94    }
95}