diff --git a/internal/gps/cmd_unix.go b/internal/gps/cmd_unix.go index f5a5f4156b..906369ea41 100644 --- a/internal/gps/cmd_unix.go +++ b/internal/gps/cmd_unix.go @@ -11,6 +11,7 @@ import ( "context" "os" "os/exec" + "syscall" "time" "github.com/pkg/errors" @@ -25,11 +26,26 @@ type cmd struct { } func commandContext(ctx context.Context, name string, arg ...string) cmd { - // Grab the caller's context and pass a derived one to CommandContext. - c := cmd{ctx: ctx} - ctx, cancel := context.WithCancel(ctx) - c.Cmd = exec.CommandContext(ctx, name, arg...) - c.cancel = cancel + // Create a one-off cancellable context for use by the CommandContext, in + // the event that we have to force a Process.Kill(). + ctx2, cancel := context.WithCancel(context.Background()) + + c := cmd{ + Cmd: exec.CommandContext(ctx2, name, arg...), + cancel: cancel, + ctx: ctx, + } + + // Force subprocesses into their own process group, rather than being in the + // same process group as the dep process. Because Ctrl-C sent from a + // terminal will send the signal to the entire currently running process + // group, this allows us to directly manage the issuance of signals to + // subprocesses. + c.Cmd.SysProcAttr = &syscall.SysProcAttr{ + Setpgid: true, + Pgid: 0, + } + return c } @@ -47,6 +63,7 @@ func (c cmd) CombinedOutput() ([]byte, error) { var b bytes.Buffer c.Cmd.Stdout = &b c.Cmd.Stderr = &b + if err := c.Cmd.Start(); err != nil { return nil, err } diff --git a/internal/gps/source_manager.go b/internal/gps/source_manager.go index 23f3c1c8b5..926c623231 100644 --- a/internal/gps/source_manager.go +++ b/internal/gps/source_manager.go @@ -741,6 +741,29 @@ const ( ctExportTree ) +func (ct callType) String() string { + switch ct { + case ctHTTPMetadata: + return "Retrieving go get metadata" + case ctListVersions: + return "Retrieving latest version list" + case ctGetManifestAndLock: + return "Reading manifest and lock data" + case ctListPackages: + return "Parsing PackageTree" + case ctSourcePing: + return "Checking for upstream existence" + case ctSourceInit: + return "Initializing local source cache" + case ctSourceFetch: + return "Fetching latest data into local source cache" + case ctExportTree: + return "Writing code tree out to disk" + default: + panic("unknown calltype") + } +} + // callInfo provides metadata about an ongoing call. type callInfo struct { name string