@@ -14,6 +14,7 @@ use std::{
1414
1515use aho_corasick:: AhoCorasick ;
1616use anyhow:: { anyhow, Context as _} ;
17+ use ignore:: gitignore:: { Gitignore , GitignoreBuilder } ;
1718use log:: log;
1819use mdbook:: {
1920 book:: { BookItems , Chapter } ,
@@ -23,9 +24,9 @@ use normpath::PathExt;
2324use once_cell:: sync:: Lazy ;
2425use pulldown_cmark:: { CodeBlockKind , CowStr , HeadingLevel , LinkType } ;
2526use regex:: Regex ;
26- use walkdir:: WalkDir ;
2727
2828use crate :: {
29+ book:: Book ,
2930 latex,
3031 pandoc:: { self , OutputFormat , RenderContext } ,
3132} ;
@@ -97,19 +98,8 @@ impl<'book> Preprocessor<'book> {
9798 }
9899 fs:: create_dir_all ( & preprocessed) ?;
99100
100- for entry in WalkDir :: new ( & ctx. book . source_dir ) . follow_links ( true ) {
101- let entry = entry?;
102- let src = entry. path ( ) ;
103- let dest = preprocessed. join ( src. strip_prefix ( & ctx. book . source_dir ) . unwrap ( ) ) ;
104- if entry. file_type ( ) . is_dir ( ) {
105- fs:: create_dir_all ( & dest)
106- . with_context ( || format ! ( "Unable to create directory '{}'" , dest. display( ) ) ) ?
107- } else {
108- fs:: copy ( src, & dest) . with_context ( || {
109- format ! ( "Unable to copy '{}' -> '{}'" , src. display( ) , dest. display( ) )
110- } ) ?;
111- }
112- }
101+ let ignore = build_ignore ( & ctx. book ) ?;
102+ copy_recursive ( & ctx. book . source_dir , & preprocessed, & ignore) ?;
113103
114104 let mut chapters = HashMap :: new ( ) ;
115105 for section in ctx. book . book . iter ( ) {
@@ -1275,6 +1265,71 @@ impl fmt::Debug for IndexedChapter<'_> {
12751265 }
12761266}
12771267
1268+ fn copy_recursive ( src : & Path , dst : & Path , ignore : & Gitignore ) -> anyhow:: Result < ( ) > {
1269+ for e in src
1270+ . read_dir ( )
1271+ . with_context ( || format ! ( "Unable to read directory {src:#?}" ) ) ?
1272+ {
1273+ let cur = e?. path ( ) ;
1274+
1275+ if ignore. matched ( & cur, cur. is_dir ( ) ) . is_ignore ( ) {
1276+ continue ;
1277+ }
1278+
1279+ if cur. is_dir ( ) {
1280+ let dir = dst. join ( cur. strip_prefix ( & src) . unwrap ( ) ) ;
1281+
1282+ fs:: create_dir_all ( & dir)
1283+ . with_context ( || format ! ( "Unable to create directory {dir:#?}" ) ) ?;
1284+
1285+ copy_recursive ( & cur, & dir, ignore) ?;
1286+ } else {
1287+ let dst = dst. join ( cur. strip_prefix ( & src) . unwrap ( ) ) ;
1288+
1289+ fs:: copy ( cur, & dst) . with_context ( || {
1290+ format ! ( "Unable to copy '{}' -> '{}'" , src. display( ) , dst. display( ) )
1291+ } ) ?;
1292+ }
1293+ }
1294+
1295+ Ok ( ( ) )
1296+ }
1297+
1298+ fn build_ignore ( book : & Book ) -> anyhow:: Result < Gitignore > {
1299+ let root = book. root . canonicalize ( ) ?;
1300+ let mut src = book. source_dir . canonicalize ( ) ?;
1301+
1302+ let mut builder = GitignoreBuilder :: new ( & src) ;
1303+
1304+ let mdbook_ignore = src. join ( ".mdbookignore" ) ;
1305+ if mdbook_ignore. exists ( ) {
1306+ if let Some ( err) = builder. add ( mdbook_ignore) {
1307+ log:: warn!( "Unable to load '.mdbookignore' file: {}" , err) ;
1308+ }
1309+ }
1310+
1311+ loop {
1312+ let git_ignore = src. join ( ".gitignore" ) ;
1313+ if git_ignore. exists ( ) {
1314+ if let Some ( err) = builder. add ( git_ignore) {
1315+ log:: warn!( "Unable to load '.gitignore' file: {}" , err) ;
1316+ }
1317+ }
1318+
1319+ if src == root {
1320+ break ;
1321+ }
1322+
1323+ let Some ( parent) = src. parent ( ) else {
1324+ break ;
1325+ } ;
1326+
1327+ src = parent. canonicalize ( ) ?;
1328+ }
1329+
1330+ Ok ( builder. build ( ) ?)
1331+ }
1332+
12781333#[ cfg( test) ]
12791334mod tests {
12801335 use super :: Preprocessor ;
0 commit comments