mirror of https://github.com/Hilbis/Hilbish
feat!: add start function to jobs
the commit itself adds a few things but the main purpose is to facilitate a lua side start function that can restart the job there is a breaking change in the hilbish.job.add function; it is now required to provide an extra table for arguments, since the first cmd table isnt really what's actually ranextended-job-api
parent
827c25fb57
commit
c78d7f5627
70
exec.go
70
exec.go
|
@ -239,7 +239,7 @@ func execCommand(cmd string, terminalOut bool) (io.Writer, io.Writer, error) {
|
||||||
|
|
||||||
stmtStr := buf.String()
|
stmtStr := buf.String()
|
||||||
buf.Reset()
|
buf.Reset()
|
||||||
jobs.add(stmtStr)
|
jobs.add(stmtStr, []string{}, "")
|
||||||
}
|
}
|
||||||
|
|
||||||
interp.ExecHandler(execHandle(bg))(runner)
|
interp.ExecHandler(execHandle(bg))(runner)
|
||||||
|
@ -357,13 +357,15 @@ func execHandle(bg bool) interp.ExecHandlerFunc {
|
||||||
Stderr: hc.Stderr,
|
Stderr: hc.Stderr,
|
||||||
}
|
}
|
||||||
|
|
||||||
err = cmd.Start()
|
|
||||||
var j *job
|
var j *job
|
||||||
if bg {
|
if bg {
|
||||||
j = jobs.getLatest()
|
j = jobs.getLatest()
|
||||||
j.setHandle(cmd.Process)
|
j.setHandle(&cmd)
|
||||||
j.start(cmd.Process.Pid)
|
err = j.start()
|
||||||
|
} else {
|
||||||
|
err = cmd.Start()
|
||||||
}
|
}
|
||||||
|
|
||||||
if err == nil {
|
if err == nil {
|
||||||
if done := ctx.Done(); done != nil {
|
if done := ctx.Done(); done != nil {
|
||||||
go func() {
|
go func() {
|
||||||
|
@ -388,35 +390,8 @@ func execHandle(bg bool) interp.ExecHandlerFunc {
|
||||||
err = cmd.Wait()
|
err = cmd.Wait()
|
||||||
}
|
}
|
||||||
|
|
||||||
var exit uint8
|
exit := handleExecErr(err)
|
||||||
switch x := err.(type) {
|
|
||||||
case *exec.ExitError:
|
|
||||||
// started, but errored - default to 1 if OS
|
|
||||||
// doesn't have exit statuses
|
|
||||||
if status, ok := x.Sys().(syscall.WaitStatus); ok {
|
|
||||||
if status.Signaled() {
|
|
||||||
if ctx.Err() != nil {
|
|
||||||
return ctx.Err()
|
|
||||||
}
|
|
||||||
exit = uint8(128 + status.Signal())
|
|
||||||
goto end
|
|
||||||
}
|
|
||||||
exit = uint8(status.ExitStatus())
|
|
||||||
goto end
|
|
||||||
}
|
|
||||||
exit = 1
|
|
||||||
goto end
|
|
||||||
case *exec.Error:
|
|
||||||
// did not start
|
|
||||||
fmt.Fprintf(hc.Stderr, "%v\n", err)
|
|
||||||
exit = 127
|
|
||||||
goto end
|
|
||||||
case nil:
|
|
||||||
goto end
|
|
||||||
default:
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
end:
|
|
||||||
if bg {
|
if bg {
|
||||||
j.exitCode = int(exit)
|
j.exitCode = int(exit)
|
||||||
j.finish()
|
j.finish()
|
||||||
|
@ -425,6 +400,35 @@ func execHandle(bg bool) interp.ExecHandlerFunc {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func handleExecErr(err error) (exit uint8) {
|
||||||
|
ctx := context.TODO()
|
||||||
|
|
||||||
|
switch x := err.(type) {
|
||||||
|
case *exec.ExitError:
|
||||||
|
// started, but errored - default to 1 if OS
|
||||||
|
// doesn't have exit statuses
|
||||||
|
if status, ok := x.Sys().(syscall.WaitStatus); ok {
|
||||||
|
if status.Signaled() {
|
||||||
|
if ctx.Err() != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
exit = uint8(128 + status.Signal())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
exit = uint8(status.ExitStatus())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
exit = 1
|
||||||
|
return
|
||||||
|
case *exec.Error:
|
||||||
|
// did not start
|
||||||
|
//fmt.Fprintf(hc.Stderr, "%v\n", err)
|
||||||
|
exit = 127
|
||||||
|
default: return
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
func lookpath(file string) error { // custom lookpath function so we know if a command is found *and* is executable
|
func lookpath(file string) error { // custom lookpath function so we know if a command is found *and* is executable
|
||||||
var skip []string
|
var skip []string
|
||||||
if runtime.GOOS == "windows" {
|
if runtime.GOOS == "windows" {
|
||||||
|
|
99
job.go
99
job.go
|
@ -3,10 +3,12 @@ package main
|
||||||
import (
|
import (
|
||||||
"sync"
|
"sync"
|
||||||
"os"
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
|
||||||
"hilbish/util"
|
"hilbish/util"
|
||||||
|
|
||||||
rt "github.com/arnodel/golua/runtime"
|
rt "github.com/arnodel/golua/runtime"
|
||||||
|
"github.com/arnodel/golua/lib/iolib"
|
||||||
)
|
)
|
||||||
|
|
||||||
var jobs *jobHandler
|
var jobs *jobHandler
|
||||||
|
@ -17,18 +19,51 @@ type job struct {
|
||||||
id int
|
id int
|
||||||
pid int
|
pid int
|
||||||
exitCode int
|
exitCode int
|
||||||
proc *os.Process
|
once bool
|
||||||
|
args []string
|
||||||
|
// save path for a few reasons, one being security (lmao) while the other
|
||||||
|
// would just be so itll be the same binary command always (path changes)
|
||||||
|
path string
|
||||||
|
handle *exec.Cmd
|
||||||
|
stdin *iolib.File
|
||||||
|
stdout *iolib.File
|
||||||
|
stderr *iolib.File
|
||||||
}
|
}
|
||||||
|
|
||||||
func (j *job) start(pid int) {
|
func (j *job) start() error {
|
||||||
j.pid = pid
|
if j.handle == nil || j.once {
|
||||||
|
// cmd cant be reused so make a new one
|
||||||
|
cmd := exec.Cmd{
|
||||||
|
Path: j.path,
|
||||||
|
Args: j.args,
|
||||||
|
Stdin: j.getStdio("in"),
|
||||||
|
Stdout: j.getStdio("out"),
|
||||||
|
Stderr: j.getStdio("err"),
|
||||||
|
}
|
||||||
|
j.setHandle(&cmd)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !j.once {
|
||||||
|
j.once = true
|
||||||
|
}
|
||||||
|
|
||||||
|
err := j.handle.Start()
|
||||||
|
proc := j.getProc()
|
||||||
|
|
||||||
|
j.pid = proc.Pid
|
||||||
j.running = true
|
j.running = true
|
||||||
|
|
||||||
hooks.Em.Emit("job.start", j.lua())
|
hooks.Em.Emit("job.start", j.lua())
|
||||||
|
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (j *job) stop() {
|
func (j *job) stop() {
|
||||||
// finish will be called in exec handle
|
// finish will be called in exec handle
|
||||||
j.proc.Kill()
|
proc := j.getProc()
|
||||||
|
if proc != nil {
|
||||||
|
proc.Kill()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (j *job) finish() {
|
func (j *job) finish() {
|
||||||
|
@ -36,13 +71,38 @@ func (j *job) finish() {
|
||||||
hooks.Em.Emit("job.done", j.lua())
|
hooks.Em.Emit("job.done", j.lua())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (j *job) setHandle(handle *os.Process) {
|
func (j *job) setHandle(handle *exec.Cmd) {
|
||||||
j.proc = handle
|
j.handle = handle
|
||||||
|
j.args = handle.Args
|
||||||
|
j.path = handle.Path
|
||||||
|
}
|
||||||
|
|
||||||
|
func (j *job) getProc() *os.Process {
|
||||||
|
handle := j.handle
|
||||||
|
if handle != nil {
|
||||||
|
return handle.Process
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (j *job) getStdio(typ string) *os.File {
|
||||||
|
// TODO: make this use std io/out/err values from job struct,
|
||||||
|
// which are lua files
|
||||||
|
var stdio *os.File
|
||||||
|
switch typ {
|
||||||
|
case "in": stdio = os.Stdin
|
||||||
|
case "out": stdio = os.Stdout
|
||||||
|
case "err": stdio = os.Stderr
|
||||||
|
}
|
||||||
|
|
||||||
|
return stdio
|
||||||
}
|
}
|
||||||
|
|
||||||
func (j *job) lua() rt.Value {
|
func (j *job) lua() rt.Value {
|
||||||
jobFuncs := map[string]util.LuaExport{
|
jobFuncs := map[string]util.LuaExport{
|
||||||
"stop": {j.luaStop, 0, false},
|
"stop": {j.luaStop, 0, false},
|
||||||
|
"start": {j.luaStart, 0, false},
|
||||||
}
|
}
|
||||||
luaJob := rt.NewTable()
|
luaJob := rt.NewTable()
|
||||||
util.SetExports(l, luaJob, jobFuncs)
|
util.SetExports(l, luaJob, jobFuncs)
|
||||||
|
@ -56,6 +116,17 @@ func (j *job) lua() rt.Value {
|
||||||
return rt.TableValue(luaJob)
|
return rt.TableValue(luaJob)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (j *job) luaStart(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
||||||
|
if !j.running {
|
||||||
|
err := j.start()
|
||||||
|
exit := handleExecErr(err)
|
||||||
|
j.exitCode = int(exit)
|
||||||
|
j.finish()
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.Next(), nil
|
||||||
|
}
|
||||||
|
|
||||||
func (j *job) luaStop(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
func (j *job) luaStop(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
||||||
if j.running {
|
if j.running {
|
||||||
j.stop()
|
j.stop()
|
||||||
|
@ -79,7 +150,7 @@ func newJobHandler() *jobHandler {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (j *jobHandler) add(cmd string) *job {
|
func (j *jobHandler) add(cmd string, args []string, path string) *job {
|
||||||
j.mu.Lock()
|
j.mu.Lock()
|
||||||
defer j.mu.Unlock()
|
defer j.mu.Unlock()
|
||||||
|
|
||||||
|
@ -88,6 +159,7 @@ func (j *jobHandler) add(cmd string) *job {
|
||||||
cmd: cmd,
|
cmd: cmd,
|
||||||
running: false,
|
running: false,
|
||||||
id: j.latestID,
|
id: j.latestID,
|
||||||
|
args: args,
|
||||||
}
|
}
|
||||||
j.jobs[j.latestID] = jb
|
j.jobs[j.latestID] = jb
|
||||||
|
|
||||||
|
@ -145,8 +217,19 @@ func (j *jobHandler) luaAddJob(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
largs, err := c.TableArg(1)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
jb := j.add(cmd)
|
var args []string
|
||||||
|
util.ForEach(largs, func(k rt.Value, v rt.Value) {
|
||||||
|
if v.Type() == rt.StringType {
|
||||||
|
args = append(args, v.AsString())
|
||||||
|
}
|
||||||
|
})
|
||||||
|
// TODO: change to lookpath for args[0]
|
||||||
|
jb := j.add(cmd, args, args[0])
|
||||||
|
|
||||||
return c.PushingNext1(t.Runtime, jb.lua()), nil
|
return c.PushingNext1(t.Runtime, jb.lua()), nil
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue