use crate::{
Error,
document::{DocumentMetadata, DocumentType},
file::FileMetadata,
site::{SiteMetadata, SiteName},
};
use std::{
collections::HashMap,
fs,
path::{Path, PathBuf},
sync::Arc,
};
use walkdir::WalkDir;
#[derive(Eq, Clone, PartialEq, Debug)]
pub enum WorkspacePath {
Root(PathBuf),
Site(PathBuf),
}
impl WorkspacePath {
pub fn path(&self) -> &Path {
match self {
Self::Root(path) => &path,
Self::Site(path) => &path,
}
}
}
#[derive(Eq, Clone, PartialEq, Debug)]
pub struct MetadatadWorkspace {
pub path: WorkspacePath,
pub sites: HashMap<SiteName, MetadatadSite>,
}
impl MetadatadWorkspace {
pub fn new_multi(root_path: &Path) -> Result<Self, Error> {
let mut sites = HashMap::new();
let root_subfolders = fs::read_dir(root_path)?;
for site_folder in root_subfolders {
let site_folder = site_folder?;
let site_name = site_folder
.file_name()
.into_string()
.map_err(|_| Error::PathContainNonUnicode)?;
if site_name.starts_with(".")
|| site_name.starts_with("_")
|| site_name.ends_with("@tmp")
{
continue;
}
let site = Arc::new(SiteMetadata::new(
Some(SiteName(site_name.clone())),
&site_folder.path(),
)?);
let item = MetadatadSite::new(site.clone())?;
sites.insert(site.name.clone(), item);
}
Ok(Self {
sites,
path: WorkspacePath::Root(root_path.to_owned()),
})
}
pub fn new_single(site_path: &Path) -> Result<(Self, SiteName), Error> {
let mut sites = HashMap::new();
let site = Arc::new(SiteMetadata::new(None, &site_path)?);
let site_name = site.name.clone();
let item = MetadatadSite::new(site.clone())?;
sites.insert(site.name.clone(), item);
Ok((
Self {
sites,
path: WorkspacePath::Site(site_path.to_owned()),
},
site_name,
))
}
}
#[derive(Eq, Clone, PartialEq, Debug)]
pub struct MetadatadSite {
pub site: Arc<SiteMetadata>,
pub documents: Vec<Arc<DocumentMetadata>>,
pub files: Arc<HashMap<PathBuf, FileMetadata>>,
}
impl MetadatadSite {
pub fn new(site: Arc<SiteMetadata>) -> Result<Self, Error> {
let mut documents = Vec::new();
let mut files = HashMap::new();
let walker = WalkDir::new(&site.source_path)
.into_iter()
.filter_entry(|entry| {
if let Some(file_name) = entry.file_name().to_str() {
if file_name == "_posts" && entry.file_type().is_dir() {
return true;
}
if file_name.starts_with(".") || file_name.starts_with("_") {
return false;
}
return true;
}
return false;
});
for entry in walker {
let entry = entry?;
if entry.file_type().is_file() {
let modified = fs::metadata(entry.path())?.modified()?;
let typ = if let Some(extension) = entry.path().extension() {
let extension = extension.to_str().ok_or(Error::PathContainNonUnicode)?;
DocumentType::try_from(extension).ok()
} else {
None
};
if let Some(typ) = typ {
let document = DocumentMetadata::new(&site, entry.path(), typ, modified)?;
documents.push(Arc::new(document));
} else {
let rel_file_path = entry.path().strip_prefix(&site.source_path)?;
let content = fs::read(entry.path())?;
let file = FileMetadata {
site: site.clone(),
path: rel_file_path.to_owned(),
source_path: entry.path().to_owned(),
content,
modified,
};
files.insert(file.path.clone(), file);
}
}
}
Ok(Self {
site,
documents,
files: Arc::new(files),
})
}
}