1
1
//! Rust containers for valid `git-config` types.
2
2
3
+ use std:: path:: PathBuf ;
3
4
use std:: { borrow:: Cow , convert:: TryFrom , fmt:: Display , str:: FromStr } ;
4
5
5
6
#[ cfg( not( target_os = "windows" ) ) ]
@@ -352,26 +353,20 @@ impl<'a> Path<'a> {
352
353
}
353
354
354
355
const PREFIX : & [ u8 ] = b"%(prefix)/" ;
356
+ const USER_HOME : & [ u8 ] = b"~/" ;
355
357
if self . starts_with ( PREFIX ) {
356
- let mut expanded = git_features :: path :: into_bytes ( git_install_dir. ok_or ( PathError :: Missing {
358
+ let git_install_dir = git_install_dir. ok_or ( PathError :: Missing {
357
359
what : "git install dir" ,
358
- } ) ?)
359
- . context ( "git install dir" ) ?
360
- . into_owned ( ) ;
361
- let ( _prefix, val) = self . split_at ( PREFIX . len ( ) - "/" . len ( ) ) ;
362
- expanded. extend ( val) ;
363
- Ok ( git_features:: path:: from_byte_vec ( expanded)
364
- . context ( "prefix-expanded path" ) ?
365
- . into ( ) )
366
- } else if self . starts_with ( b"~/" ) {
360
+ } ) ?;
361
+ let ( _prefix, path_without_trailing_slash) = self . split_at ( PREFIX . len ( ) ) ;
362
+ let path_without_trailing_slash =
363
+ git_features:: path:: from_byte_vec ( path_without_trailing_slash) . context ( "path past %(prefix)" ) ?;
364
+ Ok ( git_install_dir. join ( path_without_trailing_slash) . into ( ) )
365
+ } else if self . starts_with ( USER_HOME ) {
367
366
let home_path = dirs:: home_dir ( ) . ok_or ( PathError :: Missing { what : "home dir" } ) ?;
368
- let mut expanded = git_features:: path:: into_bytes ( home_path)
369
- . context ( "home dir" ) ?
370
- . into_owned ( ) ;
371
- let ( _prefix, val) = self . split_at ( "~" . len ( ) ) ;
372
- expanded. extend ( val) ;
373
- let expanded = git_features:: path:: convert:: to_unix_separators ( expanded) ;
374
- Ok ( git_features:: path:: from_bytes ( expanded) . context ( "tilde expanded path" ) ?)
367
+ let ( _prefix, val) = self . split_at ( USER_HOME . len ( ) ) ;
368
+ let val = git_features:: path:: from_bytes ( val) . context ( "path past ~/" ) ?;
369
+ Ok ( home_path. join ( val) . into ( ) )
375
370
} else if self . starts_with ( b"~" ) && self . contains ( & b'/' ) {
376
371
self . interpolate_user ( )
377
372
} else {
@@ -391,17 +386,15 @@ impl<'a> Path<'a> {
391
386
. iter ( )
392
387
. position ( |& e| e == b'/' )
393
388
. ok_or ( PathError :: Missing { what : "/" } ) ?;
394
- let ( username, val ) = val. split_at ( i) ;
389
+ let ( username, path_with_leading_slash ) = val. split_at ( i) ;
395
390
let username = std:: str:: from_utf8 ( username) ?;
396
391
let home = Passwd :: from_name ( username)
397
392
. map_err ( |_| PathError :: PwdFileQuery ) ?
398
393
. ok_or ( PathError :: Missing { what : "pwd user info" } ) ?
399
394
. dir ;
400
- let mut expanded = home. as_bytes ( ) . to_owned ( ) ;
401
- expanded. extend ( val) ;
402
- Ok ( git_features:: path:: from_byte_vec ( expanded)
403
- . context ( "tilded user expanded path" ) ?
404
- . into ( ) )
395
+ let path_past_user_prefix =
396
+ git_features:: path:: from_byte_slice ( & path_with_leading_slash[ 1 ..] ) . context ( "path past ~user/" ) ?;
397
+ Ok ( PathBuf :: from ( home) . join ( path_past_user_prefix) . into ( ) )
405
398
}
406
399
}
407
400
@@ -1550,19 +1543,26 @@ mod path {
1550
1543
1551
1544
#[ test]
1552
1545
fn prefix_interpolated ( ) {
1553
- let val = Cow :: Borrowed ( & b"%(prefix)/foo/bar" [ ..] ) ;
1554
- let git_install_dir = "/tmp/git" ;
1555
- let expected = & std:: path:: PathBuf :: from ( format ! ( "{}/foo/bar" , git_install_dir) ) ;
1556
- assert_eq ! (
1557
- & * Path :: from( val)
1558
- . interpolate( Some ( std:: path:: Path :: new( git_install_dir) ) )
1559
- . unwrap( ) ,
1560
- expected
1561
- ) ;
1546
+ for git_install_dir in & [ "/tmp/git" , "C:\\ git" ] {
1547
+ for ( val, expected) in & [
1548
+ ( & b"%(prefix)/foo/bar" [ ..] , "foo/bar" ) ,
1549
+ ( b"%(prefix)/foo\\ bar" , "foo\\ bar" ) ,
1550
+ ] {
1551
+ let expected =
1552
+ & std:: path:: PathBuf :: from ( format ! ( "{}{}{}" , git_install_dir, std:: path:: MAIN_SEPARATOR , expected) ) ;
1553
+ assert_eq ! (
1554
+ & * Path :: from( Cow :: Borrowed ( * val) )
1555
+ . interpolate( Some ( std:: path:: Path :: new( git_install_dir) ) )
1556
+ . unwrap( ) ,
1557
+ expected,
1558
+ "prefix interpolation keeps separators as they are"
1559
+ ) ;
1560
+ }
1561
+ }
1562
1562
}
1563
1563
1564
1564
#[ test]
1565
- fn disabled_prefix_interpoldation ( ) {
1565
+ fn disabled_prefix_interpolation ( ) {
1566
1566
let path = "./%(prefix)/foo/bar" ;
1567
1567
let git_install_dir = "/tmp/git" ;
1568
1568
assert_eq ! (
@@ -1576,17 +1576,15 @@ mod path {
1576
1576
#[ test]
1577
1577
fn tilde_interpolated ( ) {
1578
1578
let path = & b"~/foo/bar" [ ..] ;
1579
- let home = dirs:: home_dir ( )
1580
- . expect ( "empty home" )
1581
- . to_str ( )
1582
- . expect ( "invalid unicode" )
1583
- . to_owned ( ) ;
1584
- #[ cfg( target_os = "windows" ) ]
1585
- let home = home. replace ( "\\ " , "/" ) ;
1586
- let expected = format ! ( "{}/foo/bar" , home) ;
1579
+ let expected = format ! (
1580
+ "{}{}foo/bar" ,
1581
+ dirs:: home_dir( ) . expect( "empty home" ) . display( ) ,
1582
+ std:: path:: MAIN_SEPARATOR
1583
+ ) ;
1587
1584
assert_eq ! (
1588
1585
Path :: from( Cow :: Borrowed ( path) ) . interpolate( None ) . unwrap( ) . as_ref( ) ,
1589
- std:: path:: Path :: new( & expected)
1586
+ std:: path:: Path :: new( & expected) ,
1587
+ "note that path separators are not turned into slashes as we work with `std::path::Path`"
1590
1588
) ;
1591
1589
}
1592
1590
@@ -1603,12 +1601,17 @@ mod path {
1603
1601
#[ test]
1604
1602
fn user_interpolated ( ) {
1605
1603
let user = std:: env:: var ( "USER" ) . unwrap ( ) ;
1606
- let path = format ! ( "~{}/foo/bar" , user) ;
1607
1604
let home = std:: env:: var ( "HOME" ) . unwrap ( ) ;
1608
- let expected = format ! ( "{}/foo/bar" , home) ;
1609
- assert_eq ! (
1610
- & * Path :: from( Cow :: Borrowed ( path. as_bytes( ) ) ) . interpolate( None ) . unwrap( ) ,
1611
- std:: path:: Path :: new( & expected)
1612
- ) ;
1605
+ let specific_user_home = format ! ( "~{}" , user) ;
1606
+
1607
+ for path_suffix in & [ "foo/bar" , "foo\\ bar" , "" ] {
1608
+ let path = format ! ( "{}{}{}" , specific_user_home, std:: path:: MAIN_SEPARATOR , path_suffix) ;
1609
+ let expected = format ! ( "{}{}{}" , home, std:: path:: MAIN_SEPARATOR , path_suffix) ;
1610
+ assert_eq ! (
1611
+ & * Path :: from( Cow :: Borrowed ( path. as_bytes( ) ) ) . interpolate( None ) . unwrap( ) ,
1612
+ std:: path:: Path :: new( & expected) ,
1613
+ "it keeps path separators as is"
1614
+ ) ;
1615
+ }
1613
1616
}
1614
1617
}
0 commit comments