diff --git a/cmd/run.go b/cmd/run.go index 20e864b7..4218cf81 100644 --- a/cmd/run.go +++ b/cmd/run.go @@ -4,9 +4,12 @@ import ( "ags/lib" "fmt" "io" + "log" "os" + "os/exec" "path/filepath" + "github.com/fsnotify/fsnotify" "github.com/spf13/cobra" ) @@ -15,6 +18,7 @@ var ( targetDir string logFile string args []string + watch bool ) var runCommand = &cobra.Command{ @@ -48,6 +52,7 @@ var runCommand = &cobra.Command{ func init() { f := runCommand.Flags() f.BoolVar(>k4, "gtk4", false, "preload Gtk4LayerShell") + f.BoolVar(&watch, "watch", false, "restart gjs on file changes") f.StringVarP(&targetDir, "directory", "d", defaultConfigDir(), `directory to search for an "app" entry file when no positional argument is given @@ -115,19 +120,79 @@ func run(infile string) { args = append([]string{"-m", outfile}, args...) stdout, stderr, file := logging() - gjs := lib.Exec("gjs", args...) - gjs.Stdin = os.Stdin - gjs.Dir = filepath.Dir(infile) + if file != nil { + defer file.Close() + } + + var gjs *exec.Cmd + gjsStart := func() (*exec.Cmd, error) { + if gjs != nil { + if err := gjs.Process.Kill(); err != nil { + log.Printf("Failed to kill process: %v", err) + } + _ = gjs.Wait() + } + + gjs = lib.Exec("gjs", args...) + gjs.Stdin = os.Stdin + gjs.Dir = filepath.Dir(infile) - gjs.Stdout = stdout - gjs.Stderr = stderr + gjs.Stdout = stdout + gjs.Stderr = stderr - // TODO: watch and restart - if err := gjs.Run(); err != nil { + err := gjs.Start() + + return gjs, err + } + + if err := watchRun(gjsStart); err != nil { lib.Err(err) } +} - if file != nil { - file.Close() +func watchRun(gjsStart func() (*exec.Cmd, error)) error { + cmd, err := gjsStart() + if err != nil { + return err } + if !watch { + return cmd.Wait() + } + + watcher, err := fsnotify.NewWatcher() + if err != nil { + return err + } + defer watcher.Close() + + go func() { + for { + select { + case event, ok := <-watcher.Events: + if !ok { + return + } + log.Println("event:", event) + if event.Has(fsnotify.Write) { + log.Println("modified file:", event.Name) + _, _ = gjsStart() + } + case err, ok := <-watcher.Errors: + if !ok { + return + } + log.Println("error:", err) + } + } + }() + + err = watcher.Add(targetDir) + if err != nil { + return err + } + + // Block main goroutine forever. + <-make(chan struct{}) + + return nil } diff --git a/go.mod b/go.mod index ed25d418..255fb856 100644 --- a/go.mod +++ b/go.mod @@ -4,12 +4,13 @@ go 1.22.2 require ( github.com/evanw/esbuild v0.24.0 + github.com/fsnotify/fsnotify v1.8.0 github.com/spf13/cobra v1.8.1 + github.com/titanous/json5 v1.0.0 ) require ( github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/spf13/pflag v1.0.5 // indirect - github.com/titanous/json5 v1.0.0 // indirect - golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8 // indirect + golang.org/x/sys v0.27.0 // indirect ) diff --git a/go.sum b/go.sum index 96075725..75c92b19 100644 --- a/go.sum +++ b/go.sum @@ -1,8 +1,14 @@ github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/evanw/esbuild v0.24.0 h1:GZ78naTLp7FKr+K7eNuM/SLs5maeiHYRPsTg6kmdsSE= github.com/evanw/esbuild v0.24.0/go.mod h1:D2vIQZqV/vIf/VRHtViaUtViZmG7o+kKmlBfVQuRi48= +github.com/fsnotify/fsnotify v1.8.0 h1:dAwr6QBTBZIkG8roQaJjGof0pp0EeF+tNV7YBP3F/8M= +github.com/fsnotify/fsnotify v1.8.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= +github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= +github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= +github.com/robertkrimen/otto v0.2.1 h1:FVP0PJ0AHIjC+N4pKCG9yCDz6LHNPCwi/GKID5pGGF0= +github.com/robertkrimen/otto v0.2.1/go.mod h1:UPwtJ1Xu7JrLcZjNWN8orJaM5n5YEtqL//farB5FlRY= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM= github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y= @@ -10,7 +16,12 @@ github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/titanous/json5 v1.0.0 h1:hJf8Su1d9NuI/ffpxgxQfxh/UiBFZX7bMPid0rIL/7s= github.com/titanous/json5 v1.0.0/go.mod h1:7JH1M8/LHKc6cyP5o5g3CSaRj+mBrIimTxzpvmckH8c= -golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8 h1:0A+M6Uqn+Eje4kHMK80dtF3JCXC4ykBgQG4Fe06QRhQ= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.27.0 h1:wBqf8DvsY9Y/2P8gAfPDEYNuS30J4lPHJxXSb/nJZ+s= +golang.org/x/sys v0.27.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/text v0.4.0 h1:BrVqGRd7+k1DiOgtnFvAkoQEWQvBc25ouMJM6429SFg= +golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/sourcemap.v1 v1.0.5 h1:inv58fC9f9J3TK2Y2R1NPntXEn3/wjWHkonhIUODNTI= +gopkg.in/sourcemap.v1 v1.0.5/go.mod h1:2RlvNNSMglmRrcvhfuzp4hQHwOtjxlbjX7UPY/GXb78= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/nix/default.nix b/nix/default.nix index 04e13ebf..4fac98c9 100644 --- a/nix/default.nix +++ b/nix/default.nix @@ -44,7 +44,7 @@ in path = lib.cleanSource ../.; }; - vendorHash = "sha256-Pw6UNT5YkDVz4HcH7b5LfOg+K3ohrBGPGB9wYGAQ9F4="; + vendorHash = "sha256-2CahD2POdmT4Xg+j79YBeDab9mReRB5n4DtDosM8j/I="; proxyVendor = true; nativeBuildInputs = [