Adding upstream version 3.10.8.
Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
parent
37e9b6d587
commit
03bfe4079e
356 changed files with 28857 additions and 0 deletions
152
util/exec.go
Normal file
152
util/exec.go
Normal file
|
@ -0,0 +1,152 @@
|
|||
// Copyright Earl Warren <contact@earl-warren.org>
|
||||
// Copyright Loïc Dachary <loic@dachary.org>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package util
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
|
||||
"code.forgejo.org/f3/gof3/v3/logger"
|
||||
)
|
||||
|
||||
type CommandOptions struct {
|
||||
ExitCodes []int
|
||||
Log logger.MessageInterface
|
||||
}
|
||||
|
||||
func (o *CommandOptions) setDefaults() {
|
||||
if o.ExitCodes == nil {
|
||||
o.ExitCodes = []int{0}
|
||||
}
|
||||
if o.Log == nil {
|
||||
o.Log = logger.NewLogger()
|
||||
}
|
||||
}
|
||||
|
||||
func CommandWithErr(ctx context.Context, options CommandOptions, prog string, args ...string) (err error) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
var ok bool
|
||||
err, ok = r.(error)
|
||||
if !ok {
|
||||
panic(r)
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
CommandWithOptions(ctx, options, prog, args...)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func Command(ctx context.Context, log logger.MessageInterface, prog string, args ...string) string {
|
||||
options := CommandOptions{
|
||||
Log: log,
|
||||
}
|
||||
return CommandWithOptions(ctx, options, prog, args...)
|
||||
}
|
||||
|
||||
func CommandWithOptions(ctx context.Context, options CommandOptions, prog string, args ...string) string {
|
||||
if ctx == nil {
|
||||
panic("ctx context.Context is nil")
|
||||
}
|
||||
options.setDefaults()
|
||||
options.Log.Log(1, logger.Trace, "%s\n", args)
|
||||
cmd := exec.Command(prog, args...)
|
||||
SetSysProcAttribute(cmd)
|
||||
var out bytes.Buffer
|
||||
cmd.Stdout = &out
|
||||
cmd.Stderr = &out
|
||||
cmd.Env = append(
|
||||
cmd.Env,
|
||||
"GIT_TERMINAL_PROMPT=0",
|
||||
)
|
||||
|
||||
err := cmd.Start()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
ctxErr := watchCtx(ctx, cmd.Process)
|
||||
err = cmd.Wait()
|
||||
interruptErr := <-ctxErr
|
||||
// If cmd.Wait returned an error, prefer that.
|
||||
// Otherwise, report any error from the interrupt goroutine.
|
||||
if interruptErr != nil && err == nil {
|
||||
err = interruptErr
|
||||
}
|
||||
|
||||
var code int
|
||||
if err == nil {
|
||||
code = 0
|
||||
} else if exiterr, ok := err.(*exec.ExitError); ok {
|
||||
code = exiterr.ExitCode()
|
||||
if code == -1 {
|
||||
panic("killed")
|
||||
}
|
||||
} else {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
found := false
|
||||
for _, valid := range options.ExitCodes {
|
||||
if valid == code {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
panic(fmt.Errorf("%w: exit code: %d, %v, %v, %v", err, code, out.String(), prog, args))
|
||||
}
|
||||
options.Log.Log(1, logger.Trace, "%s\n", out.String())
|
||||
return out.String()
|
||||
}
|
||||
|
||||
// wrappedError wraps an error without relying on fmt.Errorf.
|
||||
type wrappedError struct {
|
||||
prefix string
|
||||
err error
|
||||
}
|
||||
|
||||
func (w wrappedError) Error() string {
|
||||
return w.prefix + ": " + w.err.Error()
|
||||
}
|
||||
|
||||
func (w wrappedError) Unwrap() error {
|
||||
return w.err
|
||||
}
|
||||
|
||||
func watchCtx(ctx context.Context, p *os.Process) <-chan error {
|
||||
if ctx == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
errc := make(chan error)
|
||||
go func() {
|
||||
select {
|
||||
case errc <- nil:
|
||||
return
|
||||
case <-ctx.Done():
|
||||
}
|
||||
|
||||
var err error
|
||||
if killErr := kill(p); killErr == nil {
|
||||
// We appear to have successfully delivered a kill signal, so any
|
||||
// program behavior from this point may be due to ctx.
|
||||
err = ctx.Err()
|
||||
} else if !errors.Is(killErr, os.ErrProcessDone) {
|
||||
err = wrappedError{
|
||||
prefix: "util: exec: error sending signal",
|
||||
err: killErr,
|
||||
}
|
||||
}
|
||||
errc <- err
|
||||
}()
|
||||
|
||||
return errc
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue