initial commit
This commit is contained in:
commit
e269ff8aea
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
icon.png
|
8
go.mod
Normal file
8
go.mod
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
module tildegit.org/jande/gohrl
|
||||||
|
|
||||||
|
go 1.18
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/mattn/go-gtk v0.0.0-20191030024613-af2e013261f5 // indirect
|
||||||
|
github.com/mqu/go-notify v0.0.0-20130719194048-ef6f6f49d093 // indirect
|
||||||
|
)
|
4
go.sum
Normal file
4
go.sum
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
github.com/mattn/go-gtk v0.0.0-20191030024613-af2e013261f5 h1:GMB3MVJnxysGrSvjWGsgK8L3XGI3F4etQQq37Py6W5A=
|
||||||
|
github.com/mattn/go-gtk v0.0.0-20191030024613-af2e013261f5/go.mod h1:PwzwfeB5syFHXORC3MtPylVcjIoTDT/9cvkKpEndGVI=
|
||||||
|
github.com/mqu/go-notify v0.0.0-20130719194048-ef6f6f49d093 h1:OvySnanP8CQIKS+MTq9AXBwEXzm0YaKeu331bWql3ug=
|
||||||
|
github.com/mqu/go-notify v0.0.0-20130719194048-ef6f6f49d093/go.mod h1:AthsKyBZ9hqwU7DBWFiOxYObyF8nVyYVubXv/pQNC5E=
|
227
main.go
Normal file
227
main.go
Normal file
|
@ -0,0 +1,227 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"hash/fnv"
|
||||||
|
"io"
|
||||||
|
"io/fs"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"os/signal"
|
||||||
|
"path/filepath"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"syscall"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/mqu/go-notify"
|
||||||
|
)
|
||||||
|
|
||||||
|
func logg(v ...any) {
|
||||||
|
spr := fmt.Sprintln(v...)
|
||||||
|
fmt.Print("\x1B[32m", time.Now().Format("15:04:05.000"), " \x1B[93m", spr[:len(spr)-1], "\x1B[0m\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
func getChildPID(pid int) int {
|
||||||
|
get, _ := filepath.Glob("/proc/" + strconv.Itoa(pid) + "/task/*/children")
|
||||||
|
for _, x := range get {
|
||||||
|
dat, err := os.ReadFile(x)
|
||||||
|
if err != nil {
|
||||||
|
logg(err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if len(dat) <= 1 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
npid, err := strconv.Atoi(string(dat)[:len(dat)-1])
|
||||||
|
if err != nil {
|
||||||
|
logg(err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
cmdl, err := os.ReadFile("/proc/" + strconv.Itoa(npid) + "/cmdline")
|
||||||
|
if err != nil {
|
||||||
|
logg(err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if !strings.HasPrefix(string(cmdl), "/tmp/go-build") {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
return npid
|
||||||
|
}
|
||||||
|
return pid
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
notify.Init("gohrl")
|
||||||
|
|
||||||
|
name := os.Args[1]
|
||||||
|
args := os.Args[2:]
|
||||||
|
|
||||||
|
cont := true
|
||||||
|
|
||||||
|
sc := make(chan os.Signal, 1)
|
||||||
|
exit := make(chan struct{}, 1)
|
||||||
|
change := make(chan struct{}, 1)
|
||||||
|
|
||||||
|
signal.Notify(sc, syscall.SIGINT, syscall.SIGTERM, os.Interrupt, os.Kill)
|
||||||
|
|
||||||
|
var cmd *exec.Cmd
|
||||||
|
|
||||||
|
var changes []string
|
||||||
|
go func() {
|
||||||
|
hash()
|
||||||
|
var ok bool
|
||||||
|
|
||||||
|
for {
|
||||||
|
time.Sleep(time.Second)
|
||||||
|
|
||||||
|
changes, ok = hash()
|
||||||
|
if !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
change <- struct{}{}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
var not *notify.NotifyNotification
|
||||||
|
|
||||||
|
for cont {
|
||||||
|
logg("starting:", name, args)
|
||||||
|
|
||||||
|
cmd = exec.Command(name, args...)
|
||||||
|
cmd.Stdout = os.Stdout
|
||||||
|
cmd.Stderr = os.Stderr
|
||||||
|
cmd.Stdin = os.Stdin
|
||||||
|
|
||||||
|
pid := 0
|
||||||
|
|
||||||
|
wait := make(chan struct{})
|
||||||
|
go func() {
|
||||||
|
cmd.Start()
|
||||||
|
pid = cmd.Process.Pid
|
||||||
|
for i := 0; pid == cmd.Process.Pid && i < 1200; i++ {
|
||||||
|
select {
|
||||||
|
case <-exit:
|
||||||
|
exit<-struct{}{}
|
||||||
|
break
|
||||||
|
case <-change:
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
time.Sleep(time.Millisecond * 100)
|
||||||
|
pid = getChildPID(cmd.Process.Pid)
|
||||||
|
}
|
||||||
|
logg("PID:", pid)
|
||||||
|
|
||||||
|
wait <- struct{}{}
|
||||||
|
cmd.Wait()
|
||||||
|
|
||||||
|
logg("program exited")
|
||||||
|
exit <- struct{}{}
|
||||||
|
}()
|
||||||
|
logg("waiting for start")
|
||||||
|
<-wait
|
||||||
|
|
||||||
|
if not != nil {
|
||||||
|
not.Update("updated applied", "now running", "/data/drive/jan/hotreload/icon.png")
|
||||||
|
not.Show()
|
||||||
|
}
|
||||||
|
|
||||||
|
kill := func() {
|
||||||
|
syscall.Kill(pid, syscall.SIGINT)
|
||||||
|
|
||||||
|
t := time.NewTimer(time.Second * 10)
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-exit:
|
||||||
|
return
|
||||||
|
case <-t.C:
|
||||||
|
logg("program didn't exit: killing")
|
||||||
|
syscall.Kill(cmd.Process.Pid, syscall.SIGTERM)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-sc:
|
||||||
|
logg("inturrupting")
|
||||||
|
cont = false
|
||||||
|
kill()
|
||||||
|
case <-change:
|
||||||
|
logg("change to code detected")
|
||||||
|
not = notify.NotificationNew("updating", strings.Join(changes, "\n"), "/data/drive/jan/hotreload/icon.png")
|
||||||
|
not.SetTimeout(2500)
|
||||||
|
not.Show()
|
||||||
|
|
||||||
|
logg("waiting for exit")
|
||||||
|
kill()
|
||||||
|
logg("restarting to apply update")
|
||||||
|
|
||||||
|
case <-exit:
|
||||||
|
logg("exit receieved, restarting")
|
||||||
|
if !cmd.ProcessState.Success() {
|
||||||
|
logg("possible error, waiting for next update")
|
||||||
|
<-change
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
time.Sleep(time.Second)
|
||||||
|
logg("releasing")
|
||||||
|
cmd.Process.Release()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var hashes = make(map[string][]byte)
|
||||||
|
|
||||||
|
var pt = false
|
||||||
|
|
||||||
|
func hash() ([]string, bool) {
|
||||||
|
dif := false
|
||||||
|
var changes = []string{}
|
||||||
|
|
||||||
|
err := filepath.WalkDir(".", func(path string, d fs.DirEntry, err error) error {
|
||||||
|
if !strings.HasSuffix(d.Name(), ".go") {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
dat, err := os.Open(filepath.Join(path))
|
||||||
|
defer dat.Close()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
var pfx = make([]byte, len("package"))
|
||||||
|
dat.Read(pfx)
|
||||||
|
if string(pfx) != "package" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
dat.Seek(0, 0)
|
||||||
|
|
||||||
|
h := fnv.New128()
|
||||||
|
_, err = io.Copy(h, dat)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
var b []byte
|
||||||
|
b = h.Sum(b)
|
||||||
|
|
||||||
|
if bytes.Compare(hashes[dat.Name()], b) != 0 {
|
||||||
|
if pt {
|
||||||
|
logg(dat.Name(), "changed, recompiling and reloading")
|
||||||
|
changes = append(changes, dat.Name())
|
||||||
|
}
|
||||||
|
dif = true
|
||||||
|
}
|
||||||
|
hashes[dat.Name()] = b
|
||||||
|
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalln(err)
|
||||||
|
}
|
||||||
|
pt = true
|
||||||
|
|
||||||
|
return changes, dif
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user