@@ -65,17 +65,17 @@ pub(crate) fn run_pre_commit_hook(repo: &gix::Repository, use_editor: bool) -> R
65
65
return Ok ( false ) ;
66
66
} ;
67
67
68
- let workdir = repo
69
- . work_dir ( )
70
- . expect ( "should not get this far with a bare repo" ) ;
68
+ let work_dir = repo. work_dir ( ) . expect ( "not a bare repo" ) ;
71
69
72
70
let mut hook_command = std:: process:: Command :: new ( hook_path) ;
71
+ hook_command. current_dir ( work_dir) ;
73
72
if !use_editor {
74
73
hook_command. env ( "GIT_EDITOR" , ":" ) ;
75
74
}
76
75
76
+ let mut hook_command = make_sh_command_on_windows ( hook_command) ;
77
+
77
78
let status = hook_command
78
- . current_dir ( workdir)
79
79
. stdin ( std:: process:: Stdio :: null ( ) )
80
80
. status ( )
81
81
. with_context ( || format ! ( "`{hook_name}` hook" ) ) ?;
@@ -128,6 +128,8 @@ pub(crate) fn run_commit_msg_hook<'repo>(
128
128
129
129
hook_command. arg ( temp_msg. filename ( ) ) ;
130
130
131
+ let mut hook_command = make_sh_command_on_windows ( hook_command) ;
132
+
131
133
let status = hook_command
132
134
. status ( )
133
135
. with_context ( || format ! ( "`{hook_name}` hook" ) ) ?;
@@ -207,3 +209,50 @@ fn is_executable(meta: &std::fs::Metadata) -> bool {
207
209
fn is_executable ( _meta : & std:: fs:: Metadata ) -> bool {
208
210
true
209
211
}
212
+
213
+ #[ cfg( not( windows) ) ]
214
+ fn make_sh_command_on_windows ( command : std:: process:: Command ) -> std:: process:: Command {
215
+ command
216
+ }
217
+
218
+ #[ cfg( windows) ]
219
+ fn make_sh_command_on_windows ( command : std:: process:: Command ) -> std:: process:: Command {
220
+ let hook_path = command
221
+ . get_program ( )
222
+ . to_str ( )
223
+ . expect ( "path to hook is valid UTF-8" ) ;
224
+ assert ! ( !hook_path. contains( '"' ) ) ;
225
+ assert ! ( !hook_path. contains( '\'' ) ) ;
226
+
227
+ let mut command_str = String :: new ( ) ;
228
+ command_str. push ( '"' ) ;
229
+ command_str. push_str ( hook_path) ;
230
+ command_str. push ( '"' ) ;
231
+ for arg in command. get_args ( ) {
232
+ let arg = arg. to_str ( ) . expect ( "hook args are valid UTF-8" ) ;
233
+ assert ! ( !arg. contains( '"' ) ) ;
234
+ assert ! ( !arg. contains( '\'' ) ) ;
235
+ command_str. push ( ' ' ) ;
236
+ command_str. push ( '"' ) ;
237
+ command_str. push_str ( arg) ;
238
+ command_str. push ( '"' ) ;
239
+ }
240
+
241
+ let mut sh_command = std:: process:: Command :: new ( "sh" ) ;
242
+ sh_command. arg ( "-c" ) ;
243
+ sh_command. arg ( command_str) ;
244
+
245
+ for ( k, opt_v) in command. get_envs ( ) {
246
+ if let Some ( v) = opt_v {
247
+ sh_command. env ( k, v) ;
248
+ } else {
249
+ sh_command. env_remove ( k) ;
250
+ }
251
+ }
252
+
253
+ if let Some ( cur_dir) = command. get_current_dir ( ) {
254
+ sh_command. current_dir ( cur_dir) ;
255
+ }
256
+
257
+ sh_command
258
+ }
0 commit comments