Partial reloading of content on change
This commit is contained in:
parent
b0cc1ac042
commit
8b5183d4ad
|
@ -6,6 +6,6 @@ use gutenberg::Site;
|
|||
|
||||
pub fn build() -> Result<()> {
|
||||
let mut site = Site::new(env::current_dir().unwrap())?;
|
||||
site.parse()?;
|
||||
site.load()?;
|
||||
site.build()
|
||||
}
|
||||
|
|
|
@ -70,7 +70,7 @@ pub fn serve(interface: &str, port: &str) -> Result<()> {
|
|||
format!("http://{}", address)
|
||||
};
|
||||
|
||||
site.parse()?;
|
||||
site.load()?;
|
||||
site.enable_live_reload();
|
||||
site.build()?;
|
||||
report_elapsed_time(start);
|
||||
|
@ -129,7 +129,7 @@ pub fn serve(interface: &str, port: &str) -> Result<()> {
|
|||
(ChangeKind::Content, _) => {
|
||||
println!("-> Content changed {}", path.display());
|
||||
// Force refresh
|
||||
rebuild_done_handling(&broadcaster, site.rebuild_after_content_change(), "/x.js");
|
||||
rebuild_done_handling(&broadcaster, site.rebuild_after_content_change(&path), "/x.js");
|
||||
},
|
||||
(ChangeKind::Templates, _) => {
|
||||
println!("-> Template changed {}", path.display());
|
||||
|
|
80
src/site.rs
80
src/site.rs
|
@ -101,39 +101,60 @@ impl Site {
|
|||
self.output_path = path.as_ref().to_path_buf();
|
||||
}
|
||||
|
||||
/// Reads all .md files in the `content` directory and create pages
|
||||
/// Reads all .md files in the `content` directory and create pages/sections
|
||||
/// out of them
|
||||
pub fn parse(&mut self) -> Result<()> {
|
||||
pub fn load(&mut self) -> Result<()> {
|
||||
let path = self.base_path.to_string_lossy().replace("\\", "/");
|
||||
let content_glob = format!("{}/{}", path, "content/**/*.md");
|
||||
|
||||
// parent_dir -> Section
|
||||
let mut sections = BTreeMap::new();
|
||||
|
||||
// Glob is giving us the result order so _index will show up first
|
||||
// for each directory
|
||||
// TODO: make that parallel, that's the main bottleneck
|
||||
// `add_section` and `add_page` can't be used in the parallel version afaik
|
||||
for entry in glob(&content_glob).unwrap().filter_map(|e| e.ok()) {
|
||||
let path = entry.as_path();
|
||||
|
||||
if path.file_name().unwrap() == "_index.md" {
|
||||
let section = Section::from_file(&path, &self.config)?;
|
||||
sections.insert(section.parent_path.clone(), section);
|
||||
self.add_section(&path)?;
|
||||
} else {
|
||||
self.add_page(&path)?;
|
||||
}
|
||||
}
|
||||
|
||||
self.populate_sections();
|
||||
self.populate_tags_and_categories();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Simple wrapper fn to avoid repeating that code in several places
|
||||
fn add_page(&mut self, path: &Path) -> Result<()> {
|
||||
let page = Page::from_file(&path, &self.config)?;
|
||||
if sections.contains_key(&page.parent_path) {
|
||||
sections.get_mut(&page.parent_path).unwrap().pages.push(page.clone());
|
||||
}
|
||||
self.pages.insert(page.file_path.clone(), page);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Simple wrapper fn to avoid repeating that code in several places
|
||||
fn add_section(&mut self, path: &Path) -> Result<()> {
|
||||
let section = Section::from_file(path, &self.config)?;
|
||||
self.sections.insert(section.parent_path.clone(), section);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Find out the direct subsections of each subsection if there are some
|
||||
/// as well as the pages for each section
|
||||
fn populate_sections(&mut self) {
|
||||
for page in self.pages.values() {
|
||||
if self.sections.contains_key(&page.parent_path) {
|
||||
self.sections.get_mut(&page.parent_path).unwrap().pages.push(page.clone());
|
||||
}
|
||||
}
|
||||
// Find out the direct subsections of each subsection if there are some
|
||||
|
||||
let mut grandparent_paths = HashMap::new();
|
||||
for section in sections.values() {
|
||||
for section in self.sections.values() {
|
||||
let grand_parent = section.parent_path.parent().unwrap().to_path_buf();
|
||||
grandparent_paths.entry(grand_parent).or_insert_with(|| vec![]).push(section.clone());
|
||||
}
|
||||
|
||||
for (parent_path, section) in &mut sections {
|
||||
for (parent_path, section) in &mut self.sections {
|
||||
section.pages.sort_by(|a, b| a.partial_cmp(b).unwrap());
|
||||
|
||||
match grandparent_paths.get(parent_path) {
|
||||
|
@ -141,15 +162,10 @@ impl Site {
|
|||
None => continue,
|
||||
};
|
||||
}
|
||||
|
||||
self.sections = sections;
|
||||
self.parse_tags_and_categories();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Separated from `parse` for easier testing
|
||||
pub fn parse_tags_and_categories(&mut self) {
|
||||
pub fn populate_tags_and_categories(&mut self) {
|
||||
for page in self.pages.values() {
|
||||
if let Some(ref category) = page.meta.category {
|
||||
self.categories
|
||||
|
@ -221,8 +237,26 @@ impl Site {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub fn rebuild_after_content_change(&mut self) -> Result<()> {
|
||||
self.parse()?;
|
||||
pub fn rebuild_after_content_change(&mut self, path: &Path) -> Result<()> {
|
||||
if path.exists() {
|
||||
// file exists, either a new one or updating content
|
||||
if self.pages.contains_key(path) {
|
||||
if path.ends_with("_index.md") {
|
||||
self.add_section(path)?;
|
||||
} else {
|
||||
// probably just an update so just re-parse that page
|
||||
self.add_page(path)?;
|
||||
}
|
||||
} else {
|
||||
// new file?
|
||||
self.add_page(path)?;
|
||||
}
|
||||
} else {
|
||||
// File doesn't exist -> a deletion so we remove it from
|
||||
self.pages.remove(path);
|
||||
}
|
||||
self.populate_sections();
|
||||
self.populate_tags_and_categories();
|
||||
self.build()
|
||||
}
|
||||
|
||||
|
|
|
@ -17,7 +17,7 @@ fn test_can_parse_site() {
|
|||
let mut path = env::current_dir().unwrap().to_path_buf();
|
||||
path.push("test_site");
|
||||
let mut site = Site::new(&path).unwrap();
|
||||
site.parse().unwrap();
|
||||
site.load().unwrap();
|
||||
|
||||
// Correct number of pages (sections are pages too)
|
||||
assert_eq!(site.pages.len(), 10);
|
||||
|
@ -89,7 +89,7 @@ fn test_can_build_site_without_live_reload() {
|
|||
let mut path = env::current_dir().unwrap().to_path_buf();
|
||||
path.push("test_site");
|
||||
let mut site = Site::new(&path).unwrap();
|
||||
site.parse().unwrap();
|
||||
site.load().unwrap();
|
||||
let tmp_dir = TempDir::new("example").expect("create temp dir");
|
||||
let public = &tmp_dir.path().join("public");
|
||||
site.set_output_path(&public);
|
||||
|
@ -130,7 +130,7 @@ fn test_can_build_site_with_live_reload() {
|
|||
let mut path = env::current_dir().unwrap().to_path_buf();
|
||||
path.push("test_site");
|
||||
let mut site = Site::new(&path).unwrap();
|
||||
site.parse().unwrap();
|
||||
site.load().unwrap();
|
||||
let tmp_dir = TempDir::new("example").expect("create temp dir");
|
||||
let public = &tmp_dir.path().join("public");
|
||||
site.set_output_path(&public);
|
||||
|
@ -168,7 +168,7 @@ fn test_can_build_site_with_categories() {
|
|||
let mut path = env::current_dir().unwrap().to_path_buf();
|
||||
path.push("test_site");
|
||||
let mut site = Site::new(&path).unwrap();
|
||||
site.parse().unwrap();
|
||||
site.load().unwrap();
|
||||
|
||||
for (i, page) in site.pages.values_mut().enumerate() {
|
||||
page.meta.category = if i % 2 == 0 {
|
||||
|
@ -177,7 +177,7 @@ fn test_can_build_site_with_categories() {
|
|||
Some("B".to_string())
|
||||
};
|
||||
}
|
||||
site.parse_tags_and_categories();
|
||||
site.populate_tags_and_categories();
|
||||
let tmp_dir = TempDir::new("example").expect("create temp dir");
|
||||
let public = &tmp_dir.path().join("public");
|
||||
site.set_output_path(&public);
|
||||
|
@ -219,7 +219,7 @@ fn test_can_build_site_with_tags() {
|
|||
let mut path = env::current_dir().unwrap().to_path_buf();
|
||||
path.push("test_site");
|
||||
let mut site = Site::new(&path).unwrap();
|
||||
site.parse().unwrap();
|
||||
site.load().unwrap();
|
||||
|
||||
for (i, page) in site.pages.values_mut().enumerate() {
|
||||
page.meta.tags = if i % 2 == 0 {
|
||||
|
@ -228,7 +228,7 @@ fn test_can_build_site_with_tags() {
|
|||
Some(vec!["tag with space".to_string()])
|
||||
};
|
||||
}
|
||||
site.parse_tags_and_categories();
|
||||
site.populate_tags_and_categories();
|
||||
|
||||
let tmp_dir = TempDir::new("example").expect("create temp dir");
|
||||
let public = &tmp_dir.path().join("public");
|
||||
|
|
Loading…
Reference in a new issue