@@ -250,6 +250,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" | |||||
dependencies = [ | dependencies = [ | ||||
"num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", | "num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
"num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", | "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
"serde 1.0.79 (registry+https://github.com/rust-lang/crates.io-index)", | |||||
"time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", | "time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
] | ] | ||||
@@ -8,7 +8,7 @@ tera = "0.11" | |||||
serde = "1" | serde = "1" | ||||
slug = "0.1" | slug = "0.1" | ||||
rayon = "1" | rayon = "1" | ||||
chrono = "0.4" | |||||
chrono = { version = "0.4", features = ["serde"] } | |||||
errors = { path = "../errors" } | errors = { path = "../errors" } | ||||
config = { path = "../config" } | config = { path = "../config" } | ||||
@@ -3,7 +3,6 @@ use std::collections::HashMap; | |||||
use std::path::{Path, PathBuf}; | use std::path::{Path, PathBuf}; | ||||
use std::result::Result as StdResult; | use std::result::Result as StdResult; | ||||
use chrono::Datelike; | |||||
use tera::{Tera, Context as TeraContext}; | use tera::{Tera, Context as TeraContext}; | ||||
use serde::ser::{SerializeStruct, self}; | use serde::ser::{SerializeStruct, self}; | ||||
use slug::slugify; | use slug::slugify; | ||||
@@ -263,11 +262,10 @@ impl ser::Serialize for Page { | |||||
state.serialize_field("title", &self.meta.title)?; | state.serialize_field("title", &self.meta.title)?; | ||||
state.serialize_field("description", &self.meta.description)?; | state.serialize_field("description", &self.meta.description)?; | ||||
state.serialize_field("date", &self.meta.date)?; | state.serialize_field("date", &self.meta.date)?; | ||||
if let Some(chrono_datetime) = self.meta.date() { | |||||
let d = chrono_datetime.date(); | |||||
state.serialize_field("year", &d.year())?; | |||||
state.serialize_field("month", &d.month())?; | |||||
state.serialize_field("day", &d.day())?; | |||||
if let Some(d) = self.meta.datetime_tuple { | |||||
state.serialize_field("year", &d.0)?; | |||||
state.serialize_field("month", &d.1)?; | |||||
state.serialize_field("day", &d.2)?; | |||||
} else { | } else { | ||||
state.serialize_field::<Option<usize>>("year", &None)?; | state.serialize_field::<Option<usize>>("year", &None)?; | ||||
state.serialize_field::<Option<usize>>("month", &None)?; | state.serialize_field::<Option<usize>>("month", &None)?; | ||||
@@ -11,7 +11,7 @@ use front_matter::SortBy; | |||||
/// To remove if `sort_pages` is changed to work on borrowed values | /// To remove if `sort_pages` is changed to work on borrowed values | ||||
/// This cannot be used in `sort_pages` currently as it takes &&Page instead of &Page | /// This cannot be used in `sort_pages` currently as it takes &&Page instead of &Page | ||||
pub fn sort_pages_by_date(a: &&Page, b: &&Page) -> Ordering { | pub fn sort_pages_by_date(a: &&Page, b: &&Page) -> Ordering { | ||||
let ord = b.meta.date().unwrap().cmp(&a.meta.date().unwrap()); | |||||
let ord = b.meta.datetime.unwrap().cmp(&a.meta.datetime.unwrap()); | |||||
if ord == Ordering::Equal { | if ord == Ordering::Equal { | ||||
a.permalink.cmp(&b.permalink) | a.permalink.cmp(&b.permalink) | ||||
} else { | } else { | ||||
@@ -33,7 +33,7 @@ pub fn sort_pages(pages: Vec<Page>, sort_by: SortBy) -> (Vec<Page>, Vec<Page>) { | |||||
.into_par_iter() | .into_par_iter() | ||||
.partition(|page| { | .partition(|page| { | ||||
match sort_by { | match sort_by { | ||||
SortBy::Date => page.meta.date.is_some(), | |||||
SortBy::Date => page.meta.datetime.is_some(), | |||||
SortBy::Weight => page.meta.weight.is_some(), | SortBy::Weight => page.meta.weight.is_some(), | ||||
_ => unreachable!() | _ => unreachable!() | ||||
} | } | ||||
@@ -42,7 +42,7 @@ pub fn sort_pages(pages: Vec<Page>, sort_by: SortBy) -> (Vec<Page>, Vec<Page>) { | |||||
match sort_by { | match sort_by { | ||||
SortBy::Date => { | SortBy::Date => { | ||||
can_be_sorted.par_sort_unstable_by(|a, b| { | can_be_sorted.par_sort_unstable_by(|a, b| { | ||||
let ord = b.meta.date().unwrap().cmp(&a.meta.date().unwrap()); | |||||
let ord = b.meta.datetime.unwrap().cmp(&a.meta.datetime.unwrap()); | |||||
if ord == Ordering::Equal { | if ord == Ordering::Equal { | ||||
a.permalink.cmp(&b.permalink) | a.permalink.cmp(&b.permalink) | ||||
} else { | } else { | ||||
@@ -159,6 +159,7 @@ mod tests { | |||||
fn create_page_with_date(date: &str) -> Page { | fn create_page_with_date(date: &str) -> Page { | ||||
let mut front_matter = PageFrontMatter::default(); | let mut front_matter = PageFrontMatter::default(); | ||||
front_matter.date = Some(date.to_string()); | front_matter.date = Some(date.to_string()); | ||||
front_matter.date_to_datetime(); | |||||
Page::new("content/hello.md", front_matter) | Page::new("content/hello.md", front_matter) | ||||
} | } | ||||
@@ -62,7 +62,7 @@ fn fix_toml_dates(table: Map<String, Value>) -> Value { | |||||
/// The front matter of every page | /// The front matter of every page | ||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] | |||||
#[derive(Debug, Clone, PartialEq, Deserialize)] | |||||
#[serde(default)] | #[serde(default)] | ||||
pub struct PageFrontMatter { | pub struct PageFrontMatter { | ||||
/// <title> of the page | /// <title> of the page | ||||
@@ -72,6 +72,12 @@ pub struct PageFrontMatter { | |||||
/// Date if we want to order pages (ie blog post) | /// Date if we want to order pages (ie blog post) | ||||
#[serde(default, deserialize_with = "from_toml_datetime")] | #[serde(default, deserialize_with = "from_toml_datetime")] | ||||
pub date: Option<String>, | pub date: Option<String>, | ||||
/// Chrono converted datetime | |||||
#[serde(default, skip_deserializing)] | |||||
pub datetime: Option<NaiveDateTime>, | |||||
/// The converted date into a (year, month, day) tuple | |||||
#[serde(default, skip_deserializing)] | |||||
pub datetime_tuple: Option<(i32, u32, u32)>, | |||||
/// Whether this page is a draft and should be ignored for pagination etc | /// Whether this page is a draft and should be ignored for pagination etc | ||||
pub draft: bool, | pub draft: bool, | ||||
/// The page slug. Will be used instead of the filename if present | /// The page slug. Will be used instead of the filename if present | ||||
@@ -124,12 +130,16 @@ impl PageFrontMatter { | |||||
Value::Object(o) => o, | Value::Object(o) => o, | ||||
_ => unreachable!("Got something other than a table in page extra"), | _ => unreachable!("Got something other than a table in page extra"), | ||||
}; | }; | ||||
f.date_to_datetime(); | |||||
Ok(f) | Ok(f) | ||||
} | } | ||||
/// Converts the TOML datetime to a Chrono naive datetime | /// Converts the TOML datetime to a Chrono naive datetime | ||||
pub fn date(&self) -> Option<NaiveDateTime> { | |||||
if let Some(ref d) = self.date { | |||||
/// Also grabs the year/month/day tuple that will be used in serialization | |||||
pub fn date_to_datetime(&mut self) { | |||||
self.datetime = if let Some(ref d) = self.date { | |||||
if d.contains('T') { | if d.contains('T') { | ||||
DateTime::parse_from_rfc3339(&d).ok().and_then(|s| Some(s.naive_local())) | DateTime::parse_from_rfc3339(&d).ok().and_then(|s| Some(s.naive_local())) | ||||
} else { | } else { | ||||
@@ -137,7 +147,13 @@ impl PageFrontMatter { | |||||
} | } | ||||
} else { | } else { | ||||
None | None | ||||
} | |||||
}; | |||||
self.datetime_tuple = if let Some(ref dt) = self.datetime { | |||||
Some((dt.year(), dt.month(), dt.day())) | |||||
} else { | |||||
None | |||||
}; | |||||
} | } | ||||
pub fn order(&self) -> usize { | pub fn order(&self) -> usize { | ||||
@@ -155,6 +171,8 @@ impl Default for PageFrontMatter { | |||||
title: None, | title: None, | ||||
description: None, | description: None, | ||||
date: None, | date: None, | ||||
datetime: None, | |||||
datetime_tuple: None, | |||||
draft: false, | draft: false, | ||||
slug: None, | slug: None, | ||||
path: None, | path: None, | ||||