update progress rendering to be closer to v0.1.10

This commit is contained in:
Jeffrey Morgan 2023-11-19 13:43:21 -05:00
parent 95b9acd324
commit c06b9b7304
4 changed files with 46 additions and 70 deletions

View file

@ -53,10 +53,6 @@ func CreateHandler(cmd *cobra.Command, args []string) error {
bars := make(map[string]*progress.Bar) bars := make(map[string]*progress.Bar)
status := fmt.Sprintf("creating %s", args[0])
spinner := progress.NewSpinner(status)
p.Add(status, spinner)
modelfile, err := os.ReadFile(filename) modelfile, err := os.ReadFile(filename)
if err != nil { if err != nil {
return err return err
@ -72,10 +68,8 @@ func CreateHandler(cmd *cobra.Command, args []string) error {
return err return err
} }
spinner.Stop() status := "transferring model data"
spinner := progress.NewSpinner(status)
status = "transferring model data"
spinner = progress.NewSpinner(status)
p.Add(status, spinner) p.Add(status, spinner)
for _, c := range commands { for _, c := range commands {
@ -179,14 +173,14 @@ func PushHandler(cmd *cobra.Command, args []string) error {
defer p.Stop() defer p.Stop()
bars := make(map[string]*progress.Bar) bars := make(map[string]*progress.Bar)
var status string
status := fmt.Sprintf("pushing %s", args[0]) var spinner *progress.Spinner
spinner := progress.NewSpinner(status)
p.Add(status, spinner)
fn := func(resp api.ProgressResponse) error { fn := func(resp api.ProgressResponse) error {
if resp.Digest != "" { if resp.Digest != "" {
if spinner != nil {
spinner.Stop() spinner.Stop()
}
bar, ok := bars[resp.Digest] bar, ok := bars[resp.Digest]
if !ok { if !ok {
@ -197,7 +191,9 @@ func PushHandler(cmd *cobra.Command, args []string) error {
bar.Set(resp.Completed) bar.Set(resp.Completed)
} else if status != resp.Status { } else if status != resp.Status {
if spinner != nil {
spinner.Stop() spinner.Stop()
}
status = resp.Status status = resp.Status
spinner = progress.NewSpinner(status) spinner = progress.NewSpinner(status)
@ -373,13 +369,14 @@ func PullHandler(cmd *cobra.Command, args []string) error {
bars := make(map[string]*progress.Bar) bars := make(map[string]*progress.Bar)
status := fmt.Sprintf("pulling %s", args[0]) var status string
spinner := progress.NewSpinner(status) var spinner *progress.Spinner
p.Add(status, spinner)
fn := func(resp api.ProgressResponse) error { fn := func(resp api.ProgressResponse) error {
if resp.Digest != "" { if resp.Digest != "" {
if spinner != nil {
spinner.Stop() spinner.Stop()
}
bar, ok := bars[resp.Digest] bar, ok := bars[resp.Digest]
if !ok { if !ok {
@ -390,7 +387,9 @@ func PullHandler(cmd *cobra.Command, args []string) error {
bar.Set(resp.Completed) bar.Set(resp.Completed)
} else if status != resp.Status { } else if status != resp.Status {
if spinner != nil {
spinner.Stop() spinner.Stop()
}
status = resp.Status status = resp.Status
spinner = progress.NewSpinner(status) spinner = progress.NewSpinner(status)

View file

@ -66,7 +66,8 @@ func (b *Bar) String() string {
mid.WriteString("▕") mid.WriteString("▕")
f := termWidth - pre.Len() - suf.Len() - 2 // add 3 extra spaces: 2 boundary characters and 1 space at the end
f := termWidth - pre.Len() - suf.Len() - 3
n := int(float64(f) * b.percent() / 100) n := int(float64(f) * b.percent() / 100)
if n > 0 { if n > 0 {

View file

@ -13,9 +13,10 @@ type State interface {
type Progress struct { type Progress struct {
mu sync.Mutex mu sync.Mutex
pos int
w io.Writer w io.Writer
pos int
ticker *time.Ticker ticker *time.Ticker
states []State states []State
} }
@ -37,6 +38,7 @@ func (p *Progress) Stop() bool {
p.ticker.Stop() p.ticker.Stop()
p.ticker = nil p.ticker = nil
p.render() p.render()
fmt.Fprint(p.w, "\n")
return true return true
} }
@ -50,11 +52,8 @@ func (p *Progress) StopAndClear() bool {
stopped := p.Stop() stopped := p.Stop()
if stopped { if stopped {
// clear the progress bar by: // clear the progress bar by:
// 1. for each line in the progress:
// a. move the cursor up one line
// b. clear the line
for i := 0; i < p.pos; i++ { for i := 0; i < p.pos; i++ {
fmt.Fprint(p.w, "\033[A\033[2K") fmt.Fprint(p.w, "\033[A\033[2K\033[1G")
} }
} }
@ -75,17 +74,23 @@ func (p *Progress) render() error {
fmt.Fprint(p.w, "\033[?25l") fmt.Fprint(p.w, "\033[?25l")
defer fmt.Fprint(p.w, "\033[?25h") defer fmt.Fprint(p.w, "\033[?25h")
if p.pos > 0 { // clear already rendered progress lines
fmt.Fprintf(p.w, "\033[%dA", p.pos) for i := 0; i < p.pos; i++ {
if i > 0 {
fmt.Fprint(p.w, "\033[A")
}
fmt.Fprint(p.w, "\033[2K\033[1G")
} }
for _, state := range p.states { // render progress lines
fmt.Fprintln(p.w, state.String()) for i, state := range p.states {
fmt.Fprint(p.w, state.String())
if i < len(p.states)-1 {
fmt.Fprint(p.w, "\n")
}
} }
if len(p.states) > 0 {
p.pos = len(p.states) p.pos = len(p.states)
}
return nil return nil
} }

View file

@ -2,11 +2,8 @@ package progress
import ( import (
"fmt" "fmt"
"os"
"strings" "strings"
"time" "time"
"golang.org/x/term"
) )
type Spinner struct { type Spinner struct {
@ -35,45 +32,28 @@ func NewSpinner(message string) *Spinner {
} }
func (s *Spinner) String() string { func (s *Spinner) String() string {
termWidth, _, err := term.GetSize(int(os.Stderr.Fd())) var sb strings.Builder
if err != nil {
panic(err)
}
var pre strings.Builder
if len(s.message) > 0 { if len(s.message) > 0 {
message := strings.TrimSpace(s.message) message := strings.TrimSpace(s.message)
if s.messageWidth > 0 && len(message) > s.messageWidth { if s.messageWidth > 0 && len(message) > s.messageWidth {
message = message[:s.messageWidth] message = message[:s.messageWidth]
} }
fmt.Fprintf(&pre, "%s", message) fmt.Fprintf(&sb, "%s", message)
if s.messageWidth-pre.Len() >= 0 { if s.messageWidth-sb.Len() >= 0 {
pre.WriteString(strings.Repeat(" ", s.messageWidth-pre.Len())) sb.WriteString(strings.Repeat(" ", s.messageWidth-sb.Len()))
} }
pre.WriteString(" ") sb.WriteString(" ")
} }
var pad int
if s.stopped.IsZero() { if s.stopped.IsZero() {
// spinner has a string length of 3 but a rune length of 1
// in order to align correctly, we need to pad with (3 - 1) = 2 spaces
spinner := s.parts[s.value] spinner := s.parts[s.value]
pre.WriteString(spinner) sb.WriteString(spinner)
pad = len(spinner) - len([]rune(spinner)) sb.WriteString(" ")
} }
var suf strings.Builder return sb.String()
fmt.Fprintf(&suf, "(%s)", s.elapsed())
var mid strings.Builder
f := termWidth - pre.Len() - mid.Len() - suf.Len() + pad
if f > 0 {
mid.WriteString(strings.Repeat(" ", f))
}
return pre.String() + mid.String() + suf.String()
} }
func (s *Spinner) start() { func (s *Spinner) start() {
@ -91,12 +71,3 @@ func (s *Spinner) Stop() {
s.stopped = time.Now() s.stopped = time.Now()
} }
} }
func (s *Spinner) elapsed() time.Duration {
stopped := s.stopped
if stopped.IsZero() {
stopped = time.Now()
}
return stopped.Sub(s.started).Round(time.Second)
}