浏览代码

(reactoring) avoid a global variable by introducing logConsumer decorator

Signed-off-by: Nicolas De Loof <[email protected]>
Nicolas De Loof 6 月之前
父节点
当前提交
6fa173124a
共有 5 个文件被更改,包括 73 次插入46 次删除
  1. 28 8
      cmd/formatter/logs.go
  2. 23 22
      cmd/formatter/shortcut.go
  3. 1 4
      internal/tracing/keyboard_metrics.go
  4. 19 10
      pkg/compose/up.go
  5. 2 2
      pkg/compose/watch.go

+ 28 - 8
cmd/formatter/logs.go

@@ -118,10 +118,6 @@ func (l *logConsumer) write(w io.Writer, container, message string) {
 	if l.ctx.Err() != nil {
 		return
 	}
-	if KeyboardManager != nil {
-		KeyboardManager.ClearKeyboardInfo()
-	}
-
 	p := l.getPresenter(container)
 	timestamp := time.Now().Format(jsonmessage.RFC3339NanoFixed)
 	for _, line := range strings.Split(message, "\n") {
@@ -131,10 +127,6 @@ func (l *logConsumer) write(w io.Writer, container, message string) {
 			_, _ = fmt.Fprintf(w, "%s%s\n", p.prefix, line)
 		}
 	}
-
-	if KeyboardManager != nil {
-		KeyboardManager.PrintKeyboardInfo()
-	}
 }
 
 func (l *logConsumer) Status(container, msg string) {
@@ -168,3 +160,31 @@ func (p *presenter) setPrefix(width int) {
 	}
 	p.prefix = p.colors(fmt.Sprintf("%-"+strconv.Itoa(width)+"s | ", p.name))
 }
+
+type logDecorator struct {
+	decorated api.LogConsumer
+	Before    func()
+	After     func()
+}
+
+func (l logDecorator) Log(containerName, message string) {
+	l.Before()
+	l.decorated.Log(containerName, message)
+	l.After()
+}
+
+func (l logDecorator) Err(containerName, message string) {
+	l.Before()
+	l.decorated.Err(containerName, message)
+	l.After()
+}
+
+func (l logDecorator) Status(container, msg string) {
+	l.Before()
+	l.decorated.Status(container, msg)
+	l.After()
+}
+
+func (l logDecorator) Register(container string) {
+	l.decorated.Register(container)
+}

+ 23 - 22
cmd/formatter/shortcut.go

@@ -22,7 +22,6 @@ import (
 	"fmt"
 	"math"
 	"os"
-	"reflect"
 	"syscall"
 	"time"
 
@@ -70,12 +69,12 @@ func (ke *KeyboardError) error() string {
 }
 
 type KeyboardWatch struct {
-	Watching     bool
-	Watcher      Toggle
-	IsConfigured bool
+	Watching bool
+	Watcher  Feature
 }
 
-type Toggle interface {
+// Feature is an compose feature that can be started/stopped by a menu command
+type Feature interface {
 	Start(context.Context) error
 	Stop() error
 }
@@ -90,31 +89,26 @@ const (
 
 type LogKeyboard struct {
 	kError                KeyboardError
-	Watch                 KeyboardWatch
+	Watch                 *KeyboardWatch
 	IsDockerDesktopActive bool
 	logLevel              KEYBOARD_LOG_LEVEL
 	signalChannel         chan<- os.Signal
 }
 
-// FIXME(ndeloof) we should avoid use of such a global reference. see use in logConsumer
-var KeyboardManager *LogKeyboard
-
-func NewKeyboardManager(isDockerDesktopActive bool, sc chan<- os.Signal, w bool, watcher Toggle) *LogKeyboard {
-	KeyboardManager = &LogKeyboard{
-		Watch: KeyboardWatch{
-			Watching:     w,
-			Watcher:      watcher,
-			IsConfigured: !reflect.ValueOf(watcher).IsNil(),
-		},
+func NewKeyboardManager(isDockerDesktopActive bool, sc chan<- os.Signal) *LogKeyboard {
+	return &LogKeyboard{
 		IsDockerDesktopActive: isDockerDesktopActive,
 		logLevel:              INFO,
 		signalChannel:         sc,
 	}
-	return KeyboardManager
 }
 
-func (lk *LogKeyboard) ClearKeyboardInfo() {
-	lk.clearNavigationMenu()
+func (lk *LogKeyboard) Decorate(l api.LogConsumer) api.LogConsumer {
+	return logDecorator{
+		decorated: l,
+		Before:    lk.clearNavigationMenu,
+		After:     lk.PrintKeyboardInfo,
+	}
 }
 
 func (lk *LogKeyboard) PrintKeyboardInfo() {
@@ -185,7 +179,7 @@ func (lk *LogKeyboard) navigationMenu() string {
 		watchInfo = navColor("   ")
 	}
 	isEnabled := " Enable"
-	if lk.Watch.Watching {
+	if lk.Watch != nil && lk.Watch.Watching {
 		isEnabled = " Disable"
 	}
 	watchInfo = watchInfo + shortcutKeyColor("w") + navColor(isEnabled+" Watch")
@@ -268,7 +262,7 @@ func (lk *LogKeyboard) keyboardError(prefix string, err error) {
 }
 
 func (lk *LogKeyboard) ToggleWatch(ctx context.Context, options api.UpOptions) {
-	if !lk.Watch.IsConfigured {
+	if lk.Watch == nil {
 		return
 	}
 	if lk.Watch.Watching {
@@ -299,7 +293,7 @@ func (lk *LogKeyboard) HandleKeyEvents(ctx context.Context, event keyboard.KeyEv
 	case 'v':
 		lk.openDockerDesktop(ctx, project)
 	case 'w':
-		if !lk.Watch.IsConfigured {
+		if lk.Watch == nil {
 			// we try to open watch docs if DD is installed
 			if lk.IsDockerDesktopActive {
 				lk.openDDWatchDocs(ctx, project)
@@ -333,6 +327,13 @@ func (lk *LogKeyboard) HandleKeyEvents(ctx context.Context, event keyboard.KeyEv
 	}
 }
 
+func (lk *LogKeyboard) EnableWatch(enabled bool, watcher Feature) {
+	lk.Watch = &KeyboardWatch{
+		Watching: enabled,
+		Watcher:  watcher,
+	}
+}
+
 func allocateSpace(lines int) {
 	for i := 0; i < lines; i++ {
 		ClearLine()

+ 1 - 4
internal/tracing/keyboard_metrics.go

@@ -22,15 +22,12 @@ import (
 	"go.opentelemetry.io/otel/attribute"
 )
 
-func KeyboardMetrics(ctx context.Context, enabled, isDockerDesktopActive, isWatchConfigured bool) {
+func KeyboardMetrics(ctx context.Context, enabled, isDockerDesktopActive bool) {
 	commandAvailable := []string{}
 	if isDockerDesktopActive {
 		commandAvailable = append(commandAvailable, "gui")
 		commandAvailable = append(commandAvailable, "gui/composeview")
 	}
-	if isWatchConfigured {
-		commandAvailable = append(commandAvailable, "watch")
-	}
 
 	AddAttributeToSpan(ctx,
 		attribute.Bool("navmenu.enabled", enabled),

+ 19 - 10
pkg/compose/up.go

@@ -70,15 +70,12 @@ func (s *composeService) Up(ctx context.Context, project *types.Project, options
 	signal.Notify(signalChan, syscall.SIGINT, syscall.SIGTERM)
 	defer signal.Stop(signalChan)
 	var isTerminated atomic.Bool
-	printer := newLogPrinter(options.Start.Attach)
 
-	watcher, err := NewWatcher(project, options, s.watch)
-	if err != nil && options.Start.Watch {
-		return err
-	}
-
-	var navigationMenu *formatter.LogKeyboard
-	var kEvents <-chan keyboard.KeyEvent
+	var (
+		logConsumer    = options.Start.Attach
+		navigationMenu *formatter.LogKeyboard
+		kEvents        <-chan keyboard.KeyEvent
+	)
 	if options.Start.NavigationMenu {
 		kEvents, err = keyboard.GetKeys(100)
 		if err != nil {
@@ -87,11 +84,23 @@ func (s *composeService) Up(ctx context.Context, project *types.Project, options
 		} else {
 			defer keyboard.Close() //nolint:errcheck
 			isDockerDesktopActive := s.isDesktopIntegrationActive()
-			tracing.KeyboardMetrics(ctx, options.Start.NavigationMenu, isDockerDesktopActive, watcher != nil)
-			navigationMenu = formatter.NewKeyboardManager(isDockerDesktopActive, signalChan, options.Start.Watch, watcher)
+			tracing.KeyboardMetrics(ctx, options.Start.NavigationMenu, isDockerDesktopActive)
+			navigationMenu = formatter.NewKeyboardManager(isDockerDesktopActive, signalChan)
+			logConsumer = navigationMenu.Decorate(logConsumer)
 		}
 	}
 
+	watcher, err := NewWatcher(project, options, s.watch, logConsumer)
+	if err != nil && options.Start.Watch {
+		return err
+	}
+
+	if navigationMenu != nil && watcher != nil {
+		navigationMenu.EnableWatch(options.Start.Watch, watcher)
+	}
+
+	printer := newLogPrinter(logConsumer)
+
 	doneCh := make(chan bool)
 	eg.Go(func() error {
 		first := true

+ 2 - 2
pkg/compose/watch.go

@@ -55,7 +55,7 @@ type Watcher struct {
 	errCh   chan error
 }
 
-func NewWatcher(project *types.Project, options api.UpOptions, w WatchFunc) (*Watcher, error) {
+func NewWatcher(project *types.Project, options api.UpOptions, w WatchFunc, consumer api.LogConsumer) (*Watcher, error) {
 	for i := range project.Services {
 		service := project.Services[i]
 
@@ -65,7 +65,7 @@ func NewWatcher(project *types.Project, options api.UpOptions, w WatchFunc) (*Wa
 			return &Watcher{
 				project: project,
 				options: api.WatchOptions{
-					LogTo: options.Start.Attach,
+					LogTo: consumer,
 					Build: build,
 				},
 				watchFn: w,