@@ -3,7 +3,7 @@ use std::path::Path;
33/// Common knowledge about the worktree that is needed across most interactions with the work tree
44#[ cfg_attr( feature = "serde1" , derive( serde:: Serialize , serde:: Deserialize ) ) ]
55#[ derive( PartialEq , Eq , Debug , Hash , Ord , PartialOrd , Clone , Copy ) ]
6- pub struct Context {
6+ pub struct Capabilities {
77 /// If true, the filesystem will store paths as decomposed unicode, i.e. `ä` becomes `"a\u{308}"`, which means that
88 /// we have to turn these forms back from decomposed to precomposed unicode before storing it in the index or generally
99 /// using it. This also applies to input received from the command-line, so callers may have to be aware of this and
@@ -15,29 +15,50 @@ pub struct Context {
1515 pub ignore_case : bool ,
1616 /// If true, we assume the the executable bit is honored as part of the files mode. If false, we assume the file system
1717 /// ignores the executable bit, hence it will be reported as 'off' even though we just tried to set it to be on.
18- pub file_mode : bool ,
18+ pub executable_bit : bool ,
1919 /// If true, the file system supports symbolic links and we should try to create them. Otherwise symbolic links will be checked
2020 /// out as files which contain the link as text.
2121 pub symlink : bool ,
2222}
2323
24- impl Context {
24+ impl Capabilities {
2525 /// try to determine all values in this context by probing them in the given `git_dir`, which
2626 /// should be on the file system the git repository is located on.
2727 /// `git_dir` is a typical git repository, expected to be populated with the typical files like `config`.
2828 ///
2929 /// All errors are ignored and interpreted on top of the default for the platform the binary is compiled for.
30- pub fn probe ( git_dir : impl AsRef < std :: path :: Path > ) -> Self {
30+ pub fn probe ( git_dir : impl AsRef < Path > ) -> Self {
3131 let root = git_dir. as_ref ( ) ;
32- let ctx = Context :: default ( ) ;
33- Context {
32+ let ctx = Capabilities :: default ( ) ;
33+ Capabilities {
3434 symlink : Self :: probe_symlink ( root) . unwrap_or ( ctx. symlink ) ,
3535 ignore_case : Self :: probe_ignore_case ( root) . unwrap_or ( ctx. ignore_case ) ,
3636 precompose_unicode : Self :: probe_precompose_unicode ( root) . unwrap_or ( ctx. precompose_unicode ) ,
37- .. ctx
37+ executable_bit : Self :: probe_file_mode ( root ) . unwrap_or ( ctx. executable_bit ) ,
3838 }
3939 }
4040
41+ #[ cfg( unix) ]
42+ fn probe_file_mode ( root : & Path ) -> std:: io:: Result < bool > {
43+ use std:: os:: unix:: fs:: { MetadataExt , OpenOptionsExt } ;
44+
45+ // test it exactly as we typically create executable files, not using chmod.
46+ let test_path = root. join ( "_test_executable_bit" ) ;
47+ let res = std:: fs:: OpenOptions :: new ( )
48+ . create_new ( true )
49+ . write ( true )
50+ . mode ( 0o777 )
51+ . open ( & test_path)
52+ . and_then ( |f| f. metadata ( ) . map ( |m| m. mode ( ) & 0o100 == 0o100 ) ) ;
53+ std:: fs:: remove_file ( test_path) ?;
54+ res
55+ }
56+
57+ #[ cfg( not( unix) ) ]
58+ fn probe_file_mode ( root : & Path ) -> std:: io:: Result < bool > {
59+ Ok ( false )
60+ }
61+
4162 fn probe_ignore_case ( git_dir : & Path ) -> std:: io:: Result < bool > {
4263 std:: fs:: metadata ( git_dir. join ( "cOnFiG" ) ) . map ( |_| true ) . or_else ( |err| {
4364 if err. kind ( ) == std:: io:: ErrorKind :: NotFound {
@@ -84,36 +105,36 @@ impl Context {
84105}
85106
86107#[ cfg( windows) ]
87- impl Default for Context {
108+ impl Default for Capabilities {
88109 fn default ( ) -> Self {
89- Context {
110+ Capabilities {
90111 precompose_unicode : false ,
91112 ignore_case : true ,
92- file_mode : false ,
113+ executable_bit : false ,
93114 symlink : false ,
94115 }
95116 }
96117}
97118
98119#[ cfg( target_os = "macos" ) ]
99- impl Default for Context {
120+ impl Default for Capabilities {
100121 fn default ( ) -> Self {
101- Context {
122+ Capabilities {
102123 precompose_unicode : true ,
103124 ignore_case : true ,
104- file_mode : true ,
125+ executable_bit : true ,
105126 symlink : true ,
106127 }
107128 }
108129}
109130
110131#[ cfg( all( unix, not( target_os = "macos" ) ) ) ]
111- impl Default for Context {
132+ impl Default for Capabilities {
112133 fn default ( ) -> Self {
113- Context {
134+ Capabilities {
114135 precompose_unicode : false ,
115136 ignore_case : false ,
116- file_mode : true ,
137+ executable_bit : true ,
117138 symlink : true ,
118139 }
119140 }
0 commit comments