@@ -245,14 +245,11 @@ impl MatchSemver {
245
245
/// underscores (`_`) and vice-versa. The return value will indicate whether the crate name has
246
246
/// been matched exactly, or if there has been a "correction" in the name that matched instead.
247
247
fn match_version ( conn : & Connection , name : & str , version : Option < & str > ) -> Option < MatchVersion > {
248
- // version is an Option<&str> from router::Router::get
249
- // need to decode first
248
+ // version is an Option<&str> from router::Router::get, need to decode first
250
249
use url:: percent_encoding:: percent_decode;
250
+
251
251
let req_version = version
252
- . and_then ( |v| match percent_decode ( v. as_bytes ( ) ) . decode_utf8 ( ) {
253
- Ok ( p) => Some ( p) ,
254
- Err ( _) => None ,
255
- } )
252
+ . and_then ( |v| percent_decode ( v. as_bytes ( ) ) . decode_utf8 ( ) . ok ( ) )
256
253
. map ( |v| {
257
254
if v == "newest" || v == "latest" {
258
255
"*" . into ( )
@@ -267,11 +264,13 @@ fn match_version(conn: &Connection, name: &str, version: Option<&str>) -> Option
267
264
let query = "SELECT name, version, releases.id
268
265
FROM releases INNER JOIN crates ON releases.crate_id = crates.id
269
266
WHERE normalize_crate_name(name) = normalize_crate_name($1) AND yanked = false" ;
267
+
270
268
let rows = conn. query ( query, & [ & name] ) . unwrap ( ) ;
271
269
let mut rows = rows. iter ( ) . peekable ( ) ;
272
270
273
271
if let Some ( row) = rows. peek ( ) {
274
272
let db_name = row. get ( 0 ) ;
273
+
275
274
if db_name != name {
276
275
corrected_name = Some ( db_name) ;
277
276
}
@@ -280,15 +279,12 @@ fn match_version(conn: &Connection, name: &str, version: Option<&str>) -> Option
280
279
rows. map ( |row| ( row. get ( 1 ) , row. get ( 2 ) ) ) . collect ( )
281
280
} ;
282
281
283
- // first check for exact match
284
- // we can't expect users to use semver in query
285
- for version in & versions {
286
- if version. 0 == req_version {
287
- return Some ( MatchVersion {
288
- corrected_name,
289
- version : MatchSemver :: Exact ( version. clone ( ) ) ,
290
- } ) ;
291
- }
282
+ // first check for exact match, we can't expect users to use semver in query
283
+ if let Some ( ( version, id) ) = versions. iter ( ) . find ( |( vers, _) | vers == & req_version) {
284
+ return Some ( MatchVersion {
285
+ corrected_name,
286
+ version : MatchSemver :: Exact ( ( version. to_owned ( ) , * id) ) ,
287
+ } ) ;
292
288
}
293
289
294
290
// Now try to match with semver
@@ -299,8 +295,7 @@ fn match_version(conn: &Connection, name: &str, version: Option<&str>) -> Option
299
295
let mut versions_sem: Vec < ( Version , i32 ) > = Vec :: new ( ) ;
300
296
301
297
for version in & versions {
302
- // in theory a crate must always have a semver compatible version
303
- // but check result just in case
298
+ // in theory a crate must always have a semver compatible version, but check result just in case
304
299
versions_sem. push ( ( Version :: parse ( & version. 0 ) . ok ( ) ?, version. 1 ) ) ;
305
300
}
306
301
@@ -309,13 +304,14 @@ fn match_version(conn: &Connection, name: &str, version: Option<&str>) -> Option
309
304
versions_sem
310
305
} ;
311
306
312
- for version in & versions_sem {
313
- if req_sem_ver. matches ( & version. 0 ) {
314
- return Some ( MatchVersion {
315
- corrected_name,
316
- version : MatchSemver :: Semver ( ( version. 0 . to_string ( ) , version. 1 ) ) ,
317
- } ) ;
318
- }
307
+ if let Some ( ( version, id) ) = versions_sem
308
+ . iter ( )
309
+ . find ( |( vers, _) | req_sem_ver. matches ( vers) )
310
+ {
311
+ return Some ( MatchVersion {
312
+ corrected_name,
313
+ version : MatchSemver :: Semver ( ( version. to_string ( ) , * id) ) ,
314
+ } ) ;
319
315
}
320
316
321
317
// semver is acting weird for '*' (any) range if a crate only have pre-release versions
@@ -404,25 +400,26 @@ impl Server {
404
400
fn duration_to_str ( ts : time:: Timespec ) -> String {
405
401
let tm = time:: at ( ts) ;
406
402
let delta = time:: now ( ) - tm;
403
+ let delta = (
404
+ delta. num_days ( ) ,
405
+ delta. num_hours ( ) ,
406
+ delta. num_minutes ( ) ,
407
+ delta. num_seconds ( ) ,
408
+ ) ;
407
409
408
- if delta. num_days ( ) > 5 {
409
- format ! ( "{}" , tm. strftime( "%b %d, %Y" ) . unwrap( ) )
410
- } else if delta. num_days ( ) > 1 {
411
- format ! ( "{} days ago" , delta. num_days( ) )
412
- } else if delta. num_days ( ) == 1 {
413
- "one day ago" . to_string ( )
414
- } else if delta. num_hours ( ) > 1 {
415
- format ! ( "{} hours ago" , delta. num_hours( ) )
416
- } else if delta. num_hours ( ) == 1 {
417
- "an hour ago" . to_string ( )
418
- } else if delta. num_minutes ( ) > 1 {
419
- format ! ( "{} minutes ago" , delta. num_minutes( ) )
420
- } else if delta. num_minutes ( ) == 1 {
421
- "one minute ago" . to_string ( )
422
- } else if delta. num_seconds ( ) > 0 {
423
- format ! ( "{} seconds ago" , delta. num_seconds( ) )
424
- } else {
425
- "just now" . to_string ( )
410
+ match delta {
411
+ ( days, ..) if days > 5 => format ! ( "{}" , tm. strftime( "%b %d, %Y" ) . unwrap( ) ) ,
412
+ ( days @ 2 ..=5 , ..) => format ! ( "{} days ago" , days) ,
413
+ ( 1 , ..) => "one day ago" . to_string ( ) ,
414
+
415
+ ( _, hours, ..) if hours > 1 => format ! ( "{} hours ago" , hours) ,
416
+ ( _, 1 , ..) => "an hour ago" . to_string ( ) ,
417
+
418
+ ( _, _, minutes, _) if minutes > 1 => format ! ( "{} minutes ago" , minutes) ,
419
+ ( _, _, 1 , _) => "one minute ago" . to_string ( ) ,
420
+
421
+ ( _, _, _, seconds) if seconds > 0 => format ! ( "{} seconds ago" , seconds) ,
422
+ _ => "just now" . to_string ( ) ,
426
423
}
427
424
}
428
425
@@ -460,10 +457,12 @@ fn style_css_handler(_: &mut Request) -> IronResult<Response> {
460
457
CacheDirective :: Public ,
461
458
CacheDirective :: MaxAge ( STATIC_FILE_CACHE_DURATION as u32 ) ,
462
459
] ;
460
+
463
461
response
464
462
. headers
465
463
. set ( ContentType ( "text/css" . parse ( ) . unwrap ( ) ) ) ;
466
464
response. headers . set ( CacheControl ( cache) ) ;
465
+
467
466
Ok ( response)
468
467
}
469
468
@@ -477,6 +476,7 @@ fn load_js(file_path_str: &'static str) -> IronResult<Response> {
477
476
. headers
478
477
. set ( ContentType ( "application/javascript" . parse ( ) . unwrap ( ) ) ) ;
479
478
response. headers . set ( CacheControl ( cache) ) ;
479
+
480
480
Ok ( response)
481
481
}
482
482
@@ -489,7 +489,9 @@ fn opensearch_xml_handler(_: &mut Request) -> IronResult<Response> {
489
489
response. headers . set ( ContentType (
490
490
"application/opensearchdescription+xml" . parse ( ) . unwrap ( ) ,
491
491
) ) ;
492
+
492
493
response. headers . set ( CacheControl ( cache) ) ;
494
+
493
495
Ok ( response)
494
496
}
495
497
@@ -525,34 +527,31 @@ pub(crate) struct MetaData {
525
527
526
528
impl MetaData {
527
529
fn from_crate ( conn : & Connection , name : & str , version : & str ) -> Option < MetaData > {
528
- if let Some ( row ) = & conn
530
+ let rows = conn
529
531
. query (
530
532
"SELECT crates.name,
531
- releases.version,
532
- releases.description,
533
- releases.target_name,
534
- releases.rustdoc_status,
535
- releases.default_target
536
- FROM releases
537
- INNER JOIN crates ON crates.id = releases.crate_id
538
- WHERE crates.name = $1 AND releases.version = $2" ,
533
+ releases.version,
534
+ releases.description,
535
+ releases.target_name,
536
+ releases.rustdoc_status,
537
+ releases.default_target
538
+ FROM releases
539
+ INNER JOIN crates ON crates.id = releases.crate_id
540
+ WHERE crates.name = $1 AND releases.version = $2" ,
539
541
& [ & name, & version] ,
540
542
)
541
- . unwrap ( )
542
- . iter ( )
543
- . next ( )
544
- {
545
- return Some ( MetaData {
546
- name : row. get ( 0 ) ,
547
- version : row. get ( 1 ) ,
548
- description : row. get ( 2 ) ,
549
- target_name : row. get ( 3 ) ,
550
- rustdoc_status : row. get ( 4 ) ,
551
- default_target : row. get ( 5 ) ,
552
- } ) ;
553
- }
543
+ . unwrap ( ) ;
554
544
555
- None
545
+ let row = rows. iter ( ) . next ( ) ?;
546
+
547
+ Some ( MetaData {
548
+ name : row. get ( 0 ) ,
549
+ version : row. get ( 1 ) ,
550
+ description : row. get ( 2 ) ,
551
+ target_name : row. get ( 3 ) ,
552
+ rustdoc_status : row. get ( 4 ) ,
553
+ default_target : row. get ( 5 ) ,
554
+ } )
556
555
}
557
556
}
558
557
@@ -565,6 +564,7 @@ impl ToJson for MetaData {
565
564
m. insert ( "target_name" . to_owned ( ) , self . target_name . to_json ( ) ) ;
566
565
m. insert ( "rustdoc_status" . to_owned ( ) , self . rustdoc_status . to_json ( ) ) ;
567
566
m. insert ( "default_target" . to_owned ( ) , self . default_target . to_json ( ) ) ;
567
+
568
568
m. to_json ( )
569
569
}
570
570
}
@@ -662,6 +662,7 @@ mod test {
662
662
let web = env. frontend ( ) ;
663
663
for krate in & [ "std" , "alloc" , "core" , "proc_macro" , "test" ] {
664
664
let target = format ! ( "https://doc.rust-lang.org/stable/{}/" , krate) ;
665
+
665
666
// with or without slash
666
667
assert_redirect ( & format ! ( "/{}" , krate) , & target, web) ?;
667
668
assert_redirect ( & format ! ( "/{}/" , krate) , & target, web) ?;
@@ -701,6 +702,7 @@ mod test {
701
702
. source_file ( "src/main.rs" , br#"println!("definitely valid rust")"# )
702
703
. create ( )
703
704
. unwrap ( ) ;
705
+
704
706
let web = env. frontend ( ) ;
705
707
assert_success ( "/crate/regex/0.3.0/source/src/main.rs" , web) ?;
706
708
assert_success ( "/crate/regex/0.3.0/source" , web) ?;
@@ -744,6 +746,7 @@ mod test {
744
746
745
747
let release_id = release ( "0.3.0" , db) ;
746
748
let query = "UPDATE releases SET yanked = true WHERE id = $1 AND version = '0.3.0'" ;
749
+
747
750
db. conn ( ) . query ( query, & [ & release_id] ) . unwrap ( ) ;
748
751
assert_eq ! ( version( None , db) , None ) ;
749
752
assert_eq ! ( version( Some ( "0.3" ) , db) , None ) ;
@@ -765,7 +768,6 @@ mod test {
765
768
release ( "0.1.0+4.1" , db) ;
766
769
release ( "0.1.1" , db) ;
767
770
assert_eq ! ( version( None , db) , semver( "0.1.1" ) ) ;
768
-
769
771
release ( "0.5.1+zstd.1.4.4" , db) ;
770
772
assert_eq ! ( version( None , db) , semver( "0.5.1+zstd.1.4.4" ) ) ;
771
773
assert_eq ! ( version( Some ( "0.5" ) , db) , semver( "0.5.1+zstd.1.4.4" ) ) ;
0 commit comments