1
- use crate :: assets:: { AssetFiles , compile_assets} ;
2
- use crate :: fs:: ensure_directory;
3
- use crate :: i18n:: { EXPLICIT_LOCALE_INFO , LocaleInfo , SUPPORTED_LOCALES , TeamHelper , create_loader} ;
4
- use crate :: rust_version:: { RustVersion , fetch_rust_version} ;
5
- use crate :: teams:: { PageData , RustTeams , encode_zulip_stream, load_rust_teams} ;
1
+ use crate :: assets:: compile_assets;
2
+ use crate :: i18n:: { TeamHelper , create_loader} ;
3
+ use crate :: redirect:: create_redirects;
4
+ use crate :: render:: { RenderCtx , render_directory, render_governance, render_index} ;
5
+ use crate :: rust_version:: RustVersion ;
6
+ use crate :: teams:: { encode_zulip_stream, load_rust_teams} ;
6
7
use anyhow:: Context ;
7
8
use handlebars:: { DirectorySourceOptions , Handlebars } ;
8
- use handlebars_fluent:: { FluentHelper , Loader , SimpleLoader } ;
9
- use serde:: Serialize ;
10
- use std:: ffi:: OsStr ;
11
- use std:: fs:: File ;
12
- use std:: io:: BufWriter ;
9
+ use handlebars_fluent:: FluentHelper ;
13
10
use std:: path:: { Path , PathBuf } ;
14
11
15
12
mod assets;
16
13
mod fs;
17
14
mod i18n;
15
+ mod redirect;
16
+ mod render;
18
17
mod rust_version;
19
18
mod teams;
20
19
@@ -33,155 +32,6 @@ fn baseurl(lang: &str) -> String {
33
32
}
34
33
}
35
34
36
- #[ derive( Serialize ) ]
37
- struct TemplateCtx < ' a , T : Serialize > {
38
- page : String ,
39
- title : String ,
40
- parent : & ' static str ,
41
- is_landing : bool ,
42
- data : & ' a T ,
43
- lang : String ,
44
- baseurl : String ,
45
- pontoon_enabled : bool ,
46
- assets : & ' a AssetFiles ,
47
- locales : & ' static [ LocaleInfo ] ,
48
- is_translation : bool ,
49
- }
50
-
51
- struct PageCtx < ' a , T : Serialize > {
52
- template_ctx : TemplateCtx < ' a , T > ,
53
- output_dir : & ' a Path ,
54
- handlebars : & ' a Handlebars < ' a > ,
55
- }
56
-
57
- impl < ' a , T : Serialize > PageCtx < ' a , T > {
58
- fn make_landing ( mut self ) -> Self {
59
- self . template_ctx . is_landing = true ;
60
- self
61
- }
62
-
63
- fn render < P : AsRef < Path > > ( self , dst_path : P ) -> anyhow:: Result < ( ) > {
64
- let path = dst_path. as_ref ( ) ;
65
- let template = & self . template_ctx . page ;
66
-
67
- let out_path = self . output_dir . join ( path) ;
68
- ensure_directory ( & out_path) ?;
69
- let mut output_file = BufWriter :: new (
70
- File :: create ( & out_path)
71
- . with_context ( || anyhow:: anyhow!( "Cannot create file at {}" , path. display( ) ) ) ?,
72
- ) ;
73
- eprintln ! ( "Rendering `{template}` into {}" , out_path. display( ) ) ;
74
-
75
- self . handlebars
76
- . render_to_write ( template, & self . template_ctx , & mut output_file)
77
- . with_context ( || {
78
- anyhow:: anyhow!(
79
- "cannot render template {template} into {}" ,
80
- out_path. display( )
81
- )
82
- } ) ?;
83
- Ok ( ( ) )
84
- }
85
- }
86
-
87
- struct RenderCtx < ' a > {
88
- handlebars : Handlebars < ' a > ,
89
- template_dir : PathBuf ,
90
- fluent_loader : SimpleLoader ,
91
- output_dir : PathBuf ,
92
- rust_version : RustVersion ,
93
- teams : RustTeams ,
94
- assets : AssetFiles ,
95
- }
96
-
97
- impl < ' a > RenderCtx < ' a > {
98
- fn page < T : Serialize > (
99
- & ' a self ,
100
- page : & str ,
101
- title_id : & str ,
102
- data : & ' a T ,
103
- lang : & str ,
104
- ) -> PageCtx < ' a , T > {
105
- let title = if title_id. is_empty ( ) {
106
- "" . into ( )
107
- } else {
108
- let lang = lang. parse ( ) . expect ( "lang should be valid" ) ;
109
- self . fluent_loader . lookup ( & lang, title_id, None )
110
- } ;
111
- PageCtx {
112
- template_ctx : TemplateCtx {
113
- page : page. to_string ( ) ,
114
- title,
115
- parent : LAYOUT ,
116
- is_landing : false ,
117
- data,
118
- baseurl : baseurl ( & lang) ,
119
- is_translation : lang != "en-US" ,
120
- lang : lang. to_string ( ) ,
121
- pontoon_enabled : PONTOON_ENABLED ,
122
- assets : & self . assets ,
123
- locales : EXPLICIT_LOCALE_INFO ,
124
- } ,
125
- output_dir : & self . output_dir ,
126
- handlebars : & self . handlebars ,
127
- }
128
- }
129
-
130
- fn copy_asset_dir < P : AsRef < Path > > ( & self , src_dir : P , dst_dir : P ) -> anyhow:: Result < ( ) > {
131
- let dst = self . output_dir . join ( dst_dir. as_ref ( ) ) ;
132
- println ! (
133
- "Copying static asset directory from {} to {}" ,
134
- src_dir. as_ref( ) . display( ) ,
135
- dst. display( )
136
- ) ;
137
- copy_dir_all ( src_dir. as_ref ( ) , dst) ?;
138
- Ok ( ( ) )
139
- }
140
-
141
- fn copy_asset_file < P : AsRef < Path > > ( & self , src : P , dst : P ) -> anyhow:: Result < ( ) > {
142
- let dst = self . output_dir . join ( dst. as_ref ( ) ) ;
143
- println ! (
144
- "Copying static asset file from {} to {}" ,
145
- src. as_ref( ) . display( ) ,
146
- dst. display( )
147
- ) ;
148
- ensure_directory ( & dst) ?;
149
- std:: fs:: copy ( src. as_ref ( ) , dst) ?;
150
- Ok ( ( ) )
151
- }
152
- }
153
-
154
- /// Calls `func` for all supported languages.
155
- /// Passes it the destination path into which should a given page be rendered, and the language
156
- /// in which it should be rendered.
157
- fn all_langs < F > ( dst_path : & str , func : F ) -> anyhow:: Result < ( ) >
158
- where
159
- F : Fn ( & str , & str ) -> anyhow:: Result < ( ) > ,
160
- {
161
- for lang in SUPPORTED_LOCALES . iter ( ) {
162
- let path = match lang {
163
- l if * l == ENGLISH => dst_path. to_string ( ) ,
164
- l => format ! ( "{l}/{dst_path}" ) ,
165
- } ;
166
- func ( & path, lang) . with_context ( || anyhow:: anyhow!( "could not handle language {lang}" ) ) ?;
167
- }
168
- Ok ( ( ) )
169
- }
170
-
171
- fn copy_dir_all ( src : impl AsRef < Path > , dst : impl AsRef < Path > ) -> std:: io:: Result < ( ) > {
172
- std:: fs:: create_dir_all ( & dst) ?;
173
- for entry in std:: fs:: read_dir ( src) ? {
174
- let entry = entry?;
175
- let ty = entry. file_type ( ) ?;
176
- if ty. is_dir ( ) {
177
- copy_dir_all ( entry. path ( ) , dst. as_ref ( ) . join ( entry. file_name ( ) ) ) ?;
178
- } else {
179
- std:: fs:: copy ( entry. path ( ) , dst. as_ref ( ) . join ( entry. file_name ( ) ) ) ?;
180
- }
181
- }
182
- Ok ( ( ) )
183
- }
184
-
185
35
fn setup_handlebars ( ) -> anyhow:: Result < Handlebars < ' static > > {
186
36
let mut handlebars: Handlebars < ' static > = Handlebars :: new ( ) ;
187
37
handlebars. set_strict_mode ( true ) ;
@@ -237,107 +87,7 @@ async fn main() -> anyhow::Result<()> {
237
87
render_directory ( & ctx, "tools" ) ?;
238
88
render_directory ( & ctx, "what" ) ?;
239
89
ctx. page ( "404" , "" , & ( ) , ENGLISH ) . render ( "404.html" ) ?;
90
+ create_redirects ( & ctx) ?;
240
91
241
- // TODO: redirects
242
-
243
- Ok ( ( ) )
244
- }
245
-
246
- fn render_index ( render_ctx : & RenderCtx ) -> anyhow:: Result < ( ) > {
247
- #[ derive( Serialize ) ]
248
- struct IndexData {
249
- rust_version : String ,
250
- }
251
- let data = IndexData {
252
- rust_version : render_ctx. rust_version . 0 . clone ( ) ,
253
- } ;
254
- all_langs ( "index.html" , |path, lang| {
255
- render_ctx
256
- . page ( "index" , "" , & data, lang)
257
- . make_landing ( )
258
- . render ( path)
259
- } )
260
- }
261
-
262
- fn render_governance ( render_ctx : & RenderCtx ) -> anyhow:: Result < ( ) > {
263
- let data = render_ctx. teams . index_data ( ) ;
264
-
265
- all_langs ( "governance/index.html" , |dst_path, lang| {
266
- render_ctx
267
- . page ( "governance/index" , "governance-page-title" , & data, lang)
268
- . render ( dst_path)
269
- } ) ?;
270
- for team in data. teams {
271
- let data: PageData = render_ctx
272
- . teams
273
- . page_data ( team. section , & team. page_name )
274
- . unwrap_or_else ( |error| panic ! ( "Page data for team {team:?} not found: {error:?}" ) ) ;
275
-
276
- // We need to render into index.html to have an extensionless URL
277
- all_langs (
278
- & format ! ( "governance/{}/index.html" , team. url) ,
279
- |dst_path, lang| {
280
- render_ctx
281
- . page (
282
- "governance/group" ,
283
- & format ! ( "governance-team-{}-title" , team. team. name) ,
284
- & data,
285
- lang,
286
- )
287
- . render ( dst_path)
288
- } ,
289
- ) ?;
290
- }
291
-
292
- Ok ( ( ) )
293
- }
294
-
295
- /// Render all templates found in the given directory.
296
- fn render_directory ( render_ctx : & RenderCtx , category : & str ) -> anyhow:: Result < ( ) > {
297
- for dir in std:: fs:: read_dir ( render_ctx. template_dir . join ( category) ) ? {
298
- let path = dir?. path ( ) ;
299
- if path. is_file ( ) && path. extension ( ) == Some ( OsStr :: new ( "hbs" ) ) {
300
- // foo.html.hbs => foo
301
- let subject = path
302
- . file_stem ( )
303
- . unwrap ( )
304
- . to_str ( )
305
- . unwrap ( )
306
- . split ( "." )
307
- . next ( )
308
- . unwrap ( ) ;
309
-
310
- // The "root" page of a category
311
- if subject == "index" {
312
- all_langs ( & format ! ( "{category}/index.html" ) , |dst_path, lang| {
313
- render_ctx
314
- . page (
315
- & format ! ( "{category}/index" ) ,
316
- & format ! ( "{category}-page-title" ) ,
317
- & ( ) ,
318
- lang,
319
- )
320
- . render ( dst_path)
321
- } ) ?;
322
- } else {
323
- // A subpage (subject) of the category
324
- // We need to render the page into a subdirectory, so that /foo/bar works without
325
- // needing a HTML suffix.
326
- all_langs (
327
- & format ! ( "{category}/{subject}/index.html" ) ,
328
- |dst_path, lang| {
329
- render_ctx
330
- . page (
331
- & format ! ( "{category}/{subject}" ) ,
332
- & format ! ( "{category}-{subject}-page-title" ) ,
333
- & ( ) ,
334
- lang,
335
- )
336
- . render ( dst_path)
337
- } ,
338
- ) ?;
339
- }
340
- }
341
- }
342
92
Ok ( ( ) )
343
93
}
0 commit comments