From d38fd5ca748b104e953c682d2990e9d50a6a43ff Mon Sep 17 00:00:00 2001 From: Jef Roosens Date: Sun, 21 Jul 2024 21:09:05 +0200 Subject: [PATCH] feat(repo): write db archive parser --- libarchive/src/lib.rs | 2 +- libarchive/src/read/mod.rs | 3 +- server/src/repo/mirror/mod.rs | 3 ++ server/src/repo/mirror/parser.rs | 75 ++++++++++++++++++++++++++++++++ server/src/repo/mod.rs | 8 ++-- 5 files changed, 84 insertions(+), 7 deletions(-) create mode 100644 server/src/repo/mirror/mod.rs create mode 100644 server/src/repo/mirror/parser.rs diff --git a/libarchive/src/lib.rs b/libarchive/src/lib.rs index e8a91f2..8ffc5ff 100644 --- a/libarchive/src/lib.rs +++ b/libarchive/src/lib.rs @@ -5,6 +5,6 @@ pub mod write; pub use archive::{ Entry, ExtractOption, ExtractOptions, Handle, ReadCompression, ReadFilter, ReadFormat, - WriteFilter, WriteFormat, + WriteFilter, WriteFormat, FileType, }; pub use error::Result; diff --git a/libarchive/src/read/mod.rs b/libarchive/src/read/mod.rs index 579b3e5..596595b 100644 --- a/libarchive/src/read/mod.rs +++ b/libarchive/src/read/mod.rs @@ -6,9 +6,10 @@ pub use builder::Builder; use crate::archive::Handle; use crate::ReadFilter; -use entries::Entries; +pub use entries::{Entries, ReadEntry}; use libarchive3_sys::ffi; use std::path::Path; +pub use file::FileReader; // Represents a read view of an archive pub trait Archive: Handle + Sized { diff --git a/server/src/repo/mirror/mod.rs b/server/src/repo/mirror/mod.rs new file mode 100644 index 0000000..02a0aab --- /dev/null +++ b/server/src/repo/mirror/mod.rs @@ -0,0 +1,3 @@ +mod parser; + +pub use parser::{DbArchiveParser, DbArchiveEntry}; diff --git a/server/src/repo/mirror/parser.rs b/server/src/repo/mirror/parser.rs new file mode 100644 index 0000000..d5270f4 --- /dev/null +++ b/server/src/repo/mirror/parser.rs @@ -0,0 +1,75 @@ +use std::{ + io::{self, BufRead}, + path::Path, +}; + +use libarchive::{ + read::{Archive, Builder, Entries, FileReader, ReadEntry}, + Entry, +}; + +pub struct DbArchiveParser<'a, T: 'a + Archive> { + entries: Entries<'a, T>, +} + +pub struct DbArchiveEntry { + name: String, + version: String, + filename: String, +} + +impl<'a, T: Archive> DbArchiveParser<'a, T> { + pub fn new(ar: &'a mut T) -> Self { + Self { + entries: Entries::new(ar), + } + } + + // parse a given entry. If the entry's not a regular file, the function returns None. + fn parse_entry(entry: ReadEntry<'a, T>) -> io::Result { + let reader = io::BufReader::new(entry); + let mut lines = reader.lines(); + + let mut name: Option = None; + let mut version: Option = None; + let mut filename: Option = None; + + while let Some(line) = lines.next().transpose()? { + match line.as_str() { + "%NAME%" => name = lines.next().transpose()?, + "%VERSION%" => version = lines.next().transpose()?, + "%FILENAME%" => filename = lines.next().transpose()?, + _ => {} + } + } + + if name.is_some() && version.is_some() && filename.is_some() { + Ok(DbArchiveEntry { + name: name.unwrap(), + version: version.unwrap(), + filename: filename.unwrap(), + }) + } else { + Err(io::Error::other("Missing fields in entry file")) + } + } +} + +impl<'a, T: Archive> Iterator for DbArchiveParser<'a, T> { + type Item = io::Result; + + fn next(&mut self) -> Option { + while let Some(entry) = self.entries.next() { + match entry { + Ok(entry) => { + if entry.filetype() == libarchive::FileType::RegularFile { + return Some(Self::parse_entry(entry)); + } + } + Err(err) => return Some(Err(err.into())), + } + } + + None + } +} diff --git a/server/src/repo/mod.rs b/server/src/repo/mod.rs index 4997b8a..96d4bfa 100644 --- a/server/src/repo/mod.rs +++ b/server/src/repo/mod.rs @@ -1,6 +1,7 @@ mod actor; mod archive; mod handle; +mod mirror; pub mod package; pub use actor::Actor; @@ -38,10 +39,7 @@ pub struct SharedState { } impl SharedState { - pub fn new( - repos_dir: impl AsRef, - conn: DbConn, - ) -> Self { + pub fn new(repos_dir: impl AsRef, conn: DbConn) -> Self { let (tx, rx) = unbounded_channel(); Self { @@ -78,7 +76,7 @@ pub fn start( std::thread::spawn(|| actor.run()); } - let handle = Handle::new(&state); + let handle = Handle::new(&state); for id in repo_ids { rt.block_on(handle.register_repo(id))?;