feat(parser): add a mechanism for checking the existence of required files

This commit is contained in:
Orhun Parmaksız 2021-11-23 23:38:43 +03:00
parent 7d1f85a90e
commit f7f323d3af
No known key found for this signature in database
GPG key ID: F83424824B3E4B90
6 changed files with 33 additions and 11 deletions

View file

@ -10,6 +10,7 @@ lazy_static! {
pub static ref PARSERS: Vec<Parser<'static>> = vec![
Parser {
glob_path: "admin-guide/sysctl/*.rst",
required_files: &["kernel.rst"],
regex: RegexBuilder::new("^\n([a-z].*)\n[=,-]{2,}+\n\n")
.multi_line(true)
.build()
@ -17,6 +18,7 @@ lazy_static! {
},
Parser {
glob_path: "networking/*-sysctl.rst",
required_files: &["ip-sysctl.rst"],
regex: RegexBuilder::new("^([a-zA-Z0-9_/-]+[ ]-[ ][a-zA-Z].*)$")
.multi_line(true)
.build()

View file

@ -4,7 +4,7 @@ use thiserror::Error as ThisError;
#[derive(Debug, ThisError)]
pub enum Error {
/// Error that may occur during I/O operations.
#[error("IO error: `{0}`")]
#[error("IO error: '{0}'")]
IoError(#[from] std::io::Error),
/// Error that may occur due to invalid UTF-8 strings.
#[error("non-UTF-8 string")]
@ -12,10 +12,13 @@ pub enum Error {
/// Error that may occur when the capture group does not exist.
#[error("capture group does not exist")]
CaptureError,
/// Error that may occur when a required file for parsing does not exist.
#[error("required file missing: '{0}'")]
MissingFileError(String),
/// Error that may occur while traversing paths using a glob pattern.
#[error("glob error: `{0}`")]
#[error("glob error: '{0}'")]
GlobError(#[from] globwalk::GlobError),
/// Error that may occur during the compilation of a regex.
#[error("regex error: `{0}`")]
#[error("regex error: '{0}'")]
RegexError(#[from] regex::Error),
}

View file

@ -1,6 +1,7 @@
use crate::document::{Document, Paragraph};
use crate::error::Error;
use crate::reader;
use globwalk::DirEntry;
use regex::{Captures, Regex, RegexBuilder};
use std::path::Path;
use std::result::Result as StdResult;
@ -13,15 +14,22 @@ use std::result::Result as StdResult;
pub struct Parser<'a> {
/// Glob pattern to specify the files to parse.
pub glob_path: &'a str,
/// Files to check during path traversal.
pub required_files: &'a [&'a str],
/// Regular expression to use for parsing.
pub regex: Regex,
}
impl<'a> Parser<'a> {
/// Constructs a new instance.
pub fn new(glob_path: &'a str, regex: &'a str) -> Result<Self, Error> {
pub fn new(
glob_path: &'a str,
required_files: &'a [&'a str],
regex: &'a str,
) -> Result<Self, Error> {
Ok(Self {
glob_path,
required_files,
regex: RegexBuilder::new(regex).multi_line(true).build()?,
})
}
@ -29,14 +37,23 @@ impl<'a> Parser<'a> {
/// Parses the files in the given base path and returns the documents.
pub fn parse(&self, base_path: &Path) -> Result<Vec<Document>, Error> {
let mut documents = Vec::new();
for file in globwalk::glob(
let glob_files = globwalk::glob(
base_path
.join(self.glob_path)
.to_str()
.ok_or(Error::Utf8Error)?,
)?
.filter_map(StdResult::ok)
{
.collect::<Vec<DirEntry>>();
self.required_files.iter().try_for_each(|file_name| {
glob_files
.iter()
.find(|file| file.file_name().to_str() == Some(file_name))
.map(drop)
.ok_or_else(|| Error::MissingFileError(file_name.to_string()))
})?;
for file in glob_files {
println!("{:?}", file);
let input = reader::read_to_string(file.path())?;
let capture_group = self
.regex
@ -59,7 +76,7 @@ mod tests {
#[test]
fn test_document_parser() -> Result<(), Error> {
let base_path = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
let parser = Parser::new("Cargo.*", r#"^(\[package\])\n"#)?;
let parser = Parser::new("Cargo.*", &["Cargo.toml"], r#"^(\[package\])\n"#)?;
let mut documents = parser.parse(base_path.as_path())?;
assert!(documents[0].paragraphs[0]

View file

@ -5,7 +5,7 @@ use systeroid_parser::parser::Parser;
#[test]
fn test_parser() -> Result<(), Error> {
let base_path = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
let parser = Parser::new("src/*.rs", r#"^(#\[cfg\(test\)\])$\n"#)?;
let parser = Parser::new("src/*.rs", &["lib.rs"], r#"^(#\[cfg\(test\)\])$\n"#)?;
let documents = parser.parse(base_path.as_path())?;
assert!(documents

View file

@ -40,7 +40,7 @@ impl<'a> App<'a> {
fn fetch_documentation(&mut self, kernel_docs: &Path) -> Result<()> {
if !kernel_docs.exists() {
eprintln!(
"warning: Linux kernel documentation is not found in path: {:?}",
"warning: linux kernel documentation is not found in path: {:?}",
kernel_docs.to_string_lossy()
);
}
@ -64,7 +64,7 @@ impl<'a> App<'a> {
}
Err(e) => {
if !pager.is_empty() {
eprintln!("error: `pager error: {}`", e);
eprintln!("pager error: `{}`", e);
}
fallback_to_default = true;
}

View file

@ -6,7 +6,7 @@ fn main() {
match systeroid::run(args) {
Ok(_) => process::exit(0),
Err(e) => {
eprintln!("error: `{}`", e);
eprintln!("{}", e);
process::exit(1)
}
}