@@ -79,6 +79,7 @@ impl CrateDetails {
7979 conn : & mut Client ,
8080 name : & str ,
8181 version : & str ,
82+ version_or_latest : & str ,
8283 up : & RepositoryStatsUpdater ,
8384 ) -> Option < CrateDetails > {
8485 // get all stuff, I love you rustfmt
@@ -150,6 +151,7 @@ impl CrateDetails {
150151 let metadata = MetaData {
151152 name : krate. get ( "name" ) ,
152153 version : krate. get ( "version" ) ,
154+ version_or_latest : version_or_latest. to_string ( ) ,
153155 description : krate. get ( "description" ) ,
154156 rustdoc_status : krate. get ( "rustdoc_status" ) ,
155157 target_name : krate. get ( "target_name" ) ,
@@ -281,16 +283,21 @@ pub fn crate_details_handler(req: &mut Request) -> IronResult<Response> {
281283 let name = cexpect ! ( req, router. find( "name" ) ) ;
282284 let req_version = router. find ( "version" ) ;
283285
284- let mut conn = extension ! ( req, Pool ) . get ( ) ?;
285-
286- match match_version ( & mut conn, name, req_version) . and_then ( |m| m. assume_exact ( ) ) ? {
287- MatchSemver :: Exact ( ( version, _) ) => {
288- let updater = extension ! ( req, RepositoryStatsUpdater ) ;
289- let details = cexpect ! ( req, CrateDetails :: new( & mut conn, name, & version, updater) ) ;
286+ if req_version == None {
287+ let url = ctry ! (
288+ req,
289+ Url :: parse( & format!( "{}/crate/{}/latest" , redirect_base( req) , name, ) ) ,
290+ ) ;
291+ return Ok ( super :: redirect ( url) ) ;
292+ }
290293
291- CrateDetailsPage { details } . into_response ( req)
292- }
294+ let mut conn = extension ! ( req, Pool ) . get ( ) ?;
293295
296+ let found_version =
297+ match_version ( & mut conn, name, req_version) . and_then ( |m| m. assume_exact ( ) ) ?;
298+ let ( version, version_or_latest) = match found_version {
299+ MatchSemver :: Exact ( ( version, _) ) => ( version. clone ( ) , version) ,
300+ MatchSemver :: Latest ( ( version, _) ) => ( version, "latest" . to_string ( ) ) ,
294301 MatchSemver :: Semver ( ( version, _) ) => {
295302 let url = ctry ! (
296303 req,
@@ -302,16 +309,24 @@ pub fn crate_details_handler(req: &mut Request) -> IronResult<Response> {
302309 ) ) ,
303310 ) ;
304311
305- Ok ( super :: redirect ( url) )
312+ return Ok ( super :: redirect ( url) ) ;
306313 }
307- }
314+ } ;
315+
316+ let updater = extension ! ( req, RepositoryStatsUpdater ) ;
317+ let details = cexpect ! (
318+ req,
319+ CrateDetails :: new( & mut conn, name, & version, & version_or_latest, updater)
320+ ) ;
321+
322+ CrateDetailsPage { details } . into_response ( req)
308323}
309324
310325#[ cfg( test) ]
311326mod tests {
312327 use super :: * ;
313328 use crate :: index:: api:: CrateOwner ;
314- use crate :: test:: { wrapper, TestDatabase } ;
329+ use crate :: test:: { assert_redirect , wrapper, TestDatabase } ;
315330 use anyhow:: { Context , Error } ;
316331 use kuchiki:: traits:: TendrilSink ;
317332 use std:: collections:: HashMap ;
@@ -326,6 +341,7 @@ mod tests {
326341 & mut db. conn ( ) ,
327342 package,
328343 version,
344+ version,
329345 db. repository_stats_updater ( ) ,
330346 )
331347 . with_context ( || anyhow:: anyhow!( "could not fetch crate details" ) ) ?;
@@ -459,6 +475,7 @@ mod tests {
459475 & mut db. conn ( ) ,
460476 "foo" ,
461477 "0.2.0" ,
478+ "0.2.0" ,
462479 db. repository_stats_updater ( ) ,
463480 )
464481 . unwrap ( ) ;
@@ -534,6 +551,7 @@ mod tests {
534551 & mut db. conn ( ) ,
535552 "foo" ,
536553 version,
554+ version,
537555 db. repository_stats_updater ( ) ,
538556 )
539557 . unwrap ( ) ;
@@ -564,6 +582,7 @@ mod tests {
564582 & mut db. conn ( ) ,
565583 "foo" ,
566584 version,
585+ version,
567586 db. repository_stats_updater ( ) ,
568587 )
569588 . unwrap ( ) ;
@@ -595,6 +614,7 @@ mod tests {
595614 & mut db. conn ( ) ,
596615 "foo" ,
597616 version,
617+ version,
598618 db. repository_stats_updater ( ) ,
599619 )
600620 . unwrap ( ) ;
@@ -634,6 +654,7 @@ mod tests {
634654 & mut db. conn ( ) ,
635655 "foo" ,
636656 version,
657+ version,
637658 db. repository_stats_updater ( ) ,
638659 )
639660 . unwrap ( ) ;
@@ -696,6 +717,7 @@ mod tests {
696717 & mut db. conn ( ) ,
697718 "foo" ,
698719 "0.0.1" ,
720+ "0.0.1" ,
699721 db. repository_stats_updater ( ) ,
700722 )
701723 . unwrap ( ) ;
@@ -726,6 +748,7 @@ mod tests {
726748 & mut db. conn ( ) ,
727749 "foo" ,
728750 "0.0.1" ,
751+ "0.0.1" ,
729752 db. repository_stats_updater ( ) ,
730753 )
731754 . unwrap ( ) ;
@@ -755,6 +778,7 @@ mod tests {
755778 & mut db. conn ( ) ,
756779 "foo" ,
757780 "0.0.1" ,
781+ "0.0.1" ,
758782 db. repository_stats_updater ( ) ,
759783 )
760784 . unwrap ( ) ;
@@ -779,6 +803,7 @@ mod tests {
779803 & mut db. conn ( ) ,
780804 "foo" ,
781805 "0.0.1" ,
806+ "0.0.1" ,
782807 db. repository_stats_updater ( ) ,
783808 )
784809 . unwrap ( ) ;
@@ -956,4 +981,42 @@ mod tests {
956981 Ok ( ( ) )
957982 } ) ;
958983 }
984+
985+ #[ test]
986+ fn latest_url ( ) {
987+ wrapper ( |env| {
988+ env. fake_release ( )
989+ . name ( "dummy" )
990+ . version ( "0.4.0" )
991+ . rustdoc_file ( "dummy/index.html" )
992+ . rustdoc_file ( "x86_64-pc-windows-msvc/dummy/index.html" )
993+ . default_target ( "x86_64-unknown-linux-gnu" )
994+ . add_target ( "x86_64-pc-windows-msvc" )
995+ . create ( ) ?;
996+ let web = env. frontend ( ) ;
997+
998+ let resp = env. frontend ( ) . get ( "/crate/dummy/latest" ) . send ( ) ?;
999+ assert ! ( resp. status( ) . is_success( ) ) ;
1000+ assert ! ( resp. url( ) . as_str( ) . ends_with( "/crate/dummy/latest" ) ) ;
1001+ let body = String :: from_utf8 ( resp. bytes ( ) . unwrap ( ) . to_vec ( ) ) . unwrap ( ) ;
1002+ assert ! ( body. contains( "<a href=\" /crate/dummy/latest/features\" " ) ) ;
1003+ assert ! ( body. contains( "<a href=\" /crate/dummy/latest/builds\" " ) ) ;
1004+ assert ! ( body. contains( "<a href=\" /crate/dummy/latest/source/\" " ) ) ;
1005+ assert ! ( body. contains( "<a href=\" /crate/dummy/latest\" " ) ) ;
1006+
1007+ assert_redirect ( "/crate/dummy/latest/" , "/crate/dummy/latest" , web) ?;
1008+ assert_redirect ( "/crate/dummy" , "/crate/dummy/latest" , web) ?;
1009+
1010+ let resp_json = env
1011+ . frontend ( )
1012+ . get ( "/crate/aquarelle/latest/builds.json" )
1013+ . send ( ) ?;
1014+ assert ! ( resp_json
1015+ . url( )
1016+ . as_str( )
1017+ . ends_with( "/crate/aquarelle/latest/builds.json" ) ) ;
1018+
1019+ Ok ( ( ) )
1020+ } ) ;
1021+ }
9591022}
0 commit comments