Compare commits

..

6 Commits

Author SHA1 Message Date
TorchedSammy 8fdde4aa58
chore: remove unused code 2022-05-21 12:47:21 -04:00
TorchedSammy dde56cbb4f
feat: make disown command get last job if id isnt suppied as arg 2022-05-21 11:54:07 -04:00
TorchedSammy bbff7098c2
feat: add jobs.last function to get last job 2022-05-21 11:53:44 -04:00
TorchedSammy b3a5c0e67c
feat: add disown command 2022-05-21 11:38:26 -04:00
TorchedSammy fc40bad092
fix: stop jobs on exit 2022-05-21 11:38:02 -04:00
TorchedSammy db6817e4ca
feat: add disown function 2022-05-21 11:37:19 -04:00
4 changed files with 105 additions and 13 deletions

75
job.go
View File

@ -1,15 +1,16 @@
package main package main
import ( import (
"errors"
"io" "io"
"os" "os"
"os/exec" "os/exec"
"sync" "sync"
"syscall"
"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
@ -73,6 +74,10 @@ func (j *job) finish() {
hooks.Em.Emit("job.done", j.lua()) hooks.Em.Emit("job.done", j.lua())
} }
func (j *job) wait() {
j.handle.Wait()
}
func (j *job) setHandle(handle *exec.Cmd) { func (j *job) setHandle(handle *exec.Cmd) {
j.handle = handle j.handle = handle
j.args = handle.Args j.args = handle.Args
@ -91,14 +96,6 @@ func (j *job) getProc() *os.Process {
return nil return nil
} }
func (j *job) setStdio(typ string, f *iolib.File) {
switch typ {
case "in": j.stdin = f.File
case "out": j.stdout = f.File
case "err": j.stderr = f.File
}
}
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},
@ -178,11 +175,41 @@ func (j *jobHandler) getLatest() *job {
return j.jobs[j.latestID] return j.jobs[j.latestID]
} }
func (j *jobHandler) disown(id int) error {
j.mu.RLock()
if j.jobs[id] == nil {
return errors.New("job doesnt exist")
}
j.mu.RUnlock()
j.mu.Lock()
delete(j.jobs, id)
j.mu.Unlock()
return nil
}
func (j *jobHandler) stopAll() {
j.mu.RLock()
defer j.mu.RUnlock()
for _, jb := range j.jobs {
// on exit, unix shell should send sighup to all jobs
if jb.running {
proc := jb.getProc()
proc.Signal(syscall.SIGHUP)
jb.wait() // waits for program to exit due to sighup
}
}
}
func (j *jobHandler) loader(rtm *rt.Runtime) *rt.Table { func (j *jobHandler) loader(rtm *rt.Runtime) *rt.Table {
jobFuncs := map[string]util.LuaExport{ jobFuncs := map[string]util.LuaExport{
"all": {j.luaAllJobs, 0, false}, "all": {j.luaAllJobs, 0, false},
"last": {j.luaLastJob, 0, false},
"get": {j.luaGetJob, 1, false}, "get": {j.luaGetJob, 1, false},
"add": {j.luaAddJob, 2, false}, "add": {j.luaAddJob, 2, false},
"disown": {j.luaDisownJob, 1, false},
} }
luaJob := rt.NewTable() luaJob := rt.NewTable()
@ -247,3 +274,33 @@ func (j *jobHandler) luaAllJobs(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
return c.PushingNext1(t.Runtime, rt.TableValue(jobTbl)), nil return c.PushingNext1(t.Runtime, rt.TableValue(jobTbl)), nil
} }
func (j *jobHandler) luaDisownJob(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
if err := c.Check1Arg(); err != nil {
return nil, err
}
jobID, err := c.IntArg(0)
if err != nil {
return nil, err
}
err = j.disown(int(jobID))
if err != nil {
return nil, err
}
return c.Next(), nil
}
func (j *jobHandler) luaLastJob(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
j.mu.RLock()
defer j.mu.RUnlock()
job := j.jobs[j.latestID]
if job == nil { // incase we dont have any jobs yet
return c.Next(), nil
}
return c.PushingNext1(t.Runtime, job.lua()), nil
}

11
main.go
View File

@ -221,6 +221,8 @@ input:
} }
fmt.Printf("\u001b[7m∆\u001b[0m" + strings.Repeat(" ", termwidth - 1) + "\r") fmt.Printf("\u001b[7m∆\u001b[0m" + strings.Repeat(" ", termwidth - 1) + "\r")
} }
exit(0)
} }
func continuePrompt(prev string) (string, error) { func continuePrompt(prev string) (string, error) {
@ -296,10 +298,17 @@ func contains(s []string, e string) bool {
} }
func exit(code int) { func exit(code int) {
// wait for all timers to finish before exiting jobs.stopAll()
// wait for all timers to finish before exiting.
// only do that when not interactive
if !interactive {
for { for {
if timers.running == 0 { if timers.running == 0 {
os.Exit(code) os.Exit(code)
} }
} }
}
os.Exit(code)
} }

View File

@ -0,0 +1,25 @@
local commander = require 'commander'
commander.register('disown', function(args)
if #hilbish.jobs.all() == 0 then
print 'disown: no current job'
return 1
end
local id
if #args < 0 then
id = tonumber(args[1])
if not id then
print 'disown: invalid id for job'
return 1
end
else
id = hilbish.jobs.last().id
end
local ok = pcall(hilbish.jobs.disown, id)
if not ok then
print 'disown: job does not exist'
return 2
end
end)

View File

@ -4,3 +4,4 @@ require 'nature.commands.cdr'
require 'nature.commands.doc' require 'nature.commands.doc'
require 'nature.commands.exit' require 'nature.commands.exit'
require 'nature.commands.guide' require 'nature.commands.guide'
require 'nature.commands.disown'