From da82b7f536c42c4651b7620cee01da295691e3c2 Mon Sep 17 00:00:00 2001 From: maddalax Date: Sun, 13 Oct 2024 16:33:08 -0500 Subject: [PATCH] config wip --- cli/htmgo/go.mod | 2 + cli/htmgo/go.sum | 2 + cli/htmgo/internal/dirutil/dir.go | 5 +++ cli/htmgo/internal/dirutil/glob.go | 50 +++++++++++++++++++++++ cli/htmgo/tasks/copyassets/bundle.go | 2 +- cli/htmgo/watcher.go | 61 +++++++++++++++++----------- framework/config/default.yml | 1 + framework/config/project.go | 55 +++++++++++++++++++++++++ htmgo-site/htmgo.yml | 5 +++ 9 files changed, 158 insertions(+), 25 deletions(-) create mode 100644 cli/htmgo/internal/dirutil/glob.go create mode 100644 framework/config/default.yml create mode 100644 framework/config/project.go create mode 100644 htmgo-site/htmgo.yml diff --git a/cli/htmgo/go.mod b/cli/htmgo/go.mod index 6bad2bb..ba191b9 100644 --- a/cli/htmgo/go.mod +++ b/cli/htmgo/go.mod @@ -11,3 +11,5 @@ require ( golang.org/x/sys v0.25.0 golang.org/x/tools v0.25.0 ) + +require github.com/bmatcuk/doublestar/v4 v4.7.1 // indirect diff --git a/cli/htmgo/go.sum b/cli/htmgo/go.sum index b8b03a7..87e7902 100644 --- a/cli/htmgo/go.sum +++ b/cli/htmgo/go.sum @@ -1,3 +1,5 @@ +github.com/bmatcuk/doublestar/v4 v4.7.1 h1:fdDeAqgT47acgwd9bd9HxJRDmc9UAmPpc+2m0CXv75Q= +github.com/bmatcuk/doublestar/v4 v4.7.1/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc= github.com/dave/jennifer v1.7.1 h1:B4jJJDHelWcDhlRQxWeo0Npa/pYKBLrirAQoTN45txo= github.com/dave/jennifer v1.7.1/go.mod h1:nXbxhEmQfOZhWml3D1cDK5M1FLnMSozpbFN/m3RmGZc= github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= diff --git a/cli/htmgo/internal/dirutil/dir.go b/cli/htmgo/internal/dirutil/dir.go index 2715277..7063e83 100644 --- a/cli/htmgo/internal/dirutil/dir.go +++ b/cli/htmgo/internal/dirutil/dir.go @@ -4,6 +4,7 @@ import ( "errors" "fmt" "github.com/maddalax/htmgo/cli/htmgo/tasks/process" + "github.com/maddalax/htmgo/framework/config" "io" "log/slog" "os" @@ -17,6 +18,10 @@ func HasFileFromRoot(file string) bool { return err == nil } +func GetConfig() *config.ProjectConfig { + return config.FromConfigFile(process.GetWorkingDir()) +} + func CreateHtmgoDir() { if !HasFileFromRoot("__htmgo") { CreateDirFromRoot("__htmgo") diff --git a/cli/htmgo/internal/dirutil/glob.go b/cli/htmgo/internal/dirutil/glob.go new file mode 100644 index 0000000..3e015c2 --- /dev/null +++ b/cli/htmgo/internal/dirutil/glob.go @@ -0,0 +1,50 @@ +package dirutil + +import ( + "fmt" + "github.com/bmatcuk/doublestar/v4" + "io/fs" + "path/filepath" +) + +func matchesAny(patterns []string, path string) bool { + for _, pattern := range patterns { + matched, err := doublestar.Match(pattern, path) + if err != nil { + fmt.Printf("Error matching pattern: %v\n", err) + return false + } + if matched { + return true + } + } + return false +} + +func IsGlobExclude(path string, excludePatterns []string) bool { + return matchesAny(excludePatterns, path) +} + +func IsGlobMatch(path string, patterns []string, excludePatterns []string) bool { + if matchesAny(excludePatterns, path) { + return false + } + return matchesAny(patterns, path) +} + +func GlobMatchDirs(root string, includePatterns, excludePatterns []string, cb func(string)) { + //directories := map[string]bool{} + // Walk through the directory recursively + _ = filepath.WalkDir(root, func(path string, d fs.DirEntry, err error) error { + if err != nil { + return err + } + if matchesAny(excludePatterns, path) { + return fs.SkipDir + } + if matchesAny(includePatterns, path) { + cb(path) + } + return nil + }) +} diff --git a/cli/htmgo/tasks/copyassets/bundle.go b/cli/htmgo/tasks/copyassets/bundle.go index a24da76..f0f7699 100644 --- a/cli/htmgo/tasks/copyassets/bundle.go +++ b/cli/htmgo/tasks/copyassets/bundle.go @@ -92,7 +92,7 @@ func CopyAssets() { }) } - if !dirutil.HasFileFromRoot("tailwind.config.js") { + if dirutil.GetConfig().Tailwind && !dirutil.HasFileFromRoot("tailwind.config.js") { err = dirutil.CopyFile( filepath.Join(assetCssDir, "tailwind.config.js"), filepath.Join(process.GetWorkingDir(), "tailwind.config.js"), diff --git a/cli/htmgo/watcher.go b/cli/htmgo/watcher.go index 0509b3d..5af47b7 100644 --- a/cli/htmgo/watcher.go +++ b/cli/htmgo/watcher.go @@ -1,9 +1,11 @@ package main import ( + "fmt" "github.com/fsnotify/fsnotify" "github.com/google/uuid" "github.com/maddalax/htmgo/cli/htmgo/internal" + "github.com/maddalax/htmgo/cli/htmgo/internal/dirutil" "github.com/maddalax/htmgo/cli/htmgo/tasks/module" "log" "log/slog" @@ -13,11 +15,10 @@ import ( "time" ) -var ignoredDirs = []string{".git", ".idea", "node_modules", "vendor"} - func startWatcher(cb func(version string, file []*fsnotify.Event)) { events := make([]*fsnotify.Event, 0) debouncer := internal.NewDebouncer(500 * time.Millisecond) + config := dirutil.GetConfig() defer func() { if r := recover(); r != nil { @@ -42,16 +43,17 @@ func startWatcher(cb func(version string, file []*fsnotify.Event)) { } if event.Has(fsnotify.Remove) { - info, err := os.Stat(event.Name) - if err != nil { + if dirutil.IsGlobMatch(event.Name, config.WatchFiles, config.WatchIgnore) { + watcher.Remove(event.Name) continue } - if info.IsDir() { - _ = watcher.Remove(event.Name) - } } if event.Has(fsnotify.Create) { + if dirutil.IsGlobMatch(event.Name, config.WatchFiles, config.WatchIgnore) { + watcher.Add(event.Name) + continue + } info, err := os.Stat(event.Name) if err != nil { slog.Error("Error getting file info:", slog.String("path", event.Name), slog.String("error", err.Error())) @@ -67,20 +69,22 @@ func startWatcher(cb func(version string, file []*fsnotify.Event)) { } } - if event.Has(fsnotify.Write) || event.Has(fsnotify.Remove) || event.Has(fsnotify.Rename) { - events = append(events, &event) - debouncer.Do(func() { - seen := make(map[string]bool) - dedupe := make([]*fsnotify.Event, 0) - for _, e := range events { - if _, ok := seen[e.Name]; !ok { - seen[e.Name] = true - dedupe = append(dedupe, e) + if dirutil.IsGlobMatch(event.Name, config.WatchFiles, config.WatchIgnore) { + if event.Has(fsnotify.Write) || event.Has(fsnotify.Remove) || event.Has(fsnotify.Rename) { + events = append(events, &event) + debouncer.Do(func() { + seen := make(map[string]bool) + dedupe := make([]*fsnotify.Event, 0) + for _, e := range events { + if _, ok := seen[e.Name]; !ok { + seen[e.Name] = true + dedupe = append(dedupe, e) + } } - } - cb(uuid.NewString()[0:6], dedupe) - events = make([]*fsnotify.Event, 0) - }) + cb(uuid.NewString()[0:6], dedupe) + events = make([]*fsnotify.Event, 0) + }) + } } case err, ok := <-watcher.Errors: if !ok { @@ -101,17 +105,25 @@ func startWatcher(cb func(version string, file []*fsnotify.Event)) { watcher.Add(assetPath) } + go func() { + for { + time.Sleep(time.Second * 5) + files := watcher.WatchList() + count := len(files) + fmt.Printf("Watching %d dirs\n", count) + } + }() + // Walk through the root directory and add all subdirectories to the watcher err = filepath.Walk(rootDir, func(path string, info os.FileInfo, err error) error { if err != nil { return err } // Ignore directories in the ignoredDirs list - for _, ignoredDir := range ignoredDirs { - if ignoredDir == info.Name() { - return filepath.SkipDir - } + if dirutil.IsGlobExclude(path, config.WatchIgnore) { + return filepath.SkipDir } + // Only watch directories if info.IsDir() { err = watcher.Add(path) @@ -123,6 +135,7 @@ func startWatcher(cb func(version string, file []*fsnotify.Event)) { } return nil }) + if err != nil { log.Fatal(err) } diff --git a/framework/config/default.yml b/framework/config/default.yml new file mode 100644 index 0000000..bd7be9a --- /dev/null +++ b/framework/config/default.yml @@ -0,0 +1 @@ +tailwind: true diff --git a/framework/config/project.go b/framework/config/project.go new file mode 100644 index 0000000..a3cd1d2 --- /dev/null +++ b/framework/config/project.go @@ -0,0 +1,55 @@ +package config + +import ( + "gopkg.in/yaml.v3" + "os" + "path" +) + +type ProjectConfig struct { + Tailwind bool `yaml:"tailwind"` + WatchIgnore []string `yaml:"watch_ignore"` + WatchFiles []string `yaml:"watch_files"` +} + +func DefaultProjectConfig() *ProjectConfig { + return &ProjectConfig{ + Tailwind: true, + WatchIgnore: []string{ + "node_modules", ".git", ".idea", "assets/dist", + }, + WatchFiles: []string{ + "**/*.go", "**/*.html", "**/*.css", "**/*.js", "**/*.json", "**/*.yaml", "**/*.yml", + }, + } +} + +func (cfg *ProjectConfig) EnhanceWithDefaults() *ProjectConfig { + defaultCfg := DefaultProjectConfig() + if len(cfg.WatchFiles) == 0 { + cfg.WatchFiles = defaultCfg.WatchFiles + } + if len(cfg.WatchIgnore) == 0 { + cfg.WatchIgnore = defaultCfg.WatchIgnore + } + return cfg +} + +func FromConfigFile(workingDir string) *ProjectConfig { + defaultCfg := DefaultProjectConfig() + names := []string{"htmgo.yaml", "htmgo.yml", "_htmgo.yaml", "_htmgo.yml"} + for _, name := range names { + filePath := path.Join(workingDir, name) + if _, err := os.Stat(filePath); err == nil { + cfg := &ProjectConfig{} + bytes, err := os.ReadFile(filePath) + if err == nil { + err = yaml.Unmarshal(bytes, cfg) + if err == nil { + return cfg.EnhanceWithDefaults() + } + } + } + } + return defaultCfg +} diff --git a/htmgo-site/htmgo.yml b/htmgo-site/htmgo.yml new file mode 100644 index 0000000..67500d7 --- /dev/null +++ b/htmgo-site/htmgo.yml @@ -0,0 +1,5 @@ +tailwind: true +# which directories to ignore when watching for changes, supports glob patterns +watch_ignore: [".git", "node_modules", "dist/*"] +# files to watch for changes that are not included by default, supports glob patterns +watch_files: ["**/*.go", "**/*.css"]