cmd/gitmirror: kill subprocesses with SIGINT before SIGKILL
Hopefully this fixes golang/go#38887 by allowing the git command to
clean up its subprocesses.
Fixes golang/go#38887.
Change-Id: Iefcb2ee7591a8bfad0df44381a320d27a8f5b4fb
Reviewed-on: https://go-review.googlesource.com/c/build/+/325771
Trust: Heschi Kreinick <heschi@google.com>
Trust: Bryan C. Mills <bcmills@google.com>
Run-TryBot: Heschi Kreinick <heschi@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Dmitri Shuralyov <dmitshur@golang.org>
diff --git a/cmd/gitmirror/gitmirror.go b/cmd/gitmirror/gitmirror.go
index 38b87d2..c128703 100644
--- a/cmd/gitmirror/gitmirror.go
+++ b/cmd/gitmirror/gitmirror.go
@@ -375,7 +375,7 @@
defer cancel()
stdout, stderr := &bytes.Buffer{}, &bytes.Buffer{}
- cmd := exec.CommandContext(ctx, "git", args...)
+ cmd := exec.Command("git", args...)
if args[0] == "clone" {
// Small hack: if we're cloning, the root doesn't exist yet.
cmd.Dir = "/"
@@ -384,7 +384,7 @@
}
cmd.Env = append(os.Environ(), "HOME="+r.mirror.homeDir)
cmd.Stdout, cmd.Stderr = stdout, stderr
- err := cmd.Run()
+ err := runCmdContext(ctx, cmd)
return stdout.Bytes(), stderr.Bytes(), err
}
@@ -702,3 +702,31 @@
fmt.Fprintf(w, "%s\n", kv)
}
}
+
+// runCommandContext runs cmd controlled by ctx.
+func runCmdContext(ctx context.Context, cmd *exec.Cmd) error {
+ if err := cmd.Start(); err != nil {
+ return err
+ }
+ resChan := make(chan error, 1)
+ go func() {
+ resChan <- cmd.Wait()
+ }()
+
+ select {
+ case err := <-resChan:
+ return err
+ case <-ctx.Done():
+ }
+ // Canceled. Interrupt and see if it ends voluntarily.
+ cmd.Process.Signal(os.Interrupt)
+ select {
+ case <-resChan:
+ return ctx.Err()
+ case <-time.After(time.Second):
+ }
+ // Didn't shut down in response to interrupt. Kill it hard.
+ cmd.Process.Kill()
+ <-resChan
+ return ctx.Err()
+}