From a75eac84908945bb722a39e94db4279b2fd52eee Mon Sep 17 00:00:00 2001 From: Max Claus Nunes Date: Sun, 22 Jul 2018 10:30:30 -0300 Subject: [PATCH] Improve watching search and configuration by improving default ignore Now it will ignore by default hidden files and folders, test files and vendor --- README.md | 18 +++++++++++++- cmd/gaper/main.go | 25 +++++++++++-------- gaper.go | 37 +++++++++++++++++----------- watcher.go | 61 +++++++++++++++++++++++++++++++++++------------ watcher_test.go | 36 ++++++++++++++++++++++++---- 5 files changed, 133 insertions(+), 44 deletions(-) diff --git a/README.md b/README.md index a1b227e..4907544 100644 --- a/README.md +++ b/README.md @@ -49,9 +49,9 @@ GLOBAL OPTIONS: --build-args value arguments used on building the program --program-args value arguments used on executing the program --verbose turns on the verbose messages from gaper + --disable-default-ignore turns off default ignore for hidden files and folders, "*_test.go" files, and vendor folder --watch value, -w value list of folders or files to watch for changes --ignore value, -i value list of folders or files to ignore for changes - (always ignores all hidden files and directories) --poll-interval value, -p value how often in milliseconds to poll watched files for changes (default: 500) --extensions value, -e value a comma-delimited list of file extensions to watch for changes (default: "go") --no-restart-on value, -n value don't automatically restart the supervised program if it ends: @@ -62,10 +62,26 @@ GLOBAL OPTIONS: --version, -v print the version ``` +Since in most projects there is no need to watch changes of: + +* hidden files and folders +* test files (`*_test.go`) +* vendor folder + +Gaper by default ignores those cases already. Although, if you need Gaper to watch those files anyway it is possible to disable this setting with `--disable-default-ignore` argument. + ### Examples +Using all defaults provided by Gaper: + +``` +gaper +``` + Ignore watch over all test files: +> no need for this in case you are not using `--disable-default-ignore` + ``` --ignore './**/*_test.go' ``` diff --git a/cmd/gaper/main.go b/cmd/gaper/main.go index 73e97f6..1b06ca2 100644 --- a/cmd/gaper/main.go +++ b/cmd/gaper/main.go @@ -17,16 +17,17 @@ var logger = gaper.NewLogger("gaper") func main() { parseArgs := func(c *cli.Context) *gaper.Config { return &gaper.Config{ - BinName: c.String("bin-name"), - BuildPath: c.String("build-path"), - BuildArgsMerged: c.String("build-args"), - ProgramArgsMerged: c.String("program-args"), - Verbose: c.Bool("verbose"), - WatchItems: c.StringSlice("watch"), - IgnoreItems: c.StringSlice("ignore"), - PollInterval: c.Int("poll-interval"), - Extensions: c.StringSlice("extensions"), - NoRestartOn: c.String("no-restart-on"), + BinName: c.String("bin-name"), + BuildPath: c.String("build-path"), + BuildArgsMerged: c.String("build-args"), + ProgramArgsMerged: c.String("program-args"), + Verbose: c.Bool("verbose"), + DisableDefaultIgnore: c.Bool("disable-default-ignore"), + WatchItems: c.StringSlice("watch"), + IgnoreItems: c.StringSlice("ignore"), + PollInterval: c.Int("poll-interval"), + Extensions: c.StringSlice("extensions"), + NoRestartOn: c.String("no-restart-on"), } } @@ -74,6 +75,10 @@ func main() { Name: "verbose", Usage: "turns on the verbose messages from gaper", }, + cli.BoolFlag{ + Name: "disable-default-ignore", + Usage: "turns off default ignore for hidden files and folders, \"*_test.go\" files, and vendor folder", + }, cli.StringSliceFlag{ Name: "watch, w", Usage: "list of folders or files to watch for changes", diff --git a/gaper.go b/gaper.go index e9319d4..c5d044e 100644 --- a/gaper.go +++ b/gaper.go @@ -37,19 +37,20 @@ var exitStatusError = 1 // Config contains all settings supported by gaper type Config struct { - BinName string - BuildPath string - BuildArgs []string - BuildArgsMerged string - ProgramArgs []string - ProgramArgsMerged string - WatchItems []string - IgnoreItems []string - PollInterval int - Extensions []string - NoRestartOn string - Verbose bool - WorkingDirectory string + BinName string + BuildPath string + BuildArgs []string + BuildArgsMerged string + ProgramArgs []string + ProgramArgsMerged string + WatchItems []string + IgnoreItems []string + PollInterval int + Extensions []string + NoRestartOn string + Verbose bool + DisableDefaultIgnore bool + WorkingDirectory string } // Run starts the whole gaper process watching for file changes or exit codes @@ -61,9 +62,17 @@ func Run(cfg *Config, chOSSiginal chan os.Signal) error { return err } + wCfg := WatcherConfig{ + DefaultIgnore: !cfg.DisableDefaultIgnore, + PollInterval: cfg.PollInterval, + WatchItems: cfg.WatchItems, + IgnoreItems: cfg.IgnoreItems, + Extensions: cfg.Extensions, + } + builder := NewBuilder(cfg.BuildPath, cfg.BinName, cfg.WorkingDirectory, cfg.BuildArgs) runner := NewRunner(os.Stdout, os.Stderr, filepath.Join(cfg.WorkingDirectory, builder.Binary()), cfg.ProgramArgs) - watcher, err := NewWatcher(cfg.PollInterval, cfg.WatchItems, cfg.IgnoreItems, cfg.Extensions) + watcher, err := NewWatcher(wCfg) if err != nil { return fmt.Errorf("watcher error: %v", err) } diff --git a/watcher.go b/watcher.go index 07bff43..1772532 100644 --- a/watcher.go +++ b/watcher.go @@ -20,6 +20,7 @@ type Watcher interface { // watcher is a interface for the watch process type watcher struct { + defaultIgnore bool pollInterval int watchItems map[string]bool ignoreItems map[string]bool @@ -28,27 +29,36 @@ type watcher struct { errors chan error } +// WatcherConfig defines the settings available for the watcher +type WatcherConfig struct { + DefaultIgnore bool + PollInterval int + WatchItems []string + IgnoreItems []string + Extensions []string +} + // NewWatcher creates a new watcher -func NewWatcher(pollInterval int, watchItems []string, ignoreItems []string, extensions []string) (Watcher, error) { - if pollInterval == 0 { - pollInterval = DefaultPoolInterval +func NewWatcher(cfg WatcherConfig) (Watcher, error) { + if cfg.PollInterval == 0 { + cfg.PollInterval = DefaultPoolInterval } - if len(extensions) == 0 { - extensions = DefaultExtensions + if len(cfg.Extensions) == 0 { + cfg.Extensions = DefaultExtensions } allowedExts := make(map[string]bool) - for _, ext := range extensions { + for _, ext := range cfg.Extensions { allowedExts["."+ext] = true } - watchPaths, err := resolvePaths(watchItems, allowedExts) + watchPaths, err := resolvePaths(cfg.WatchItems, allowedExts) if err != nil { return nil, err } - ignorePaths, err := resolvePaths(ignoreItems, allowedExts) + ignorePaths, err := resolvePaths(cfg.IgnoreItems, allowedExts) if err != nil { return nil, err } @@ -58,7 +68,8 @@ func NewWatcher(pollInterval int, watchItems []string, ignoreItems []string, ext return &watcher{ events: make(chan string), errors: make(chan error), - pollInterval: pollInterval, + defaultIgnore: cfg.DefaultIgnore, + pollInterval: cfg.PollInterval, watchItems: watchPaths, ignoreItems: ignorePaths, allowedExtensions: allowedExts, @@ -105,12 +116,7 @@ func (w *watcher) scanChange(watchPath string) (string, error) { var fileChanged string err := filepath.Walk(watchPath, func(path string, info os.FileInfo, err error) error { - // always ignore hidden files and directories - if dir := filepath.Base(path); dir[0] == '.' && dir != "." { - return skipFile(info) - } - - if _, ignored := w.ignoreItems[path]; ignored { + if w.ignoreFile(path, info) { return skipFile(info) } @@ -130,6 +136,31 @@ func (w *watcher) scanChange(watchPath string) (string, error) { return fileChanged, nil } +func (w *watcher) ignoreFile(path string, info os.FileInfo) bool { + // check if preset ignore is enabled + if w.defaultIgnore { + // check for hidden files and directories + if name := info.Name(); name[0] == '.' && name != "." { + return true + } + + // check if it is a Go testing file + if strings.HasSuffix(path, "_test.go") { + return true + } + + // check if it is the vendor folder + if info.IsDir() && info.Name() == "vendor" { + return true + } + } + + if _, ignored := w.ignoreItems[path]; ignored { + return true + } + return false +} + func resolvePaths(paths []string, extensions map[string]bool) (map[string]bool, error) { result := map[string]bool{} diff --git a/watcher_test.go b/watcher_test.go index d6816b3..7f42432 100644 --- a/watcher_test.go +++ b/watcher_test.go @@ -16,7 +16,14 @@ func TestWatcherDefaultValues(t *testing.T) { var ignoreItems []string var extensions []string - wt, err := NewWatcher(pollInterval, watchItems, ignoreItems, extensions) + wCfg := WatcherConfig{ + DefaultIgnore: true, + PollInterval: pollInterval, + WatchItems: watchItems, + IgnoreItems: ignoreItems, + Extensions: extensions, + } + wt, err := NewWatcher(wCfg) expectedPath := "testdata/server" if runtime.GOOS == OSWindows { @@ -37,7 +44,14 @@ func TestWatcherGlobPath(t *testing.T) { ignoreItems := []string{"./testdata/**/*_test.go"} var extensions []string - wt, err := NewWatcher(pollInterval, watchItems, ignoreItems, extensions) + wCfg := WatcherConfig{ + DefaultIgnore: true, + PollInterval: pollInterval, + WatchItems: watchItems, + IgnoreItems: ignoreItems, + Extensions: extensions, + } + wt, err := NewWatcher(wCfg) assert.Nil(t, err, "wacher error") w := wt.(*watcher) assert.Equal(t, map[string]bool{"testdata/server/main_test.go": true}, w.ignoreItems) @@ -49,7 +63,14 @@ func TestWatcherRemoveOverlapdPaths(t *testing.T) { ignoreItems := []string{"./testdata/**/*", "./testdata/server"} var extensions []string - wt, err := NewWatcher(pollInterval, watchItems, ignoreItems, extensions) + wCfg := WatcherConfig{ + DefaultIgnore: true, + PollInterval: pollInterval, + WatchItems: watchItems, + IgnoreItems: ignoreItems, + Extensions: extensions, + } + wt, err := NewWatcher(wCfg) assert.Nil(t, err, "wacher error") w := wt.(*watcher) assert.Equal(t, map[string]bool{"./testdata/server": true}, w.ignoreItems) @@ -69,7 +90,14 @@ func TestWatcherWatchChange(t *testing.T) { ignoreItems := []string{testfile} extensions := []string{"go"} - w, err := NewWatcher(pollInterval, watchItems, ignoreItems, extensions) + wCfg := WatcherConfig{ + DefaultIgnore: true, + PollInterval: pollInterval, + WatchItems: watchItems, + IgnoreItems: ignoreItems, + Extensions: extensions, + } + w, err := NewWatcher(wCfg) assert.Nil(t, err, "wacher error") go w.Watch()