mirror of
https://github.com/stashapp/stash.git
synced 2025-12-11 02:42:43 +01:00
104 lines
2.1 KiB
Go
104 lines
2.1 KiB
Go
package astikit
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"os/exec"
|
|
"strings"
|
|
"sync"
|
|
)
|
|
|
|
// Statuses
|
|
const (
|
|
ExecStatusCrashed = "crashed"
|
|
ExecStatusRunning = "running"
|
|
ExecStatusStopped = "stopped"
|
|
)
|
|
|
|
// ExecHandler represents an object capable of handling the execution of a cmd
|
|
type ExecHandler struct {
|
|
cancel context.CancelFunc
|
|
ctx context.Context
|
|
err error
|
|
o sync.Once
|
|
stopped bool
|
|
}
|
|
|
|
// Status returns the cmd status
|
|
func (h *ExecHandler) Status() string {
|
|
if h.ctx.Err() != nil {
|
|
if h.stopped || h.err == nil {
|
|
return ExecStatusStopped
|
|
}
|
|
return ExecStatusCrashed
|
|
}
|
|
return ExecStatusRunning
|
|
}
|
|
|
|
// Stop stops the cmd
|
|
func (h *ExecHandler) Stop() {
|
|
h.o.Do(func() {
|
|
h.cancel()
|
|
h.stopped = true
|
|
})
|
|
}
|
|
|
|
// ExecCmdOptions represents exec options
|
|
type ExecCmdOptions struct {
|
|
Args []string
|
|
CmdAdapter func(cmd *exec.Cmd, h *ExecHandler) error
|
|
Name string
|
|
StopFunc func(cmd *exec.Cmd) error
|
|
}
|
|
|
|
// ExecCmd executes a cmd
|
|
// The process will be stopped when the worker stops
|
|
func ExecCmd(w *Worker, o ExecCmdOptions) (h *ExecHandler, err error) {
|
|
// Create handler
|
|
h = &ExecHandler{}
|
|
h.ctx, h.cancel = context.WithCancel(w.Context())
|
|
|
|
// Create command
|
|
cmd := exec.Command(o.Name, o.Args...)
|
|
|
|
// Adapt command
|
|
if o.CmdAdapter != nil {
|
|
if err = o.CmdAdapter(cmd, h); err != nil {
|
|
err = fmt.Errorf("astikit: adapting cmd failed: %w", err)
|
|
return
|
|
}
|
|
}
|
|
|
|
// Start
|
|
w.Logger().Infof("astikit: starting %s", strings.Join(cmd.Args, " "))
|
|
if err = cmd.Start(); err != nil {
|
|
err = fmt.Errorf("astikit: executing %s: %w", strings.Join(cmd.Args, " "), err)
|
|
return
|
|
}
|
|
|
|
// Handle context
|
|
go func() {
|
|
// Wait for context to be done
|
|
<-h.ctx.Done()
|
|
|
|
// Get stop func
|
|
f := func() error { return cmd.Process.Kill() }
|
|
if o.StopFunc != nil {
|
|
f = func() error { return o.StopFunc(cmd) }
|
|
}
|
|
|
|
// Stop
|
|
if err = f(); err != nil {
|
|
w.Logger().Error(fmt.Errorf("astikit: stopping cmd failed: %w", err))
|
|
return
|
|
}
|
|
}()
|
|
|
|
// Execute in a task
|
|
w.NewTask().Do(func() {
|
|
h.err = cmd.Wait()
|
|
h.cancel()
|
|
w.Logger().Infof("astikit: status is now %s for %s", h.Status(), strings.Join(cmd.Args, " "))
|
|
})
|
|
return
|
|
}
|