@@ -5,7 +5,6 @@ use std::path::PathBuf;
55use std:: process;
66
77use std:: fs;
8- use std:: fs:: copy;
98use std:: io;
109use std:: path:: Path ;
1110
@@ -16,12 +15,15 @@ use markdown::Constructs;
1615use markdown:: Options ;
1716use markdown:: ParseOptions ;
1817
18+ use chrono:: { DateTime , Local } ;
19+
1920#[ derive( Debug ) ]
2021#[ allow( dead_code) ]
2122pub enum PostBuildError {
2223 GeneralIOError ( std:: io:: Error ) ,
2324 TemplateBuildError ( std:: io:: Error ) ,
2425 MissingRequiredKey ( String ) ,
26+ PostFilesMissing ,
2527}
2628
2729#[ derive( Debug ) ]
@@ -34,6 +36,14 @@ pub enum SiteBuildError {
3436 MissingRequiredKey ( String ) ,
3537}
3638
39+ struct PostInfo {
40+ name : String ,
41+ title : String ,
42+ description : String ,
43+ timestamp_display : String ,
44+ timestamp : i64 ,
45+ }
46+
3747pub fn build_site ( source_dir : & PathBuf , output_dir : & PathBuf ) -> Result < ( ) , SiteBuildError > {
3848 match fs:: create_dir_all ( & output_dir) {
3949 Ok ( _) => ( ) ,
@@ -66,14 +76,6 @@ pub fn build_site(source_dir: &PathBuf, output_dir: &PathBuf) -> Result<(), Site
6676 } ;
6777 }
6878
69- let site_index = source_dir. join ( "index.html" ) ;
70- if site_index. exists ( ) {
71- match copy ( & site_index, & output_dir. join ( "index.html" ) ) {
72- Ok ( _) => ( ) ,
73- Err ( e) => return Err ( SiteBuildError :: GeneralIOError ( e) ) ,
74- }
75- }
76-
7779 let prelude_path = source_dir. join ( "prelude.html" ) ;
7880 let prelude = match fs:: read_to_string ( & prelude_path) {
7981 Ok ( content) => content,
@@ -94,6 +96,9 @@ pub fn build_site(source_dir: &PathBuf, output_dir: &PathBuf) -> Result<(), Site
9496 Err ( e) => return Err ( SiteBuildError :: GeneralIOError ( e) ) ,
9597 } ;
9698
99+ // Impure, but I'm lazy.
100+ let mut post_infos: Vec < PostInfo > = Vec :: new ( ) ;
101+
97102 for entry in entries {
98103 let post_dir = match entry {
99104 Ok ( p) => p. path ( ) ,
@@ -102,7 +107,11 @@ pub fn build_site(source_dir: &PathBuf, output_dir: &PathBuf) -> Result<(), Site
102107
103108 if post_dir. is_dir ( ) {
104109 match process_post ( & post_dir, & output_dir, & site_config, & prelude) {
105- Ok ( _) => continue ,
110+ Ok ( post) => {
111+ if let Some ( post_info) = post {
112+ post_infos. push ( post_info) ;
113+ }
114+ }
106115 Err ( e) => {
107116 eprintln ! ( "Failed to build post: {e:?}. Continuing..." ) ;
108117 continue ;
@@ -111,6 +120,27 @@ pub fn build_site(source_dir: &PathBuf, output_dir: &PathBuf) -> Result<(), Site
111120 }
112121 }
113122
123+ // Sort posts by timestamps
124+ post_infos. sort_by ( |a, b| b. timestamp . cmp ( & a. timestamp ) ) ;
125+
126+ // Make a simple posts index.
127+ // THIS IS DOGSHIT LMAO
128+
129+ let mut posts_index = String :: new ( ) ;
130+ posts_index. push_str ( "<html><head><title>Posts</title></head><body>" ) ;
131+ posts_index. push_str ( "<h1>Posts</h1><ul>" ) ;
132+ for post in & post_infos {
133+ posts_index. push_str ( & format ! (
134+ "<li><a href=\" {}/index.html\" >{}</a> - {} - {}</li>" ,
135+ post. name, post. title, post. description, post. timestamp_display
136+ ) ) ;
137+ }
138+ posts_index. push_str ( "</ul></body></html>" ) ;
139+ match fs:: write ( output_dir. join ( "index.html" ) , posts_index) {
140+ Ok ( _) => ( ) ,
141+ Err ( e) => return Err ( SiteBuildError :: GeneralIOError ( e) ) ,
142+ }
143+
114144 Ok ( ( ) )
115145}
116146
@@ -119,12 +149,12 @@ fn process_post(
119149 output_dir : & Path ,
120150 site_config : & HashMap < String , toml:: Value > ,
121151 prelude : & str ,
122- ) -> Result < ( ) , PostBuildError > {
152+ ) -> Result < Option < PostInfo > , PostBuildError > {
123153 let post_toml_path = post_dir. join ( "post.toml" ) ;
124154 let content_path = post_dir. join ( "content.md" ) ;
125155
126156 if !post_toml_path. exists ( ) || !content_path. exists ( ) {
127- return Ok ( ( ) ) ;
157+ return Err ( PostBuildError :: PostFilesMissing ) ;
128158 }
129159
130160 println ! ( "Processing post: {}" , post_dir. display( ) ) ;
@@ -183,6 +213,31 @@ fn process_post(
183213
184214 let post_name = post_dir. file_name ( ) . unwrap ( ) . to_string_lossy ( ) ;
185215 let post_output_dir = output_dir. join ( & * post_name) ;
216+
217+ // Check if post is built by checking if the target directory has any
218+ // timestamps older than any timestamp in the source directory.
219+ // If it's older, continue.
220+ // If it's newer, return Ok(None).
221+ let post_build_timestamp = match fs:: metadata ( & post_output_dir) {
222+ Ok ( metadata) => metadata. modified ( ) . unwrap ( ) ,
223+ Err ( _) => std:: time:: SystemTime :: UNIX_EPOCH ,
224+ } ;
225+ let post_source_timestamp = match fs:: metadata ( & post_dir) {
226+ Ok ( metadata) => metadata. modified ( ) . unwrap ( ) ,
227+ Err ( _) => {
228+ return Err ( PostBuildError :: GeneralIOError (
229+ std:: io:: Error :: new (
230+ std:: io:: ErrorKind :: NotFound ,
231+ "Failed to get post directory metadata" ,
232+ ) , // NOTE: I should migrate to these errors instead of general IO handling whatever
233+ ) ) ;
234+ }
235+ } ;
236+
237+ if post_source_timestamp < post_build_timestamp {
238+ return Ok ( None ) ;
239+ }
240+
186241 match fs:: create_dir_all ( & post_output_dir) {
187242 Ok ( _) => ( ) ,
188243 Err ( e) => return Err ( PostBuildError :: GeneralIOError ( e) ) ,
@@ -208,13 +263,22 @@ fn process_post(
208263 Err ( e) => return Err ( PostBuildError :: GeneralIOError ( e) ) ,
209264 }
210265 }
211-
212266 println ! ( " Built post: {}" , post_name) ;
213267 }
214268 Err ( e) => return Err ( PostBuildError :: TemplateBuildError ( e) ) ,
215269 }
216270
217- Ok ( ( ) )
271+ let current_local: DateTime < Local > = Local :: now ( ) ;
272+ let current_time = current_local. format ( "%Y-%m-%d %H:%M:%S" ) . to_string ( ) ;
273+
274+ Ok ( Some ( PostInfo {
275+ // Unwrapping is fine here bc we error checked earlier
276+ name : post_name. to_string ( ) ,
277+ title : post_config. get ( "Title" ) . unwrap ( ) . to_string ( ) ,
278+ description : post_config. get ( "Description" ) . unwrap ( ) . to_string ( ) ,
279+ timestamp_display : current_time,
280+ timestamp : current_local. timestamp ( ) ,
281+ } ) )
218282}
219283
220284pub fn copy_directory ( src : & Path , dst : & Path ) -> io:: Result < ( ) > {
0 commit comments