From 7be4d83ca31fdb43a14f16b4551854c5b55cf556 Mon Sep 17 00:00:00 2001 From: Chewing_Bever Date: Wed, 12 Jul 2023 23:51:07 +0200 Subject: [PATCH] feat: start of pkg info parsing code --- libarchive/src/lib.rs | 4 + libarchive/src/read/mod.rs | 10 +++ server/src/repo/manager.rs | 16 ++++ server/src/repo/mod.rs | 1 + server/src/repo/package.rs | 147 +++++++++++++++++++++++++++++++++++++ 5 files changed, 178 insertions(+) create mode 100644 server/src/repo/manager.rs create mode 100644 server/src/repo/package.rs diff --git a/libarchive/src/lib.rs b/libarchive/src/lib.rs index 25ad235..bd99b1b 100644 --- a/libarchive/src/lib.rs +++ b/libarchive/src/lib.rs @@ -2,4 +2,8 @@ pub mod archive; pub mod error; pub mod read; +pub use archive::{ + Entry, ExtractOption, ExtractOptions, Handle, ReadCompression, ReadFilter, ReadFormat, + WriteFilter, WriteFormat, +}; pub use error::Result; diff --git a/libarchive/src/read/mod.rs b/libarchive/src/read/mod.rs index d5108b8..75df3c8 100644 --- a/libarchive/src/read/mod.rs +++ b/libarchive/src/read/mod.rs @@ -5,6 +5,7 @@ mod file; pub use builder::Builder; use crate::archive::Handle; +use crate::ReadFilter; use entries::Entries; use libarchive3_sys::ffi; use std::path::Path; @@ -18,4 +19,13 @@ pub trait Archive: Handle + Sized { fn entries<'a>(&'a mut self) -> Entries<'a, Self> { Entries::new(self) } + + fn filter(&mut self, index: i32) -> ReadFilter { + let res = unsafe { ffi::archive_filter_code(self.handle_mut(), index) }; + + match res { + 0 => ReadFilter::None, + _ => panic!("Unknown filter type"), + } + } } diff --git a/server/src/repo/manager.rs b/server/src/repo/manager.rs new file mode 100644 index 0000000..7dc9eb6 --- /dev/null +++ b/server/src/repo/manager.rs @@ -0,0 +1,16 @@ +use std::path::{Path, PathBuf}; + +/// Overarching abstraction that orchestrates updating the repositories stored on the server +pub struct RepoGroupManager { + repo_dir: PathBuf, + pkg_dir: PathBuf, +} + +impl RepoGroupManager { + fn new, P2: AsRef>(repo_dir: P1, pkg_dir: P2) -> Self { + RepoGroupManager { + repo_dir: repo_dir.as_ref().to_path_buf(), + pkg_dir: pkg_dir.as_ref().to_path_buf(), + } + } +} diff --git a/server/src/repo/mod.rs b/server/src/repo/mod.rs index ab8d34b..f060de1 100644 --- a/server/src/repo/mod.rs +++ b/server/src/repo/mod.rs @@ -1,4 +1,5 @@ mod manager; +mod package; use axum::extract::{BodyStream, Path, State}; use axum::http::StatusCode; diff --git a/server/src/repo/package.rs b/server/src/repo/package.rs new file mode 100644 index 0000000..cb46af2 --- /dev/null +++ b/server/src/repo/package.rs @@ -0,0 +1,147 @@ +use libarchive::read::{Archive, Builder}; +use libarchive::{Entry, ReadFilter}; +use std::fmt; +use std::io::{self, BufRead, BufReader, Read}; +use std::path::{Path, PathBuf}; + +const IGNORED_FILES: [&str; 5] = [".BUILDINFO", ".INSTALL", ".MTREE", ".PKGINFO", ".CHANGELOG"]; + +pub struct Package { + path: PathBuf, + info: PkgInfo, + files: Vec, + compression: ReadFilter, +} + +#[derive(Default)] +pub struct PkgInfo { + name: String, + base: String, + version: String, + description: String, + size: i64, + csize: i64, + url: String, + arch: String, + build_date: i64, + packager: String, + pgpsig: String, + pgpsigsize: i64, + groups: Vec, + licenses: Vec, + replaces: Vec, + depends: Vec, + conflicts: Vec, + provides: Vec, + optdepends: Vec, + makedepends: Vec, + checkdepends: Vec, +} + +#[derive(Debug, PartialEq, Eq)] +enum ParsePkgInfoError { + InvalidSize, + InvalidBuildDate, + InvalidPgpSigSize, +} + +impl fmt::Display for ParsePkgInfoError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let s = match self { + Self::InvalidSize => "invalid size", + Self::InvalidBuildDate => "invalid build date", + Self::InvalidPgpSigSize => "invalid pgp sig size", + }; + + write!(f, "{}", s) + } +} + +impl PkgInfo { + pub fn extend>(&mut self, line: S) -> Result<(), ParsePkgInfoError> { + let line = line.as_ref(); + + if !line.starts_with('#') { + if let Some((key, value)) = line.split_once(',').map(|(k, v)| (k.trim(), v.trim())) { + match key { + "pkgname" => self.name = value.to_string(), + "pkgbase" => self.base = value.to_string(), + "pkgver" => self.version = value.to_string(), + "pkgdesc" => self.description = value.to_string(), + "size" => { + self.size = value.parse().map_err(|_| ParsePkgInfoError::InvalidSize)? + } + "url" => self.url = value.to_string(), + "arch" => self.arch = value.to_string(), + "builddate" => { + self.build_date = value + .parse() + .map_err(|_| ParsePkgInfoError::InvalidBuildDate)? + } + "packager" => self.packager = value.to_string(), + "pgpsig" => self.pgpsig = value.to_string(), + "pgpsigsize" => { + self.pgpsigsize = value + .parse() + .map_err(|_| ParsePkgInfoError::InvalidBuildDate)? + } + "group" => self.groups.push(value.to_string()), + "license" => self.licenses.push(value.to_string()), + "replaces" => self.replaces.push(value.to_string()), + "depend" => self.depends.push(value.to_string()), + "conflict" => self.conflicts.push(value.to_string()), + "provides" => self.provides.push(value.to_string()), + "optdepend" => self.optdepends.push(value.to_string()), + "makedepend" => self.makedepends.push(value.to_string()), + "checkdepend" => self.checkdepends.push(value.to_string()), + _ => (), + } + } + } + + Ok(()) + } + + pub fn parse(reader: R) -> io::Result { + let mut info = Self::default(); + let buf_reader = BufReader::new(reader); + + for line in buf_reader.lines() { + info.extend(line?).map_err(|e| { + io::Error::new(io::ErrorKind::Other, format!("pkg info parse error: {}", e)) + })?; + } + + Ok(info) + } +} + +impl Package { + pub fn open>(path: P) -> io::Result { + let mut builder = Builder::new(); + builder.support_format(libarchive::ReadFormat::Tar)?; + builder.support_filter(libarchive::ReadFilter::All)?; + + let mut ar = builder.open_file(path)?; + + let mut info: PkgInfo; + let mut files: Vec = Vec::new(); + + for entry in ar.entries() { + let entry = entry?; + let path_name = entry.pathname(); + + if !IGNORED_FILES.iter().any(|p| p == &path_name) { + files.push(PathBuf::from(path_name)); + } + + if path_name == ".PKGINFO" { + let size = entry.size(); + info = PkgInfo::parse(entry)?; + info.size = size; + } + } + + todo!() + } +}