@@ -2,14 +2,19 @@ use crate::db::Pool;
2
2
use crate :: error:: Result ;
3
3
use arc_swap:: ArcSwap ;
4
4
use chrono:: { DateTime , Utc } ;
5
+ use failure:: ResultExt ;
5
6
use notify:: { watcher, RecursiveMode , Watcher } ;
6
7
use postgres:: Connection ;
7
8
use serde_json:: Value ;
8
9
use std:: collections:: HashMap ;
10
+ use std:: path:: PathBuf ;
9
11
use std:: sync:: { mpsc:: channel, Arc } ;
10
12
use std:: thread;
11
13
use std:: time:: Duration ;
12
14
use tera:: { Result as TeraResult , Tera } ;
15
+ use walkdir:: WalkDir ;
16
+
17
+ const TEMPLATES_DIRECTORY : & str = "tera-templates" ;
13
18
14
19
/// Holds all data relevant to templating
15
20
#[ derive( Debug ) ]
@@ -84,7 +89,16 @@ fn load_rustc_resource_suffix(conn: &Connection) -> Result<String> {
84
89
}
85
90
86
91
pub ( super ) fn load_templates ( conn : & Connection ) -> Result < Tera > {
87
- let mut tera = Tera :: new ( "tera-templates/**/*" ) ?;
92
+ // This uses a custom function to find the templates in the filesystem instead of Tera's
93
+ // builtin way (passing a glob expression to Tera::new), speeding up the startup of the
94
+ // application and running the tests.
95
+ //
96
+ // The problem with Tera's template loading code is, it walks all the files in the current
97
+ // directory and matches them against the provided glob expression. Unfortunately this means
98
+ // Tera will walk all the rustwide workspaces, the git repository and a bunch of other
99
+ // unrelated data, slowing down the search a lot.
100
+ let mut tera = Tera :: default ( ) ;
101
+ tera. add_template_files ( find_templates_in_filesystem ( TEMPLATES_DIRECTORY ) ?) ?;
88
102
89
103
// This function will return any global alert, if present.
90
104
ReturnValue :: add_function_to (
@@ -120,6 +134,32 @@ pub(super) fn load_templates(conn: &Connection) -> Result<Tera> {
120
134
Ok ( tera)
121
135
}
122
136
137
+ fn find_templates_in_filesystem ( base : & str ) -> Result < Vec < ( PathBuf , Option < String > ) > > {
138
+ let root = std:: fs:: canonicalize ( base) ?;
139
+
140
+ let mut files = Vec :: new ( ) ;
141
+ for entry in WalkDir :: new ( & root) {
142
+ let entry = entry?;
143
+ let path = entry. path ( ) ;
144
+
145
+ if !entry. metadata ( ) ?. is_file ( ) {
146
+ continue ;
147
+ }
148
+
149
+ // Strip the root directory from the path and use it as the template name.
150
+ let name = path
151
+ . strip_prefix ( & root)
152
+ . with_context ( |_| format ! ( "{} is not a child of {}" , path. display( ) , root. display( ) ) ) ?
153
+ . to_str ( )
154
+ . ok_or_else ( || failure:: format_err!( "path {} is not UTF-8" , path. display( ) ) ) ?
155
+ . to_string ( ) ;
156
+
157
+ files. push ( ( path. to_path_buf ( ) , Some ( name) ) ) ;
158
+ }
159
+
160
+ Ok ( files)
161
+ }
162
+
123
163
/// Simple function that returns the pre-defined value.
124
164
struct ReturnValue {
125
165
name : & ' static str ,
0 commit comments