From 4a70260ea53ba5c7162b51bc02f16d37a951ec1c Mon Sep 17 00:00:00 2001 From: Zoe <62722391+juls0730@users.noreply.github.com> Date: Mon, 6 Oct 2025 15:54:31 -0500 Subject: [PATCH] Better debugging, and several bug fixes This commit brings a greater experience for developers working on ZQDGR, and also fixes a number of bugs. The following bugs have been fixed: - Scripts that died in watch mode did not restart once changes were made - Created and deleted files did not cause a reload - script.Stop is now used in every place where we kill the process, this ensures that the process is *eventually* actually killed --- main.go | 44 +++++++++++++++++++++++++------------------ watcher.go | 48 +++++++++++++++++++++++++++-------------------- zqdgr.config.json | 2 +- 3 files changed, 55 insertions(+), 39 deletions(-) diff --git a/main.go b/main.go index 89d9d72..c1d9137 100644 --- a/main.go +++ b/main.go @@ -8,6 +8,7 @@ import ( "flag" "fmt" "log" + "log/slog" "net/http" "os" "os/exec" @@ -15,6 +16,7 @@ import ( "path" "path/filepath" "runtime" + "strconv" "strings" "sync" "syscall" @@ -231,6 +233,8 @@ func (s *Script) Stop(lock bool) error { } func (s *Script) Restart() error { + slog.Debug("Restarting script", "script", s.scriptName) + s.mutex.Lock() err := s.Stop(false) @@ -325,6 +329,9 @@ func (zqdgr *ZQDGR) loadConfig() error { } func main() { + var err error + var debugMode bool + noWs := flag.Bool("no-ws", false, "Disable WebSocket server") configDir := flag.String("config", ".", "Path to the config directory") disableReloadConfig := flag.Bool("no-reload-config", false, "Do not restart ZQDGR on config file change") @@ -332,6 +339,18 @@ func main() { flag.Parse() + debugModeVal, ok := os.LookupEnv("ZQDGR_DEBUG") + if ok { + debugMode, err = strconv.ParseBool(debugModeVal) + if err != nil { + log.Fatal(err) + } + + if debugMode { + slog.SetLogLoggerLevel(slog.LevelDebug) + } + } + originalArgs := os.Args os.Args = flag.Args() @@ -525,19 +544,7 @@ func main() { log.Println("Received signal, exiting...") if script.command != nil { - var signal syscall.Signal - switch zqdgr.Config.ShutdownSignal { - case "SIGINT": - signal = syscall.SIGINT - case "SIGTERM": - signal = syscall.SIGTERM - case "SIGQUIT": - signal = syscall.SIGQUIT - default: - signal = syscall.SIGKILL - } - - syscall.Kill(-script.command.Process.Pid, signal) + script.Stop(true) } os.Exit(0) @@ -645,15 +652,15 @@ func main() { if !ok { timer = time.AfterFunc(waitFor, func() { + slog.Debug("FSnotify event received", "event", event) + if event.Op&fsnotify.Remove == fsnotify.Remove || event.Op&fsnotify.Write == fsnotify.Write || event.Op&fsnotify.Create == fsnotify.Create { - if os.Getenv("ZQDGR_DEBUG") != "" { - fmt.Println("File changed:", event.Name) - } + slog.Debug("File changed", "file", event.Name) if strings.HasSuffix(event.Name, "zqdgr.config.json") { // re-exec the exact same command if !*disableReloadConfig { - log.Println("zqdgr.config.json has changed, restarting...") + fmt.Println("zqdgr.config.json has changed, restarting...") executable, err := os.Executable() if err != nil { log.Fatal(err) @@ -673,7 +680,8 @@ func main() { } } - if directoryShouldBeTracked(&watcherConfig, event.Name) { + if pathShouldBeTracked(&watcherConfig, event.Name) && event.Op&fsnotify.Create == fsnotify.Create { + slog.Debug("Adding new file to watcher", "file", event.Name) watcher.(NotifyWatcher).watcher.Add(event.Name) } diff --git a/watcher.go b/watcher.go index 1c4f88e..7c80691 100644 --- a/watcher.go +++ b/watcher.go @@ -4,7 +4,7 @@ import ( "errors" "fmt" "log" - "os" + "log/slog" "path/filepath" "strings" @@ -34,7 +34,9 @@ func (g *globList) Matches(value string) bool { func matchesPattern(pattern []string, path string) bool { for _, p := range pattern { + slog.Debug("checking path against pattern", "pattern", p, "path", path) if matched, _ := doublestar.Match(p, path); matched { + slog.Debug("path matches pattern", "pattern", p, "path", path) return true } } @@ -42,17 +44,13 @@ func matchesPattern(pattern []string, path string) bool { return false } -func directoryShouldBeTracked(cfg *WatcherConfig, path string) bool { +func pathShouldBeTracked(cfg *WatcherConfig, path string) bool { base := filepath.Dir(path) - if os.Getenv("ZQDGR_DEBUG") != "" { - log.Printf("checking %s against %s %v\n", path, base, *cfg) - } + slog.Debug("checking file against path", "path", path, "base", base) if cfg.excludedGlobs.Matches(base) { - if os.Getenv("ZQDGR_DEBUG") != "" { - log.Printf("%s is excluded\n", base) - } + slog.Debug("file is excluded", "path", path) return false } @@ -86,9 +84,7 @@ func (n NotifyWatcher) Close() error { } func (n NotifyWatcher) AddFile(path string) error { - if os.Getenv("ZQDGR_DEBUG") != "" { - log.Printf("manually adding file\n") - } + slog.Debug("manually adding file", "file", path) return n.add(path) } @@ -125,24 +121,36 @@ func NewWatcher(cfg *WatcherConfig) (FileWatcher, error) { func addFiles(fw FileWatcher) error { cfg := fw.getConfig() for _, pattern := range cfg.pattern { - if os.Getenv("ZQDGR_DEBUG") != "" { - fmt.Printf("processing glob %s\n", pattern) - } + slog.Debug("adding pattern", "pattern", pattern) matches, err := doublestar.Glob(pattern) if err != nil { log.Fatalf("Bad pattern \"%s\": %s", pattern, err.Error()) } + trackedDirs := make(map[string]bool) for _, match := range matches { - if os.Getenv("ZQDGR_DEBUG") != "" { - log.Printf("checking %s\n", match) + base := filepath.Dir(match) + // this allows us to track file creations and deletions + if !trackedDirs[base] { + if cfg.excludedGlobs.Matches(base) { + slog.Debug("directory is excluded", "file", match) + continue + } + + trackedDirs[base] = true + + slog.Debug("adding directory", "dir", base) + + if err := fw.add(base); err != nil { + return fmt.Errorf("FileWatcher.Add(): %v", err) + } } - if directoryShouldBeTracked(cfg, match) { - if os.Getenv("ZQDGR_DEBUG") != "" { - log.Printf("%s is not excluded\n", match) - } + slog.Debug("adding file", "file", match) + + if pathShouldBeTracked(cfg, match) { + slog.Debug("path should be tracked", "file", match) if err := fw.add(match); err != nil { return fmt.Errorf("FileWatcher.Add(): %v", err) diff --git a/zqdgr.config.json b/zqdgr.config.json index 57fb854..0056870 100644 --- a/zqdgr.config.json +++ b/zqdgr.config.json @@ -1,6 +1,6 @@ { "name": "zqdgr", - "version": "0.0.4a", + "version": "0.0.5", "description": "zqdgr is a quick and dirty Golang runner", "author": "juls0730", "license": "BSL-1.0",