Improve watching search and configuration by improving default ignore

Now it will ignore by default hidden files and folders, test files and vendor
This commit is contained in:
Max Claus Nunes 2018-07-22 10:30:30 -03:00
parent 586c834cb9
commit a75eac8490
5 changed files with 133 additions and 44 deletions

View File

@ -49,9 +49,9 @@ GLOBAL OPTIONS:
--build-args value arguments used on building the program --build-args value arguments used on building the program
--program-args value arguments used on executing the program --program-args value arguments used on executing the program
--verbose turns on the verbose messages from gaper --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 --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 --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) --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") --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: --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 --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 ### Examples
Using all defaults provided by Gaper:
```
gaper
```
Ignore watch over all test files: Ignore watch over all test files:
> no need for this in case you are not using `--disable-default-ignore`
``` ```
--ignore './**/*_test.go' --ignore './**/*_test.go'
``` ```

View File

@ -17,16 +17,17 @@ var logger = gaper.NewLogger("gaper")
func main() { func main() {
parseArgs := func(c *cli.Context) *gaper.Config { parseArgs := func(c *cli.Context) *gaper.Config {
return &gaper.Config{ return &gaper.Config{
BinName: c.String("bin-name"), BinName: c.String("bin-name"),
BuildPath: c.String("build-path"), BuildPath: c.String("build-path"),
BuildArgsMerged: c.String("build-args"), BuildArgsMerged: c.String("build-args"),
ProgramArgsMerged: c.String("program-args"), ProgramArgsMerged: c.String("program-args"),
Verbose: c.Bool("verbose"), Verbose: c.Bool("verbose"),
WatchItems: c.StringSlice("watch"), DisableDefaultIgnore: c.Bool("disable-default-ignore"),
IgnoreItems: c.StringSlice("ignore"), WatchItems: c.StringSlice("watch"),
PollInterval: c.Int("poll-interval"), IgnoreItems: c.StringSlice("ignore"),
Extensions: c.StringSlice("extensions"), PollInterval: c.Int("poll-interval"),
NoRestartOn: c.String("no-restart-on"), Extensions: c.StringSlice("extensions"),
NoRestartOn: c.String("no-restart-on"),
} }
} }
@ -74,6 +75,10 @@ func main() {
Name: "verbose", Name: "verbose",
Usage: "turns on the verbose messages from gaper", 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{ cli.StringSliceFlag{
Name: "watch, w", Name: "watch, w",
Usage: "list of folders or files to watch for changes", Usage: "list of folders or files to watch for changes",

View File

@ -37,19 +37,20 @@ var exitStatusError = 1
// Config contains all settings supported by gaper // Config contains all settings supported by gaper
type Config struct { type Config struct {
BinName string BinName string
BuildPath string BuildPath string
BuildArgs []string BuildArgs []string
BuildArgsMerged string BuildArgsMerged string
ProgramArgs []string ProgramArgs []string
ProgramArgsMerged string ProgramArgsMerged string
WatchItems []string WatchItems []string
IgnoreItems []string IgnoreItems []string
PollInterval int PollInterval int
Extensions []string Extensions []string
NoRestartOn string NoRestartOn string
Verbose bool Verbose bool
WorkingDirectory string DisableDefaultIgnore bool
WorkingDirectory string
} }
// Run starts the whole gaper process watching for file changes or exit codes // 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 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) builder := NewBuilder(cfg.BuildPath, cfg.BinName, cfg.WorkingDirectory, cfg.BuildArgs)
runner := NewRunner(os.Stdout, os.Stderr, filepath.Join(cfg.WorkingDirectory, builder.Binary()), cfg.ProgramArgs) 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 { if err != nil {
return fmt.Errorf("watcher error: %v", err) return fmt.Errorf("watcher error: %v", err)
} }

View File

@ -20,6 +20,7 @@ type Watcher interface {
// watcher is a interface for the watch process // watcher is a interface for the watch process
type watcher struct { type watcher struct {
defaultIgnore bool
pollInterval int pollInterval int
watchItems map[string]bool watchItems map[string]bool
ignoreItems map[string]bool ignoreItems map[string]bool
@ -28,27 +29,36 @@ type watcher struct {
errors chan error 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 // NewWatcher creates a new watcher
func NewWatcher(pollInterval int, watchItems []string, ignoreItems []string, extensions []string) (Watcher, error) { func NewWatcher(cfg WatcherConfig) (Watcher, error) {
if pollInterval == 0 { if cfg.PollInterval == 0 {
pollInterval = DefaultPoolInterval cfg.PollInterval = DefaultPoolInterval
} }
if len(extensions) == 0 { if len(cfg.Extensions) == 0 {
extensions = DefaultExtensions cfg.Extensions = DefaultExtensions
} }
allowedExts := make(map[string]bool) allowedExts := make(map[string]bool)
for _, ext := range extensions { for _, ext := range cfg.Extensions {
allowedExts["."+ext] = true allowedExts["."+ext] = true
} }
watchPaths, err := resolvePaths(watchItems, allowedExts) watchPaths, err := resolvePaths(cfg.WatchItems, allowedExts)
if err != nil { if err != nil {
return nil, err return nil, err
} }
ignorePaths, err := resolvePaths(ignoreItems, allowedExts) ignorePaths, err := resolvePaths(cfg.IgnoreItems, allowedExts)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -58,7 +68,8 @@ func NewWatcher(pollInterval int, watchItems []string, ignoreItems []string, ext
return &watcher{ return &watcher{
events: make(chan string), events: make(chan string),
errors: make(chan error), errors: make(chan error),
pollInterval: pollInterval, defaultIgnore: cfg.DefaultIgnore,
pollInterval: cfg.PollInterval,
watchItems: watchPaths, watchItems: watchPaths,
ignoreItems: ignorePaths, ignoreItems: ignorePaths,
allowedExtensions: allowedExts, allowedExtensions: allowedExts,
@ -105,12 +116,7 @@ func (w *watcher) scanChange(watchPath string) (string, error) {
var fileChanged string var fileChanged string
err := filepath.Walk(watchPath, func(path string, info os.FileInfo, err error) error { err := filepath.Walk(watchPath, func(path string, info os.FileInfo, err error) error {
// always ignore hidden files and directories if w.ignoreFile(path, info) {
if dir := filepath.Base(path); dir[0] == '.' && dir != "." {
return skipFile(info)
}
if _, ignored := w.ignoreItems[path]; ignored {
return skipFile(info) return skipFile(info)
} }
@ -130,6 +136,31 @@ func (w *watcher) scanChange(watchPath string) (string, error) {
return fileChanged, nil 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) { func resolvePaths(paths []string, extensions map[string]bool) (map[string]bool, error) {
result := map[string]bool{} result := map[string]bool{}

View File

@ -16,7 +16,14 @@ func TestWatcherDefaultValues(t *testing.T) {
var ignoreItems []string var ignoreItems []string
var extensions []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" expectedPath := "testdata/server"
if runtime.GOOS == OSWindows { if runtime.GOOS == OSWindows {
@ -37,7 +44,14 @@ func TestWatcherGlobPath(t *testing.T) {
ignoreItems := []string{"./testdata/**/*_test.go"} ignoreItems := []string{"./testdata/**/*_test.go"}
var extensions []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)
assert.Nil(t, err, "wacher error") assert.Nil(t, err, "wacher error")
w := wt.(*watcher) w := wt.(*watcher)
assert.Equal(t, map[string]bool{"testdata/server/main_test.go": true}, w.ignoreItems) 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"} ignoreItems := []string{"./testdata/**/*", "./testdata/server"}
var extensions []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)
assert.Nil(t, err, "wacher error") assert.Nil(t, err, "wacher error")
w := wt.(*watcher) w := wt.(*watcher)
assert.Equal(t, map[string]bool{"./testdata/server": true}, w.ignoreItems) assert.Equal(t, map[string]bool{"./testdata/server": true}, w.ignoreItems)
@ -69,7 +90,14 @@ func TestWatcherWatchChange(t *testing.T) {
ignoreItems := []string{testfile} ignoreItems := []string{testfile}
extensions := []string{"go"} 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") assert.Nil(t, err, "wacher error")
go w.Watch() go w.Watch()