use std::path::{Path, PathBuf};
use std::{fs, io};
use anyhow::Context;
use anyhow::Result;
pub struct PostList {
pub root_dir: PathBuf,
pub post_file: PostListType,
}
#[derive(Clone)]
pub enum PostListType {
IndexBaseName(String),
AnyContentFile,
}
impl PostList {
pub fn retrieve_files(&self) -> io::Result<Vec<PathBuf>> {
let mut posts = vec![];
let entries = fs::read_dir(self.root_dir.as_path())?;
for entry in entries.flatten() {
if let Ok(file_type) = entry.file_type() {
if !file_type.is_file() {
continue;
}
let file_name = entry.file_name();
if let Some(file_name) = file_name.to_str() {
if file_name.ends_with(".md") || file_name.ends_with(".html") || file_name.ends_with(".htm") {
posts.push(entry.path());
}
}
}
}
Ok(posts)
}
pub fn retrieve_dirs(&self) -> Result<Vec<(PathBuf, String)>> {
let dirs = Self::list_dirs(self.root_dir.as_path())?;
let post_dirs = Self::filter_dirs(&self.post_file, dirs);
Ok(post_dirs)
}
fn list_dirs(posts_dir: &Path) -> Result<Vec<PathBuf>> {
let mut dirs: Vec<PathBuf> = vec![];
let entries = fs::read_dir(posts_dir)
.context(format!("Could not list dirs from [{}]", posts_dir.to_str().unwrap()))?;
for path in entries.flatten() {
if let Ok(file_type) = path.file_type() {
if file_type.is_dir() {
dirs.push(path.path());
}
}
}
Ok(dirs)
}
fn filter_dirs(post_file: &PostListType, dirs: Vec<PathBuf>) -> Vec<(PathBuf, String)> {
let mut post_dirs = vec![];
for dir in dirs {
if let Some(file_name) = Self::contains_file(&dir, post_file).unwrap() {
post_dirs.push((dir, file_name));
}
}
post_dirs
}
fn contains_file(dir: &PathBuf, base_name: &PostListType) -> Result<Option<String>> {
let entries = fs::read_dir(dir)
.context(format!("Could not read directory {}", dir.to_str().unwrap()))?;
for entry in entries {
let entry = entry?;
if entry.file_type()?.is_file() {
let file_name = entry.file_name().to_str().unwrap().to_string();
match base_name {
PostListType::IndexBaseName(base_name) => {
if file_name.contains(base_name) {
return Ok(Some(file_name.to_string()));
}
}
PostListType::AnyContentFile => {
if file_name.ends_with(".md") || file_name.ends_with(".htm") || file_name.ends_with(".html") {
return Ok(Some(file_name.to_string()));
}
}
}
}
}
Ok(None)
}
}