diff options
Diffstat (limited to 'src/site.rs')
-rw-r--r-- | src/site.rs | 181 |
1 files changed, 105 insertions, 76 deletions
diff --git a/src/site.rs b/src/site.rs index fd28a2b..2d1368d 100644 --- a/src/site.rs +++ b/src/site.rs @@ -1,23 +1,23 @@ use crate::error::SiteError; +use crate::name::{Name, NameBuilder, Names}; use crate::page::{MarkdownPage, UnprocessedPage, WikitextPage}; use crate::parser::WikitextParser; use crate::token::TokenPatterns; -use crate::util::{join_subpath, make_path_absolute, make_path_relative_to, make_relative_link}; +use crate::util::make_relative_link; use log::{debug, info, trace}; use std::collections::HashMap; use std::path::{Path, PathBuf}; use walkdir::WalkDir; pub struct Site { + builder: NameBuilder, wikitext_pages: Vec<WikitextPage>, unprocessed_pages: Vec<UnprocessedPage>, markdown_pages: Vec<MarkdownPage>, - files: Vec<PathBuf>, - included_files: Vec<PathBuf>, + files: Names, patterns: TokenPatterns, - srcdir: PathBuf, - destdir: PathBuf, - pages: PageSet, + name_queue: Vec<Name>, + page_queue: PageSet, } impl Site { @@ -29,55 +29,73 @@ impl Site { P: AsRef<Path>, { Self { + builder: NameBuilder::new(srcdir.as_ref(), destdir.as_ref()), wikitext_pages: vec![], unprocessed_pages: vec![], markdown_pages: vec![], - files: vec![], - included_files: vec![], + files: Names::default(), patterns: TokenPatterns::default(), - srcdir: srcdir.as_ref().into(), - destdir: destdir.as_ref().into(), - pages: PageSet::default(), + name_queue: vec![], + page_queue: PageSet::default(), } } pub fn scan(&mut self) -> Result<(), SiteError> { - for filename in Self::all_files(&self.srcdir)? { - self.included_files - .push(make_path_relative_to(&self.srcdir, &filename)); - if Self::is_markdown(&filename) { - let page = WikitextPage::read(&self.srcdir, &filename)?; - self.add_wikitextpage(page); - } else if filename.is_file() || filename.is_symlink() { - self.add_other_file(filename); + for name in self.all_files()? { + trace!("scan: name={}", name); + if name.is_wikitext_page() { + trace!("scan: it's a page"); + self.name_queue.push(name); + } else { + trace!("scan: it's a non-page file"); + let filename = name.source_path(); + if filename.is_file() || filename.is_symlink() { + self.add_other_file(name); + } } } Ok(()) } - pub fn add_wikitextpage(&mut self, page: WikitextPage) { + fn add_wikitextpage(&mut self, page: WikitextPage) { info!("add wikitext page {}", page.meta().path().display()); - self.pages.insert(&page); + self.page_queue.insert(&page); self.wikitext_pages.push(page); } - pub fn add_other_file(&mut self, filename: PathBuf) { - info!("add other file {}", filename.display()); - let filename = make_path_relative_to(&self.srcdir, &filename); - let filename = make_path_absolute(&filename); - self.files.push(filename); + fn add_other_file(&mut self, name: Name) { + info!("add other file {}", name); + self.files.insert(name); } pub fn process(&mut self) -> Result<(), SiteError> { + trace!("processing queues"); loop { - if !self.process_wikipage()? && !self.process_unrocessed_page()? { + if !self.process_name()? + && !self.process_wikipage()? + && !self.process_unrocessed_page()? + { + trace!("processing queues done"); break; } } Ok(()) } - pub fn process_wikipage(&mut self) -> Result<bool, SiteError> { + fn process_name(&mut self) -> Result<bool, SiteError> { + if let Some(name) = self.name_queue.pop() { + debug!("loading wikitext page {}", name.source_path().display()); + let page = WikitextPage::read(&name)?; + self.files.insert(name); + self.add_wikitextpage(page); + Ok(true) + } else { + trace!("name_queue was empty"); + Ok(false) + } + } + + fn process_wikipage(&mut self) -> Result<bool, SiteError> { if let Some(page) = self.wikitext_pages.pop() { debug!("processing wikitext page {}", page.meta().path().display()); let mut parser = WikitextParser::new(page.wikitext(), &self.patterns); @@ -85,11 +103,12 @@ impl Site { self.unprocessed_pages.push(page); Ok(true) } else { + trace!("wikitext_ages was empty"); Ok(false) } } - pub fn process_unrocessed_page(&mut self) -> Result<bool, SiteError> { + fn process_unrocessed_page(&mut self) -> Result<bool, SiteError> { if let Some(page) = self.unprocessed_pages.pop() { debug!( "processing unprocessed page {}", @@ -99,6 +118,7 @@ impl Site { self.markdown_pages.push(page); Ok(true) } else { + trace!("unprocessed_ages was empty"); Ok(false) } } @@ -107,35 +127,38 @@ impl Site { &self.markdown_pages } - pub fn files(&self) -> &[PathBuf] { - &self.files - } - - pub fn included_files(&self) -> &[PathBuf] { - &self.included_files - } - - pub fn input_filename(&self, filename: &Path) -> Result<PathBuf, SiteError> { - Ok(join_subpath(&self.srcdir, filename)) + pub fn files_only(&self) -> impl Iterator<Item = &Name> { + self.files.files() } - pub fn output_filename(&self, filename: &Path) -> Result<PathBuf, SiteError> { - Ok(join_subpath(&self.destdir, filename)) + pub fn pages_and_files(&self) -> impl Iterator<Item = &Name> { + self.files.iter().chain(self.name_queue.iter()) } - fn all_files(root: &Path) -> Result<Vec<PathBuf>, SiteError> { - let mut files = vec![]; + fn all_files(&self) -> Result<Vec<Name>, SiteError> { + let mut names = vec![]; + let root = self.builder.srcdir(); + trace!("all_files: root={}", root.display()); for e in WalkDir::new(root) { let e = e.map_err(|err| SiteError::WalkDir(root.to_path_buf(), err))?; let path = e.path(); + trace!("all_files: path={}", path.display()); if Self::is_excluded(path) { debug!("exclude {}", path.display()); } else { debug!("include {}", path.display()); - files.push(path.to_path_buf()); + if Self::is_markdown(path) { + trace!("it's markdown"); + names.push(self.builder.page(path)); + } else if path.is_file() { + trace!("it's not markdown"); + names.push(self.builder.file(path)); + } else { + trace!("it's not a file"); + } } } - Ok(files) + Ok(names) } fn is_excluded(path: &Path) -> bool { @@ -182,7 +205,7 @@ impl Site { // Is target absolute? if target.starts_with("/") { - if let Some(path) = self.pages.get(target) { + if let Some(path) = self.page_queue.get(target) { trace!("absolute target exists"); return Ok(path.into()); } else { @@ -194,7 +217,7 @@ impl Site { // Does a sub-page exist? let path = page.join(target); trace!("checking for subpage {}", path.display()); - if let Some(path) = self.pages.get(&path) { + if let Some(path) = self.page_queue.get(&path) { trace!("subpage exists: {}", path.display()); return Ok(path.into()); } @@ -207,7 +230,7 @@ impl Site { parent.display(), path.display() ); - if let Some(path) = self.pages.get(path.as_path()) { + if let Some(path) = self.page_queue.get(path.as_path()) { trace!("sibling page exists: {}", path.display()); return Ok(path.into()); } @@ -224,8 +247,8 @@ impl Site { } fn file_exists(&self, filename: &Path) -> bool { - for existing in self.files.iter() { - if filename == existing { + for existing in self.files.files() { + if filename == existing.page_path() { return true; } } @@ -256,32 +279,37 @@ impl PageSet { #[cfg(test)] mod test { - use super::{Site, SiteError, WikitextPage}; + use super::{NameBuilder, Site, SiteError, WikitextPage}; use crate::page::MetaBuilder; use std::{ path::{Path, PathBuf}, time::SystemTime, }; + fn site() -> Site { + Site::new("/src", "/dest") + } + + fn builder() -> NameBuilder { + NameBuilder::new(Path::new("/src"), Path::new("/dest")) + } + fn page(path: &str) -> WikitextPage { + let name = builder().page(Path::new(path)); let mtime = SystemTime::now(); - let meta = MetaBuilder::default() - .path(PathBuf::from(path)) - .mtime(mtime) - .build(); + let meta = MetaBuilder::default().name(name).mtime(mtime).build(); WikitextPage::new(meta, "".into()) } #[test] fn has_no_pages_initially() { - let site = Site::new(".", "."); - assert_eq!(site.markdown_pages().to_vec(), vec![]); + assert_eq!(site().markdown_pages().to_vec(), vec![]); } #[test] fn absolute_link_resolves_to_link_relative_root_of_site() { - let mut site = Site::new(".", "."); - site.add_wikitextpage(page("/yo/yoyo")); + let mut site = site(); + site.add_wikitextpage(page("/src/yo/yoyo")); assert_eq!( site.resolve("/foo/bar", "/yo/yoyo").unwrap(), Path::new("../yo/yoyo") @@ -290,11 +318,11 @@ mod test { #[test] fn link_to_missing_is_an_error() { - let site = Site::new(".", "."); - match site.resolve("/foo/bar", "yo") { + let site = site(); + match site.resolve("/src/foo/bar", "yo") { Err(SiteError::PageMissing(page, target)) => { assert_eq!(target, PathBuf::from("yo")); - assert_eq!(page, PathBuf::from("/foo/bar")); + assert_eq!(page, PathBuf::from("/src/foo/bar")); } _ => panic!("unexpected success"), } @@ -302,40 +330,40 @@ mod test { #[test] fn link_to_sibling_resolves_to_it() { - let mut site = Site::new(".", "."); - site.add_wikitextpage(page("/foo/yo")); + let mut site = site(); + site.add_wikitextpage(page("/src/foo/yo")); site.process().unwrap(); assert_eq!(site.resolve("/foo/bar", "yo").unwrap(), Path::new("yo")); } #[test] fn link_using_other_casing_is_resolved() { - let mut site = Site::new(".", "."); - site.add_wikitextpage(page("/foo/yo")); + let mut site = site(); + site.add_wikitextpage(page("/src/foo/yo")); site.process().unwrap(); assert_eq!(site.resolve("/foo/bar", "YO").unwrap(), Path::new("yo")); } #[test] fn link_to_sublpage_resolves_to_it() { - let mut site = Site::new(".", "."); - site.add_wikitextpage(page("/foo/bar/yo")); + let mut site = site(); + site.add_wikitextpage(page("/src/foo/bar/yo")); site.process().unwrap(); assert_eq!(site.resolve("/foo/bar", "yo").unwrap(), Path::new("bar/yo")); } #[test] fn link_to_sublpage_resolves_to_it_and_not_sibling() { - let mut site = Site::new(".", "."); - site.add_wikitextpage(page("/foo/bar/yo")); - site.add_wikitextpage(page("/foo/yo")); + let mut site = site(); + site.add_wikitextpage(page("/src/foo/bar/yo")); + site.add_wikitextpage(page("/src/foo/yo")); site.process().unwrap(); assert_eq!(site.resolve("/foo/bar", "yo").unwrap(), Path::new("bar/yo")); } #[test] fn link_to_unrelated_subpage_is_an_error() { - let mut site = Site::new(".", "."); + let mut site = site(); site.process().unwrap(); match site.resolve("/foo/bar", "yo/yoyo") { Err(SiteError::PageMissing(page, target)) => { @@ -348,8 +376,8 @@ mod test { #[test] fn link_to_subsubpage_resolves_to_it() { - let mut site = Site::new(".", "."); - site.add_wikitextpage(page("/foo/bar/yo/yoyo")); + let mut site = site(); + site.add_wikitextpage(page("/src/foo/bar/yo/yoyo")); site.process().unwrap(); assert_eq!( site.resolve("/foo/bar", "yo/yoyo").unwrap(), @@ -359,8 +387,9 @@ mod test { #[test] fn link_to_sibling_file_resolves_to_it() { - let mut site = Site::new("/src", "/dest"); - site.add_other_file(PathBuf::from("/src/foo/bar.jpg")); + let mut site = site(); + let name = builder().file(Path::new("/src/foo/bar.jpg")); + site.add_other_file(name); site.process().unwrap(); assert_eq!( site.resolve("/foo/bar", "bar.jpg").unwrap(), |