From cba7ff6c247b0bb9a0f2e16e79034a2443fe3d70 Mon Sep 17 00:00:00 2001 From: Daniel Nephin Date: Fri, 28 May 2021 15:24:46 -0400 Subject: [PATCH] internal/filewatcher: rename some types and methods The new names should hopefully make this code easier to read and understand. --- cmd/watch.go | 8 +++---- internal/filewatcher/term_unix.go | 33 +++++++++++++++++----------- internal/filewatcher/term_windows.go | 12 +++++----- internal/filewatcher/watch.go | 32 +++++++++++++-------------- internal/filewatcher/watch_test.go | 2 +- 5 files changed, 47 insertions(+), 40 deletions(-) diff --git a/cmd/watch.go b/cmd/watch.go index 79733646..0864ec5e 100644 --- a/cmd/watch.go +++ b/cmd/watch.go @@ -22,15 +22,15 @@ type watchRuns struct { prevExec *testjson.Execution } -func (w *watchRuns) run(runOpts filewatcher.RunOptions) error { - if runOpts.Debug { +func (w *watchRuns) run(event filewatcher.Event) error { + if event.Debug { path, cleanup, err := delveInitFile(w.prevExec) if err != nil { return fmt.Errorf("failed to write delve init file: %w", err) } defer cleanup() o := delveOpts{ - pkgPath: runOpts.PkgPath, + pkgPath: event.PkgPath, args: w.opts.args, initFilePath: path, } @@ -41,7 +41,7 @@ func (w *watchRuns) run(runOpts filewatcher.RunOptions) error { } opts := w.opts - opts.packages = []string{runOpts.PkgPath} + opts.packages = []string{event.PkgPath} var err error if w.prevExec, err = runSingle(&opts); !isExitCoder(err) { return err diff --git a/internal/filewatcher/term_unix.go b/internal/filewatcher/term_unix.go index c9e2e76f..267b8c93 100644 --- a/internal/filewatcher/term_unix.go +++ b/internal/filewatcher/term_unix.go @@ -12,18 +12,20 @@ import ( "gotest.tools/gotestsum/log" ) -type redoHandler struct { - ch chan RunOptions +type terminal struct { + ch chan Event reset func() } -func newRedoHandler() *redoHandler { - h := &redoHandler{ch: make(chan RunOptions)} - h.SetupTerm() +func newTerminal() *terminal { + h := &terminal{ch: make(chan Event)} + h.Start() return h } -func (r *redoHandler) SetupTerm() { +// Start the terminal is non-blocking read mode. The terminal can be reset to +// normal mode by calling Reset. +func (r *terminal) Start() { if r == nil { return } @@ -59,7 +61,9 @@ func enableNonBlockingRead(fd int) (func(), error) { return reset, nil } -func (r *redoHandler) Run(ctx context.Context) { +// Monitor the terminal for key presses. If the key press is associated with an +// action, an event will be sent to channel returned by Events. +func (r *terminal) Monitor(ctx context.Context) { if r == nil { return } @@ -76,16 +80,16 @@ func (r *redoHandler) Run(ctx context.Context) { switch char { case 'r': chResume = make(chan struct{}) - r.ch <- RunOptions{resume: chResume} + r.ch <- Event{resume: chResume} case 'd': chResume = make(chan struct{}) - r.ch <- RunOptions{Debug: true, resume: chResume} + r.ch <- Event{Debug: true, resume: chResume} case 'a': chResume = make(chan struct{}) - r.ch <- RunOptions{resume: chResume, PkgPath: "./..."} + r.ch <- Event{resume: chResume, PkgPath: "./..."} case 'l': chResume = make(chan struct{}) - r.ch <- RunOptions{resume: chResume, reloadPaths: true} + r.ch <- Event{resume: chResume, reloadPaths: true} case '\n': fmt.Println() continue @@ -101,14 +105,17 @@ func (r *redoHandler) Run(ctx context.Context) { } } -func (r *redoHandler) Ch() <-chan RunOptions { +// Events returns a channel which will receive events when keys are pressed. +// When an event is received, the caller must close the resume channel to +// resume monitoring for events. +func (r *terminal) Events() <-chan Event { if r == nil { return nil } return r.ch } -func (r *redoHandler) ResetTerm() { +func (r *terminal) Reset() { if r != nil && r.reset != nil { r.reset() } diff --git a/internal/filewatcher/term_windows.go b/internal/filewatcher/term_windows.go index 5929d1e8..2c22c1ac 100644 --- a/internal/filewatcher/term_windows.go +++ b/internal/filewatcher/term_windows.go @@ -2,18 +2,18 @@ package filewatcher import "context" -type redoHandler struct{} +type terminal struct{} -func newRedoHandler() *redoHandler { +func newTerminal() *terminal { return nil } -func (r *redoHandler) Run(_ context.Context) {} +func (r *terminal) Monitor(context.Context) {} -func (r *redoHandler) Ch() <-chan RunOptions { +func (r *terminal) Events() <-chan Event { return nil } -func (r *redoHandler) SetupTerm() {} +func (r *terminal) Start() {} -func (r *redoHandler) ResetTerm() {} +func (r *terminal) Reset() {} diff --git a/internal/filewatcher/watch.go b/internal/filewatcher/watch.go index 9db8b118..13a8e23a 100644 --- a/internal/filewatcher/watch.go +++ b/internal/filewatcher/watch.go @@ -15,7 +15,7 @@ import ( const maxDepth = 7 -type RunOptions struct { +type Event struct { PkgPath string Debug bool resume chan struct{} @@ -24,7 +24,7 @@ type RunOptions struct { // Watch dirs for filesystem events, and run tests when .go files are saved. // nolint: gocyclo -func Watch(dirs []string, run func(opts RunOptions) error) error { +func Watch(dirs []string, run func(Event) error) error { ctx, cancel := context.WithCancel(context.Background()) defer cancel() @@ -41,9 +41,9 @@ func Watch(dirs []string, run func(opts RunOptions) error) error { timer := time.NewTimer(maxIdleTime) defer timer.Stop() - redo := newRedoHandler() - defer redo.ResetTerm() - go redo.Run(ctx) + term := newTerminal() + defer term.Reset() + go term.Monitor(ctx) h := &handler{last: time.Now(), fn: run} for { @@ -51,23 +51,23 @@ func Watch(dirs []string, run func(opts RunOptions) error) error { case <-timer.C: return fmt.Errorf("exceeded idle timeout while watching files") - case opts := <-redo.Ch(): + case event := <-term.Events(): resetTimer(timer) - if opts.reloadPaths { + if event.reloadPaths { if err := loadPaths(watcher, dirs); err != nil { return err } - close(opts.resume) + close(event.resume) continue } - redo.ResetTerm() - if err := h.runTests(opts); err != nil { - return fmt.Errorf("failed to rerun tests for %v: %v", opts.PkgPath, err) + term.Reset() + if err := h.runTests(event); err != nil { + return fmt.Errorf("failed to rerun tests for %v: %v", event.PkgPath, err) } - redo.SetupTerm() - close(opts.resume) + term.Start() + close(event.resume) case event := <-watcher.Events: resetTimer(timer) @@ -218,7 +218,7 @@ func handleDirCreated(watcher *fsnotify.Watcher, event fsnotify.Event) (handled type handler struct { last time.Time lastPath string - fn func(opts RunOptions) error + fn func(opts Event) error } const floodThreshold = 250 * time.Millisecond @@ -236,10 +236,10 @@ func (h *handler) handleEvent(event fsnotify.Event) error { log.Debugf("skipping event received less than %v after the previous", floodThreshold) return nil } - return h.runTests(RunOptions{PkgPath: "./" + filepath.Dir(event.Name)}) + return h.runTests(Event{PkgPath: "./" + filepath.Dir(event.Name)}) } -func (h *handler) runTests(opts RunOptions) error { +func (h *handler) runTests(opts Event) error { if opts.PkgPath == "" { opts.PkgPath = h.lastPath } diff --git a/internal/filewatcher/watch_test.go b/internal/filewatcher/watch_test.go index 15f350f6..f02f8a3e 100644 --- a/internal/filewatcher/watch_test.go +++ b/internal/filewatcher/watch_test.go @@ -22,7 +22,7 @@ func TestHandler_HandleEvent(t *testing.T) { fn := func(t *testing.T, tc testCase) { var ran bool - run := func(opts RunOptions) error { + run := func(opts Event) error { ran = true return nil }