Skip to content

Commit

Permalink
feat: VoxProvider trait
Browse files Browse the repository at this point in the history
Building using the file system is moved to the `fs_provider` feature.
  • Loading branch information
emmyoh committed Oct 28, 2024
1 parent 2bb8835 commit 30dc29a
Show file tree
Hide file tree
Showing 9 changed files with 1,185 additions and 900 deletions.
20 changes: 11 additions & 9 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,33 +23,35 @@ required-features = ["cli"]

[dependencies]
chrono = { version = "0.4.38", features = ["serde", "unstable-locales"] }
clap = { version = "4.5.17", features = ["derive", "cargo"], optional = true }
comrak = { version = "0.28.0", features = ["syntect", "shortcodes"], default-features = false }
clap = { version = "4.5.20", features = ["derive", "cargo"], optional = true }
comrak = { version = "0.29.0", features = ["syntect", "shortcodes"], default-features = false }
daggy = { version = "0.8.0", features = ["stable_dag"] }
toml = "0.8.19"
liquid = "0.26.9"
liquid-core = "0.26.9"
liquid-lib = { version = "0.26.9", features = ["all", "stdlib", "jekyll", "shopify", "extra"] }
serde = "1.0.210"
serde = "1.0.213"
sys-locale = "0.3.1"
latex2mathml = "0.2.3"
ahash = { version = "0.8.11", features = ["std", "serde", "runtime-rng"] }
mimalloc = { version = "0.1.43", optional = true }
ticky = { version = "1.0.2", optional = true }
ticky = { version = "1.0.2" }
miette = { version = "7.2.0", features = ["fancy", "syntect-highlighter"] }
thiserror = "1.0.63"
thiserror = "1.0.65"
glob = "0.3.1"
tokio = { version = "1.40.0", features = ["full"], optional = true }
futures = "0.3.30"
tokio = { version = "1.41.0", features = ["full"], optional = true }
futures = "0.3.31"
tracing-subscriber = { version = "0.3.18", optional = true, features = ["env-filter"]}
tracing = "0.1.40"
notify-debouncer-full = { version = "0.3.1", default-features = false, optional = true }
notify-debouncer-full = { version = "0.4.0", default-features = false, optional = true }
actix-files = { version = "0.6.6", optional = true }
actix-web = { version = "4.9.0", optional = true }
layout-rs = "0.1.2"
html-escape = "0.2.13"
syntect = "5.2.0"
path-clean = "1.0.1"

[features]
default = []
cli = ["dep:mimalloc", "dep:ticky", "dep:tokio", "dep:clap", "dep:tracing-subscriber", "dep:notify-debouncer-full", "dep:actix-files", "dep:actix-web"]
cli = ["fs_provider", "dep:mimalloc", "dep:tokio", "dep:clap", "dep:tracing-subscriber", "dep:notify-debouncer-full", "dep:actix-files", "dep:actix-web"]
fs_provider = []
86 changes: 10 additions & 76 deletions src/builds.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,16 @@ use crate::page::Page;
use ahash::AHashMap;
use chrono::Locale;
use daggy::{
petgraph::{
algo::toposort,
dot::{Config, Dot},
Direction,
},
petgraph::{algo::toposort, Direction},
stable_dag::StableDag,
NodeIndex, Walker,
};
use layout::gv::DotParser;
use layout::gv::GraphBuilder;
use layout::{backends::svg::SVGWriter, core::color::Color, std_shapes::shapes::ShapeKind};
use liquid::{to_object, Object, Parser};
use liquid_core::to_value;
use miette::IntoDiagnostic;
use std::{env, fs, path::PathBuf};
use tracing::{debug, trace, warn};
use path_clean::PathClean;
use std::path::PathBuf;
use tracing::{debug, trace};

/// Information held in memory while performing a build.
#[derive(Clone, Default)]
Expand All @@ -42,58 +36,6 @@ pub enum EdgeType {
}

impl Build {
/// Visualise the DAG.
pub fn visualise_dag(&mut self) -> miette::Result<()> {
let dag_graph = self.dag.graph();
let dag_graphviz = Dot::with_attr_getters(
dag_graph,
&[Config::NodeNoLabel, Config::EdgeNoLabel],
&|_graph, edge| format!("label = \"{:?}\"", edge.weight()),
&|_graph, node| {
let path = PathBuf::from(node.1.to_path_string());
let relative_path = path
.strip_prefix(fs::canonicalize(env::current_dir().unwrap()).unwrap())
.unwrap();
let label = relative_path.to_string_lossy().to_string();
format!("label = \"{}\"", label)
},
);
let mut parser = DotParser::new(&format!("{:?}", dag_graphviz));
let tree = parser.process();
if let Ok(tree) = tree {
let mut gb = GraphBuilder::new();
gb.visit_graph(&tree);
let mut vg = gb.get();
let mut svg = SVGWriter::new();
for node_handle in vg.iter_nodes() {
let node = vg.element_mut(node_handle);
let old_shape = node.shape.clone();
if let ShapeKind::Circle(label) = old_shape {
node.shape = ShapeKind::Box(label.clone());
if Page::is_layout_path(label.clone())? {
node.look.fill_color = Some(Color::fast("#FFDFBA"));
} else {
match Page::get_collections_from_path(label)? {
Some(_) => {
node.look.fill_color = Some(Color::fast("#DAFFBA"));
}
None => {
node.look.fill_color = Some(Color::fast("#BADAFF"));
}
}
}
}
}
vg.do_it(false, false, false, &mut svg);
let content = svg.finalize();
std::fs::create_dir_all("output").into_diagnostic()?;
std::fs::write("output/dag.svg", content).into_diagnostic()?;
} else {
warn!("Unable to visualise the DAG.")
}
Ok(())
}

/// Get all descendants of a page in a DAG.
///
/// # Arguments
Expand Down Expand Up @@ -160,7 +102,7 @@ impl Build {
let parents = dag.parents(root_index).iter(dag).collect::<Vec<_>>();
for parent in parents {
let parent_page = &dag.graph()[parent.1];
if !parent_page.is_layout()? {
if !parent_page.is_layout() {
ancestors.push(parent.1);
}
let parent_ancestors = Build::get_non_layout_ancestors(dag, parent.1)?;
Expand Down Expand Up @@ -188,7 +130,7 @@ impl Build {
let ancestor_page = &self.dag.graph()[ancestor];
let ancestor_object =
liquid_core::Value::Object(to_object(&ancestor_page).into_diagnostic()?);
if ancestor_page.is_layout()? {
if ancestor_page.is_layout() {
let ancestor_object =
liquid_core::Value::Object(to_object(&ancestor_page).into_diagnostic()?);
layout_ancestor_contexts.push(ancestor_object);
Expand All @@ -210,11 +152,8 @@ impl Build {
/// # Returns
///
/// A list of all nodes that were rendered.
pub fn render_all(&mut self, visualise_dag: bool) -> miette::Result<Vec<NodeIndex>> {
pub fn render_all(&mut self) -> miette::Result<Vec<NodeIndex>> {
trace!("Rendering all pages … ");
if visualise_dag {
self.visualise_dag()?;
}
let mut rendered_indices = Vec::new();
let indices = toposort(&self.dag.graph(), None).unwrap_or_default();
for index in indices {
Expand Down Expand Up @@ -242,16 +181,11 @@ impl Build {
recursive: bool,
rendered_indices: &mut Vec<NodeIndex>,
) -> miette::Result<()> {
let current_directory =
fs::canonicalize(env::current_dir().into_diagnostic()?).into_diagnostic()?;
let root_page = self.dag.graph()[root_index].to_owned();
let root_path = fs::canonicalize(root_page.to_path_string()).into_diagnostic()?;
let root_path_difference = root_path
.strip_prefix(&current_directory)
.into_diagnostic()?;
debug!("Rendering page: {:?}", root_path_difference);
let root_path: PathBuf = PathBuf::from(root_page.to_path_string()).clean();
debug!("Rendering page: {:?}", root_path);
let mut root_contexts = self.contexts.clone();
if root_path_difference.starts_with(PathBuf::from("layouts/")) {
if root_path.starts_with(PathBuf::from("layouts/")) {
debug!("Page is a layout page … ");
let layout_object =
liquid_core::Value::Object(to_object(&root_page).into_diagnostic()?);
Expand Down
2 changes: 1 addition & 1 deletion src/date.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ use chrono::NaiveDateTime;
use chrono::NaiveTime;
use chrono::TimeZone;
use chrono::Utc;
use core::fmt;
use serde::Deserialize;
use serde::Serialize;
use std::fmt;
use sys_locale::get_locale;
use tracing::debug;

Expand Down
35 changes: 35 additions & 0 deletions src/fs_provider.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
use crate::provider::VoxProvider;
use miette::IntoDiagnostic;

#[derive(Debug)]
/// A provider of the Vox build system that reads & writes from the file system.
pub struct FsProvider;
impl VoxProvider for FsProvider {
fn read_to_string(path: impl AsRef<std::path::Path>) -> miette::Result<String> {
std::fs::read_to_string(path).into_diagnostic()
}
fn write_file(
path: impl AsRef<std::path::Path> + Clone,
contents: impl AsRef<[u8]>,
) -> miette::Result<()> {
if let Some(parent_path) = path.as_ref().parent() {
std::fs::create_dir_all(parent_path).into_diagnostic()?;
}
std::fs::write(path, contents).into_diagnostic()
}
fn remove_file(path: impl AsRef<std::path::Path>) -> miette::Result<()> {
std::fs::remove_file(path).into_diagnostic()
}
fn list_vox_files() -> miette::Result<Vec<std::path::PathBuf>> {
Ok(glob::glob("**/*.vox")
.into_diagnostic()?
.filter_map(Result::ok)
.collect())
}
fn list_snippets() -> miette::Result<Vec<std::path::PathBuf>> {
Ok(glob::glob("snippets/**/*")
.into_diagnostic()?
.filter_map(Result::ok)
.collect())
}
}
8 changes: 6 additions & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,9 @@ pub mod page;
/// Errors originating during the build process.
pub mod error;

/// Template parsing and rendering.
pub mod templates;
/// The interface to the Vox build system.
pub mod provider;

/// A provider of the Vox build system that reads & writes from the file system.
#[cfg(feature = "fs_provider")]
pub mod fs_provider;
Loading

0 comments on commit 30dc29a

Please sign in to comment.