@@ -156,6 +156,7 @@ impl ToTokens for EmbedAsset {
156156struct EmbedAssets {
157157 assets_dir : AssetsDir ,
158158 validated_ignore_dirs : IgnoreDirs ,
159+ validated_ignore_files : IgnoreFiles ,
159160 should_compress : ShouldCompress ,
160161 should_strip_html_ext : ShouldStripHtmlExt ,
161162 cache_busted_paths : CacheBustedPaths ,
@@ -168,6 +169,7 @@ impl Parse for EmbedAssets {
168169 // Default to no compression
169170 let mut maybe_should_compress = None ;
170171 let mut maybe_ignore_dirs = None ;
172+ let mut maybe_ignore_files = None ;
171173 let mut maybe_should_strip_html_ext = None ;
172174 let mut maybe_cache_busted_paths = None ;
173175
@@ -185,6 +187,10 @@ impl Parse for EmbedAssets {
185187 let value = input. parse ( ) ?;
186188 maybe_ignore_dirs = Some ( value) ;
187189 }
190+ "ignore_files" => {
191+ let value = input. parse ( ) ?;
192+ maybe_ignore_files = Some ( value) ;
193+ }
188194 "strip_html_ext" => {
189195 let value = input. parse ( ) ?;
190196 maybe_should_strip_html_ext = Some ( value) ;
@@ -196,7 +202,7 @@ impl Parse for EmbedAssets {
196202 _ => {
197203 return Err ( syn:: Error :: new (
198204 key. span ( ) ,
199- "Unknown key in embed_assets! macro. Expected `compress`, `ignore_dirs`, `strip_html_ext`, or `cache_busted_paths`" ,
205+ "Unknown key in embed_assets! macro. Expected `compress`, `ignore_dirs`, `ignore_files`, ` strip_html_ext`, or `cache_busted_paths`" ,
200206 ) ) ;
201207 }
202208 }
@@ -219,6 +225,9 @@ impl Parse for EmbedAssets {
219225 let ignore_dirs_with_span = maybe_ignore_dirs. unwrap_or ( IgnoreDirsWithSpan ( vec ! [ ] ) ) ;
220226 let validated_ignore_dirs = validate_ignore_dirs ( ignore_dirs_with_span, & assets_dir. 0 ) ?;
221227
228+ let ignore_files_with_span = maybe_ignore_files. unwrap_or ( IgnoreFilesWithSpan ( vec ! [ ] ) ) ;
229+ let validated_ignore_files = validate_ignore_files ( ignore_files_with_span, & assets_dir. 0 ) ?;
230+
222231 let maybe_cache_busted_paths =
223232 maybe_cache_busted_paths. unwrap_or ( CacheBustedPathsWithSpan ( vec ! [ ] ) ) ;
224233 let cache_busted_paths =
@@ -227,6 +236,7 @@ impl Parse for EmbedAssets {
227236 Ok ( Self {
228237 assets_dir,
229238 validated_ignore_dirs,
239+ validated_ignore_files,
230240 should_compress,
231241 should_strip_html_ext,
232242 cache_busted_paths,
@@ -238,13 +248,15 @@ impl ToTokens for EmbedAssets {
238248 fn to_tokens ( & self , tokens : & mut TokenStream ) {
239249 let AssetsDir ( assets_dir) = & self . assets_dir ;
240250 let ignore_dirs = & self . validated_ignore_dirs ;
251+ let ignore_files = & self . validated_ignore_files ;
241252 let ShouldCompress ( should_compress) = & self . should_compress ;
242253 let ShouldStripHtmlExt ( should_strip_html_ext) = & self . should_strip_html_ext ;
243254 let cache_busted_paths = & self . cache_busted_paths ;
244255
245256 let result = generate_static_routes (
246257 assets_dir,
247258 ignore_dirs,
259+ ignore_files,
248260 should_compress,
249261 should_strip_html_ext,
250262 cache_busted_paths,
@@ -306,6 +318,10 @@ struct IgnoreDirs(Vec<PathBuf>);
306318
307319struct IgnoreDirsWithSpan ( Vec < ( PathBuf , Span ) > ) ;
308320
321+ struct IgnoreFiles ( Vec < PathBuf > ) ;
322+
323+ struct IgnoreFilesWithSpan ( Vec < ( PathBuf , Span ) > ) ;
324+
309325impl Parse for IgnoreDirsWithSpan {
310326 fn parse ( input : ParseStream ) -> syn:: Result < Self > {
311327 let dirs = parse_dirs ( input) ?;
@@ -314,6 +330,14 @@ impl Parse for IgnoreDirsWithSpan {
314330 }
315331}
316332
333+ impl Parse for IgnoreFilesWithSpan {
334+ fn parse ( input : ParseStream ) -> syn:: Result < Self > {
335+ let files = parse_dirs ( input) ?; // reuse parse_dirs since it's just parsing paths
336+
337+ Ok ( IgnoreFilesWithSpan ( files) )
338+ }
339+ }
340+
317341fn validate_ignore_dirs (
318342 ignore_dirs : IgnoreDirsWithSpan ,
319343 assets_dir : & LitStr ,
@@ -350,6 +374,42 @@ fn validate_ignore_dirs(
350374 Ok ( IgnoreDirs ( valid_ignore_dirs) )
351375}
352376
377+ fn validate_ignore_files (
378+ ignore_files : IgnoreFilesWithSpan ,
379+ assets_dir : & LitStr ,
380+ ) -> syn:: Result < IgnoreFiles > {
381+ let mut valid_ignore_files = Vec :: new ( ) ;
382+ for ( file, span) in ignore_files. 0 {
383+ let full_path = PathBuf :: from ( assets_dir. value ( ) ) . join ( & file) ;
384+ match fs:: metadata ( & full_path) {
385+ Ok ( meta) if meta. is_dir ( ) => {
386+ return Err ( syn:: Error :: new (
387+ span,
388+ "The specified ignored file is a directory. Use ignore_dirs instead." ,
389+ ) ) ;
390+ }
391+ Ok ( _) => valid_ignore_files. push ( full_path) ,
392+ Err ( e) if matches ! ( e. kind( ) , std:: io:: ErrorKind :: NotFound ) => {
393+ return Err ( syn:: Error :: new (
394+ span,
395+ "The specified ignored file does not exist" ,
396+ ) )
397+ }
398+ Err ( e) => {
399+ return Err ( syn:: Error :: new (
400+ span,
401+ format ! (
402+ "Error reading ignored file {}: {}" ,
403+ file. to_string_lossy( ) ,
404+ DisplayFullError ( & e)
405+ ) ,
406+ ) )
407+ }
408+ }
409+ }
410+ Ok ( IgnoreFiles ( valid_ignore_files) )
411+ }
412+
353413struct ShouldCompress ( LitBool ) ;
354414
355415impl Parse for ShouldCompress {
@@ -453,6 +513,7 @@ fn parse_dirs(input: ParseStream) -> syn::Result<Vec<(PathBuf, Span)>> {
453513fn generate_static_routes (
454514 assets_dir : & LitStr ,
455515 ignore_dirs : & IgnoreDirs ,
516+ ignore_files : & IgnoreFiles ,
456517 should_compress : & LitBool ,
457518 should_strip_html_ext : & LitBool ,
458519 cache_busted_paths : & CacheBustedPaths ,
@@ -468,6 +529,11 @@ fn generate_static_routes(
468529 . iter ( )
469530 . map ( |d| d. canonicalize ( ) . map_err ( Error :: CannotCanonicalizeIgnoreDir ) )
470531 . collect :: < Result < Vec < _ > , _ > > ( ) ?;
532+ let canon_ignore_files = ignore_files
533+ . 0
534+ . iter ( )
535+ . map ( |f| f. canonicalize ( ) . map_err ( Error :: CannotCanonicalizeFile ) )
536+ . collect :: < Result < Vec < _ > , _ > > ( ) ?;
471537 let canon_cache_busted_dirs = cache_busted_paths
472538 . dirs
473539 . iter ( )
@@ -498,6 +564,11 @@ fn generate_static_routes(
498564 continue ;
499565 }
500566
567+ // Skip `entry`s which are explicitly ignored files
568+ if canon_ignore_files. contains ( & entry) {
569+ continue ;
570+ }
571+
501572 let mut is_entry_cache_busted = false ;
502573 if canon_cache_busted_dirs
503574 . iter ( )
0 commit comments