Skip to content

Commit

Permalink
Root Objects (#22)
Browse files Browse the repository at this point in the history
Breaking change

Move return type of objects from HashMap<String, Vec<Object>> to HashMap<String, ObjectEntry> where ObjectEntry is an enum of Object(Object) or List(Vec<Object>)

Then, when reading files, allow either defining object/foo/*.toml or object/foo.toml. In the latter case, objects.foo will be an object itself rather than an array, and there will only ever be one of them.

If both are defined, the build will fail.
  • Loading branch information
jesseditson authored Mar 20, 2024
1 parent 114dc3d commit 94a7b4c
Show file tree
Hide file tree
Showing 10 changed files with 215 additions and 66 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/rust-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ jobs:
- name: cargo test build
run: cargo build --tests --release
- name: cargo test binary
run: cargo test --release --features=binary -- --test-threads=1
run: ./test-bin.sh

# msrv-check:
# name: Minimum Stable Rust Version Check
Expand Down
14 changes: 10 additions & 4 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ mod file_system_stdlib;
#[cfg(feature = "binary")]
mod server;
use file_system_mutex::FileSystemMutex;
use object::Object;
use object::{Object, ObjectEntry};
use semver::{Version, VersionReq};

// Re-exports
Expand Down Expand Up @@ -202,13 +202,13 @@ impl<F: FileSystemAPI> Archival<F> {
Ok(())
}

pub fn get_objects(&self) -> Result<HashMap<String, Vec<Object>>, Box<dyn Error>> {
pub fn get_objects(&self) -> Result<HashMap<String, ObjectEntry>, Box<dyn Error>> {
self.fs_mutex.with_fs(|fs| self.site.get_objects(fs))
}
pub fn get_objects_sorted(
&self,
sort: impl Fn(&Object, &Object) -> Ordering,
) -> Result<HashMap<String, Vec<Object>>, Box<dyn Error>> {
) -> Result<HashMap<String, ObjectEntry>, Box<dyn Error>> {
self.fs_mutex
.with_fs(|fs| self.site.get_objects_sorted(fs, sort))
}
Expand Down Expand Up @@ -315,9 +315,15 @@ mod lib {
let zip = include_bytes!("../tests/fixtures/archival-website.zip");
unpack_zip(zip.to_vec(), &mut fs)?;
let archival = Archival::new(fs)?;
assert_eq!(archival.site.object_definitions.len(), 2);
assert_eq!(archival.site.object_definitions.len(), 3);
assert!(archival.site.object_definitions.contains_key("section"));
assert!(archival.site.object_definitions.contains_key("post"));
assert!(archival.site.object_definitions.contains_key("site"));
let objects = archival.get_objects()?;
let section_objs = objects.get("section").unwrap();
assert!(matches!(section_objs, ObjectEntry::List(_)));
let site_obj = objects.get("site").unwrap();
assert!(matches!(site_obj, ObjectEntry::Object(_)));
archival.build()?;
let dist_files = archival.dist_files();
println!("dist_files: \n{}", dist_files.join("\n"));
Expand Down
33 changes: 20 additions & 13 deletions src/main.rs
Original file line number Diff line number Diff line change
@@ -1,18 +1,25 @@
#[cfg(feature = "binary")]
use archival::binary;
use tracing_subscriber::{fmt, prelude::*, EnvFilter};

fn main() {
tracing_subscriber::registry()
.with(fmt::layer())
.with(EnvFilter::from_default_env())
.init();
#[cfg(feature = "binary")]
match binary::binary(std::env::args()) {
Ok(c) => std::process::exit(c.code()),
Err(e) => {
eprintln!("Error: {e}");
std::process::exit(1);
binary::main();
#[cfg(not(feature = "binary"))]
println!("archival was built without the binary feature.")
}

#[cfg(feature = "binary")]
mod binary {
use archival::binary;
use tracing_subscriber::{fmt, prelude::*, EnvFilter};
pub fn main() {
tracing_subscriber::registry()
.with(fmt::layer())
.with(EnvFilter::from_default_env())
.init();
match binary::binary(std::env::args()) {
Ok(c) => std::process::exit(c.code()),
Err(e) => {
eprintln!("Error: {e}");
std::process::exit(1);
}
}
}
}
4 changes: 2 additions & 2 deletions src/manifest.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
use clap::ValueEnum;
use serde::{Deserialize, Serialize};
use std::{
error::Error,
Expand Down Expand Up @@ -39,7 +38,8 @@ pub struct Manifest {
pub cdn_url: String,
}

#[derive(Clone, Debug, ValueEnum)]
#[derive(Clone, Debug)]
#[cfg_attr(feature = "binary", derive(clap::ValueEnum))]
pub enum ManifestField {
ArchivalVersion,
SiteUrl,
Expand Down
2 changes: 2 additions & 0 deletions src/object.rs → src/object/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ use serde::{Deserialize, Serialize};
use std::{collections::HashMap, error::Error, fmt::Debug, path::Path};
use toml::Table;
use tracing::warn;
mod object_entry;
pub use object_entry::ObjectEntry;

#[derive(Debug, ObjectView, ValueView, Deserialize, Serialize, Clone)]
#[cfg_attr(feature = "typescript", derive(typescript_type_def::TypeDef))]
Expand Down
99 changes: 99 additions & 0 deletions src/object/object_entry.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
use crate::object::Object;
use serde::{Deserialize, Serialize};

#[derive(Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(feature = "typescript", derive(typescript_type_def::TypeDef))]
pub enum ObjectEntry {
List(Vec<Object>),
Object(Object),
}

impl ObjectEntry {
pub fn from_vec(vec: Vec<Object>) -> Self {
Self::List(vec)
}
pub fn from_object(object: Object) -> Self {
Self::Object(object)
}
}

pub struct ObjectEntryIterator<'a> {
entry: &'a ObjectEntry,
index: usize,
}

impl<'a> Iterator for ObjectEntryIterator<'a> {
type Item = &'a Object;
fn next(&mut self) -> Option<Self::Item> {
match self.entry {
ObjectEntry::List(l) => {
let o = l.get(self.index);
self.index += 1;
o
}
ObjectEntry::Object(o) => {
if self.index == 0 {
self.index = usize::MAX;
Some(o)
} else {
None
}
}
}
}
}

impl<'a> ObjectEntry {
pub fn iter_mut(&'a mut self) -> ObjectEntryMutIterator<'a> {
self.into_iter()
}
}

impl<'a> IntoIterator for &'a ObjectEntry {
type Item = &'a Object;
type IntoIter = ObjectEntryIterator<'a>;

fn into_iter(self) -> Self::IntoIter {
ObjectEntryIterator {
entry: self,
index: 0,
}
}
}

impl<'a> IntoIterator for &'a mut ObjectEntry {
type Item = &'a mut Object;
type IntoIter = ObjectEntryMutIterator<'a>;

fn into_iter(self) -> Self::IntoIter {
ObjectEntryMutIterator {
entry: self,
index: 0,
}
}
}
pub struct ObjectEntryMutIterator<'a> {
entry: &'a mut ObjectEntry,
index: usize,
}

impl<'a> Iterator for ObjectEntryMutIterator<'a> {
type Item = &'a mut Object;
fn next(&mut self) -> Option<Self::Item> {
match self.entry {
ObjectEntry::List(l) => {
let o = l.get_mut(self.index);
self.index += 1;
unsafe { std::mem::transmute(o) }
}
ObjectEntry::Object(o) => {
if self.index == 0 {
self.index = usize::MAX;
unsafe { std::mem::transmute(o) }
} else {
None
}
}
}
}
}
25 changes: 16 additions & 9 deletions src/page.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
use crate::{object::Object, object_definition::ObjectDefinition};
use crate::{
object::{Object, ObjectEntry},
object_definition::ObjectDefinition,
};
use liquid::ValueView;
use liquid_core::Value;
use regex::Regex;
use std::{collections::HashMap, error::Error, fmt};

Expand Down Expand Up @@ -113,12 +117,15 @@ impl<'a> Page<'a> {
pub fn render(
&self,
parser: &liquid::Parser,
objects_map: &HashMap<String, Vec<Object>>,
objects_map: &HashMap<String, ObjectEntry>,
) -> Result<String, Box<dyn Error>> {
tracing::debug!("rendering {}", self.name);
let mut objects: HashMap<String, Vec<liquid::model::Value>> = HashMap::new();
for (name, objs) in objects_map {
let values = objs.iter().map(|o| o.liquid_object()).collect();
let mut objects: HashMap<String, liquid::model::Value> = HashMap::new();
for (name, obj_entry) in objects_map {
let values = match obj_entry {
ObjectEntry::List(l) => Value::array(l.iter().map(|o| o.liquid_object())),
ObjectEntry::Object(o) => o.liquid_object(),
};
objects.insert(name.to_string(), values);
}
let globals = liquid::object!({ "objects": objects, "page": self.name });
Expand Down Expand Up @@ -162,7 +169,7 @@ mod tests {

use super::*;

fn get_objects_map() -> HashMap<String, Vec<Object>> {
fn get_objects_map() -> HashMap<String, ObjectEntry> {
let tour_dates_objects = vec![HashMap::from([
(
"date".to_string(),
Expand Down Expand Up @@ -217,8 +224,8 @@ mod tests {
};

HashMap::from([
("artist".to_string(), vec![artist]),
("c".to_string(), vec![c]),
("artist".to_string(), ObjectEntry::from_vec(vec![artist])),
("c".to_string(), ObjectEntry::from_vec(vec![c])),
])
}

Expand Down Expand Up @@ -321,7 +328,7 @@ mod tests {
fn template_page() -> Result<(), Box<dyn Error>> {
let liquid_parser = liquid_parser::get(None, None, &MemoryFileSystem::default())?;
let objects_map = get_objects_map();
let object = objects_map["artist"].first().unwrap();
let object = objects_map["artist"].into_iter().next().unwrap();
let artist_def = artist_definition();
let page = Page::new_with_template(
"tormenta-rey".to_string(),
Expand Down
Loading

0 comments on commit 94a7b4c

Please sign in to comment.