Skip to content

Commit

Permalink
Improve watching search and configuration by improving default ignore
Browse files Browse the repository at this point in the history
Now it will ignore by default hidden files and folders, test files and vendor
  • Loading branch information
maxcnunes committed Jul 22, 2018
1 parent 586c834 commit a75eac8
Show file tree
Hide file tree
Showing 5 changed files with 133 additions and 44 deletions.
18 changes: 17 additions & 1 deletion README.md
Expand Up @@ -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:
Expand All @@ -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'
```
Expand Down
25 changes: 15 additions & 10 deletions cmd/gaper/main.go
Expand Up @@ -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"),
}
}

Expand Down Expand Up @@ -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",
Expand Down
37 changes: 23 additions & 14 deletions gaper.go
Expand Up @@ -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
Expand All @@ -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)
}
Expand Down
61 changes: 46 additions & 15 deletions watcher.go
Expand Up @@ -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
Expand All @@ -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
}
Expand All @@ -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,
Expand Down Expand Up @@ -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)
}

Expand All @@ -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{}

Expand Down
36 changes: 32 additions & 4 deletions watcher_test.go
Expand Up @@ -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 {
Expand All @@ -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)
Expand All @@ -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)
Expand All @@ -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()
Expand Down

0 comments on commit a75eac8

Please sign in to comment.