1
+ use git_config:: parse:: section;
2
+ use git_discover:: DOT_GIT_DIR ;
3
+ use std:: convert:: TryFrom ;
1
4
use std:: {
2
5
fs:: { self , OpenOptions } ,
3
6
io:: Write ,
4
7
path:: { Path , PathBuf } ,
5
8
} ;
6
9
7
- use crate :: bstr:: ByteSlice ;
8
-
9
10
/// The error used in [`into()`].
10
11
#[ derive( Debug , thiserror:: Error ) ]
11
12
#[ allow( missing_docs) ]
@@ -22,8 +23,6 @@ pub enum Error {
22
23
CreateDirectory { source : std:: io:: Error , path : PathBuf } ,
23
24
}
24
25
25
- const GIT_DIR_NAME : & str = ".git" ;
26
-
27
26
const TPL_INFO_EXCLUDE : & [ u8 ] = include_bytes ! ( "assets/baseline-init/info/exclude" ) ;
28
27
const TPL_HOOKS_APPLYPATCH_MSG : & [ u8 ] = include_bytes ! ( "assets/baseline-init/hooks/applypatch-msg.sample" ) ;
29
28
const TPL_HOOKS_COMMIT_MSG : & [ u8 ] = include_bytes ! ( "assets/baseline-init/hooks/commit-msg.sample" ) ;
@@ -37,7 +36,6 @@ const TPL_HOOKS_PRE_REBASE: &[u8] = include_bytes!("assets/baseline-init/hooks/p
37
36
const TPL_HOOKS_PRE_RECEIVE : & [ u8 ] = include_bytes ! ( "assets/baseline-init/hooks/pre-receive.sample" ) ;
38
37
const TPL_HOOKS_PREPARE_COMMIT_MSG : & [ u8 ] = include_bytes ! ( "assets/baseline-init/hooks/prepare-commit-msg.sample" ) ;
39
38
const TPL_HOOKS_UPDATE : & [ u8 ] = include_bytes ! ( "assets/baseline-init/hooks/update.sample" ) ;
40
- const TPL_CONFIG : & [ u8 ] = include_bytes ! ( "assets/baseline-init/config" ) ;
41
39
const TPL_DESCRIPTION : & [ u8 ] = include_bytes ! ( "assets/baseline-init/description" ) ;
42
40
const TPL_HEAD : & [ u8 ] = include_bytes ! ( "assets/baseline-init/HEAD" ) ;
43
41
@@ -99,14 +97,22 @@ fn create_dir(p: &Path) -> Result<(), Error> {
99
97
}
100
98
101
99
/// Options for use in [`into()`];
100
+ #[ derive( Copy , Clone ) ]
102
101
pub struct Options {
103
102
/// If true, the repository will be a bare repository without a worktree.
104
103
pub bare : bool ,
104
+
105
+ /// If set, use these filesytem capabilities to populate the respective git-config fields.
106
+ /// If `None`, the directory will be probed.
107
+ pub fs_capabilities : Option < git_worktree:: fs:: Capabilities > ,
105
108
}
106
109
107
110
/// Create a new `.git` repository of `kind` within the possibly non-existing `directory`
108
111
/// and return its path.
109
- pub fn into ( directory : impl Into < PathBuf > , Options { bare } : Options ) -> Result < git_discover:: repository:: Path , Error > {
112
+ pub fn into (
113
+ directory : impl Into < PathBuf > ,
114
+ Options { bare, fs_capabilities } : Options ,
115
+ ) -> Result < git_discover:: repository:: Path , Error > {
110
116
let mut dot_git = directory. into ( ) ;
111
117
112
118
if bare {
@@ -121,7 +127,7 @@ pub fn into(directory: impl Into<PathBuf>, Options { bare }: Options) -> Result<
121
127
return Err ( Error :: DirectoryNotEmpty { path : dot_git } ) ;
122
128
}
123
129
} else {
124
- dot_git. push ( GIT_DIR_NAME ) ;
130
+ dot_git. push ( DOT_GIT_DIR ) ;
125
131
126
132
if dot_git. is_dir ( ) {
127
133
return Err ( Error :: DirectoryExists { path : dot_git } ) ;
@@ -166,19 +172,29 @@ pub fn into(directory: impl Into<PathBuf>, Options { bare }: Options) -> Result<
166
172
create_dir ( PathCursor ( cursor. as_mut ( ) ) . at ( "tags" ) ) ?;
167
173
}
168
174
169
- for ( tpl, filename) in & [
170
- ( TPL_HEAD , "HEAD" ) ,
171
- ( TPL_DESCRIPTION , "description" ) ,
172
- ( TPL_CONFIG , "config" ) ,
173
- ] {
174
- if * filename == "config" {
175
- write_file (
176
- & tpl. replace ( "{bare-value}" , if bare { "true" } else { "false" } ) ,
177
- PathCursor ( & mut dot_git) . at ( filename) ,
178
- ) ?;
179
- } else {
180
- write_file ( tpl, PathCursor ( & mut dot_git) . at ( filename) ) ?;
175
+ for ( tpl, filename) in & [ ( TPL_HEAD , "HEAD" ) , ( TPL_DESCRIPTION , "description" ) ] {
176
+ write_file ( tpl, PathCursor ( & mut dot_git) . at ( filename) ) ?;
177
+ }
178
+
179
+ {
180
+ let mut config = git_config:: File :: default ( ) ;
181
+ {
182
+ let caps = fs_capabilities. unwrap_or_else ( || git_worktree:: fs:: Capabilities :: probe ( & dot_git) ) ;
183
+ let mut core = config. new_section ( "core" , None ) . expect ( "valid section name" ) ;
184
+
185
+ core. push ( key ( "repositoryformatversion" ) , "0" ) ;
186
+ core. push ( key ( "filemode" ) , bool ( caps. executable_bit ) ) ;
187
+ core. push ( key ( "bare" ) , bool ( bare) ) ;
188
+ core. push ( key ( "logallrefupdates" ) , bool ( !bare) ) ;
189
+ core. push ( key ( "symlinks" ) , bool ( caps. symlink ) ) ;
190
+ core. push ( key ( "ignorecase" ) , bool ( caps. ignore_case ) ) ;
191
+ core. push ( key ( "precomposeunicode" ) , bool ( caps. precompose_unicode ) ) ;
181
192
}
193
+ let config_path = dot_git. join ( "config" ) ;
194
+ std:: fs:: write ( & config_path, & config. to_bstring ( ) ) . map_err ( |err| Error :: IoWrite {
195
+ source : err,
196
+ path : config_path,
197
+ } ) ?;
182
198
}
183
199
184
200
Ok ( git_discover:: repository:: Path :: from_dot_git_dir (
@@ -187,3 +203,14 @@ pub fn into(directory: impl Into<PathBuf>, Options { bare }: Options) -> Result<
187
203
. unwrap_or ( git_discover:: repository:: Kind :: WorkTree { linked_git_dir : None } ) ,
188
204
) )
189
205
}
206
+
207
+ fn key ( name : & ' static str ) -> section:: Key < ' static > {
208
+ section:: Key :: try_from ( name) . expect ( "valid key name" )
209
+ }
210
+
211
+ fn bool ( v : bool ) -> & ' static str {
212
+ match v {
213
+ true => "true" ,
214
+ false => "false" ,
215
+ }
216
+ }
0 commit comments