func()

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
}