initial commit

This commit is contained in:
Jan Delta 2022-11-26 17:03:33 +09:00
commit e269ff8aea
4 changed files with 240 additions and 0 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
icon.png

8
go.mod Normal file
View 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
View 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
View 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
}