@@ -6,57 +6,80 @@ use std::collections::HashMap;
6
6
use std:: collections:: HashSet ;
7
7
use std:: fmt;
8
8
use std:: fs;
9
+ use std:: process;
9
10
use std:: str:: FromStr ;
10
11
use structopt:: StructOpt ;
12
+ use constants:: Message ;
13
+
14
+ mod constants;
15
+
16
+ const HELP : & str = r#"
17
+ Example:
18
+ json_diff f source1.json source2.json
19
+ json_diff d '{...}' '{...}'
20
+
21
+ Option:
22
+ f : read input from json files
23
+ d : read input from command line"# ;
11
24
12
25
#[ derive( Debug ) ]
13
26
struct AppError {
14
- message : String ,
27
+ message : Message ,
15
28
}
16
29
impl fmt:: Display for AppError {
17
30
fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
18
31
write ! ( f, "{}" , self . message)
19
32
}
20
33
}
21
34
22
- enum CliOptions {
35
+ enum InputReadMode {
23
36
D ,
24
37
F ,
25
38
}
26
- impl FromStr for CliOptions {
39
+ impl FromStr for InputReadMode {
27
40
type Err = AppError ;
28
41
fn from_str ( s : & str ) -> Result < Self , Self :: Err > {
29
42
match s {
30
- "d" => Ok ( CliOptions :: D ) ,
31
- "f" => Ok ( CliOptions :: F ) ,
43
+ "d" => Ok ( InputReadMode :: D ) ,
44
+ "f" => Ok ( InputReadMode :: F ) ,
32
45
_ => Err ( Self :: Err {
33
- message : "BAD option" . to_string ( ) ,
46
+ message : Message :: BadOption ,
34
47
} ) ,
35
48
}
36
49
}
37
50
}
38
51
39
52
#[ derive( StructOpt ) ]
53
+ #[ structopt( about = HELP ) ]
40
54
struct Cli {
41
- option : CliOptions ,
55
+ read_mode : InputReadMode ,
42
56
source1 : String ,
43
57
source2 : String ,
44
58
}
45
59
60
+ fn error_exit ( message : constants:: Message ) -> ! {
61
+ eprintln ! ( "{}" , message) ;
62
+ process:: exit ( 1 ) ;
63
+ }
64
+
46
65
fn main ( ) {
47
66
let args = Cli :: from_args ( ) ;
48
67
49
- let ( data1, data2) = match args. option {
50
- CliOptions :: D => ( args. source1 , args. source2 ) ,
51
- CliOptions :: F => {
52
- ( fs:: read_to_string ( args. source1 )
53
- . expect ( & format ! ( "Error occurred while reading source1" ) ) ,
54
- fs:: read_to_string ( args. source2 )
55
- . expect ( & format ! ( "Error occurred while reading source2" ) ) )
68
+ let ( data1, data2) = match args. read_mode {
69
+ InputReadMode :: D => ( args. source1 , args. source2 ) ,
70
+ InputReadMode :: F => {
71
+ if let Ok ( d1) = fs:: read_to_string ( args. source1 ) {
72
+ if let Ok ( d2) = fs:: read_to_string ( args. source2 ) {
73
+ ( d1, d2)
74
+ } else {
75
+ error_exit ( Message :: SOURCE2 ) ;
76
+ }
77
+ } else {
78
+ error_exit ( Message :: SOURCE1 ) ;
79
+ }
56
80
}
57
81
} ;
58
82
display_output ( compare_jsons ( & data1, & data2) ) ;
59
-
60
83
}
61
84
62
85
fn display_output ( result : Mismatch ) {
@@ -66,42 +89,42 @@ fn display_output(result: Mismatch) {
66
89
keys_in_both : KeyNode :: Nil ,
67
90
} ;
68
91
if no_mismatch == result {
69
- println ! ( "No mismatch was found." ) ;
92
+ println ! ( "{}" , Message :: NoMismatch ) ;
70
93
} else {
71
94
match result. keys_in_both {
72
95
KeyNode :: Node ( _) => {
73
96
let mut keys = Vec :: new ( ) ;
74
97
result. keys_in_both . absolute_keys ( & mut keys, None ) ;
75
- println ! ( "Mismatched:" ) ;
98
+ println ! ( "{}:" , Message :: Mismatch ) ;
76
99
for key in keys {
77
100
println ! ( "{}" , key) ;
78
101
}
79
102
}
80
- KeyNode :: Value ( _, _) => println ! ( "Mismatch at root." ) ,
103
+ KeyNode :: Value ( _, _) => println ! ( "{}" , Message :: RootMismatch ) ,
81
104
KeyNode :: Nil => ( ) ,
82
105
}
83
106
match result. left_only_keys {
84
107
KeyNode :: Node ( _) => {
85
108
let mut keys = Vec :: new ( ) ;
86
109
result. left_only_keys . absolute_keys ( & mut keys, None ) ;
87
- println ! ( "Extra on left:" ) ;
110
+ println ! ( "{}:" , Message :: LeftExtra ) ;
88
111
for key in keys {
89
112
println ! ( "{}" , key. red( ) . bold( ) ) ;
90
113
}
91
114
}
92
- KeyNode :: Value ( _, _) => ( ) , // TODO left_only_keys should never be Value type => Throw an error
115
+ KeyNode :: Value ( _, _) => error_exit ( Message :: UnknownError ) ,
93
116
KeyNode :: Nil => ( ) ,
94
117
}
95
118
match result. right_only_keys {
96
119
KeyNode :: Node ( _) => {
97
120
let mut keys = Vec :: new ( ) ;
98
121
result. right_only_keys . absolute_keys ( & mut keys, None ) ;
99
- println ! ( "Extra on right:" ) ;
122
+ println ! ( "{}:" , Message :: RightExtra ) ;
100
123
for key in keys {
101
124
println ! ( "{}" , key. green( ) . bold( ) ) ;
102
125
}
103
126
}
104
- KeyNode :: Value ( _, _) => ( ) , // TODO right_only_keys should never be Value type => Throw an error
127
+ KeyNode :: Value ( _, _) => error_exit ( Message :: UnknownError ) ,
105
128
KeyNode :: Nil => ( ) ,
106
129
}
107
130
}
@@ -162,10 +185,15 @@ impl Mismatch {
162
185
}
163
186
164
187
fn compare_jsons ( a : & str , b : & str ) -> Mismatch {
165
- let value1: Value = serde_json:: from_str ( a) . unwrap ( ) ;
166
- let value2: Value = serde_json:: from_str ( b) . unwrap ( ) ;
167
-
168
- match_json ( & value1, & value2)
188
+ if let Ok ( value1) = serde_json:: from_str ( a) {
189
+ if let Ok ( value2) = serde_json:: from_str ( b) {
190
+ match_json ( & value1, & value2)
191
+ } else {
192
+ error_exit ( Message :: JSON2 ) ;
193
+ }
194
+ } else {
195
+ error_exit ( Message :: JSON1 ) ;
196
+ }
169
197
}
170
198
171
199
fn match_json ( value1 : & Value , value2 : & Value ) -> Mismatch {
0 commit comments