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} ;
67use anyhow:: Context ;
78use 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 ;
1310use std:: path:: { Path , PathBuf } ;
1411
1512mod assets;
1613mod fs;
1714mod i18n;
15+ mod redirect;
16+ mod render;
1817mod rust_version;
1918mod teams;
2019
@@ -33,155 +32,6 @@ fn baseurl(lang: &str) -> String {
3332 }
3433}
3534
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-
18535fn setup_handlebars ( ) -> anyhow:: Result < Handlebars < ' static > > {
18636 let mut handlebars: Handlebars < ' static > = Handlebars :: new ( ) ;
18737 handlebars. set_strict_mode ( true ) ;
@@ -237,107 +87,7 @@ async fn main() -> anyhow::Result<()> {
23787 render_directory ( & ctx, "tools" ) ?;
23888 render_directory ( & ctx, "what" ) ?;
23989 ctx. page ( "404" , "" , & ( ) , ENGLISH ) . render ( "404.html" ) ?;
90+ create_redirects ( & ctx) ?;
24091
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- }
34292 Ok ( ( ) )
34393}
0 commit comments