in internal/pkg/cli/run_local.go [625:717]
func (o *runLocalOpts) watchLocalFiles(stopCh <-chan struct{}) (<-chan interface{}, <-chan error, error) {
workspacePath := o.ws.Path()
watchCh := make(chan interface{})
watchErrCh := make(chan error)
watcher, err := o.newRecursiveWatcher()
if err != nil {
return nil, nil, fmt.Errorf("file: %w", err)
}
if err = watcher.Add(workspacePath); err != nil {
return nil, nil, err
}
watcherEvents := watcher.Events()
watcherErrors := watcher.Errors()
debounceTimer := time.NewTimer(o.debounceTime)
debounceTimerRunning := false
if !debounceTimer.Stop() {
// flush the timer in case stop is called after the timer finishes
<-debounceTimer.C
}
go func() {
for {
select {
case <-stopCh:
watcher.Close()
return
case err, ok := <-watcherErrors:
watchErrCh <- err
if !ok {
watcher.Close()
return
}
case event, ok := <-watcherEvents:
if !ok {
watcher.Close()
return
}
// skip chmod events
if event.Has(fsnotify.Chmod) {
break
}
parent := workspacePath
suffix, _ := strings.CutPrefix(event.Name, parent+"/")
// check if any subdirectories within copilot directory are hidden
// fsnotify events are always of form /a/b/c, don't use filepath.Split as that's OS dependent
isHidden := false
for _, child := range strings.Split(suffix, "/") {
parent = filepath.Join(parent, child)
subdirHidden, err := file.IsHiddenFile(child)
if err != nil {
break
}
if subdirHidden {
isHidden = true
}
}
// skip updates from files matching .dockerignore patterns
isExcluded := false
for _, pattern := range o.dockerExcludes {
matches, err := filepath.Match(pattern, suffix)
if err != nil {
break
}
if matches {
isExcluded = true
}
}
if !isHidden && !isExcluded {
if !debounceTimerRunning {
fmt.Println("Restarting task...")
debounceTimerRunning = true
}
debounceTimer.Reset(o.debounceTime)
}
case <-debounceTimer.C:
debounceTimerRunning = false
watchCh <- nil
}
}
}()
return watchCh, watchErrCh, nil
}