diff --git a/.gitmodules b/.gitmodules index 9f291304..97cbb0d2 100644 --- a/.gitmodules +++ b/.gitmodules @@ -13,9 +13,6 @@ [submodule "sublime_syntaxes/Julia-sublime"] path = sublime_syntaxes/Julia-sublime url = https://github.com/JuliaEditorSupport/Julia-sublime.git -[submodule "sublime_syntaxes/Elm.tmLanguage"] - path = sublime_syntaxes/Elm.tmLanguage - url = https://github.com/elm-community/Elm.tmLanguage.git [submodule "sublime_syntaxes/sublime_toml_highlighting"] path = sublime_syntaxes/sublime_toml_highlighting url = https://github.com/Jayflux/sublime_toml_highlighting.git @@ -31,3 +28,6 @@ [submodule "sublime_syntaxes/TypeScript-TmLanguage"] path = sublime_syntaxes/TypeScript-TmLanguage url = https://github.com/Microsoft/TypeScript-TmLanguage +[submodule "sublime_syntaxes/SublimeElmLanguageSupport"] + path = sublime_syntaxes/SublimeElmLanguageSupport + url = https://github.com/elm-community/SublimeElmLanguageSupport diff --git a/Cargo.lock b/Cargo.lock index d5a59d58..5b858e32 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -282,6 +282,11 @@ dependencies = [ "toml 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "fs_extra" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "fsevent" version = "0.2.17" @@ -342,6 +347,7 @@ dependencies = [ "iron 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "mount 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "notify 4.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "rebuild 0.1.0", "site 0.1.0", "staticfile 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "term-painter 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", @@ -864,6 +870,19 @@ dependencies = [ "rand 0.3.20 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "rebuild" +version = "0.1.0" +dependencies = [ + "content 0.1.0", + "errors 0.1.0", + "front_matter 0.1.0", + "fs_extra 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "highlighting 0.1.0", + "site 0.1.0", + "tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "redox_syscall" version = "0.1.37" @@ -1446,6 +1465,7 @@ dependencies = [ "checksum filetime 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)" = "714653f3e34871534de23771ac7b26e999651a0a228f47beb324dfdf1dd4b10f" "checksum flate2 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9fac2277e84e5e858483756647a9d0aa8d9a2b7cba517fd84325a0aaa69a0909" "checksum fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2fad85553e09a6f881f739c29f0b00b0f01357c743266d478b68951ce23285f3" +"checksum fs_extra 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5f2a4a2034423744d2cc7ca2068453168dcdb82c438419e639a26bd87839c674" "checksum fsevent 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)" = "c4bbbf71584aeed076100b5665ac14e3d85eeb31fdbb45fbd41ef9a682b5ec05" "checksum fsevent-sys 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "1a772d36c338d07a032d5375a36f15f9a7043bf0cb8ce7cee658e037c6032874" "checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" diff --git a/Cargo.toml b/Cargo.toml index 899f573b..d65bab0c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -36,6 +36,7 @@ errors = { path = "components/errors" } content = { path = "components/content" } front_matter = { path = "components/front_matter" } utils = { path = "components/utils" } +rebuild = { path = "components/rebuild" } [workspace] members = [ @@ -45,6 +46,7 @@ members = [ "components/front_matter", "components/highlighting", "components/pagination", + "components/rebuild", "components/rendering", "components/site", "components/taxonomies", diff --git a/README.md b/README.md index 7af3212d..9dcabe9b 100644 --- a/README.md +++ b/README.md @@ -45,7 +45,7 @@ You can also add a submodule to the repository of the wanted syntax: ```bash $ cd sublime_syntaxes -$ git submodule add https://github.com/elm-community/Elm.tmLanguage.git +$ git submodule add https://github.com/elm-community/SublimeElmLanguageSupport ``` Note that you can also only copy manually the updated syntax definition file but this means diff --git a/components/content/src/page.rs b/components/content/src/page.rs index 41ad47fa..59e1299e 100644 --- a/components/content/src/page.rs +++ b/components/content/src/page.rs @@ -59,7 +59,7 @@ impl Page { Page { file: FileInfo::new_page(file_path), - meta: meta, + meta, raw_content: "".to_string(), assets: vec![], content: "".to_string(), diff --git a/components/rebuild/Cargo.toml b/components/rebuild/Cargo.toml new file mode 100644 index 00000000..a7980970 --- /dev/null +++ b/components/rebuild/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "rebuild" +version = "0.1.0" +authors = ["Vincent Prouillet "] + +[dependencies] +errors = { path = "../errors" } +front_matter = { path = "../front_matter" } +highlighting = { path = "../highlighting" } +content = { path = "../content" } +site = { path = "../site" } + +[dev-dependencies] +tempdir = "0.3" +fs_extra = "1.1.0" diff --git a/components/rebuild/src/lib.rs b/components/rebuild/src/lib.rs new file mode 100644 index 00000000..520706d8 --- /dev/null +++ b/components/rebuild/src/lib.rs @@ -0,0 +1,371 @@ +extern crate site; +extern crate errors; +extern crate content; +extern crate front_matter; + +use std::path::{Path, Component}; + +use errors::Result; +use site::Site; +use content::{Page, Section}; +use front_matter::{PageFrontMatter, SectionFrontMatter}; + + +/// Finds the section that contains the page given if there is one +pub fn find_parent_section<'a>(site: &'a Site, page: &Page) -> Option<&'a Section> { + for section in site.sections.values() { + if section.is_child_page(&page.file.path) { + return Some(section) + } + } + + None +} + + +#[derive(Debug, Clone, Copy, PartialEq)] +pub enum PageChangesNeeded { + /// Editing `tags` + Tags, + /// Editing `categories` + Categories, + /// Editing `date`, `order` or `weight` + Sort, + /// Editing anything causes a re-render of the page + Render, +} + +#[derive(Debug, Clone, Copy, PartialEq)] +pub enum SectionChangesNeeded { + /// Editing `sort_by` + Sort, + /// Editing `title`, `description`, `extra`, `template` or setting `render` to true + Render, + /// Editing `paginate_by`, `paginate_path` or `insert_anchor_links` + RenderWithPages, + /// Setting `render` to false + Delete, +} + +/// Evaluates all the params in the front matter that changed so we can do the smallest +/// delta in the serve command +/// Order matters as the actions will be done in insertion order +fn find_section_front_matter_changes(current: &SectionFrontMatter, new: &SectionFrontMatter) -> Vec { + let mut changes_needed = vec![]; + + if current.sort_by != new.sort_by { + changes_needed.push(SectionChangesNeeded::Sort); + } + + // We want to hide the section + // TODO: what to do on redirect_path change? + if current.should_render() && !new.should_render() { + changes_needed.push(SectionChangesNeeded::Delete); + // Nothing else we can do + return changes_needed; + } + + if current.paginate_by != new.paginate_by + || current.paginate_path != new.paginate_path + || current.insert_anchor_links != new.insert_anchor_links { + changes_needed.push(SectionChangesNeeded::RenderWithPages); + // Nothing else we can do + return changes_needed; + } + + // Any new change will trigger a re-rendering of the section page only + changes_needed.push(SectionChangesNeeded::Render); + changes_needed +} + +/// Evaluates all the params in the front matter that changed so we can do the smallest +/// delta in the serve command +/// Order matters as the actions will be done in insertion order +fn find_page_front_matter_changes(current: &PageFrontMatter, other: &PageFrontMatter) -> Vec { + let mut changes_needed = vec![]; + + if current.tags != other.tags { + changes_needed.push(PageChangesNeeded::Tags); + } + + if current.category != other.category { + changes_needed.push(PageChangesNeeded::Categories); + } + + if current.date != other.date || current.order != other.order || current.weight != other.weight { + changes_needed.push(PageChangesNeeded::Sort); + } + + changes_needed.push(PageChangesNeeded::Render); + changes_needed +} + +/// Handles a path deletion: could be a page, a section, a folder +fn delete_element(site: &mut Site, path: &Path, is_section: bool) -> Result<()> { + // Ignore the event if this path was not known + if !site.sections.contains_key(path) && !site.pages.contains_key(path) { + return Ok(()); + } + + if is_section { + if let Some(s) = site.pages.remove(path) { + site.permalinks.remove(&s.file.relative); + site.populate_sections(); + } + } else { + if let Some(p) = site.pages.remove(path) { + site.permalinks.remove(&p.file.relative); + + if p.meta.has_tags() || p.meta.category.is_some() { + site.populate_tags_and_categories(); + } + + // if there is a parent section, we will need to re-render it + // most likely + if find_parent_section(site, &p).is_some() { + site.populate_sections(); + } + }; + } + + // Ensure we have our fn updated so it doesn't contain the permalink(s)/section/page deleted + site.register_tera_global_fns(); + // Deletion is something that doesn't happen all the time so we + // don't need to optimise it too much + return site.build(); +} + +/// Handles a `_index.md` (a section) being edited in some ways +fn handle_section_editing(site: &mut Site, path: &Path) -> Result<()> { + let section = Section::from_file(path, &site.config)?; + match site.add_section(section, true)? { + // Updating a section + Some(prev) => { + if site.sections[path].meta == prev.meta { + // Front matter didn't change, only content did + // so we render only the section page, not its pages + return site.render_section(&site.sections[path], false); + } + + // Front matter changed + for changes in find_section_front_matter_changes(&site.sections[path].meta, &prev.meta) { + // Sort always comes first if present so the rendering will be fine + match changes { + SectionChangesNeeded::Sort => { + site.sort_sections_pages(Some(path)); + site.register_tera_global_fns(); + }, + SectionChangesNeeded::Render => site.render_section(&site.sections[path], false)?, + SectionChangesNeeded::RenderWithPages => site.render_section(&site.sections[path], true)?, + // not a common enough operation to make it worth optimizing + SectionChangesNeeded::Delete => { + site.populate_sections(); + site.build()?; + }, + }; + } + return Ok(()); + }, + // New section, only render that one + None => { + site.populate_sections(); + site.register_tera_global_fns(); + return site.render_section(&site.sections[path], true); + } + }; +} + +macro_rules! render_parent_section { + ($site: expr, $path: expr) => { + match find_parent_section($site, &$site.pages[$path]) { + Some(s) => { + $site.render_section(s, false)?; + }, + None => (), + }; + } +} + +/// Handles a page being edited in some ways +fn handle_page_editing(site: &mut Site, path: &Path) -> Result<()> { + let page = Page::from_file(path, &site.config)?; + match site.add_page(page, true)? { + // Updating a page + Some(prev) => { + // Front matter didn't change, only content did + if site.pages[path].meta == prev.meta { + // Other than the page itself, the summary might be seen + // on a paginated list for a blog for example + if site.pages[path].summary.is_some() { + render_parent_section!(site, path); + } + // TODO: register_tera_global_fns is expensive as it involves lots of cloning + // I can't think of a valid usecase where you would need the content + // of a page through a global fn so it's commented out for now + // site.register_tera_global_fns(); + return site.render_page(& site.pages[path]); + } + + // Front matter changed + let mut taxonomies_populated = false; + let mut sections_populated = false; + for changes in find_page_front_matter_changes(&site.pages[path].meta, &prev.meta) { + // Sort always comes first if present so the rendering will be fine + match changes { + PageChangesNeeded::Tags => { + if !taxonomies_populated { + site.populate_tags_and_categories(); + taxonomies_populated = true; + } + site.register_tera_global_fns(); + site.render_tags()?; + }, + PageChangesNeeded::Categories => { + if !taxonomies_populated { + site.populate_tags_and_categories(); + taxonomies_populated = true; + } + site.register_tera_global_fns(); + site.render_categories()?; + }, + PageChangesNeeded::Sort => { + let section_path = match find_parent_section(site, &site.pages[path]) { + Some(s) => s.file.path.clone(), + None => continue // Do nothing if it's an orphan page + }; + if !sections_populated { + site.populate_sections(); + sections_populated = true; + } + site.sort_sections_pages(Some(§ion_path)); + site.register_tera_global_fns(); + site.render_index()?; + }, + PageChangesNeeded::Render => { + if !sections_populated { + site.populate_sections(); + sections_populated = true; + } + site.register_tera_global_fns(); + render_parent_section!(site, path); + site.render_page(&site.pages[path])?; + }, + }; + } + Ok(()) + }, + // It's a new page! + None => { + site.populate_sections(); + site.populate_tags_and_categories(); + site.register_tera_global_fns(); + // No need to optimise that yet, we can revisit if it becomes an issue + site.build() + } + } +} + + +// What happens when a section or a page is changed +pub fn after_content_change(site: &mut Site, path: &Path) -> Result<()> { + let is_section = path.file_name().unwrap() == "_index.md"; + + // A page or section got deleted + if !path.exists() { + delete_element(site, path, is_section)?; + } + + if is_section { + handle_section_editing(site, path) + } else { + handle_page_editing(site, path) + } +} + +/// What happens when a template is changed +pub fn after_template_change(site: &mut Site, path: &Path) -> Result<()> { + site.tera.full_reload()?; + let filename = path.file_name().unwrap().to_str().unwrap(); + + match filename { + "sitemap.xml" => site.render_sitemap(), + "rss.xml" => site.render_rss_feed(), + "robots.txt" => site.render_robots(), + "categories.html" | "category.html" => site.render_categories(), + "tags.html" | "tag.html" => site.render_tags(), + "page.html" => { + site.render_sections()?; + site.render_orphan_pages() + }, + "section.html" => site.render_sections(), + // Either the index or some unknown template changed + // We can't really know what this change affects so rebuild all + // the things + _ => { + // If we are updating a shortcode, re-render the markdown of all pages/site + // because we have no clue which one needs rebuilding + // TODO: look if there the shortcode is used in the markdown instead of re-rendering + // everything + if path.components().collect::>().contains(&Component::Normal("shortcodes".as_ref())) { + site.render_markdown()?; + } + site.populate_sections(); + site.render_sections()?; + site.render_orphan_pages()?; + site.render_categories()?; + site.render_tags() + }, + } +} + + +#[cfg(test)] +mod tests { + use front_matter::{PageFrontMatter, SectionFrontMatter, SortBy}; + use super::{ + find_page_front_matter_changes, find_section_front_matter_changes, + PageChangesNeeded, SectionChangesNeeded + }; + + #[test] + fn can_find_tag_changes_in_page_frontmatter() { + let new = PageFrontMatter { tags: Some(vec!["a tag".to_string()]), ..PageFrontMatter::default() }; + let changes = find_page_front_matter_changes(&PageFrontMatter::default(), &new); + assert_eq!(changes, vec![PageChangesNeeded::Tags, PageChangesNeeded::Render]); + } + + #[test] + fn can_find_category_changes_in_page_frontmatter() { + let current = PageFrontMatter { category: Some("a category".to_string()), ..PageFrontMatter::default() }; + let changes = find_page_front_matter_changes(¤t, &PageFrontMatter::default()); + assert_eq!(changes, vec![PageChangesNeeded::Categories, PageChangesNeeded::Render]); + } + + #[test] + fn can_find_multiple_changes_in_page_frontmatter() { + let current = PageFrontMatter { category: Some("a category".to_string()), order: Some(1), ..PageFrontMatter::default() }; + let changes = find_page_front_matter_changes(¤t, &PageFrontMatter::default()); + assert_eq!(changes, vec![PageChangesNeeded::Categories, PageChangesNeeded::Sort, PageChangesNeeded::Render]); + } + + #[test] + fn can_find_sort_changes_in_section_frontmatter() { + let new = SectionFrontMatter { sort_by: Some(SortBy::Date), ..SectionFrontMatter::default() }; + let changes = find_section_front_matter_changes(&SectionFrontMatter::default(), &new); + assert_eq!(changes, vec![SectionChangesNeeded::Sort, SectionChangesNeeded::Render]); + } + + #[test] + fn can_find_render_changes_in_section_frontmatter() { + let new = SectionFrontMatter { render: Some(false), ..SectionFrontMatter::default() }; + let changes = find_section_front_matter_changes(&SectionFrontMatter::default(), &new); + assert_eq!(changes, vec![SectionChangesNeeded::Delete]); + } + + #[test] + fn can_find_paginate_by_changes_in_section_frontmatter() { + let new = SectionFrontMatter { paginate_by: Some(10), ..SectionFrontMatter::default() }; + let changes = find_section_front_matter_changes(&SectionFrontMatter::default(), &new); + assert_eq!(changes, vec![SectionChangesNeeded::RenderWithPages]); + } +} diff --git a/components/rebuild/tests/rebuild.rs b/components/rebuild/tests/rebuild.rs new file mode 100644 index 00000000..9aeabfbc --- /dev/null +++ b/components/rebuild/tests/rebuild.rs @@ -0,0 +1,126 @@ +extern crate rebuild; +extern crate site; +extern crate tempdir; +extern crate fs_extra; + +use std::env; +use std::fs::{remove_dir_all, File}; +use std::io::prelude::*; + +use fs_extra::dir; +use tempdir::TempDir; +use site::Site; + +use rebuild::after_content_change; + +// Loads the test_site in a tempdir and build it there +// Returns (site_path_in_tempdir, site) +macro_rules! load_and_build_site { + ($tmp_dir: expr) => { + { + let mut path = env::current_dir().unwrap().parent().unwrap().parent().unwrap().to_path_buf(); + path.push("test_site"); + let mut options = dir::CopyOptions::new(); + options.copy_inside = true; + dir::copy(&path, &$tmp_dir, &options).unwrap(); + + let site_path = $tmp_dir.path().join("test_site"); + // delete useless sections for those tests + remove_dir_all(site_path.join("content").join("paginated")).unwrap(); + remove_dir_all(site_path.join("content").join("posts")).unwrap(); + + let mut site = Site::new(&site_path, "config.toml").unwrap(); + site.load().unwrap(); + let public = &site_path.join("public"); + site.set_output_path(&public); + site.build().unwrap(); + + (site_path, site) + } + } +} + +/// Replace the file at the path (starting from root) by the given content +/// and return the file path that was modified +macro_rules! edit_file { + ($site_path: expr, $path: expr, $content: expr) => { + { + let mut t = $site_path.clone(); + for c in $path.split('/') { + t.push(c); + } + let mut file = File::create(&t).expect("Could not open/create file"); + file.write_all($content).expect("Could not write to the file"); + t + } + } +} + +macro_rules! file_contains { + ($site_path: expr, $path: expr, $text: expr) => { + { + let mut path = $site_path.clone(); + for component in $path.split("/") { + path.push(component); + } + let mut file = File::open(&path).unwrap(); + let mut s = String::new(); + file.read_to_string(&mut s).unwrap(); + println!("{:?} -> {}", path, s); + s.contains($text) + } + } +} + +#[test] +fn can_rebuild_after_simple_change_to_page_content() { + let tmp_dir = TempDir::new("example").expect("create temp dir"); + let (site_path, mut site) = load_and_build_site!(tmp_dir); + let file_path = edit_file!(site_path, "content/rebuild/first.md", br#" ++++ +title = "first" +order = 1 +date = 2017-01-01 ++++ + +Some content"#); + + let res = after_content_change(&mut site, &file_path); + assert!(res.is_ok()); + assert!(file_contains!(site_path, "public/rebuild/first/index.html", "

Some content

")); +} + +#[test] +fn can_rebuild_after_title_change_page_global_func_usage() { + let tmp_dir = TempDir::new("example").expect("create temp dir"); + let (site_path, mut site) = load_and_build_site!(tmp_dir); + let file_path = edit_file!(site_path, "content/rebuild/first.md", br#" ++++ +title = "Premier" +order = 10 +date = 2017-01-01 ++++ + +# A title"#); + + let res = after_content_change(&mut site, &file_path); + assert!(res.is_ok()); + assert!(file_contains!(site_path, "public/rebuild/index.html", "

Premier

")); +} + +#[test] +fn can_rebuild_after_sort_change_in_section() { + let tmp_dir = TempDir::new("example").expect("create temp dir"); + let (site_path, mut site) = load_and_build_site!(tmp_dir); + let file_path = edit_file!(site_path, "content/rebuild/_index.md", br#" ++++ +paginate_by = 1 +sort_by = "order" +template = "rebuild.html" ++++ +"#); + + let res = after_content_change(&mut site, &file_path); + assert!(res.is_ok()); + assert!(file_contains!(site_path, "public/rebuild/index.html", "

second

first

")); +} diff --git a/components/site/Cargo.toml b/components/site/Cargo.toml index 21b79ee7..85f6fc5c 100644 --- a/components/site/Cargo.toml +++ b/components/site/Cargo.toml @@ -21,6 +21,5 @@ pagination = { path = "../pagination" } taxonomies = { path = "../taxonomies" } content = { path = "../content" } - [dev-dependencies] tempdir = "0.3" diff --git a/components/site/src/lib.rs b/components/site/src/lib.rs index ff069491..1e776b96 100644 --- a/components/site/src/lib.rs +++ b/components/site/src/lib.rs @@ -275,7 +275,7 @@ impl Site { /// Add a page to the site /// The `render` parameter is used in the serve command, when rebuilding a page. /// If `true`, it will also render the markdown for that page - /// Returns the previous page struct if there was one + /// Returns the previous page struct if there was one at the same path pub fn add_page(&mut self, page: Page, render: bool) -> Result> { let path = page.file.path.clone(); self.permalinks.insert(page.file.relative.clone(), page.permalink.clone()); @@ -293,7 +293,7 @@ impl Site { /// Add a section to the site /// The `render` parameter is used in the serve command, when rebuilding a page. /// If `true`, it will also render the markdown for that page - /// Returns the previous section struct if there was one + /// Returns the previous section struct if there was one at the same path pub fn add_section(&mut self, section: Section, render: bool) -> Result> { let path = section.file.path.clone(); self.permalinks.insert(section.file.relative.clone(), section.permalink.clone()); @@ -333,11 +333,11 @@ impl Site { section.ignored_pages = vec![]; } - // TODO: use references instead of cloning to avoid having to call populate_section on - // content change for page in self.pages.values() { let parent_section_path = page.file.parent.join("_index.md"); if self.sections.contains_key(&parent_section_path) { + // TODO: use references instead of cloning to avoid having to call populate_section on + // content change self.sections.get_mut(&parent_section_path).unwrap().pages.push(page.clone()); } } diff --git a/components/site/tests/site.rs b/components/site/tests/site.rs index 8ee271d8..af82538d 100644 --- a/components/site/tests/site.rs +++ b/components/site/tests/site.rs @@ -12,13 +12,13 @@ use site::Site; #[test] fn can_parse_site() { - let mut path = env::current_dir().unwrap().to_path_buf(); + let mut path = env::current_dir().unwrap().parent().unwrap().parent().unwrap().to_path_buf(); path.push("test_site"); let mut site = Site::new(&path, "config.toml").unwrap(); site.load().unwrap(); // Correct number of pages (sections are pages too) - assert_eq!(site.pages.len(), 12); + assert_eq!(site.pages.len(), 14); let posts_path = path.join("content").join("posts"); // Make sure we remove all the pwd + content from the sections @@ -34,11 +34,11 @@ fn can_parse_site() { assert_eq!(asset_folder_post.file.components, vec!["posts".to_string()]); // That we have the right number of sections - assert_eq!(site.sections.len(), 6); + assert_eq!(site.sections.len(), 7); // And that the sections are correct let index_section = &site.sections[&path.join("content").join("_index.md")]; - assert_eq!(index_section.subsections.len(), 2); + assert_eq!(index_section.subsections.len(), 3); assert_eq!(index_section.pages.len(), 1); let posts_section = &site.sections[&posts_path.join("_index.md")]; @@ -91,7 +91,7 @@ macro_rules! file_contains { #[test] fn can_build_site_without_live_reload() { - let mut path = env::current_dir().unwrap().to_path_buf(); + let mut path = env::current_dir().unwrap().parent().unwrap().parent().unwrap().to_path_buf(); path.push("test_site"); let mut site = Site::new(&path, "config.toml").unwrap(); site.load().unwrap(); @@ -152,7 +152,7 @@ fn can_build_site_without_live_reload() { #[test] fn can_build_site_with_live_reload() { - let mut path = env::current_dir().unwrap().to_path_buf(); + let mut path = env::current_dir().unwrap().parent().unwrap().parent().unwrap().to_path_buf(); path.push("test_site"); let mut site = Site::new(&path, "config.toml").unwrap(); site.load().unwrap(); @@ -190,7 +190,7 @@ fn can_build_site_with_live_reload() { #[test] fn can_build_site_with_categories() { - let mut path = env::current_dir().unwrap().to_path_buf(); + let mut path = env::current_dir().unwrap().parent().unwrap().parent().unwrap().to_path_buf(); path.push("test_site"); let mut site = Site::new(&path, "config.toml").unwrap(); site.config.generate_categories_pages = Some(true); @@ -244,7 +244,7 @@ fn can_build_site_with_categories() { #[test] fn can_build_site_with_tags() { - let mut path = env::current_dir().unwrap().to_path_buf(); + let mut path = env::current_dir().unwrap().parent().unwrap().parent().unwrap().to_path_buf(); path.push("test_site"); let mut site = Site::new(&path, "config.toml").unwrap(); site.config.generate_tags_pages = Some(true); @@ -296,7 +296,7 @@ fn can_build_site_with_tags() { #[test] fn can_build_site_and_insert_anchor_links() { - let mut path = env::current_dir().unwrap().to_path_buf(); + let mut path = env::current_dir().unwrap().parent().unwrap().parent().unwrap().to_path_buf(); path.push("test_site"); let mut site = Site::new(&path, "config.toml").unwrap(); site.load().unwrap(); @@ -313,7 +313,7 @@ fn can_build_site_and_insert_anchor_links() { #[test] fn can_build_site_with_pagination_for_section() { - let mut path = env::current_dir().unwrap().to_path_buf(); + let mut path = env::current_dir().unwrap().parent().unwrap().parent().unwrap().to_path_buf(); path.push("test_site"); let mut site = Site::new(&path, "config.toml").unwrap(); site.load().unwrap(); @@ -372,7 +372,7 @@ fn can_build_site_with_pagination_for_section() { #[test] fn can_build_site_with_pagination_for_index() { - let mut path = env::current_dir().unwrap().to_path_buf(); + let mut path = env::current_dir().unwrap().parent().unwrap().parent().unwrap().to_path_buf(); path.push("test_site"); let mut site = Site::new(&path, "config.toml").unwrap(); site.load().unwrap(); @@ -417,7 +417,7 @@ fn can_build_site_with_pagination_for_index() { #[test] fn can_build_rss_feed() { - let mut path = env::current_dir().unwrap().to_path_buf(); + let mut path = env::current_dir().unwrap().parent().unwrap().parent().unwrap().to_path_buf(); path.push("test_site"); let mut site = Site::new(&path, "config.toml").unwrap(); site.load().unwrap(); diff --git a/components/templates/src/global_fns.rs b/components/templates/src/global_fns.rs index a0c76726..dd149c76 100644 --- a/components/templates/src/global_fns.rs +++ b/components/templates/src/global_fns.rs @@ -54,11 +54,15 @@ pub fn make_get_page(all_pages: &HashMap) -> GlobalFn { pub fn make_get_section(all_sections: &HashMap) -> GlobalFn { let mut sections = HashMap::new(); for section in all_sections.values() { + if section.file.components == vec!["rebuild".to_string()] { + //println!("Setting sections:\n{:#?}", section.pages[0]); + } sections.insert(section.file.relative.clone(), section.clone()); } Box::new(move |args| -> Result { let path = required_string_arg!(args.get("path"), "`get_section` requires a `path` argument with a string value"); + //println!("Found {:#?}", sections.get(&path).unwrap().pages[0]); match sections.get(&path) { Some(p) => Ok(to_value(p).unwrap()), None => Err(format!("Section `{}` not found.", path).into()) diff --git a/docs/content/documentation/content/section.md b/docs/content/documentation/content/section.md index c98b04f5..d32baa32 100644 --- a/docs/content/documentation/content/section.md +++ b/docs/content/documentation/content/section.md @@ -52,7 +52,7 @@ paginate_path = "page" # Options are "left", "right" and "none" insert_anchor_links = "none" -# Whether to render that section or not. +# Whether to render that section homepage or not. # Useful when the section is only there to organize things but is not meant # to be used directly render = true diff --git a/docs/content/documentation/templates/overview.md b/docs/content/documentation/templates/overview.md index 03f77ecf..7782fdd1 100644 --- a/docs/content/documentation/templates/overview.md +++ b/docs/content/documentation/templates/overview.md @@ -51,7 +51,7 @@ Takes a path to a `.md` file and returns the associated page Takes a path to a `_index.md` file and returns the associated section ```jinja2 -{% set section = get_page(path="blog/_index.md") %} +{% set section = get_section(path="blog/_index.md") %} ``` ### ` get_url` diff --git a/src/cmd/serve.rs b/src/cmd/serve.rs index 88bbb9eb..22ff97f3 100644 --- a/src/cmd/serve.rs +++ b/src/cmd/serve.rs @@ -62,7 +62,6 @@ fn livereload_handler(_: &mut Request) -> IronResult { Ok(Response::with((status::Ok, LIVE_RELOAD.to_string()))) } - fn rebuild_done_handling(broadcaster: &Sender, res: Result<()>, reload_path: &str) { match res { Ok(_) => { diff --git a/src/main.rs b/src/main.rs index 253561d8..e7c98446 100644 --- a/src/main.rs +++ b/src/main.rs @@ -16,12 +16,12 @@ extern crate errors; extern crate content; extern crate front_matter; extern crate utils; +extern crate rebuild; use std::time::Instant; mod cmd; mod console; -mod rebuild; mod cli; mod prompt; diff --git a/src/rebuild.rs b/src/rebuild.rs deleted file mode 100644 index dea923cf..00000000 --- a/src/rebuild.rs +++ /dev/null @@ -1,265 +0,0 @@ -use std::path::{Path, Component}; - -use errors::Result; -use site::Site; -use content::{Page, Section}; -use front_matter::{PageFrontMatter, SectionFrontMatter}; - - -/// Finds the section that contains the page given if there is one -pub fn find_parent_section<'a>(site: &'a Site, page: &Page) -> Option<&'a Section> { - for section in site.sections.values() { - if section.is_child_page(&page.file.path) { - return Some(section) - } - } - - None -} - - -#[derive(Debug, Clone, Copy, PartialEq)] -enum PageChangesNeeded { - /// Editing `tags` - Tags, - /// Editing `categories` - Categories, - /// Editing `date` or `order` - Sort, - /// Editing anything else - Render, -} - -// TODO: seems like editing sort_by/render do weird stuff -#[derive(Debug, Clone, Copy, PartialEq)] -enum SectionChangesNeeded { - /// Editing `sort_by` - Sort, - /// Editing `title`, `description`, `extra`, `template` or setting `render` to true - Render, - /// Editing `paginate_by`, `paginate_path` or `insert_anchor_links` - RenderWithPages, - /// Setting `render` to false - Delete, -} - -/// Evaluates all the params in the front matter that changed so we can do the smallest -/// delta in the serve command -fn find_section_front_matter_changes(current: &SectionFrontMatter, other: &SectionFrontMatter) -> Vec { - let mut changes_needed = vec![]; - - if current.sort_by != other.sort_by { - changes_needed.push(SectionChangesNeeded::Sort); - } - - if !current.should_render() && other.should_render() { - changes_needed.push(SectionChangesNeeded::Delete); - // Nothing else we can do - return changes_needed; - } - - if current.paginate_by != other.paginate_by - || current.paginate_path != other.paginate_path - || current.insert_anchor_links != other.insert_anchor_links { - changes_needed.push(SectionChangesNeeded::RenderWithPages); - // Nothing else we can do - return changes_needed; - } - - // Any other change will trigger a re-rendering of the section page only - changes_needed.push(SectionChangesNeeded::Render); - changes_needed -} - -/// Evaluates all the params in the front matter that changed so we can do the smallest -/// delta in the serve command -fn find_page_front_matter_changes(current: &PageFrontMatter, other: &PageFrontMatter) -> Vec { - let mut changes_needed = vec![]; - - if current.tags != other.tags { - changes_needed.push(PageChangesNeeded::Tags); - } - - if current.category != other.category { - changes_needed.push(PageChangesNeeded::Categories); - } - - if current.date != other.date || current.order != other.order { - changes_needed.push(PageChangesNeeded::Sort); - } - - changes_needed.push(PageChangesNeeded::Render); - changes_needed -} - -// What happens when a section or a page is changed -pub fn after_content_change(site: &mut Site, path: &Path) -> Result<()> { - let is_section = path.file_name().unwrap() == "_index.md"; - - // A page or section got deleted - if !path.exists() { - // A folder got deleted, ignore this event - if !site.sections.contains_key(path) && !site.pages.contains_key(path) { - return Ok(()); - } - - if is_section { - // A section was deleted, many things can be impacted: - // - the pages of the section are becoming orphans - // - any page that was referencing the section (index, etc) - let relative_path = site.sections[path].file.relative.clone(); - // Remove the link to it and the section itself from the Site - site.permalinks.remove(&relative_path); - site.sections.remove(path); - site.populate_sections(); - } else { - // A page was deleted, many things can be impacted: - // - the section the page is in - // - any page that was referencing the section (index, etc) - let relative_path = site.pages[path].file.relative.clone(); - site.permalinks.remove(&relative_path); - if let Some(p) = site.pages.remove(path) { - if p.meta.has_tags() || p.meta.category.is_some() { - site.populate_tags_and_categories(); - } - - if find_parent_section(site, &p).is_some() { - site.populate_sections(); - } - }; - } - // Ensure we have our fn updated so it doesn't contain the permalinks deleted - site.register_tera_global_fns(); - // Deletion is something that doesn't happen all the time so we - // don't need to optimise it too much - return site.build(); - } - - // A section was edited - if is_section { - let section = Section::from_file(path, &site.config)?; - match site.add_section(section, true)? { - Some(prev) => { - // Updating a section - let current_meta = site.sections[path].meta.clone(); - // Front matter didn't change, only content did - // so we render only the section page, not its pages - if current_meta == prev.meta { - return site.render_section(&site.sections[path], false); - } - - // Front matter changed - for changes in find_section_front_matter_changes(¤t_meta, &prev.meta) { - // Sort always comes first if present so the rendering will be fine - match changes { - SectionChangesNeeded::Sort => site.sort_sections_pages(Some(path)), - SectionChangesNeeded::Render => site.render_section(&site.sections[path], false)?, - SectionChangesNeeded::RenderWithPages => site.render_section(&site.sections[path], true)?, - // can't be arsed to make the Delete efficient, it's not a common enough operation - SectionChangesNeeded::Delete => { - site.populate_sections(); - site.build()?; - }, - }; - } - return Ok(()); - }, - None => { - // New section, only render that one - site.populate_sections(); - site.register_tera_global_fns(); - return site.render_section(&site.sections[path], true); - } - }; - } - - // A page was edited - let page = Page::from_file(path, &site.config)?; - match site.add_page(page, true)? { - Some(prev) => { - // Updating a page - let current = site.pages[path].clone(); - // Front matter didn't change, only content did - // so we render only the section page, not its content - if current.meta == prev.meta { - return site.render_page(¤t); - } - - // Front matter changed - for changes in find_page_front_matter_changes(¤t.meta, &prev.meta) { - // Sort always comes first if present so the rendering will be fine - match changes { - PageChangesNeeded::Tags => { - site.populate_tags_and_categories(); - site.render_tags()?; - }, - PageChangesNeeded::Categories => { - site.populate_tags_and_categories(); - site.render_categories()?; - }, - PageChangesNeeded::Sort => { - let section_path = match find_parent_section(site, &site.pages[path]) { - Some(s) => s.file.path.clone(), - None => continue // Do nothing if it's an orphan page - }; - site.populate_sections(); - site.sort_sections_pages(Some(§ion_path)); - site.render_index()?; - }, - PageChangesNeeded::Render => { - site.render_page(&site.pages[path])?; - }, - }; - } - site.register_tera_global_fns(); - return Ok(()); - - }, - None => { - // It's a new page! - site.populate_sections(); - site.populate_tags_and_categories(); - site.register_tera_global_fns(); - // No need to optimise that yet, we can revisit if it becomes an issue - site.build()?; - } - } - - Ok(()) -} - -/// What happens when a template is changed -pub fn after_template_change(site: &mut Site, path: &Path) -> Result<()> { - site.tera.full_reload()?; - let filename = path.file_name().unwrap().to_str().unwrap(); - - match filename { - "sitemap.xml" => site.render_sitemap(), - "rss.xml" => site.render_rss_feed(), - "robots.txt" => site.render_robots(), - "categories.html" | "category.html" => site.render_categories(), - "tags.html" | "tag.html" => site.render_tags(), - "page.html" => { - site.render_sections()?; - site.render_orphan_pages() - }, - "section.html" => site.render_sections(), - // Either the index or some unknown template changed - // We can't really know what this change affects so rebuild all - // the things - _ => { - // If we are updating a shortcode, re-render the markdown of all pages/site - // because we have no clue which one needs rebuilding - // TODO: look if there the shortcode is used in the markdown instead of re-rendering - // everything - if path.components().collect::>().contains(&Component::Normal("shortcodes".as_ref())) { - site.render_markdown()?; - } - site.populate_sections(); - site.render_sections()?; - site.render_orphan_pages()?; - site.render_categories()?; - site.render_tags() - }, - } -} diff --git a/sublime_syntaxes/LESS-sublime b/sublime_syntaxes/LESS-sublime index df5a2752..987eb726 160000 --- a/sublime_syntaxes/LESS-sublime +++ b/sublime_syntaxes/LESS-sublime @@ -1 +1 @@ -Subproject commit df5a27523dd37ebe67ba4c7d36ea162dae95b2c3 +Subproject commit 987eb72681357b7872a46e8409dfb6f43f2fa673 diff --git a/sublime_syntaxes/Elm.tmLanguage b/sublime_syntaxes/SublimeElmLanguageSupport similarity index 100% rename from sublime_syntaxes/Elm.tmLanguage rename to sublime_syntaxes/SublimeElmLanguageSupport diff --git a/sublime_syntaxes/TypeScript-TmLanguage b/sublime_syntaxes/TypeScript-TmLanguage index c29d12d8..0247d144 160000 --- a/sublime_syntaxes/TypeScript-TmLanguage +++ b/sublime_syntaxes/TypeScript-TmLanguage @@ -1 +1 @@ -Subproject commit c29d12d8aceb1a68af4cb6e466199846f41dd2ed +Subproject commit 0247d1444a66e683bb4005df38218a0fd9576d03 diff --git a/sublime_syntaxes/newlines.packdump b/sublime_syntaxes/newlines.packdump index 2a258523..da6ccf15 100644 Binary files a/sublime_syntaxes/newlines.packdump and b/sublime_syntaxes/newlines.packdump differ diff --git a/sublime_syntaxes/nonewlines.packdump b/sublime_syntaxes/nonewlines.packdump index be4f8fb1..35a71ed7 100644 Binary files a/sublime_syntaxes/nonewlines.packdump and b/sublime_syntaxes/nonewlines.packdump differ diff --git a/test_site/README.md b/test_site/README.md new file mode 100644 index 00000000..55c1ec12 --- /dev/null +++ b/test_site/README.md @@ -0,0 +1 @@ +Test site used by some components (`site`, `rebuild`) for integration tests. diff --git a/components/site/test_site/config.staging.toml b/test_site/config.staging.toml similarity index 100% rename from components/site/test_site/config.staging.toml rename to test_site/config.staging.toml diff --git a/components/site/test_site/config.toml b/test_site/config.toml similarity index 100% rename from components/site/test_site/config.toml rename to test_site/config.toml diff --git a/components/site/test_site/content/hello.md b/test_site/content/hello.md similarity index 100% rename from components/site/test_site/content/hello.md rename to test_site/content/hello.md diff --git a/components/site/test_site/content/paginated/_index.md b/test_site/content/paginated/_index.md similarity index 100% rename from components/site/test_site/content/paginated/_index.md rename to test_site/content/paginated/_index.md diff --git a/components/site/test_site/content/posts/_index.md b/test_site/content/posts/_index.md similarity index 100% rename from components/site/test_site/content/posts/_index.md rename to test_site/content/posts/_index.md diff --git a/components/site/test_site/content/posts/draft.md b/test_site/content/posts/draft.md similarity index 100% rename from components/site/test_site/content/posts/draft.md rename to test_site/content/posts/draft.md diff --git a/components/site/test_site/content/posts/fixed-slug.md b/test_site/content/posts/fixed-slug.md similarity index 100% rename from components/site/test_site/content/posts/fixed-slug.md rename to test_site/content/posts/fixed-slug.md diff --git a/components/site/test_site/content/posts/fixed-url.md b/test_site/content/posts/fixed-url.md similarity index 100% rename from components/site/test_site/content/posts/fixed-url.md rename to test_site/content/posts/fixed-url.md diff --git a/components/site/test_site/content/posts/no-section/simple.md b/test_site/content/posts/no-section/simple.md similarity index 100% rename from components/site/test_site/content/posts/no-section/simple.md rename to test_site/content/posts/no-section/simple.md diff --git a/components/site/test_site/content/posts/python.md b/test_site/content/posts/python.md similarity index 100% rename from components/site/test_site/content/posts/python.md rename to test_site/content/posts/python.md diff --git a/components/site/test_site/content/posts/simple.md b/test_site/content/posts/simple.md similarity index 100% rename from components/site/test_site/content/posts/simple.md rename to test_site/content/posts/simple.md diff --git a/components/site/test_site/content/posts/tutorials/_index.md b/test_site/content/posts/tutorials/_index.md similarity index 100% rename from components/site/test_site/content/posts/tutorials/_index.md rename to test_site/content/posts/tutorials/_index.md diff --git a/components/site/test_site/content/posts/tutorials/devops/_index.md b/test_site/content/posts/tutorials/devops/_index.md similarity index 100% rename from components/site/test_site/content/posts/tutorials/devops/_index.md rename to test_site/content/posts/tutorials/devops/_index.md diff --git a/components/site/test_site/content/posts/tutorials/devops/docker.md b/test_site/content/posts/tutorials/devops/docker.md similarity index 100% rename from components/site/test_site/content/posts/tutorials/devops/docker.md rename to test_site/content/posts/tutorials/devops/docker.md diff --git a/components/site/test_site/content/posts/tutorials/devops/nix.md b/test_site/content/posts/tutorials/devops/nix.md similarity index 100% rename from components/site/test_site/content/posts/tutorials/devops/nix.md rename to test_site/content/posts/tutorials/devops/nix.md diff --git a/components/site/test_site/content/posts/tutorials/programming/_index.md b/test_site/content/posts/tutorials/programming/_index.md similarity index 100% rename from components/site/test_site/content/posts/tutorials/programming/_index.md rename to test_site/content/posts/tutorials/programming/_index.md diff --git a/components/site/test_site/content/posts/tutorials/programming/python.md b/test_site/content/posts/tutorials/programming/python.md similarity index 100% rename from components/site/test_site/content/posts/tutorials/programming/python.md rename to test_site/content/posts/tutorials/programming/python.md diff --git a/components/site/test_site/content/posts/tutorials/programming/rust.md b/test_site/content/posts/tutorials/programming/rust.md similarity index 100% rename from components/site/test_site/content/posts/tutorials/programming/rust.md rename to test_site/content/posts/tutorials/programming/rust.md diff --git a/components/site/test_site/content/posts/with-assets/index.md b/test_site/content/posts/with-assets/index.md similarity index 100% rename from components/site/test_site/content/posts/with-assets/index.md rename to test_site/content/posts/with-assets/index.md diff --git a/components/site/test_site/content/posts/with-assets/with.js b/test_site/content/posts/with-assets/with.js similarity index 100% rename from components/site/test_site/content/posts/with-assets/with.js rename to test_site/content/posts/with-assets/with.js diff --git a/test_site/content/rebuild/_index.md b/test_site/content/rebuild/_index.md new file mode 100644 index 00000000..c617948a --- /dev/null +++ b/test_site/content/rebuild/_index.md @@ -0,0 +1,5 @@ ++++ +paginate_by = 1 +sort_by = "order" +template = "rebuild.html" ++++ diff --git a/test_site/content/rebuild/first.md b/test_site/content/rebuild/first.md new file mode 100644 index 00000000..a3bd65e6 --- /dev/null +++ b/test_site/content/rebuild/first.md @@ -0,0 +1,7 @@ ++++ +title = "first" +order = 10 +date = 2017-01-01 ++++ + +# A title diff --git a/test_site/content/rebuild/second.md b/test_site/content/rebuild/second.md new file mode 100644 index 00000000..4a849192 --- /dev/null +++ b/test_site/content/rebuild/second.md @@ -0,0 +1,7 @@ ++++ +title = "second" +order = 100 +date = 2016-01-01 ++++ + +# A title diff --git a/components/site/test_site/sass/_included.scss b/test_site/sass/_included.scss similarity index 100% rename from components/site/test_site/sass/_included.scss rename to test_site/sass/_included.scss diff --git a/components/site/test_site/sass/blog.scss b/test_site/sass/blog.scss similarity index 100% rename from components/site/test_site/sass/blog.scss rename to test_site/sass/blog.scss diff --git a/components/site/test_site/static/scripts/hello.js b/test_site/static/scripts/hello.js similarity index 100% rename from components/site/test_site/static/scripts/hello.js rename to test_site/static/scripts/hello.js diff --git a/components/site/test_site/static/site.css b/test_site/static/site.css similarity index 100% rename from components/site/test_site/static/site.css rename to test_site/static/site.css diff --git a/components/site/test_site/templates/categories.html b/test_site/templates/categories.html similarity index 100% rename from components/site/test_site/templates/categories.html rename to test_site/templates/categories.html diff --git a/components/site/test_site/templates/category.html b/test_site/templates/category.html similarity index 100% rename from components/site/test_site/templates/category.html rename to test_site/templates/category.html diff --git a/components/site/test_site/templates/index.html b/test_site/templates/index.html similarity index 100% rename from components/site/test_site/templates/index.html rename to test_site/templates/index.html diff --git a/components/site/test_site/templates/index_paginated.html b/test_site/templates/index_paginated.html similarity index 100% rename from components/site/test_site/templates/index_paginated.html rename to test_site/templates/index_paginated.html diff --git a/components/site/test_site/templates/page.html b/test_site/templates/page.html similarity index 100% rename from components/site/test_site/templates/page.html rename to test_site/templates/page.html diff --git a/test_site/templates/rebuild.html b/test_site/templates/rebuild.html new file mode 100644 index 00000000..e0357903 --- /dev/null +++ b/test_site/templates/rebuild.html @@ -0,0 +1,7 @@ +{# Testing that global functions/section get reloaded properly #} + +{% set section = get_section(path="rebuild/_index.md") %} + +{% for page in section.pages -%} +

{{ page.title }}

+{%- endfor %} diff --git a/components/site/test_site/templates/section.html b/test_site/templates/section.html similarity index 100% rename from components/site/test_site/templates/section.html rename to test_site/templates/section.html diff --git a/components/site/test_site/templates/section_paginated.html b/test_site/templates/section_paginated.html similarity index 100% rename from components/site/test_site/templates/section_paginated.html rename to test_site/templates/section_paginated.html diff --git a/components/site/test_site/templates/shortcodes/basic.html b/test_site/templates/shortcodes/basic.html similarity index 100% rename from components/site/test_site/templates/shortcodes/basic.html rename to test_site/templates/shortcodes/basic.html diff --git a/components/site/test_site/templates/shortcodes/pirate.html b/test_site/templates/shortcodes/pirate.html similarity index 100% rename from components/site/test_site/templates/shortcodes/pirate.html rename to test_site/templates/shortcodes/pirate.html diff --git a/components/site/test_site/templates/tag.html b/test_site/templates/tag.html similarity index 100% rename from components/site/test_site/templates/tag.html rename to test_site/templates/tag.html diff --git a/components/site/test_site/templates/tags.html b/test_site/templates/tags.html similarity index 100% rename from components/site/test_site/templates/tags.html rename to test_site/templates/tags.html diff --git a/components/site/test_site/themes/sample/sass/sample.scss b/test_site/themes/sample/sass/sample.scss similarity index 100% rename from components/site/test_site/themes/sample/sass/sample.scss rename to test_site/themes/sample/sass/sample.scss diff --git a/components/site/test_site/themes/sample/static/some.js b/test_site/themes/sample/static/some.js similarity index 100% rename from components/site/test_site/themes/sample/static/some.js rename to test_site/themes/sample/static/some.js diff --git a/components/site/test_site/themes/sample/templates/category.html b/test_site/themes/sample/templates/category.html similarity index 100% rename from components/site/test_site/themes/sample/templates/category.html rename to test_site/themes/sample/templates/category.html diff --git a/components/site/test_site/themes/sample/templates/child.html b/test_site/themes/sample/templates/child.html similarity index 100% rename from components/site/test_site/themes/sample/templates/child.html rename to test_site/themes/sample/templates/child.html diff --git a/components/site/test_site/themes/sample/templates/included.html b/test_site/themes/sample/templates/included.html similarity index 100% rename from components/site/test_site/themes/sample/templates/included.html rename to test_site/themes/sample/templates/included.html diff --git a/components/site/test_site/themes/sample/templates/index.html b/test_site/themes/sample/templates/index.html similarity index 100% rename from components/site/test_site/themes/sample/templates/index.html rename to test_site/themes/sample/templates/index.html diff --git a/components/site/test_site/themes/sample/templates/macros.html b/test_site/themes/sample/templates/macros.html similarity index 100% rename from components/site/test_site/themes/sample/templates/macros.html rename to test_site/themes/sample/templates/macros.html diff --git a/components/site/test_site/themes/sample/templates/using-macros.html b/test_site/themes/sample/templates/using-macros.html similarity index 100% rename from components/site/test_site/themes/sample/templates/using-macros.html rename to test_site/themes/sample/templates/using-macros.html diff --git a/components/site/test_site/themes/sample/theme.toml b/test_site/themes/sample/theme.toml similarity index 100% rename from components/site/test_site/themes/sample/theme.toml rename to test_site/themes/sample/theme.toml