@@ -375,7 +375,7 @@ func (r *repo) runGitQuiet(args ...string) ([]byte, []byte, error) {
375
375
defer cancel ()
376
376
377
377
stdout , stderr := & bytes.Buffer {}, & bytes.Buffer {}
378
- cmd := exec .CommandContext ( ctx , "git" , args ... )
378
+ cmd := exec .Command ( "git" , args ... )
379
379
if args [0 ] == "clone" {
380
380
// Small hack: if we're cloning, the root doesn't exist yet.
381
381
cmd .Dir = "/"
@@ -384,7 +384,7 @@ func (r *repo) runGitQuiet(args ...string) ([]byte, []byte, error) {
384
384
}
385
385
cmd .Env = append (os .Environ (), "HOME=" + r .mirror .homeDir )
386
386
cmd .Stdout , cmd .Stderr = stdout , stderr
387
- err := cmd . Run ( )
387
+ err := runCmdContext ( ctx , cmd )
388
388
return stdout .Bytes (), stderr .Bytes (), err
389
389
}
390
390
@@ -702,3 +702,31 @@ func handleDebugEnv(w http.ResponseWriter, r *http.Request) {
702
702
fmt .Fprintf (w , "%s\n " , kv )
703
703
}
704
704
}
705
+
706
+ // runCommandContext runs cmd controlled by ctx.
707
+ func runCmdContext (ctx context.Context , cmd * exec.Cmd ) error {
708
+ if err := cmd .Start (); err != nil {
709
+ return err
710
+ }
711
+ resChan := make (chan error , 1 )
712
+ go func () {
713
+ resChan <- cmd .Wait ()
714
+ }()
715
+
716
+ select {
717
+ case err := <- resChan :
718
+ return err
719
+ case <- ctx .Done ():
720
+ }
721
+ // Canceled. Interrupt and see if it ends voluntarily.
722
+ cmd .Process .Signal (os .Interrupt )
723
+ select {
724
+ case <- resChan :
725
+ return ctx .Err ()
726
+ case <- time .After (time .Second ):
727
+ }
728
+ // Didn't shut down in response to interrupt. Kill it hard.
729
+ cmd .Process .Kill ()
730
+ <- resChan
731
+ return ctx .Err ()
732
+ }
0 commit comments