1
+ mod blogs;
1
2
mod posts;
2
3
4
+ use crate :: blogs:: Blog ;
3
5
use crate :: posts:: Post ;
4
6
use handlebars:: { Context , Handlebars , Helper , HelperResult , Output , RenderContext , RenderError } ;
5
7
use sass_rs:: { compile_file, Options } ;
6
8
use serde_derive:: Serialize ;
7
9
use serde_json:: json;
10
+ use std:: convert:: AsRef ;
8
11
use std:: error:: Error ;
9
12
use std:: fs:: { self , File } ;
10
13
use std:: io:: Write ;
11
- use std:: path:: PathBuf ;
14
+ use std:: path:: { Path , PathBuf } ;
12
15
13
- struct Blog {
16
+ struct Generator {
14
17
handlebars : Handlebars ,
15
- posts : Vec < Post > ,
18
+ blogs : Vec < Blog > ,
16
19
out_directory : PathBuf ,
17
20
}
18
21
@@ -62,73 +65,34 @@ fn hb_month_helper<'a>(
62
65
Ok ( ( ) )
63
66
}
64
67
65
- impl Blog {
66
- fn new < T > ( out_directory : T , posts_directory : T ) -> Result < Blog , Box < dyn Error > >
67
- where
68
- T : Into < PathBuf > ,
69
- {
68
+ impl Generator {
69
+ fn new (
70
+ out_directory : impl AsRef < Path > ,
71
+ posts_directory : impl AsRef < Path > ,
72
+ ) -> Result < Generator , Box < dyn Error > > {
70
73
let mut handlebars = Handlebars :: new ( ) ;
71
-
72
74
handlebars. set_strict_mode ( true ) ;
73
-
74
75
handlebars. register_templates_directory ( ".hbs" , "templates" ) ?;
75
-
76
76
handlebars. register_helper ( "month_name" , Box :: new ( hb_month_helper) ) ;
77
77
78
- let posts = Blog :: load_posts ( posts_directory. into ( ) ) ?;
79
-
80
- Ok ( Blog {
78
+ Ok ( Generator {
81
79
handlebars,
82
- posts ,
83
- out_directory : out_directory. into ( ) ,
80
+ blogs : crate :: blogs :: load ( posts_directory . as_ref ( ) ) ? ,
81
+ out_directory : out_directory. as_ref ( ) . into ( ) ,
84
82
} )
85
83
}
86
84
87
- fn load_posts ( dir : PathBuf ) -> Result < Vec < Post > , Box < dyn Error > > {
88
- let mut posts = Vec :: new ( ) ;
89
-
90
- for entry in fs:: read_dir ( dir) ? {
91
- let path = entry?. path ( ) ;
92
-
93
- // ignore vim temporary files
94
- let filename = path. file_name ( ) . unwrap ( ) . to_str ( ) . unwrap ( ) ;
95
- if filename. starts_with ( "." ) && filename. ends_with ( ".swp" ) {
96
- continue ;
97
- }
98
-
99
- posts. push ( Post :: open ( & path) ?) ;
100
- }
101
-
102
- // finally, sort the posts. oldest first.
103
- posts. sort_by_key ( |post| post. url . clone ( ) ) ;
104
- posts. reverse ( ) ;
105
-
106
- for i in 1 ..posts. len ( ) {
107
- posts[ i] . show_year = posts[ i - 1 ] . year != posts[ i] . year ;
108
- }
109
-
110
- Ok ( posts)
111
- }
112
-
113
85
fn render ( & self ) -> Result < ( ) , Box < dyn Error > > {
114
86
// make sure our output directory exists
115
87
fs:: create_dir_all ( & self . out_directory ) ?;
116
88
117
- self . render_index ( ) ?;
118
-
119
- self . render_posts ( ) ?;
120
-
121
- self . render_feed ( ) ?;
122
-
89
+ for blog in & self . blogs {
90
+ self . render_blog ( blog) ?;
91
+ }
123
92
self . compile_sass ( "app" ) ;
124
93
self . compile_sass ( "fonts" ) ;
125
-
126
94
self . concat_vendor_css ( vec ! [ "skeleton" , "tachyons" ] ) ;
127
-
128
95
self . copy_static_files ( ) ?;
129
-
130
- self . generate_releases_feed ( ) ?;
131
-
132
96
Ok ( ( ) )
133
97
}
134
98
@@ -154,70 +118,85 @@ impl Blog {
154
118
fs:: write ( "./static/styles/vendor.css" , & concatted) . expect ( "couldn't write vendor css" ) ;
155
119
}
156
120
157
- fn render_index ( & self ) -> Result < ( ) , Box < dyn Error > > {
121
+ fn render_blog ( & self , blog : & Blog ) -> Result < ( ) , Box < dyn Error > > {
122
+ std:: fs:: create_dir_all ( self . out_directory . join ( blog. prefix ( ) ) ) ?;
123
+
124
+ self . render_index ( blog) ?;
125
+ self . render_feed ( blog) ?;
126
+ self . render_releases_feed ( blog) ?;
127
+ for post in blog. posts ( ) {
128
+ self . render_post ( blog, post) ?;
129
+ }
130
+ Ok ( ( ) )
131
+ }
132
+
133
+ fn render_index ( & self , blog : & Blog ) -> Result < ( ) , Box < dyn Error > > {
158
134
let data = json ! ( {
159
- "title" : "The Rust Programming Language Blog" ,
135
+ "title" : blog . index_title ( ) ,
160
136
"parent" : "layout" ,
161
- "posts " : self . posts ,
137
+ "blog " : blog ,
162
138
} ) ;
163
-
164
- self . render_template ( "index.html" , "index" , data) ?;
165
-
139
+ self . render_template ( blog. prefix ( ) . join ( "index.html" ) , "index" , data) ?;
166
140
Ok ( ( ) )
167
141
}
168
142
169
- fn render_posts ( & self ) -> Result < ( ) , Box < dyn Error > > {
170
- for post in & self . posts {
171
- // first, we create the path
172
- //let path = PathBuf::from(&self.out_directory);
173
-
174
- let path = PathBuf :: from ( & post. year ) ;
175
- let path = path. join ( & post. month ) ;
176
- let path = path. join ( & post. day ) ;
177
-
178
- fs:: create_dir_all ( self . out_directory . join ( & path) ) ?;
143
+ fn render_post ( & self , blog : & Blog , post : & Post ) -> Result < ( ) , Box < dyn Error > > {
144
+ let path = blog
145
+ . prefix ( )
146
+ . join ( & post. year )
147
+ . join ( & post. month )
148
+ . join ( & post. day ) ;
149
+ fs:: create_dir_all ( self . out_directory . join ( & path) ) ?;
179
150
180
- // then, we render the page in that path
181
- let mut filename = PathBuf :: from ( & post. filename ) ;
182
- filename. set_extension ( "html" ) ;
151
+ // then, we render the page in that path
152
+ let mut filename = PathBuf :: from ( & post. filename ) ;
153
+ filename. set_extension ( "html" ) ;
183
154
184
- let data = json ! ( {
185
- "title" : format!( "{} | Rust Blog" , post. title) ,
186
- "parent" : "layout" ,
187
- "post" : post,
188
- } ) ;
189
-
190
- self . render_template ( path. join ( filename) . to_str ( ) . unwrap ( ) , "post" , data) ?;
191
- }
155
+ let data = json ! ( {
156
+ "title" : format!( "{} | {}" , post. title, blog. title( ) ) ,
157
+ "parent" : "layout" ,
158
+ "blog" : blog,
159
+ "post" : post,
160
+ } ) ;
192
161
162
+ self . render_template ( path. join ( filename) , "post" , data) ?;
193
163
Ok ( ( ) )
194
164
}
195
165
196
- fn render_feed ( & self ) -> Result < ( ) , Box < dyn Error > > {
197
- let posts: Vec < _ > = self . posts . iter ( ) . by_ref ( ) . take ( 10 ) . collect ( ) ;
198
- let data =
199
- json ! ( { "posts" : posts, "feed_updated" : time:: now_utc( ) . rfc3339( ) . to_string( ) } ) ;
166
+ fn render_feed ( & self , blog : & Blog ) -> Result < ( ) , Box < dyn Error > > {
167
+ let posts: Vec < _ > = blog. posts ( ) . iter ( ) . take ( 10 ) . collect ( ) ;
168
+ let data = json ! ( {
169
+ "blog" : blog,
170
+ "posts" : posts,
171
+ "feed_updated" : time:: now_utc( ) . rfc3339( ) . to_string( ) ,
172
+ } ) ;
200
173
201
- self . render_template ( "feed.xml" , "feed" , data) ?;
174
+ self . render_template ( blog . prefix ( ) . join ( "feed.xml" ) , "feed" , data) ?;
202
175
Ok ( ( ) )
203
176
}
204
177
205
- fn generate_releases_feed ( & self ) -> Result < ( ) , Box < dyn Error > > {
206
- let posts = self . posts . clone ( ) ;
178
+ fn render_releases_feed ( & self , blog : & Blog ) -> Result < ( ) , Box < dyn Error > > {
179
+ let posts = blog . posts ( ) . iter ( ) . cloned ( ) . collect :: < Vec < _ > > ( ) ;
207
180
let is_released: Vec < & Post > = posts. iter ( ) . filter ( |post| post. release ) . collect ( ) ;
208
181
let releases: Vec < ReleasePost > = is_released
209
182
. iter ( )
210
183
. map ( |post| ReleasePost {
211
184
title : post. title . clone ( ) ,
212
- url : post. url . clone ( ) ,
185
+ url : blog
186
+ . prefix ( )
187
+ . join ( post. url . clone ( ) )
188
+ . to_string_lossy ( )
189
+ . to_string ( ) ,
213
190
} )
214
191
. collect ( ) ;
215
192
let data = Releases {
216
193
releases : releases,
217
194
feed_updated : time:: now_utc ( ) . rfc3339 ( ) . to_string ( ) ,
218
195
} ;
219
196
fs:: write (
220
- self . out_directory . join ( "releases.json" ) ,
197
+ self . out_directory
198
+ . join ( blog. prefix ( ) )
199
+ . join ( "releases.json" ) ,
221
200
serde_json:: to_string ( & data) ?,
222
201
) ?;
223
202
Ok ( ( ) )
@@ -239,22 +218,19 @@ impl Blog {
239
218
240
219
fn render_template (
241
220
& self ,
242
- name : & str ,
221
+ name : impl AsRef < Path > ,
243
222
template : & str ,
244
223
data : serde_json:: Value ,
245
224
) -> Result < ( ) , Box < dyn Error > > {
246
- let out_file = self . out_directory . join ( name) ;
247
-
225
+ let out_file = self . out_directory . join ( name. as_ref ( ) ) ;
248
226
let file = File :: create ( out_file) ?;
249
-
250
227
self . handlebars . render_to_write ( template, & data, file) ?;
251
-
252
228
Ok ( ( ) )
253
229
}
254
230
}
255
231
256
232
fn main ( ) -> Result < ( ) , Box < dyn Error > > {
257
- let blog = Blog :: new ( "site" , "posts" ) ?;
233
+ let blog = Generator :: new ( "site" , "posts" ) ?;
258
234
259
235
blog. render ( ) ?;
260
236
0 commit comments