/* Copyright (c) Edgeless Systems GmbH SPDX-License-Identifier: AGPL-3.0-only */ package cmd import ( "fmt" "io" "sync" "sync/atomic" "time" "github.com/spf13/cobra" ) var ( spinnerStates = []string{"⣾", "⣽", "⣻", "⢿", "⡿", "⣟", "⣯", "⣷"} dotsStates = []string{".", "..", "..."} ) type spinnerInterf interface { Start(text string, showDots bool) Stop() } type spinner struct { out *cobra.Command delay time.Duration wg *sync.WaitGroup stop int32 } func newSpinner(c *cobra.Command, writer io.Writer) (*spinner, *interruptSpinWriter) { spinner := &spinner{ out: c, wg: &sync.WaitGroup{}, delay: 100 * time.Millisecond, stop: 0, } if writer != nil { interruptWriter := &interruptSpinWriter{ writer: writer, spinner: spinner, } return spinner, interruptWriter } return spinner, nil } func (s *spinner) Start(text string, showDots bool) { s.wg.Add(1) go func() { defer s.wg.Done() for i := 0; ; i = (i + 1) % len(spinnerStates) { if atomic.LoadInt32(&s.stop) != 0 { break } dotsState := "" if showDots { dotsState = dotsStates[i%len(dotsStates)] } state := fmt.Sprintf("\r%s %s%s", spinnerStates[i], text, dotsState) s.out.Print(state) time.Sleep(s.delay) } dotsState := "" if showDots { dotsState = dotsStates[len(dotsStates)-1] } finalState := fmt.Sprintf("\r%s%s ", text, dotsState) s.out.Println(finalState) }() } func (s *spinner) Stop() { atomic.StoreInt32(&s.stop, 1) s.wg.Wait() } type interruptSpinWriter struct { spinner *spinner writer io.Writer } func (w *interruptSpinWriter) Write(p []byte) (n int, err error) { w.spinner.Stop() return w.writer.Write(p) } type nopSpinner struct{} func (s nopSpinner) Start(string, bool) {} func (s nopSpinner) Stop() {}