2018-05-22 21:43:36 +02:00
|
|
|
// Copyright 2016-2018, Pulumi Corporation.
|
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
// you may not use this file except in compliance with the License.
|
|
|
|
// You may obtain a copy of the License at
|
|
|
|
//
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
//
|
|
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
// See the License for the specific language governing permissions and
|
|
|
|
// limitations under the License.
|
2018-01-18 23:33:03 +01:00
|
|
|
|
|
|
|
package cmdutil
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"time"
|
2018-02-24 04:36:44 +01:00
|
|
|
"unicode/utf8"
|
2018-01-18 23:33:03 +01:00
|
|
|
)
|
|
|
|
|
2018-04-10 21:03:11 +02:00
|
|
|
// NewSpinnerAndTicker returns a new Spinner and a ticker that will fire an event when the next call
|
|
|
|
// to Spinner.Tick() should be called. NewSpinnerAndTicket takes into account if stdout is
|
|
|
|
// connected to a tty or not and returns either a nice animated spinner that updates quickly, using
|
|
|
|
// the specified ttyFrames, or a simple spinner that just prints a dot on each tick and updates
|
|
|
|
// slowly.
|
|
|
|
func NewSpinnerAndTicker(prefix string, ttyFrames []string, timesPerSecond time.Duration) (Spinner, *time.Ticker) {
|
2018-02-16 03:22:17 +01:00
|
|
|
if ttyFrames == nil {
|
2018-02-21 18:42:06 +01:00
|
|
|
// If explicit tick frames weren't specified, default to unicode for Mac and ASCII for Windows/Linux.
|
|
|
|
if Emoji {
|
|
|
|
ttyFrames = DefaultEmojiSpinFrames
|
|
|
|
} else {
|
|
|
|
ttyFrames = DefaultASCIISpinFrames
|
|
|
|
}
|
2018-02-16 03:22:17 +01:00
|
|
|
}
|
|
|
|
|
2018-10-05 01:20:01 +02:00
|
|
|
if InteractiveTerminal() {
|
2018-02-16 03:22:17 +01:00
|
|
|
return &ttySpinner{
|
|
|
|
prefix: prefix,
|
|
|
|
frames: ttyFrames,
|
2018-04-10 21:03:11 +02:00
|
|
|
}, time.NewTicker(time.Second / timesPerSecond)
|
2018-01-18 23:33:03 +01:00
|
|
|
}
|
2018-02-16 03:22:17 +01:00
|
|
|
|
|
|
|
return &dotSpinner{
|
|
|
|
prefix: prefix,
|
|
|
|
}, time.NewTicker(time.Second * 20)
|
2018-01-18 23:33:03 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// Spinner represents a very simple progress reporter.
|
|
|
|
type Spinner interface {
|
|
|
|
// Print the next frame of the spinner. After Tick() has been called, there should be no writes to Stdout before
|
|
|
|
// calling Reset().
|
|
|
|
Tick()
|
|
|
|
|
|
|
|
// Called to release ownership of stdout, so others may write to it.
|
|
|
|
Reset()
|
|
|
|
}
|
|
|
|
|
2018-02-16 03:22:17 +01:00
|
|
|
var (
|
2018-02-21 18:42:06 +01:00
|
|
|
// DefaultASCIISpinFrames is the default set of symbols to show while spinning in an ASCII TTY setting.
|
|
|
|
DefaultASCIISpinFrames = []string{
|
|
|
|
"|", "/", "-", "\\",
|
|
|
|
}
|
|
|
|
// DefaultEmojiSpinFrames is the default set of symbols to show while spinning in a Unicode-enabled TTY setting.
|
|
|
|
DefaultEmojiSpinFrames = []string{
|
|
|
|
"⠋", "⠙", "⠚", "⠒", "⠂", "⠂", "⠒", "⠲", "⠴", "⠦", "⠖", "⠒", "⠐", "⠐", "⠒", "⠓", "⠋",
|
|
|
|
}
|
2018-02-16 03:22:17 +01:00
|
|
|
)
|
2018-01-18 23:33:03 +01:00
|
|
|
|
|
|
|
// ttySpinner is the spinner that can be used when standard out is a tty. When we are connected to a TTY we can erase
|
|
|
|
// characters we've written and provide a nice quick progress spinner.
|
|
|
|
type ttySpinner struct {
|
2018-02-24 04:36:44 +01:00
|
|
|
prefix string
|
|
|
|
frames []string
|
|
|
|
index int
|
|
|
|
lastWritten int
|
2018-01-18 23:33:03 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
func (spin *ttySpinner) Tick() {
|
2018-02-24 04:36:44 +01:00
|
|
|
if spin.lastWritten > 0 {
|
|
|
|
for i := 0; i < spin.lastWritten; i++ {
|
|
|
|
fmt.Print("\b \b")
|
|
|
|
}
|
2018-02-16 03:22:17 +01:00
|
|
|
} else {
|
|
|
|
fmt.Print(spin.prefix)
|
|
|
|
}
|
2018-02-24 04:36:44 +01:00
|
|
|
frame := spin.frames[spin.index]
|
|
|
|
fmt.Print(frame)
|
|
|
|
spin.lastWritten = utf8.RuneCountInString(frame)
|
2018-02-16 03:22:17 +01:00
|
|
|
spin.index = (spin.index + 1) % len(spin.frames)
|
2018-01-18 23:33:03 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
func (spin *ttySpinner) Reset() {
|
2018-02-24 04:36:44 +01:00
|
|
|
if spin.lastWritten > 0 {
|
|
|
|
for i := 0; i < len(spin.prefix)+spin.lastWritten; i++ {
|
|
|
|
fmt.Print("\b \b")
|
2018-02-16 03:22:17 +01:00
|
|
|
}
|
|
|
|
}
|
2018-01-18 23:33:03 +01:00
|
|
|
spin.index = 0
|
2018-02-24 04:36:44 +01:00
|
|
|
spin.lastWritten = 0
|
2018-01-18 23:33:03 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// dotSpinner is the spinner that can be used when standard out is not a tty. In this case, we just write a single
|
|
|
|
// dot on each tick.
|
|
|
|
type dotSpinner struct {
|
2018-02-16 03:22:17 +01:00
|
|
|
prefix string
|
2018-01-18 23:33:03 +01:00
|
|
|
hasWritten bool
|
|
|
|
}
|
|
|
|
|
|
|
|
func (spin *dotSpinner) Tick() {
|
|
|
|
if !spin.hasWritten {
|
2018-02-16 03:22:17 +01:00
|
|
|
fmt.Print(spin.prefix)
|
2018-01-18 23:33:03 +01:00
|
|
|
}
|
|
|
|
fmt.Printf(".")
|
|
|
|
spin.hasWritten = true
|
|
|
|
}
|
|
|
|
|
|
|
|
func (spin *dotSpinner) Reset() {
|
|
|
|
if spin.hasWritten {
|
|
|
|
fmt.Println()
|
|
|
|
}
|
|
|
|
spin.hasWritten = false
|
|
|
|
}
|