Merged in make-build-more-robust (pull request #42)
Improve build robustness
This commit is contained in:
commit
d097eeecbb
|
@ -3,9 +3,10 @@
|
|||
releases_release_uri = "https://github.com/dorianpula/rookeries/releases/%s"
|
||||
releases_issue_uri = "https://bitbucket.org/dorianpula/rookeries/issues/%s"
|
||||
|
||||
* :release:`0.18.0 <2019-02-??>`
|
||||
* :release:`0.18.0 <2019-03-??>`
|
||||
* :feature:`38` Add support for TOML-based frontmatter for Markdown source files.
|
||||
* :feature:`38` Use new and improved site format.
|
||||
* :feature:`42` Add ability to query page and build information in template.
|
||||
* :feature:`39` Add support for git initialization and deployment.
|
||||
* :support:`37` General code clean-up as part of using Rust 2018.
|
||||
* :support:`37` Add support for migrating old versions of Rookeries site to a newer version.
|
||||
|
|
|
@ -1,22 +1,60 @@
|
|||
use crate::migration::PreStable18Site;
|
||||
use crate::{
|
||||
cli::{caution_message, header_message, success_message},
|
||||
cli::{caution_message, details_message, header_message, success_message},
|
||||
errors::RookeriesError,
|
||||
files::{build_path, copy_directory, copy_file, create_directory, FileType},
|
||||
migration::PreStable18Site,
|
||||
Page, PageHeader, Project, Rookeries, Site,
|
||||
};
|
||||
use chrono::prelude::*;
|
||||
use colored::Colorize;
|
||||
use serde_json::json;
|
||||
use serde::ser::{Serialize, SerializeStruct, Serializer};
|
||||
use std::{
|
||||
ffi::OsString,
|
||||
fs::{read_dir, read_to_string, remove_dir_all, write},
|
||||
path::Path,
|
||||
path::{Path, PathBuf},
|
||||
};
|
||||
use uuid::Uuid;
|
||||
|
||||
const ROOKERIES_UNKNOWN_PLACEHOLDER: &str = "???";
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
/// Information about the current build.
|
||||
pub struct BuildInfo {
|
||||
git_revision_id: String,
|
||||
build_time: DateTime<Local>,
|
||||
content_build_id: Uuid,
|
||||
}
|
||||
|
||||
impl BuildInfo {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
git_revision_id: Rookeries::git_revision(),
|
||||
build_time: Local::now(),
|
||||
content_build_id: Uuid::new_v4(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn formatted_build_time(&self) -> String {
|
||||
self.build_time.to_rfc3339_opts(SecondsFormat::Secs, true)
|
||||
}
|
||||
}
|
||||
|
||||
impl Serialize for BuildInfo {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
// 3 is the number of fields in the struct.
|
||||
let mut state = serializer.serialize_struct("BuildInfo", 5)?;
|
||||
state.serialize_field("gitRevision", &self.git_revision_id)?;
|
||||
state.serialize_field("contentBuildId", &self.content_build_id)?;
|
||||
state.serialize_field("buildTime", &self.formatted_build_time())?;
|
||||
state.serialize_field("app", &Rookeries::name())?;
|
||||
state.serialize_field("version", &Rookeries::current_version())?;
|
||||
state.end()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn build_site(project: &Project, activate_dev_mode: bool) -> Result<(), RookeriesError> {
|
||||
header_message("Building the site...");
|
||||
|
||||
|
@ -45,229 +83,71 @@ pub fn build_site(project: &Project, activate_dev_mode: bool) -> Result<(), Rook
|
|||
&project_site.title.green(),
|
||||
));
|
||||
|
||||
// Build a list of the pages to build out.
|
||||
header_message("Searching for pages...");
|
||||
let mut site_source_pages: Vec<OsString> = Vec::new();
|
||||
for entry in read_dir(project.root_dir())? {
|
||||
// TODO: Make the search recursive through directories.
|
||||
let path = entry?.path();
|
||||
if path.is_file()
|
||||
&& path.extension() != None
|
||||
&& path.extension().unwrap_or(&path.as_os_str()) == "md"
|
||||
{
|
||||
site_source_pages.push(path.into_os_string());
|
||||
}
|
||||
}
|
||||
site_source_pages.sort();
|
||||
for source in &site_source_pages {
|
||||
let path = Path::new(source);
|
||||
success_message(&format!("Found {}", path.display()));
|
||||
}
|
||||
let site_source_pages = find_source_pages(project)?;
|
||||
|
||||
// TODO: Add in support for figuring out the index page or allowing one to be set.
|
||||
header_message("Compiling page information...");
|
||||
header_message("Extracting page information...");
|
||||
|
||||
// TODO: Add warning about a missing index page.
|
||||
// TODO: Add support for aliases (e.g. such as about being an index page)
|
||||
let site_source_pages: Vec<Page> = site_source_pages
|
||||
.iter()
|
||||
.map(|source_page| {
|
||||
// TODO: Extract separate per page build.
|
||||
let source_path = Path::new(source_page);
|
||||
|
||||
let slug = source_path
|
||||
.file_stem()
|
||||
.unwrap_or_else(|| source_path.as_os_str())
|
||||
.to_str()
|
||||
.unwrap_or(ROOKERIES_UNKNOWN_PLACEHOLDER)
|
||||
.to_string();
|
||||
|
||||
let raw_content = read_to_string(source_path)
|
||||
.map_err(|err| {
|
||||
let source_page_err = source_page
|
||||
.clone()
|
||||
.into_string()
|
||||
.unwrap_or_else(|_| ROOKERIES_UNKNOWN_PLACEHOLDER.to_string());
|
||||
RookeriesError::ReadFileFailure(err, source_page_err, FileType::SourceMarkdown)
|
||||
})
|
||||
.unwrap_or_else(|_| ROOKERIES_UNKNOWN_PLACEHOLDER.to_string());
|
||||
|
||||
// Extract the page header from the content.
|
||||
let parsed_content: Vec<&str> = raw_content.split("+++").collect();
|
||||
let (header, content) = if parsed_content.len() > 1 {
|
||||
(parsed_content[1], parsed_content[2])
|
||||
} else {
|
||||
("", parsed_content[parsed_content.len() - 1])
|
||||
};
|
||||
|
||||
// TODO: Remember to check valid titles post-migration.
|
||||
let older_post_title = match &older_site {
|
||||
None => None,
|
||||
Some(older_site_def) => Some(older_site_def.get_title_page(&slug)),
|
||||
};
|
||||
let header = toml::from_str(&header).unwrap_or_else(|_| match older_post_title {
|
||||
None => PageHeader::new(slug.clone()),
|
||||
Some(title) => PageHeader { title },
|
||||
});
|
||||
success_message(&format!("Compiling \"{}\" page", &slug.green()));
|
||||
|
||||
Page {
|
||||
title: header.title,
|
||||
slug,
|
||||
content: content.to_string(),
|
||||
created_at: None,
|
||||
}
|
||||
})
|
||||
.map(|source_page| build_page_from_path(&older_site, source_page))
|
||||
.collect();
|
||||
|
||||
// Create a build directory for the resulting files.
|
||||
header_message("Preparing build directory...");
|
||||
let build_directory = project.build_dir();
|
||||
if build_directory.exists() {
|
||||
caution_message("Recreating build directory...");
|
||||
remove_dir_all(&build_directory)?;
|
||||
create_directory(&build_directory, FileType::BuildRoot)?;
|
||||
} else {
|
||||
create_directory(&build_directory, FileType::BuildRoot)?;
|
||||
}
|
||||
// TODO: Clean this up.
|
||||
header_message("Preparing for the build...");
|
||||
let build_directory = create_build_directory(project)?;
|
||||
let build_info = BuildInfo::new();
|
||||
success_message("Build information compiled.");
|
||||
|
||||
header_message("Initialize page rendering system...");
|
||||
let mut render_engine = tera::Tera::default();
|
||||
// TODO: Add templates programmatically.
|
||||
let template_path = project.template_dir().join("base_index.html");
|
||||
let another_template_path = project.template_dir().join("sample.html");
|
||||
render_engine
|
||||
.add_template_files(vec![
|
||||
(&template_path, Some("index")),
|
||||
(&another_template_path, Some("sample")),
|
||||
])
|
||||
.map_err(RookeriesError::TemplateSetupFailure)?;
|
||||
let render_engine = prepare_render_engine(project)?;
|
||||
let mut ctx = prepare_render_context(activate_dev_mode, older_site, &project_site, &build_info);
|
||||
success_message("Render system initialized.");
|
||||
|
||||
let build_timestamp: DateTime<Local> = Local::now();
|
||||
let build_timestamp = build_timestamp.to_rfc3339_opts(SecondsFormat::Secs, true);
|
||||
let status = json!({
|
||||
"version": Rookeries::current_version(),
|
||||
"app": env!("CARGO_PKG_NAME").to_string(),
|
||||
"gitRevision": Rookeries::git_revision(),
|
||||
"contentBuildId": Uuid::new_v4(),
|
||||
"buildTime": build_timestamp,
|
||||
});
|
||||
|
||||
header_message("Creating the index page...");
|
||||
let mut ctx = tera::Context::new();
|
||||
// TODO: Figure out better support for Pre 0.18.0 version sites.
|
||||
if let Some(older_site) = older_site {
|
||||
let deprecation_message = format!(
|
||||
"{} Using deprecated values: {} and {} in the templates.",
|
||||
"WARNING!".yellow(),
|
||||
"site.name".yellow(),
|
||||
"plugins".yellow(),
|
||||
);
|
||||
caution_message(&deprecation_message);
|
||||
let deprecation_message = format!(
|
||||
"{} Update these values to: {} and {} respectively in the templates.",
|
||||
"RECOMMENDATION:".yellow(),
|
||||
"site.title".yellow(),
|
||||
"site.plugins".yellow(),
|
||||
);
|
||||
caution_message(&deprecation_message);
|
||||
ctx.insert("site", &older_site);
|
||||
let plugins: Vec<String> = project_site
|
||||
.plugins
|
||||
.iter()
|
||||
.map(|plugin| plugin.name.clone())
|
||||
.collect();
|
||||
ctx.insert("plugins", &plugins)
|
||||
} else {
|
||||
ctx.insert("site", &project_site);
|
||||
}
|
||||
header_message("Rendering the site...");
|
||||
let api_path = project.build_api_dir();
|
||||
create_directory(&api_path, FileType::APIRoot)?;
|
||||
build_artifact(&build_info, &api_path)?;
|
||||
build_site_api_repr(&project_site, &api_path)?;
|
||||
let api_pages_path = &api_path.join("pages");
|
||||
create_directory(&api_pages_path, FileType::PageAPI)?;
|
||||
|
||||
// TODO: Add ensure index page added into the site source pages.
|
||||
// TODO: Ensure getting the right page as documented in the landingPage
|
||||
ctx.insert("current_page", "index");
|
||||
ctx.insert("rookeries", &status);
|
||||
if activate_dev_mode {
|
||||
ctx.insert("dev_mode", "active");
|
||||
}
|
||||
|
||||
// TODO: Add index pages into the site source pages.
|
||||
let render_page_str = render_engine
|
||||
.render("sample", &ctx)
|
||||
.map_err(|err| RookeriesError::RenderTemplateFailure(err, "index".to_string()))?;
|
||||
|
||||
write(build_directory.join("index.html"), render_page_str).map_err(|err| {
|
||||
RookeriesError::WriteFileFailure(err, "index.html".to_string(), FileType::RenderedHtml)
|
||||
})?;
|
||||
success_message(&format!("Created the {} HTML page.", "index".green()));
|
||||
|
||||
header_message("Creating the pages...");
|
||||
header_message("Rendering the pages...");
|
||||
for page in &site_source_pages {
|
||||
create_directory(&build_directory.join(&page.slug), FileType::Page)?;
|
||||
ctx.insert("current_page", &page.slug);
|
||||
let render_page_str = render_engine.render("index", &ctx).map_err(|err| {
|
||||
RookeriesError::RenderTemplateFailure(err, format!("{}/index", &page.slug))
|
||||
let page_directory = if &page.slug == "index" {
|
||||
project.build_dir()
|
||||
} else {
|
||||
build_directory.join(&page.slug)
|
||||
};
|
||||
|
||||
create_directory(&page_directory, FileType::Page)?;
|
||||
ctx.insert("page", &page);
|
||||
let render_page_str = render_engine.render("sample", &ctx).map_err(|err| {
|
||||
let template_render_path = if &page.slug == "index" {
|
||||
String::from("index")
|
||||
} else {
|
||||
format!("{}/index", &page.slug)
|
||||
};
|
||||
RookeriesError::RenderTemplateFailure(err, template_render_path)
|
||||
})?;
|
||||
write(
|
||||
build_directory.join(&page.slug).join("index.html"),
|
||||
render_page_str,
|
||||
)
|
||||
.map_err(|err| {
|
||||
write(page_directory.join("index.html"), render_page_str).map_err(|err| {
|
||||
RookeriesError::WriteFileFailure(
|
||||
err,
|
||||
format!("{}/index.html", &page.slug),
|
||||
FileType::RenderedHtml,
|
||||
)
|
||||
})?;
|
||||
success_message(&format!("Created the {} HTML page.", &page.slug.green()));
|
||||
}
|
||||
details_message(&format!(
|
||||
"Rendered the {} {}.",
|
||||
&page.slug.yellow(),
|
||||
FileType::RenderedHtml.to_string().yellow()
|
||||
));
|
||||
|
||||
// Create the API representations.
|
||||
header_message("Creating the API JSON files...");
|
||||
let api_path = &build_directory.join("api");
|
||||
create_directory(&api_path, FileType::APIRoot)?;
|
||||
|
||||
// Create a build artifact.
|
||||
let status = serde_json::to_string_pretty(&status).map_err(|err| {
|
||||
RookeriesError::JsonSerializationError(
|
||||
err,
|
||||
"_build.json".to_string(),
|
||||
FileType::BuildArtifactJson,
|
||||
)
|
||||
})?;
|
||||
write(api_path.join("_build.json"), status).map_err(|err| {
|
||||
RookeriesError::WriteFileFailure(
|
||||
err,
|
||||
"api/_build.json".to_string(),
|
||||
FileType::BuildArtifactJson,
|
||||
)
|
||||
})?;
|
||||
success_message(&format!(
|
||||
"Created the {}.",
|
||||
FileType::BuildArtifactJson.to_string().green()
|
||||
));
|
||||
|
||||
let site_json = serde_json::to_string_pretty(&project_site).map_err(|err| {
|
||||
RookeriesError::JsonSerializationError(
|
||||
err,
|
||||
"site.json".to_string(),
|
||||
FileType::RenderedSiteJson,
|
||||
)
|
||||
})?;
|
||||
write(&api_path.join("site.json"), site_json).map_err(|err| {
|
||||
RookeriesError::WriteFileFailure(
|
||||
err,
|
||||
"api/site.json".to_string(),
|
||||
FileType::RenderedSiteJson,
|
||||
)
|
||||
})?;
|
||||
success_message(&format!(
|
||||
"Created the {}.",
|
||||
FileType::RenderedSiteJson.to_string().green()
|
||||
));
|
||||
|
||||
// Create all the page API reps.
|
||||
let api_pages_path = &api_path.join("pages");
|
||||
create_directory(&api_pages_path, FileType::PageAPI)?;
|
||||
for page in site_source_pages {
|
||||
// Create the page API reps.
|
||||
let page_json_filename = format!("{}.json", &page.slug);
|
||||
let page_json = serde_json::to_string_pretty(&page).map_err(|err| {
|
||||
RookeriesError::JsonSerializationError(
|
||||
|
@ -276,15 +156,15 @@ pub fn build_site(project: &Project, activate_dev_mode: bool) -> Result<(), Rook
|
|||
FileType::RenderedPageJson,
|
||||
)
|
||||
})?;
|
||||
|
||||
write(api_pages_path.join(&page_json_filename), page_json).map_err(|err| {
|
||||
RookeriesError::WriteFileFailure(err, page_json_filename, FileType::RenderedPageJson)
|
||||
})?;
|
||||
success_message(&format!(
|
||||
"Created the {} for the {} page.",
|
||||
FileType::RenderedPageJson.to_string().green(),
|
||||
&page.slug.green(),
|
||||
details_message(&format!(
|
||||
"Rendered the {} {}.",
|
||||
&page.slug.yellow(),
|
||||
FileType::RenderedPageJson.to_string().yellow()
|
||||
));
|
||||
success_message(&format!("Rendered the {} page.", &page.slug.green(),));
|
||||
}
|
||||
|
||||
// Bring in the static file directory.
|
||||
|
@ -328,3 +208,188 @@ pub fn build_site(project: &Project, activate_dev_mode: bool) -> Result<(), Rook
|
|||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn build_site_api_repr(project_site: &Site, api_path: &PathBuf) -> Result<(), RookeriesError> {
|
||||
let site_json = serde_json::to_string_pretty(&project_site).map_err(|err| {
|
||||
RookeriesError::JsonSerializationError(
|
||||
err,
|
||||
"site.json".to_string(),
|
||||
FileType::RenderedSiteJson,
|
||||
)
|
||||
})?;
|
||||
write(&api_path.join("site.json"), site_json).map_err(|err| {
|
||||
RookeriesError::WriteFileFailure(
|
||||
err,
|
||||
"api/site.json".to_string(),
|
||||
FileType::RenderedSiteJson,
|
||||
)
|
||||
})?;
|
||||
success_message(&format!(
|
||||
"Rendered the {}.",
|
||||
FileType::RenderedSiteJson.to_string().green()
|
||||
));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn build_artifact(build_info: &BuildInfo, api_path: &PathBuf) -> Result<(), RookeriesError> {
|
||||
// Create a build artifact.
|
||||
let status = serde_json::to_string_pretty(&build_info).map_err(|err| {
|
||||
RookeriesError::JsonSerializationError(
|
||||
err,
|
||||
"_build.json".to_string(),
|
||||
FileType::BuildArtifactJson,
|
||||
)
|
||||
})?;
|
||||
write(api_path.join("_build.json"), status).map_err(|err| {
|
||||
RookeriesError::WriteFileFailure(
|
||||
err,
|
||||
"api/_build.json".to_string(),
|
||||
FileType::BuildArtifactJson,
|
||||
)
|
||||
})?;
|
||||
success_message(&format!(
|
||||
"Rendered the {}.",
|
||||
FileType::BuildArtifactJson.to_string().green()
|
||||
));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn prepare_render_context(
|
||||
activate_dev_mode: bool,
|
||||
older_site: Option<PreStable18Site>,
|
||||
project_site: &Site,
|
||||
build_info: &BuildInfo,
|
||||
) -> tera::Context {
|
||||
let mut ctx = tera::Context::new();
|
||||
|
||||
// TODO: Figure out better support for Pre 0.18.0 version sites.
|
||||
if let Some(older_site) = older_site {
|
||||
let deprecation_message = format!(
|
||||
"{} Using deprecated values: {} and {} in the templates.",
|
||||
"WARNING!".yellow(),
|
||||
"site.name".yellow(),
|
||||
"plugins".yellow(),
|
||||
);
|
||||
caution_message(&deprecation_message);
|
||||
let deprecation_message = format!(
|
||||
"{} Update these values to: {} and {} respectively in the templates.",
|
||||
"RECOMMENDATION:".yellow(),
|
||||
"site.title".yellow(),
|
||||
"site.plugins".yellow(),
|
||||
);
|
||||
caution_message(&deprecation_message);
|
||||
ctx.insert("site", &older_site);
|
||||
let plugins: Vec<String> = project_site
|
||||
.plugins
|
||||
.iter()
|
||||
.map(|plugin| plugin.name.clone())
|
||||
.collect();
|
||||
ctx.insert("plugins", &plugins)
|
||||
} else {
|
||||
ctx.insert("site", &project_site);
|
||||
}
|
||||
|
||||
ctx.insert("rookeries", &build_info);
|
||||
if activate_dev_mode {
|
||||
ctx.insert("dev_mode", "active");
|
||||
}
|
||||
ctx
|
||||
}
|
||||
|
||||
fn prepare_render_engine(project: &Project) -> Result<tera::Tera, RookeriesError> {
|
||||
let mut render_engine = tera::Tera::default();
|
||||
// TODO: Add templates programmatically.
|
||||
let template_path = project.template_dir().join("base_index.html");
|
||||
let another_template_path = project.template_dir().join("sample.html");
|
||||
render_engine
|
||||
.add_template_files(vec![
|
||||
(&template_path, Some("index")),
|
||||
(&another_template_path, Some("sample")),
|
||||
])
|
||||
.map_err(RookeriesError::TemplateSetupFailure)?;
|
||||
Ok(render_engine)
|
||||
}
|
||||
|
||||
fn create_build_directory(project: &Project) -> Result<PathBuf, RookeriesError> {
|
||||
// Create a build directory for the resulting files.
|
||||
let build_directory = project.build_dir();
|
||||
if build_directory.exists() {
|
||||
caution_message("Recreating build directory...");
|
||||
remove_dir_all(&build_directory)?;
|
||||
create_directory(&build_directory, FileType::BuildRoot)?;
|
||||
} else {
|
||||
create_directory(&build_directory, FileType::BuildRoot)?;
|
||||
}
|
||||
success_message("Build directory ready.");
|
||||
Ok(build_directory)
|
||||
}
|
||||
|
||||
fn build_page_from_path(older_site: &Option<PreStable18Site>, source_page: &OsString) -> Page {
|
||||
// TODO: Extract separate per page build.
|
||||
let source_path = Path::new(source_page);
|
||||
|
||||
let slug = source_path
|
||||
.file_stem()
|
||||
.unwrap_or_else(|| source_path.as_os_str())
|
||||
.to_str()
|
||||
.unwrap_or(ROOKERIES_UNKNOWN_PLACEHOLDER)
|
||||
.to_string();
|
||||
|
||||
let raw_content = read_to_string(source_path)
|
||||
.map_err(|err| {
|
||||
let source_page_err = source_page
|
||||
.clone()
|
||||
.into_string()
|
||||
.unwrap_or_else(|_| ROOKERIES_UNKNOWN_PLACEHOLDER.to_string());
|
||||
RookeriesError::ReadFileFailure(err, source_page_err, FileType::SourceMarkdown)
|
||||
})
|
||||
.unwrap_or_else(|_| ROOKERIES_UNKNOWN_PLACEHOLDER.to_string());
|
||||
|
||||
// Extract the page header from the content.
|
||||
let parsed_content: Vec<&str> = raw_content.split("+++").collect();
|
||||
let (header, content) = if parsed_content.len() > 1 {
|
||||
(parsed_content[1], parsed_content[2])
|
||||
} else {
|
||||
("", parsed_content[parsed_content.len() - 1])
|
||||
};
|
||||
|
||||
// TODO: Remember to check valid titles post-migration.
|
||||
let older_post_title = match &older_site {
|
||||
None => None,
|
||||
Some(older_site_def) => Some(older_site_def.get_title_page(&slug)),
|
||||
};
|
||||
let header = toml::from_str(&header).unwrap_or_else(|_| match older_post_title {
|
||||
None => PageHeader::new(slug.clone()),
|
||||
Some(title) => PageHeader { title },
|
||||
});
|
||||
success_message(&format!("Extracted \"{}\" page", &slug.green()));
|
||||
|
||||
Page {
|
||||
title: header.title,
|
||||
slug,
|
||||
content: content.to_string(),
|
||||
created_at: None,
|
||||
}
|
||||
}
|
||||
|
||||
fn find_source_pages(project: &Project) -> Result<Vec<OsString>, RookeriesError> {
|
||||
// Build a list of the pages to build out.
|
||||
header_message("Searching for pages...");
|
||||
let mut site_source_pages: Vec<OsString> = Vec::new();
|
||||
for entry in read_dir(project.root_dir())? {
|
||||
// TODO: Make the search recursive through directories.
|
||||
let path = entry?.path();
|
||||
if path.is_file()
|
||||
&& path.extension() != None
|
||||
&& path.extension().unwrap_or(&path.as_os_str()) == "md"
|
||||
{
|
||||
site_source_pages.push(path.into_os_string());
|
||||
}
|
||||
}
|
||||
site_source_pages.sort();
|
||||
for source in &site_source_pages {
|
||||
let path = Path::new(source);
|
||||
success_message(&format!("Found {}", path.display()));
|
||||
}
|
||||
Ok(site_source_pages)
|
||||
}
|
||||
|
|
|
@ -19,7 +19,6 @@ pub fn initialize_site(project: Project) -> Result<(), RookeriesError> {
|
|||
header_message("Initializing a new site...");
|
||||
|
||||
// TODO: Add support for interactive wizard to populate values.
|
||||
// TODO: Add support for .gitignore + git initialization. (Maybe post initialization plugins).
|
||||
let project_initial_details: Site = Default::default();
|
||||
prepare_project_directory(&project)?;
|
||||
initialize_git(&project)?;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use crate::{
|
||||
cli::{caution_message, details_message, success_message},
|
||||
cli::{caution_message, details_message},
|
||||
errors::RookeriesError,
|
||||
};
|
||||
use colored::Colorize;
|
||||
|
@ -182,12 +182,9 @@ pub fn create_directory(
|
|||
) -> Result<(), RookeriesError> {
|
||||
fs::create_dir_all(target_directory)
|
||||
.map_err(|err| RookeriesError::CreateDirectoryFailure(err, directory_type))?;
|
||||
success_message(&format!(
|
||||
"Created the {} directory.",
|
||||
directory_type.to_string().green(),
|
||||
));
|
||||
details_message(&format!(
|
||||
"Directory created at: {}",
|
||||
"Created {} directory at: {}",
|
||||
directory_type.to_string().yellow(),
|
||||
target_directory.display().to_string().yellow(),
|
||||
));
|
||||
Ok(())
|
||||
|
|
12
src/lib.rs
12
src/lib.rs
|
@ -38,6 +38,10 @@ impl Project {
|
|||
pub fn build_dir(&self) -> PathBuf {
|
||||
self.root_dir().join("build")
|
||||
}
|
||||
/// Gets a path to the project's build API directory. This contains the built site.
|
||||
pub fn build_api_dir(&self) -> PathBuf {
|
||||
self.build_dir().join("api")
|
||||
}
|
||||
/// Gets a path to the project's directory of static assets.
|
||||
pub fn static_assets_dir(&self) -> PathBuf {
|
||||
self.root_dir().join("static")
|
||||
|
@ -148,6 +152,11 @@ impl Default for Site {
|
|||
pub struct Rookeries {}
|
||||
|
||||
impl Rookeries {
|
||||
/// Gets the name of the app.
|
||||
pub fn name() -> String {
|
||||
env!("CARGO_PKG_NAME").to_string()
|
||||
}
|
||||
|
||||
/// Gets the current version of the app.
|
||||
pub fn current_version() -> String {
|
||||
env!("CARGO_PKG_VERSION").to_string()
|
||||
|
@ -161,7 +170,8 @@ impl Rookeries {
|
|||
/// Gets a pretty variant of the app version for the `--version` flag.
|
||||
pub fn print_app_version() -> String {
|
||||
format!(
|
||||
"rookeries v{version} © 2013-2020 {authors}",
|
||||
"{name} v{version} © 2013-2020 {authors}",
|
||||
name = Rookeries::name(),
|
||||
version = Rookeries::current_version(),
|
||||
authors = env!("CARGO_PKG_AUTHORS"),
|
||||
)
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en" xmlns="http://www.w3.org/1999/html">
|
||||
<head>
|
||||
<title>{{ site.title }} :: {{ current_page }}</title>
|
||||
<title>{{ page.title }} - {{ site.title }}</title>
|
||||
<link rel="icon" type="image/icon" href="/static/favicon.ico" />
|
||||
<link rel="stylesheet"
|
||||
type="text/css"
|
||||
|
@ -14,7 +14,7 @@
|
|||
<div class="rookeries-layout">
|
||||
<dark-mode-switch theme="dark"></dark-mode-switch>
|
||||
<header>
|
||||
<h1>Sample Header</h1>
|
||||
<h1>{{ page.title }}</h1>
|
||||
</header>
|
||||
|
||||
<nav>
|
||||
|
|
|
@ -61,7 +61,6 @@ fn test_init_creates_site() {
|
|||
let expected_output = format!(
|
||||
"
|
||||
▶ Initializing a new site...
|
||||
✔ Created the project root directory.
|
||||
✔ Created a new project in {test_directory}
|
||||
✔ Initialized git support for project.
|
||||
✔ Created a site.toml!
|
||||
|
@ -78,7 +77,6 @@ fn test_init_creates_site() {
|
|||
✔ Copied over sample Markdown: license.md
|
||||
|
||||
▶ Adding plugins to site...
|
||||
✔ Created the plugin directory.
|
||||
✔ Copied over the dark-mode-switch plugin!
|
||||
|
||||
▶ Site initialized. You can now start building your new site. Happy hacking! ✔
|
||||
|
@ -176,7 +174,6 @@ fn assert_valid_directory(path: &Path) {
|
|||
assert!(path.is_dir());
|
||||
}
|
||||
|
||||
// TODO: Add a test with plugins and extras.
|
||||
#[test]
|
||||
fn test_build_builds_site() {
|
||||
let mut rng = thread_rng();
|
||||
|
@ -197,35 +194,24 @@ fn test_build_builds_site() {
|
|||
✔ Found {test_directory}/index.md
|
||||
✔ Found {test_directory}/license.md
|
||||
|
||||
▶ Compiling page information...
|
||||
✔ Compiling \"demo\" page
|
||||
✔ Compiling \"index\" page
|
||||
✔ Compiling \"license\" page
|
||||
▶ Extracting page information...
|
||||
✔ Extracted \"demo\" page
|
||||
✔ Extracted \"index\" page
|
||||
✔ Extracted \"license\" page
|
||||
|
||||
▶ Preparing build directory...
|
||||
✔ Created the build directory.
|
||||
▶ Preparing for the build...
|
||||
✔ Build directory ready.
|
||||
✔ Build information compiled.
|
||||
✔ Render system initialized.
|
||||
|
||||
▶ Initialize page rendering system...
|
||||
▶ Rendering the site...
|
||||
✔ Rendered the build artifact JSON.
|
||||
✔ Rendered the site JSON.
|
||||
|
||||
▶ Creating the index page...
|
||||
✔ Created the index HTML page.
|
||||
|
||||
▶ Creating the pages...
|
||||
✔ Created the page directory.
|
||||
✔ Created the demo HTML page.
|
||||
✔ Created the page directory.
|
||||
✔ Created the index HTML page.
|
||||
✔ Created the page directory.
|
||||
✔ Created the license HTML page.
|
||||
|
||||
▶ Creating the API JSON files...
|
||||
✔ Created the API root directory.
|
||||
✔ Created the build artifact JSON.
|
||||
✔ Created the site JSON.
|
||||
✔ Created the API page root directory.
|
||||
✔ Created the page JSON for the demo page.
|
||||
✔ Created the page JSON for the index page.
|
||||
✔ Created the page JSON for the license page.
|
||||
▶ Rendering the pages...
|
||||
✔ Rendered the demo page.
|
||||
✔ Rendered the index page.
|
||||
✔ Rendered the license page.
|
||||
|
||||
▶ Copying static assets to built site...
|
||||
✔ Copied over static asset directory!
|
||||
|
@ -286,7 +272,12 @@ fn test_build_builds_site() {
|
|||
|
||||
// Check if pages are present and rendered as expected.
|
||||
for test_page_name in expected_pages() {
|
||||
let actual_page_path = build_dir.join(format!("{}/index.html", &test_page_name));
|
||||
let actual_page_path = if test_page_name == "index" {
|
||||
String::from("index.html")
|
||||
} else {
|
||||
format!("{}/index.html", &test_page_name)
|
||||
};
|
||||
let actual_page_path = build_dir.join(actual_page_path);
|
||||
assert_file_readable_into_string(&actual_page_path);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue