@@ -2,26 +2,59 @@ use std::fmt::{self, Display, Formatter};
2
2
use std:: path:: { Path , PathBuf } ;
3
3
use std:: collections:: VecDeque ;
4
4
use std:: fs:: File ;
5
- use std:: io:: Read ;
5
+ use std:: io:: { Read , Write } ;
6
6
7
7
use super :: summary:: { parse_summary, Link , SectionNumber , Summary , SummaryItem } ;
8
+ use config:: BuildConfig ;
8
9
use errors:: * ;
9
10
10
11
11
12
/// Load a book into memory from its `src/` directory.
12
- pub fn load_book < P : AsRef < Path > > ( src_dir : P ) -> Result < Book > {
13
+ pub fn load_book < P : AsRef < Path > > ( src_dir : P , cfg : & BuildConfig ) -> Result < Book > {
13
14
let src_dir = src_dir. as_ref ( ) ;
14
15
let summary_md = src_dir. join ( "SUMMARY.md" ) ;
15
16
16
17
let mut summary_content = String :: new ( ) ;
17
- File :: open ( summary_md) . chain_err ( || "Couldn't open SUMMARY.md" ) ?
18
- . read_to_string ( & mut summary_content) ?;
18
+ File :: open ( summary_md)
19
+ . chain_err ( || "Couldn't open SUMMARY.md" ) ?
20
+ . read_to_string ( & mut summary_content) ?;
19
21
20
22
let summary = parse_summary ( & summary_content) . chain_err ( || "Summary parsing failed" ) ?;
21
23
24
+ if cfg. create_missing {
25
+ create_missing ( & src_dir, & summary) . chain_err ( || "Unable to create missing chapters" ) ?;
26
+ }
27
+
22
28
load_book_from_disk ( & summary, src_dir)
23
29
}
24
30
31
+ fn create_missing ( src_dir : & Path , summary : & Summary ) -> Result < ( ) > {
32
+ let mut items: Vec < _ > = summary
33
+ . prefix_chapters
34
+ . iter ( )
35
+ . chain ( summary. numbered_chapters . iter ( ) )
36
+ . chain ( summary. suffix_chapters . iter ( ) )
37
+ . collect ( ) ;
38
+
39
+ while !items. is_empty ( ) {
40
+ let next = items. pop ( ) . expect ( "already checked" ) ;
41
+
42
+ if let SummaryItem :: Link ( ref link) = * next {
43
+ let filename = src_dir. join ( & link. location ) ;
44
+ if !filename. exists ( ) {
45
+ debug ! ( "[*] Creating missing file {}" , filename. display( ) ) ;
46
+
47
+ let mut f = File :: create ( & filename) ?;
48
+ writeln ! ( f, "# {}" , link. name) ?;
49
+ }
50
+
51
+ items. extend ( & link. nested_items ) ;
52
+ }
53
+ }
54
+
55
+ Ok ( ( ) )
56
+ }
57
+
25
58
26
59
/// A dumb tree structure representing a book.
27
60
///
@@ -124,22 +157,23 @@ fn load_chapter<P: AsRef<Path>>(link: &Link, src_dir: P) -> Result<Chapter> {
124
157
src_dir. join ( & link. location )
125
158
} ;
126
159
127
- let mut f = File :: open ( & location) . chain_err ( || {
128
- format ! ( "Chapter file not found, {}" , link. location. display( ) )
129
- } ) ?;
160
+ let mut f = File :: open ( & location)
161
+ . chain_err ( || format ! ( "Chapter file not found, {}" , link. location. display( ) ) ) ?;
130
162
131
163
let mut content = String :: new ( ) ;
132
164
f. read_to_string ( & mut content) ?;
133
165
134
- let stripped = location. strip_prefix ( & src_dir)
135
- . expect ( "Chapters are always inside a book" ) ;
166
+ let stripped = location
167
+ . strip_prefix ( & src_dir)
168
+ . expect ( "Chapters are always inside a book" ) ;
136
169
137
170
let mut ch = Chapter :: new ( & link. name , content, stripped) ;
138
171
ch. number = link. number . clone ( ) ;
139
172
140
- let sub_items = link. nested_items . iter ( )
141
- . map ( |i| load_summary_item ( i, src_dir) )
142
- . collect :: < Result < Vec < _ > > > ( ) ?;
173
+ let sub_items = link. nested_items
174
+ . iter ( )
175
+ . map ( |i| load_summary_item ( i, src_dir) )
176
+ . collect :: < Result < Vec < _ > > > ( ) ?;
143
177
144
178
ch. sub_items = sub_items;
145
179
@@ -206,9 +240,10 @@ And here is some \
206
240
let temp = TempDir :: new ( "book" ) . unwrap ( ) ;
207
241
208
242
let chapter_path = temp. path ( ) . join ( "chapter_1.md" ) ;
209
- File :: create ( & chapter_path) . unwrap ( )
210
- . write ( DUMMY_SRC . as_bytes ( ) )
211
- . unwrap ( ) ;
243
+ File :: create ( & chapter_path)
244
+ . unwrap ( )
245
+ . write ( DUMMY_SRC . as_bytes ( ) )
246
+ . unwrap ( ) ;
212
247
213
248
let link = Link :: new ( "Chapter 1" , chapter_path) ;
214
249
@@ -221,9 +256,10 @@ And here is some \
221
256
222
257
let second_path = temp_dir. path ( ) . join ( "second.md" ) ;
223
258
224
- File :: create ( & second_path) . unwrap ( )
225
- . write_all ( "Hello World!" . as_bytes ( ) )
226
- . unwrap ( ) ;
259
+ File :: create ( & second_path)
260
+ . unwrap ( )
261
+ . write_all ( "Hello World!" . as_bytes ( ) )
262
+ . unwrap ( ) ;
227
263
228
264
229
265
let mut second = Link :: new ( "Nested Chapter 1" , & second_path) ;
@@ -356,11 +392,12 @@ And here is some \
356
392
assert_eq ! ( got. len( ) , 5 ) ;
357
393
358
394
// checking the chapter names are in the order should be sufficient here...
359
- let chapter_names: Vec < String > = got. into_iter ( ) . filter_map ( |i| match * i {
360
- BookItem :: Chapter ( ref ch) => Some ( ch. name . clone ( ) ) ,
361
- _ => None ,
362
- } )
363
- . collect ( ) ;
395
+ let chapter_names: Vec < String > = got. into_iter ( )
396
+ . filter_map ( |i| match * i {
397
+ BookItem :: Chapter ( ref ch) => Some ( ch. name . clone ( ) ) ,
398
+ _ => None ,
399
+ } )
400
+ . collect ( ) ;
364
401
let should_be: Vec < _ > = vec ! [
365
402
String :: from( "Chapter 1" ) ,
366
403
String :: from( "Hello World" ) ,
0 commit comments