1
- use serde_json;
1
+ extern crate toml;
2
+
3
+ use std:: process:: exit;
2
4
use std:: fs:: File ;
3
5
use std:: io:: Read ;
4
6
use std:: path:: { Path , PathBuf } ;
7
+ use std:: collections:: BTreeMap ;
8
+ use std:: str:: FromStr ;
9
+ use serde_json;
5
10
6
11
#[ derive( Debug , Clone ) ]
7
12
pub struct BookConfig {
@@ -18,7 +23,6 @@ pub struct BookConfig {
18
23
multilingual : bool ,
19
24
}
20
25
21
-
22
26
impl BookConfig {
23
27
pub fn new ( root : & Path ) -> Self {
24
28
BookConfig {
@@ -40,71 +44,117 @@ impl BookConfig {
40
44
41
45
debug ! ( "[fn]: read_config" ) ;
42
46
43
- // If the file does not exist, return early
44
- let mut config_file = match File :: open ( root. join ( "book.json" ) ) {
45
- Ok ( f) => f,
46
- Err ( _) => {
47
- debug ! ( "[*]: Failed to open {:?}" , root. join( "book.json" ) ) ;
48
- return self ;
49
- } ,
47
+ let read_file = |path : PathBuf | -> String {
48
+ let mut data = String :: new ( ) ;
49
+ let mut f: File = match File :: open ( & path) {
50
+ Ok ( x) => x,
51
+ Err ( _) => {
52
+ error ! ( "[*]: Failed to open {:?}" , & path) ;
53
+ exit ( 2 ) ;
54
+ }
55
+ } ;
56
+ if let Err ( _) = f. read_to_string ( & mut data) {
57
+ error ! ( "[*]: Failed to read {:?}" , & path) ;
58
+ exit ( 2 ) ;
59
+ }
60
+ data
50
61
} ;
51
62
52
- debug ! ( "[*]: Reading config" ) ;
53
- let mut data = String :: new ( ) ;
63
+ // Read book.toml or book.json if exists
54
64
55
- // Just return if an error occured.
56
- // I would like to propagate the error, but I have to return `&self`
57
- if let Err ( _) = config_file. read_to_string ( & mut data) {
58
- return self ;
65
+ if Path :: new ( root. join ( "book.toml" ) . as_os_str ( ) ) . exists ( ) {
66
+
67
+ debug ! ( "[*]: Reading config" ) ;
68
+ let data = read_file ( root. join ( "book.toml" ) ) ;
69
+ self . parse_from_toml_string ( & data) ;
70
+
71
+ } else if Path :: new ( root. join ( "book.json" ) . as_os_str ( ) ) . exists ( ) {
72
+
73
+ debug ! ( "[*]: Reading config" ) ;
74
+ let data = read_file ( root. join ( "book.json" ) ) ;
75
+ self . parse_from_json_string ( & data) ;
76
+
77
+ } else {
78
+ debug ! ( "[*]: No book.toml or book.json was found, using defaults." ) ;
59
79
}
60
80
61
- // Convert to JSON
62
- if let Ok ( config) = serde_json:: from_str :: < serde_json:: Value > ( & data) {
63
- // Extract data
81
+ self
82
+ }
64
83
65
- let config = config . as_object ( ) . unwrap ( ) ;
84
+ pub fn parse_from_toml_string ( & mut self , data : & String ) -> & mut Self {
66
85
67
- debug ! ( "[*]: Extracting data from config" ) ;
68
- // Title, author, description
69
- if let Some ( a) = config. get ( "title" ) {
70
- self . title = a. to_string ( ) . replace ( "\" " , "" )
71
- }
72
- if let Some ( a) = config. get ( "author" ) {
73
- self . author = a. to_string ( ) . replace ( "\" " , "" )
74
- }
75
- if let Some ( a) = config. get ( "description" ) {
76
- self . description = a. to_string ( ) . replace ( "\" " , "" )
86
+ let mut parser = toml:: Parser :: new ( & data) ;
87
+
88
+ let config = match parser. parse ( ) {
89
+ Some ( x) => { x} ,
90
+ None => {
91
+ error ! ( "[*]: Toml parse errors in book.toml: {:?}" , parser. errors) ;
92
+ exit ( 2 ) ;
77
93
}
94
+ } ;
78
95
79
- // Destination folder
80
- if let Some ( a) = config. get ( "dest" ) {
81
- let mut dest = PathBuf :: from ( & a. to_string ( ) . replace ( "\" " , "" ) ) ;
96
+ self . parse_from_btreemap ( & config) ;
82
97
83
- // If path is relative make it absolute from the parent directory of src
84
- if dest. is_relative ( ) {
85
- dest = self . get_root ( ) . join ( & dest) ;
86
- }
87
- self . set_dest ( & dest) ;
98
+ self
99
+ }
100
+
101
+ /// Parses the string to JSON and converts it to BTreeMap<String, toml::Value>.
102
+ pub fn parse_from_json_string ( & mut self , data : & String ) -> & mut Self {
103
+
104
+ let c: serde_json:: Value = match serde_json:: from_str ( & data) {
105
+ Ok ( x) => x,
106
+ Err ( e) => {
107
+ error ! ( "[*]: JSON parse errors in book.json: {:?}" , e) ;
108
+ exit ( 2 ) ;
88
109
}
110
+ } ;
89
111
90
- // Source folder
91
- if let Some ( a) = config. get ( "src" ) {
92
- let mut src = PathBuf :: from ( & a. to_string ( ) . replace ( "\" " , "" ) ) ;
93
- if src. is_relative ( ) {
94
- src = self . get_root ( ) . join ( & src) ;
95
- }
96
- self . set_src ( & src) ;
112
+ let config = json_object_to_btreemap ( & c. as_object ( ) . unwrap ( ) ) ;
113
+ self . parse_from_btreemap ( & config) ;
114
+
115
+ self
116
+ }
117
+
118
+ pub fn parse_from_btreemap ( & mut self , config : & BTreeMap < String , toml:: Value > ) -> & mut Self {
119
+
120
+ // Title, author, description
121
+ if let Some ( a) = config. get ( "title" ) {
122
+ self . title = a. to_string ( ) . replace ( "\" " , "" ) ;
123
+ }
124
+ if let Some ( a) = config. get ( "author" ) {
125
+ self . author = a. to_string ( ) . replace ( "\" " , "" ) ;
126
+ }
127
+ if let Some ( a) = config. get ( "description" ) {
128
+ self . description = a. to_string ( ) . replace ( "\" " , "" ) ;
129
+ }
130
+
131
+ // Destination folder
132
+ if let Some ( a) = config. get ( "dest" ) {
133
+ let mut dest = PathBuf :: from ( & a. to_string ( ) . replace ( "\" " , "" ) ) ;
134
+
135
+ // If path is relative make it absolute from the parent directory of src
136
+ if dest. is_relative ( ) {
137
+ dest = self . get_root ( ) . join ( & dest) ;
97
138
}
139
+ self . set_dest ( & dest) ;
140
+ }
98
141
99
- // Theme path folder
100
- if let Some ( a) = config. get ( "theme_path" ) {
101
- let mut theme_path = PathBuf :: from ( & a. to_string ( ) . replace ( "\" " , "" ) ) ;
102
- if theme_path. is_relative ( ) {
103
- theme_path = self . get_root ( ) . join ( & theme_path) ;
104
- }
105
- self . set_theme_path ( & theme_path) ;
142
+ // Source folder
143
+ if let Some ( a) = config. get ( "src" ) {
144
+ let mut src = PathBuf :: from ( & a. to_string ( ) . replace ( "\" " , "" ) ) ;
145
+ if src. is_relative ( ) {
146
+ src = self . get_root ( ) . join ( & src) ;
106
147
}
148
+ self . set_src ( & src) ;
149
+ }
107
150
151
+ // Theme path folder
152
+ if let Some ( a) = config. get ( "theme_path" ) {
153
+ let mut theme_path = PathBuf :: from ( & a. to_string ( ) . replace ( "\" " , "" ) ) ;
154
+ if theme_path. is_relative ( ) {
155
+ theme_path = self . get_root ( ) . join ( & theme_path) ;
156
+ }
157
+ self . set_theme_path ( & theme_path) ;
108
158
}
109
159
110
160
self
@@ -146,3 +196,33 @@ impl BookConfig {
146
196
self
147
197
}
148
198
}
199
+
200
+ pub fn json_object_to_btreemap ( json : & serde_json:: Map < String , serde_json:: Value > ) -> BTreeMap < String , toml:: Value > {
201
+ let mut config: BTreeMap < String , toml:: Value > = BTreeMap :: new ( ) ;
202
+
203
+ for ( key, value) in json. iter ( ) {
204
+ config. insert (
205
+ String :: from_str ( key) . unwrap ( ) ,
206
+ json_value_to_toml_value ( value. to_owned ( ) )
207
+ ) ;
208
+ }
209
+
210
+ config
211
+ }
212
+
213
+ pub fn json_value_to_toml_value ( json : serde_json:: Value ) -> toml:: Value {
214
+ match json {
215
+ serde_json:: Value :: Null => toml:: Value :: String ( "" . to_string ( ) ) ,
216
+ serde_json:: Value :: Bool ( x) => toml:: Value :: Boolean ( x) ,
217
+ serde_json:: Value :: I64 ( x) => toml:: Value :: Integer ( x) ,
218
+ serde_json:: Value :: U64 ( x) => toml:: Value :: Integer ( x as i64 ) ,
219
+ serde_json:: Value :: F64 ( x) => toml:: Value :: Float ( x) ,
220
+ serde_json:: Value :: String ( x) => toml:: Value :: String ( x) ,
221
+ serde_json:: Value :: Array ( x) => {
222
+ toml:: Value :: Array ( x. iter ( ) . map ( |v| json_value_to_toml_value ( v. to_owned ( ) ) ) . collect ( ) )
223
+ } ,
224
+ serde_json:: Value :: Object ( x) => {
225
+ toml:: Value :: Table ( json_object_to_btreemap ( & x) )
226
+ } ,
227
+ }
228
+ }
0 commit comments