impl Repo and md5-cache reading

This commit is contained in:
John Turner
2025-10-29 20:06:59 +00:00
parent 8937e096a4
commit 72b6774e2b
4 changed files with 403 additions and 22 deletions

303
src/ebuild/repo/mod.rs Normal file
View File

@@ -0,0 +1,303 @@
use std::{
fs, io,
path::{Path, PathBuf},
};
use get::Get;
use mon::{Parser, input::InputIter, tag, whitespace1};
use crate::{
Parseable,
atom::{self, Atom},
ebuild::{Depend, Eapi, Ebuild, Eclass, License, SrcUri},
useflag::IUseFlag,
};
#[derive(Debug, thiserror::Error)]
pub enum Error {
#[error("io error: {0}")]
Io(#[from] io::Error),
#[error("failed to decode path: {0}")]
Unicode(PathBuf),
#[error("parser error: {0}")]
Parser(String),
}
#[derive(Debug, Clone, Get)]
pub struct Repo {
#[get(kind = "deref")]
path: PathBuf,
}
#[derive(Debug, Clone, Get)]
pub struct Category {
name: atom::Category,
#[get(kind = "deref")]
path: PathBuf,
}
#[derive(Debug)]
pub struct Categories(fs::ReadDir);
#[derive(Debug)]
pub struct Ebuilds(fs::ReadDir);
impl Repo {
pub fn new<P: AsRef<Path>>(path: P) -> Self {
Self {
path: path.as_ref().to_path_buf(),
}
}
pub fn categories(&self) -> Result<Categories, Error> {
Ok(Categories(fs::read_dir(
self.path.as_path().join("metadata/md5-cache"),
)?))
}
}
impl Category {
pub fn ebuilds(&self) -> Result<Ebuilds, Error> {
Ok(Ebuilds(fs::read_dir(self.path.as_path())?))
}
}
impl Iterator for Categories {
type Item = Result<Category, Error>;
fn next(&mut self) -> Option<Self::Item> {
match self.0.next()? {
Ok(entry) => match read_category(entry.path()) {
Ok(category) => Some(Ok(category)),
Err(e) => Some(Err(e)),
},
Err(e) => Some(Err(Error::Io(e))),
}
}
}
impl Iterator for Ebuilds {
type Item = Result<Ebuild, Error>;
fn next(&mut self) -> Option<Self::Item> {
match self.0.next()? {
Ok(entry) => match read_ebuild(entry.path()) {
Ok(ebuild) => Some(Ok(ebuild)),
Err(e) => Some(Err(e)),
},
_ => todo!(),
}
}
}
fn read_category(path: PathBuf) -> Result<Category, Error> {
let file_name = path
.as_path()
.file_name()
.unwrap()
.to_str()
.ok_or(Error::Unicode(path.clone()))?;
let name = atom::Category::parser()
.parse_finished(InputIter::new(file_name))
.map_err(|_| Error::Parser(file_name.to_string()))?;
Ok(Category { name, path })
}
fn read_ebuild(path: PathBuf) -> Result<Ebuild, Error> {
let file_name = path
.as_path()
.file_name()
.unwrap()
.to_str()
.ok_or(Error::Unicode(path.clone()))?;
let (name, version) = atom::Name::parser()
.and(atom::Version::parser().preceded_by(tag("-")))
.parse_finished(InputIter::new(file_name))
.map_err(|_| Error::Parser(file_name.to_string()))?;
let metadata = fs::read_to_string(path.as_path())?;
Ok(Ebuild {
name,
version,
slot: match read_slot(&metadata) {
Some(Ok(slot)) => Some(slot),
Some(Err(e)) => return Err(e),
None => None,
},
homepage: read_homepage(&metadata),
src_uri: match read_src_uri(&metadata) {
Some(Ok(src_uri)) => src_uri,
Some(Err(e)) => return Err(e),
None => Vec::new(),
},
eapi: match read_eapi(&metadata) {
Some(Ok(eapi)) => Some(eapi),
Some(Err(e)) => return Err(e),
None => None,
},
inherit: match read_inherit(&metadata) {
Some(Ok(inherit)) => inherit,
Some(Err(e)) => return Err(e),
None => Vec::new(),
},
iuse: match read_iuse(&metadata) {
Some(Ok(iuse)) => iuse,
Some(Err(e)) => return Err(e),
None => Vec::new(),
},
license: match read_license(&metadata) {
Some(Ok(license)) => license,
Some(Err(e)) => return Err(e),
None => Vec::new(),
},
description: read_description(&metadata),
depend: match read_depend(&metadata) {
Some(Ok(depend)) => depend,
Some(Err(e)) => return Err(e),
None => Vec::new(),
},
bdepend: match read_bdepend(&metadata) {
Some(Ok(depend)) => depend,
Some(Err(e)) => return Err(e),
None => Vec::new(),
},
rdepend: match read_rdepend(&metadata) {
Some(Ok(depend)) => depend,
Some(Err(e)) => return Err(e),
None => Vec::new(),
},
idepend: match read_idepend(&metadata) {
Some(Ok(depend)) => depend,
Some(Err(e)) => return Err(e),
None => Vec::new(),
},
})
}
fn read_slot(input: &str) -> Option<Result<atom::Slot, Error>> {
let line = input.lines().find_map(|line| line.strip_prefix("SLOT="))?;
match atom::Slot::parser().parse_finished(InputIter::new(line)) {
Ok(slot) => Some(Ok(slot)),
Err(_) => Some(Err(Error::Parser(line.to_string()))),
}
}
fn read_homepage(input: &str) -> Option<String> {
input
.lines()
.find_map(|line| line.strip_prefix("HOMEPAGE=").map(|s| s.to_string()))
}
fn read_src_uri(input: &str) -> Option<Result<Vec<Depend<SrcUri>>, Error>> {
let line = input
.lines()
.find_map(|line| line.strip_prefix("SRC_URI="))?;
match Depend::<SrcUri>::parser()
.separated_list(whitespace1(), 0..)
.parse_finished(InputIter::new(line))
{
Ok(slot) => Some(Ok(slot)),
Err(_) => Some(Err(Error::Parser(line.to_string()))),
}
}
fn read_eapi(input: &str) -> Option<Result<Eapi, Error>> {
let line = input.lines().find_map(|line| line.strip_prefix("EAPI="))?;
match Eapi::parser().parse_finished(InputIter::new(line)) {
Ok(slot) => Some(Ok(slot)),
Err(_) => Some(Err(Error::Parser(line.to_string()))),
}
}
fn read_inherit(input: &str) -> Option<Result<Vec<Eclass>, Error>> {
let line = input
.lines()
.find_map(|line| line.strip_prefix("INHERIT="))?;
match Eclass::parser()
.separated_list(whitespace1(), 0..)
.parse_finished(InputIter::new(line))
{
Ok(inherit) => Some(Ok(inherit)),
Err(_) => Some(Err(Error::Parser(line.to_string()))),
}
}
fn read_iuse(input: &str) -> Option<Result<Vec<IUseFlag>, Error>> {
let line = input.lines().find_map(|line| line.strip_prefix("IUSE="))?;
match IUseFlag::parser()
.separated_list(whitespace1(), 0..)
.parse_finished(InputIter::new(line))
{
Ok(iuse) => Some(Ok(iuse)),
Err(_) => Some(Err(Error::Parser(line.to_string()))),
}
}
fn read_license(input: &str) -> Option<Result<Vec<Depend<License>>, Error>> {
let line = input
.lines()
.find_map(|line| line.strip_suffix("LICENSE="))?;
match Depend::<License>::parser()
.separated_list(whitespace1(), 0..)
.parse_finished(InputIter::new(line))
{
Ok(license) => Some(Ok(license)),
Err(_) => Some(Err(Error::Parser(line.to_string()))),
}
}
fn read_description(input: &str) -> Option<String> {
input
.lines()
.find_map(|line| line.strip_prefix("DESCRIPTION=").map(|s| s.to_string()))
}
fn read_depend(input: &str) -> Option<Result<Vec<Depend<Atom>>, Error>> {
let line = input
.lines()
.find_map(|line| line.strip_prefix("DEPEND="))?;
Some(parse_depends(line))
}
fn read_bdepend(input: &str) -> Option<Result<Vec<Depend<Atom>>, Error>> {
let line = input
.lines()
.find_map(|line| line.strip_prefix("BDEPEND="))?;
Some(parse_depends(line))
}
fn read_rdepend(input: &str) -> Option<Result<Vec<Depend<Atom>>, Error>> {
let line = input
.lines()
.find_map(|line| line.strip_prefix("RDEPEND="))?;
Some(parse_depends(line))
}
fn read_idepend(input: &str) -> Option<Result<Vec<Depend<Atom>>, Error>> {
let line = input
.lines()
.find_map(|line| line.strip_prefix("IDEPEND="))?;
Some(parse_depends(line))
}
fn parse_depends(line: &str) -> Result<Vec<Depend<Atom>>, Error> {
Depend::<Atom>::parser()
.separated_list(whitespace1(), 0..)
.parse_finished(InputIter::new(line))
.map_err(|_| Error::Parser(line.to_string()))
}