1
1
//! Source code browser
2
2
3
- use super :: file:: File as DbFile ;
4
- use super :: page:: Page ;
5
- use super :: MetaData ;
6
- use crate :: db:: Pool ;
7
- use crate :: Config ;
8
- use iron:: prelude:: * ;
3
+ use crate :: {
4
+ db:: Pool ,
5
+ impl_webpage,
6
+ web:: { error:: Nope , file:: File as DbFile , page:: WebPage , MetaData } ,
7
+ Config ,
8
+ } ;
9
+ use iron:: { status:: Status , IronError , IronResult , Request , Response } ;
9
10
use postgres:: Connection ;
10
11
use router:: Router ;
11
- use serde:: ser :: { Serialize , SerializeStruct , Serializer } ;
12
+ use serde:: Serialize ;
12
13
use serde_json:: Value ;
13
14
use std:: cmp:: Ordering ;
14
- use std:: collections:: HashMap ;
15
15
16
- /// A source file's type
17
- #[ derive( PartialEq , PartialOrd ) ]
18
- enum FileType {
19
- Dir ,
20
- Text ,
21
- Binary ,
22
- RustSource ,
23
- }
24
-
25
- /// A source file
26
- #[ derive( PartialEq , PartialOrd ) ]
16
+ /// A source file's name and mime type
17
+ #[ derive( Debug , Clone , PartialEq , Eq , PartialOrd , Serialize ) ]
27
18
struct File {
19
+ /// The name of the file
28
20
name : String ,
29
- file_type : FileType ,
21
+ /// The mime type of the file
22
+ mime : String ,
30
23
}
31
24
32
25
/// A list of source files
26
+ #[ derive( Debug , Clone , PartialEq , Serialize ) ]
33
27
struct FileList {
34
28
metadata : MetaData ,
35
29
files : Vec < File > ,
36
30
}
37
31
38
- impl Serialize for FileList {
39
- fn serialize < S > ( & self , serializer : S ) -> Result < S :: Ok , S :: Error >
40
- where
41
- S : Serializer ,
42
- {
43
- let mut state = serializer. serialize_struct ( "FileList" , 2 ) ?;
44
- state. serialize_field ( "metadata" , & self . metadata ) ?;
45
-
46
- let mut files = Vec :: with_capacity ( self . files . len ( ) ) ;
47
- for file in & self . files {
48
- let mut map = HashMap :: with_capacity ( 2 ) ;
49
- map. insert ( "name" , Value :: String ( file. name . to_owned ( ) ) ) ;
50
-
51
- let file_type = match file. file_type {
52
- FileType :: Dir => "file_type_dir" ,
53
- FileType :: Text => "file_type_text" ,
54
- FileType :: Binary => "file_type_binary" ,
55
- FileType :: RustSource => "file_type_rust_source" ,
56
- } ;
57
- map. insert ( file_type, Value :: Bool ( true ) ) ;
58
-
59
- files. push ( map) ;
60
- }
61
- state. serialize_field ( "files" , & files) ?;
62
-
63
- state. end ( )
64
- }
65
- }
66
-
67
32
impl FileList {
68
33
/// Gets FileList from a request path
69
34
///
@@ -126,19 +91,15 @@ impl FileList {
126
91
let path_splited: Vec < & str > = path. split ( '/' ) . collect ( ) ;
127
92
128
93
// if path have '/' it is a directory
129
- let ftype = if path_splited. len ( ) > 1 {
130
- FileType :: Dir
131
- } else if mime. starts_with ( "text" ) && path_splited[ 0 ] . ends_with ( ".rs" ) {
132
- FileType :: RustSource
133
- } else if mime. starts_with ( "text" ) {
134
- FileType :: Text
94
+ let mime = if path_splited. len ( ) > 1 {
95
+ "dir" . to_owned ( )
135
96
} else {
136
- FileType :: Binary
97
+ mime . to_owned ( )
137
98
} ;
138
99
139
100
let file = File {
140
101
name : path_splited[ 0 ] . to_owned ( ) ,
141
- file_type : ftype ,
102
+ mime ,
142
103
} ;
143
104
144
105
// avoid adding duplicates, a directory may occur more than once
@@ -155,9 +116,9 @@ impl FileList {
155
116
156
117
file_list. sort_by ( |a, b| {
157
118
// directories must be listed first
158
- if a. file_type == FileType :: Dir && b. file_type != FileType :: Dir {
119
+ if a. mime == "dir" && b. mime != "dir" {
159
120
Ordering :: Less
160
- } else if a. file_type != FileType :: Dir && b. file_type == FileType :: Dir {
121
+ } else if a. mime != "dir" && b. mime == "dir" {
161
122
Ordering :: Greater
162
123
} else {
163
124
a. name . to_lowercase ( ) . cmp ( & b. name . to_lowercase ( ) )
@@ -181,6 +142,18 @@ impl FileList {
181
142
}
182
143
}
183
144
145
+ #[ derive( Debug , Clone , PartialEq , Serialize ) ]
146
+ struct SourcePage {
147
+ file_list : FileList ,
148
+ show_parent_link : bool ,
149
+ file_content : Option < String > ,
150
+ is_rust_source : bool ,
151
+ }
152
+
153
+ impl_webpage ! {
154
+ SourcePage = "crate/source.html" ,
155
+ }
156
+
184
157
pub fn source_browser_handler ( req : & mut Request ) -> IronResult < Response > {
185
158
let router = extension ! ( req, Router ) ;
186
159
let name = cexpect ! ( req, router. find( "name" ) ) ;
@@ -222,7 +195,7 @@ pub fn source_browser_handler(req: &mut Request) -> IronResult<Response> {
222
195
None
223
196
} ;
224
197
225
- let ( content , is_rust_source) = if let Some ( file) = file {
198
+ let ( file_content , is_rust_source) = if let Some ( file) = file {
226
199
// serve the file with DatabaseFileHandler if file isn't text and not empty
227
200
if !file. 0 . mime . starts_with ( "text" ) && !file. is_empty ( ) {
228
201
return Ok ( file. serve ( ) ) ;
@@ -238,77 +211,21 @@ pub fn source_browser_handler(req: &mut Request) -> IronResult<Response> {
238
211
( None , false )
239
212
} ;
240
213
241
- let list = FileList :: from_path ( & conn, & name, & version, & req_path) ;
242
- if list. is_none ( ) {
243
- use super :: error:: Nope ;
244
- use iron:: status;
245
- return Err ( IronError :: new ( Nope :: NoResults , status:: NotFound ) ) ;
246
- }
247
-
248
- let page = Page :: new ( list)
249
- . set_bool ( "show_parent_link" , !req_path. is_empty ( ) )
250
- . set_true ( "javascript_highlightjs" )
251
- . set_true ( "show_package_navigation" )
252
- . set_true ( "package_source_tab" ) ;
214
+ let file_list = FileList :: from_path ( & conn, & name, & version, & req_path)
215
+ . ok_or_else ( || IronError :: new ( Nope :: NoResults , Status :: NotFound ) ) ?;
253
216
254
- if let Some ( content) = content {
255
- page. set ( "file_content" , & content)
256
- . set_bool ( "file_content_rust_source" , is_rust_source)
257
- . to_resp ( "source" )
258
- } else {
259
- page. to_resp ( "source" )
217
+ SourcePage {
218
+ file_list,
219
+ show_parent_link : !req_path. is_empty ( ) ,
220
+ file_content,
221
+ is_rust_source,
260
222
}
223
+ . into_response ( req)
261
224
}
262
225
263
226
#[ cfg( test) ]
264
227
mod tests {
265
- use super :: * ;
266
228
use crate :: test:: { assert_success, wrapper} ;
267
- use serde_json:: json;
268
-
269
- #[ test]
270
- fn serialize_file_list ( ) {
271
- let file_list = FileList {
272
- metadata : MetaData {
273
- name : "rcc" . to_string ( ) ,
274
- version : "0.0.0" . to_string ( ) ,
275
- description : Some ( "it compiles an unholy language" . to_string ( ) ) ,
276
- target_name : None ,
277
- rustdoc_status : true ,
278
- default_target : "x86_64-unknown-linux-gnu" . to_string ( ) ,
279
- } ,
280
- files : vec ! [
281
- File {
282
- name: "main.rs" . to_string( ) ,
283
- file_type: FileType :: RustSource ,
284
- } ,
285
- File {
286
- name: "lib.rs" . to_string( ) ,
287
- file_type: FileType :: RustSource ,
288
- } ,
289
- ] ,
290
- } ;
291
-
292
- let correct_json = json ! ( {
293
- "metadata" : {
294
- "name" : "rcc" ,
295
- "version" : "0.0.0" ,
296
- "description" : "it compiles an unholy language" ,
297
- "target_name" : null,
298
- "rustdoc_status" : true ,
299
- "default_target" : "x86_64-unknown-linux-gnu"
300
- } ,
301
- "files" : [ {
302
- "name" : "main.rs" ,
303
- "file_type_rust_source" : true
304
- } , {
305
- "name" : "lib.rs" ,
306
- "file_type_rust_source" : true
307
- } ] ,
308
- } ) ;
309
-
310
- assert_eq ! ( correct_json, serde_json:: to_value( & file_list) . unwrap( ) , ) ;
311
- }
312
229
313
230
#[ test]
314
231
fn cargo_ok_not_skipped ( ) {
0 commit comments