1
1
extern crate colored;
2
2
extern crate git2;
3
- extern crate tokei;
4
3
extern crate license;
4
+ extern crate tokei;
5
5
6
+ use colored:: Color ;
6
7
use colored:: * ;
7
- use git2:: Error ;
8
8
use git2:: Repository ;
9
- use std:: fmt;
10
- use std:: fs;
11
- use std:: process:: { Command , Stdio } ;
12
- use std:: str:: FromStr ;
13
9
use license:: License ;
14
- use std:: ffi:: OsStr ;
15
- use std:: fmt:: Write ;
16
- use std:: process:: exit;
10
+ use std:: {
11
+ convert:: From ,
12
+ ffi:: OsStr ,
13
+ fmt,
14
+ fmt:: Write ,
15
+ fs,
16
+ process:: { Command , Stdio } ,
17
+ result,
18
+ str:: FromStr ,
19
+ } ;
20
+
21
+ type Result < T > = result:: Result < T , Error > ;
17
22
18
23
struct Info {
19
24
project_name : String ,
@@ -27,7 +32,7 @@ struct Info {
27
32
impl fmt:: Display for Info {
28
33
fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
29
34
let mut buffer = String :: new ( ) ;
30
- let color = get_color ( & self . language ) ;
35
+ let color = self . color ( ) ;
31
36
32
37
writeln ! (
33
38
buffer,
@@ -49,12 +54,7 @@ impl fmt::Display for Info {
49
54
"Author: "
50
55
} ;
51
56
52
- writeln ! (
53
- buffer,
54
- "{}{}" ,
55
- title. color( color) . bold( ) ,
56
- self . authors. first( ) . unwrap( )
57
- ) ?;
57
+ writeln ! ( buffer, "{}{}" , title. color( color) . bold( ) , self . authors[ 0 ] ) ?;
58
58
59
59
let title = " " . repeat ( title. len ( ) ) ;
60
60
@@ -119,27 +119,6 @@ enum Language {
119
119
TypeScript ,
120
120
}
121
121
122
- fn get_color ( l : & Language ) -> & str {
123
- match l {
124
- Language :: C => "cyan" ,
125
- Language :: Clojure => "cyan" ,
126
- Language :: Cpp => "yellow" ,
127
- Language :: Csharp => "white" ,
128
- Language :: Go => "white" ,
129
- Language :: Haskell => "cyan" ,
130
- Language :: Java => "green" ,
131
- Language :: Lisp => "yellow" ,
132
- Language :: Lua => "blue" ,
133
- Language :: Python => "magenta" ,
134
- Language :: R => "blue" ,
135
- Language :: Ruby => "magenta" ,
136
- Language :: Rust => "cyan" ,
137
- Language :: Scala => "blue" ,
138
- Language :: Shell => "green" ,
139
- Language :: TypeScript => "cyan" ,
140
- }
141
- }
142
-
143
122
impl fmt:: Display for Language {
144
123
fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
145
124
match * self {
@@ -163,42 +142,28 @@ impl fmt::Display for Language {
163
142
}
164
143
}
165
144
166
- fn main ( ) {
145
+ fn main ( ) -> Result < ( ) > {
167
146
let tokei_langs = project_languages ( ) ;
168
- let language = match get_dominant_language ( & tokei_langs) {
169
- Some ( language) => language,
170
- None => {
171
- eprintln ! ( "Error: Could not find any source code in this directory." ) ;
172
- exit ( 1 ) ;
173
- }
174
- } ;
147
+ let language = get_dominant_language ( & tokei_langs) . ok_or ( Error :: SourceCodeNotFound ) ?;
175
148
176
149
if !is_git_installed ( ) {
177
- eprintln ! ( "Error: Could not execute git for project information." ) ;
178
- exit ( 1 ) ;
150
+ return Err ( Error :: GitNotInstalled ) ;
179
151
}
180
152
181
153
let authors = get_authors ( 3 ) ;
182
- let config: Configuration = match get_configuration ( ) {
183
- Ok ( config) => config,
184
- Err ( _) => {
185
- eprintln ! ( "Error: Could not retrieve git configuration data" ) ;
186
- exit ( 1 ) ;
187
- }
188
- } ;
189
-
190
-
154
+ let config = get_configuration ( ) ?;
191
155
192
156
let info = Info {
193
157
project_name : config. repository_name ,
194
158
language,
195
159
authors,
196
160
repo : config. repository_url ,
197
161
number_of_lines : get_total_loc ( & tokei_langs) ,
198
- license : project_license ( ) ,
162
+ license : project_license ( ) ? ,
199
163
} ;
200
164
201
165
println ! ( "{}" , info) ;
166
+ Ok ( ( ) )
202
167
}
203
168
204
169
fn project_languages ( ) -> tokei:: Languages {
@@ -208,25 +173,31 @@ fn project_languages() -> tokei::Languages {
208
173
languages
209
174
}
210
175
211
- fn project_license ( ) -> String {
212
- let output = fs:: read_dir ( "." ) . unwrap ( )
213
- . filter_map ( Result :: ok)
176
+ fn project_license ( ) -> Result < String > {
177
+ let output = fs:: read_dir ( "." )
178
+ . map_err ( |_| Error :: ReadDirectory ) ?
179
+ . filter_map ( result:: Result :: ok)
214
180
. map ( |entry| entry. path ( ) )
215
- . filter ( |entry| entry. is_file ( )
216
- && entry. file_name ( )
181
+ . filter (
182
+ |entry| {
183
+ entry. is_file ( )
184
+ && entry
185
+ . file_name ( )
217
186
. map ( OsStr :: to_string_lossy)
218
187
. unwrap_or ( "" . into ( ) )
219
- . starts_with ( "LICENSE" ) // TODO: multiple prefixes, like COPYING?
188
+ . starts_with ( "LICENSE" )
189
+ } , // TODO: multiple prefixes, like COPYING?
220
190
)
221
191
. map ( |entry| license:: Kind :: from_str ( & fs:: read_to_string ( entry) . unwrap_or ( "" . into ( ) ) ) )
222
- . filter_map ( Result :: ok)
192
+ . filter_map ( result :: Result :: ok)
223
193
. map ( |license| license. name ( ) . to_string ( ) )
224
- . collect :: < Vec < _ > > ( ) . join ( ", " ) ;
194
+ . collect :: < Vec < _ > > ( )
195
+ . join ( ", " ) ;
225
196
226
197
if output == "" {
227
- "Unknown" . into ( )
198
+ Ok ( "Unknown" . into ( ) )
228
199
} else {
229
- output
200
+ Ok ( output)
230
201
}
231
202
}
232
203
@@ -244,9 +215,9 @@ struct Configuration {
244
215
pub repository_url : String ,
245
216
}
246
217
247
- fn get_configuration ( ) -> Result < Configuration , Error > {
248
- let repo = Repository :: open ( "./" ) ?;
249
- let config = repo. config ( ) ?;
218
+ fn get_configuration ( ) -> Result < Configuration > {
219
+ let repo = Repository :: open ( "./" ) . map_err ( |_| Error :: GitNotInstalled ) ?;
220
+ let config = repo. config ( ) . map_err ( |_| Error :: NoGitData ) ?;
250
221
let mut remote_url = String :: new ( ) ;
251
222
let mut repository_name = String :: new ( ) ;
252
223
let mut remote_upstream: Option < String > = None ;
@@ -303,7 +274,8 @@ fn get_authors(n: usize) -> Vec<String> {
303
274
304
275
// sort authors by commit count where the one with most commit count is first
305
276
let mut authors: Vec < ( String , usize ) > = authors. into_iter ( ) . collect ( ) ;
306
- authors. sort_by ( |( _, count1) , ( _, count2) | count2. cmp ( count1) ) ;
277
+ authors. sort_by_key ( |( _, c) | * c) ;
278
+ authors. reverse ( ) ;
307
279
308
280
// truncate the vector so we only get the count of authors we specified as 'n'
309
281
authors. truncate ( n) ;
@@ -404,4 +376,49 @@ impl Info {
404
376
// _ => include_str!("../resources/unknown.ascii"),
405
377
}
406
378
}
379
+
380
+ fn color ( & self ) -> Color {
381
+ match self . language {
382
+ Language :: C => Color :: Cyan ,
383
+ Language :: Clojure => Color :: Cyan ,
384
+ Language :: Cpp => Color :: Yellow ,
385
+ Language :: Csharp => Color :: White ,
386
+ Language :: Go => Color :: White ,
387
+ Language :: Haskell => Color :: Cyan ,
388
+ Language :: Java => Color :: Green ,
389
+ Language :: Lisp => Color :: Yellow ,
390
+ Language :: Lua => Color :: Blue ,
391
+ Language :: Python => Color :: Magenta ,
392
+ Language :: R => Color :: Blue ,
393
+ Language :: Ruby => Color :: Magenta ,
394
+ Language :: Rust => Color :: Cyan ,
395
+ Language :: Scala => Color :: Blue ,
396
+ Language :: Shell => Color :: Green ,
397
+ Language :: TypeScript => Color :: Cyan ,
398
+ }
399
+ }
400
+ }
401
+
402
+ /// Custom error type
403
+ enum Error {
404
+ /// Sourcecode could be located
405
+ SourceCodeNotFound ,
406
+ /// Git is not installed or did not function properly
407
+ GitNotInstalled ,
408
+ /// Did not find any git data in the directory
409
+ NoGitData ,
410
+ /// An IO error occoured while reading ./
411
+ ReadDirectory ,
412
+ }
413
+
414
+ impl fmt:: Debug for Error {
415
+ fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
416
+ let content = match self {
417
+ Error :: SourceCodeNotFound => "Could not find any source code in this directory" ,
418
+ Error :: GitNotInstalled => "Git failed to execute" ,
419
+ Error :: NoGitData => "Could not retrieve git configuration data" ,
420
+ Error :: ReadDirectory => "Could read directory ./" ,
421
+ } ;
422
+ write ! ( f, "{}" , content)
423
+ }
407
424
}
0 commit comments