Skip to content

Commit

Permalink
progress: render never started trackers properly (#273)
Browse files Browse the repository at this point in the history
  • Loading branch information
NathanBaulch authored Aug 26, 2023
1 parent f16973f commit 13d3a1d
Show file tree
Hide file tree
Showing 28 changed files with 221 additions and 235 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ jobs:
- name: Checkout Code
uses: actions/checkout@v2

# Set up the GoLang enviroment
# Set up the GoLang environment
- name: Set up Go
uses: actions/setup-go@v2
with:
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -111,4 +111,4 @@ the following from within your code folder to do the same:
```
find . -type f -name "*.go" | grep -v vendor | xargs sed -i 's/jedib0t\/go-pretty\//jedib0t\/go-pretty\/v6\//g'
```
If you are on MacOS, you'll have to use `sed -i ''` instead of `sed -i`.
If you are on macOS, you'll have to use `sed -i ''` instead of `sed -i`.
2 changes: 1 addition & 1 deletion cmd/demo-progress/demo.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ func trackSomething(pw progress.Writer, idx int64, updateMessage bool) {
}
pw.SetPinnedMessages(
fmt.Sprintf(">> Current Time: %-32s", time.Now().Format(time.RFC3339)),
fmt.Sprintf(">> Total Time: %-32s", time.Now().Sub(timeStart).Round(time.Millisecond)),
fmt.Sprintf(">> Total Time: %-32s", time.Since(timeStart).Round(time.Millisecond)),
)
case <-updateTicker:
if updateMessage {
Expand Down
12 changes: 4 additions & 8 deletions list/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ type listItem struct {
Text string
}

// List helps print a 2-dimensional array in a human readable pretty-List.
// List helps print a 2-dimensional array in a human-readable pretty-List.
type List struct {
// approxSize stores the approximate output length/size
approxSize int
Expand Down Expand Up @@ -71,7 +71,7 @@ func (l *List) Reset() {
l.style = nil
}

// SetHTMLCSSClass sets the the HTML CSS Class to use on the <ul> node
// SetHTMLCSSClass sets the HTML CSS Class to use on the <ul> node
// when rendering the List in HTML format. Recursive lists would use a numbered
// index suffix. For ex., if the cssClass is set as "foo"; the <ul> for level 0
// would have the class set as "foo"; the <ul> for level 1 would have "foo-1".
Expand Down Expand Up @@ -101,12 +101,8 @@ func (l *List) Style() *Style {

func (l *List) analyzeAndStringify(item interface{}) *listItem {
itemStr := fmt.Sprint(item)
if strings.Contains(itemStr, "\t") {
itemStr = strings.Replace(itemStr, "\t", " ", -1)
}
if strings.Contains(itemStr, "\r") {
itemStr = strings.Replace(itemStr, "\r", "", -1)
}
itemStr = strings.ReplaceAll(itemStr, "\t", " ")
itemStr = strings.ReplaceAll(itemStr, "\r", "")
return &listItem{
Level: l.level,
Text: itemStr,
Expand Down
14 changes: 7 additions & 7 deletions list/render.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,10 @@ func (l *List) Render() string {
out.Grow(l.approxSize)
for idx, item := range l.items {
hint := renderHint{
isTopItem: bool(idx == 0),
isFirstItem: bool(idx == 0 || item.Level > l.items[idx-1].Level),
isTopItem: idx == 0,
isFirstItem: idx == 0 || item.Level > l.items[idx-1].Level,
isLastItem: !l.hasMoreItemsInLevel(item.Level, idx),
isBottomItem: bool(idx == len(l.items)-1),
isBottomItem: idx == len(l.items)-1,
}
if hint.isFirstItem && hint.isLastItem {
hint.isOnlyItem = true
Expand Down Expand Up @@ -56,7 +56,7 @@ func (l *List) renderItem(out *strings.Builder, idx int, item *listItem, hint re
}

// render the prefix or the leading text before the actual item
l.renderItemBulletPrefix(out, idx, item.Level, lineIdx, hint)
l.renderItemBulletPrefix(out, idx, item.Level)
l.renderItemBullet(out, lineIdx, hint)

// render the actual item
Expand All @@ -73,11 +73,11 @@ func (l *List) renderItemBullet(out *strings.Builder, lineIdx int, hint renderHi
out.WriteString(l.style.CharItemVertical)
}
} else {
l.renderItemBulletSingleLine(out, lineIdx, hint)
l.renderItemBulletSingleLine(out, hint)
}
}

func (l *List) renderItemBulletSingleLine(out *strings.Builder, lineIdx int, hint renderHint) {
func (l *List) renderItemBulletSingleLine(out *strings.Builder, hint renderHint) {
// single-line item.Text (or first line of a multi-line item.Text)
if hint.isOnlyItem {
if hint.isTopItem {
Expand All @@ -97,7 +97,7 @@ func (l *List) renderItemBulletSingleLine(out *strings.Builder, lineIdx int, hin
out.WriteRune(' ')
}

func (l *List) renderItemBulletPrefix(out *strings.Builder, itemIdx int, itemLevel int, lineIdx int, hint renderHint) {
func (l *List) renderItemBulletPrefix(out *strings.Builder, itemIdx int, itemLevel int) {
// write a prefix if one has been set in l.style
if l.style.LinePrefix != "" {
out.WriteString(l.style.LinePrefix)
Expand Down
1 change: 0 additions & 1 deletion list/render_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -331,5 +331,4 @@ func TestList_Render_UnindentAll(t *testing.T) {
* Way
* Right?`
assert.Equal(t, expectedOut, lw.Render())

}
2 changes: 1 addition & 1 deletion list/writer.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package list

import "io"

// Writer declares the interfaces that can be used to setup and render a list.
// Writer declares the interfaces that can be used to set up and render a list.
type Writer interface {
AppendItem(item interface{})
AppendItems(items []interface{})
Expand Down
4 changes: 2 additions & 2 deletions progress/progress.go
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,7 @@ func (p *Progress) SetPinnedMessages(messages ...string) {
}

// SetSortBy defines the sorting mechanism to use to sort the Active Trackers
// before rendering the. Default: no-sorting == sort-by-insertion-order.
// before rendering. Default: no-sorting == sort-by-insertion-order.
func (p *Progress) SetSortBy(sortBy SortBy) {
p.sortBy = sortBy
}
Expand All @@ -221,7 +221,7 @@ func (p *Progress) SetTrackerPosition(position Position) {
}

// SetUpdateFrequency sets the update frequency while rendering the trackers.
// the lower the value, the more number of times the Trackers get refreshed. A
// the lower the value, the more frequently the Trackers get refreshed. A
// sane value would be 250ms.
func (p *Progress) SetUpdateFrequency(frequency time.Duration) {
p.updateFrequency = frequency
Expand Down
4 changes: 2 additions & 2 deletions progress/progress_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -169,8 +169,8 @@ func TestProgress_SetUpdateFrequency(t *testing.T) {
p.initForRender()
assert.Equal(t, DefaultUpdateFrequency, p.updateFrequency)

p.SetUpdateFrequency(time.Duration(time.Second))
assert.Equal(t, time.Duration(time.Second), p.updateFrequency)
p.SetUpdateFrequency(time.Second)
assert.Equal(t, time.Second, p.updateFrequency)
}

func TestProgress_ShowETA(t *testing.T) {
Expand Down
20 changes: 9 additions & 11 deletions progress/render.go
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ func (p *Progress) generateTrackerStrIndeterminate(maxLen int) string {
}

return p.style.Colors.Tracker.Sprintf("%s%s%s",
p.style.Chars.BoxLeft, string(pUnfinished), p.style.Chars.BoxRight,
p.style.Chars.BoxLeft, pUnfinished, p.style.Chars.BoxRight,
)
}

Expand Down Expand Up @@ -185,12 +185,8 @@ func (p *Progress) renderPinnedMessages(out *strings.Builder) {

func (p *Progress) renderTracker(out *strings.Builder, t *Tracker, hint renderHint) {
message := t.message()
if strings.Contains(message, "\t") {
message = strings.Replace(message, "\t", " ", -1)
}
if strings.Contains(message, "\r") {
message = strings.Replace(message, "\r", "", -1)
}
message = strings.ReplaceAll(message, "\t", " ")
message = strings.ReplaceAll(message, "\r", "")
if p.messageWidth > 0 {
messageLen := text.RuneWidthWithoutEscSequences(message)
if messageLen < p.messageWidth {
Expand Down Expand Up @@ -412,10 +408,12 @@ func (p *Progress) renderTrackerStatsSpeedInternal(out *strings.Builder, speed s

func (p *Progress) renderTrackerStatsTime(outStats *strings.Builder, t *Tracker, hint renderHint) {
var td, tp time.Duration
if t.IsDone() {
td = t.timeStop.Sub(t.timeStart)
} else if !t.timeStart.IsZero() {
td = time.Since(t.timeStart)
if !t.timeStart.IsZero() {
if t.IsDone() {
td = t.timeStop.Sub(t.timeStart)
} else {
td = time.Since(t.timeStart)
}
}
if hint.isOverallTracker {
tp = p.style.Options.TimeOverallPrecision
Expand Down
86 changes: 53 additions & 33 deletions progress/render_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,13 +55,11 @@ func trackSomething(pw Writer, tracker *Tracker) {

c := time.Tick(trackerIncrementInterval)
for !tracker.IsDone() {
select {
case <-c:
if tracker.value+incrementPerCycle > tracker.Total {
tracker.Increment(tracker.Total - tracker.value)
} else {
tracker.Increment(incrementPerCycle)
}
<-c
if tracker.value+incrementPerCycle > tracker.Total {
tracker.Increment(tracker.Total - tracker.value)
} else {
tracker.Increment(incrementPerCycle)
}
}
}
Expand All @@ -75,15 +73,13 @@ func trackSomethingDeferred(pw Writer, tracker *Tracker) {

c := time.Tick(trackerIncrementInterval)
for !tracker.IsDone() {
select {
case <-c:
if skip {
skip = false
} else if tracker.value+incrementPerCycle > tracker.Total {
tracker.Increment(tracker.Total - tracker.value)
} else {
tracker.Increment(incrementPerCycle)
}
<-c
if skip {
skip = false
} else if tracker.value+incrementPerCycle > tracker.Total {
tracker.Increment(tracker.Total - tracker.value)
} else {
tracker.Increment(incrementPerCycle)
}
}
}
Expand All @@ -97,13 +93,11 @@ func trackSomethingErrored(pw Writer, tracker *Tracker) {

c := time.Tick(trackerIncrementInterval)
for !tracker.IsDone() {
select {
case <-c:
if tracker.value+incrementPerCycle > total {
tracker.MarkAsErrored()
} else {
tracker.IncrementWithError(incrementPerCycle)
}
<-c
if tracker.value+incrementPerCycle > total {
tracker.MarkAsErrored()
} else {
tracker.IncrementWithError(incrementPerCycle)
}
}
}
Expand All @@ -117,16 +111,14 @@ func trackSomethingIndeterminate(pw Writer, tracker *Tracker) {

c := time.Tick(trackerIncrementInterval)
for !tracker.IsDone() {
select {
case <-c:
if tracker.value+incrementPerCycle > total {
tracker.Increment(total - tracker.value)
} else {
tracker.Increment(incrementPerCycle)
}
if tracker.Value() >= total {
tracker.MarkAsDone()
}
<-c
if tracker.value+incrementPerCycle > total {
tracker.Increment(total - tracker.value)
} else {
tracker.Increment(incrementPerCycle)
}
if tracker.Value() >= total {
tracker.MarkAsDone()
}
}
}
Expand Down Expand Up @@ -338,6 +330,34 @@ func TestProgress_generateTrackerStr_Indeterminate(t *testing.T) {
}
}

func TestProgress_RenderNeverStarted(t *testing.T) {
renderOutput := strings.Builder{}

pw := generateWriter()
pw.SetOutputWriter(&renderOutput)

tr := &Tracker{DeferStart: true}
pw.AppendTracker(tr)

go pw.Render()
time.Sleep(renderWaitTime)
tr.MarkAsDone()
pw.Stop()
time.Sleep(time.Second)

expectedOutPatterns := []*regexp.Regexp{
regexp.MustCompile(`\s*\.\.\. {2}\?\?\? {2}\[\.{23}] \[0 in 0s]`),
regexp.MustCompile(`\s*\.\.\. done! \[0 in 0s]`),
}
out := renderOutput.String()
for _, expectedOutPattern := range expectedOutPatterns {
if !expectedOutPattern.MatchString(out) {
assert.Fail(t, "Failed to find a pattern in the Output.", expectedOutPattern.String())
}
}
showOutputOnFailure(t, out)
}

func TestProgress_RenderNothing(t *testing.T) {
renderOutput := outputWriter{}

Expand Down
68 changes: 32 additions & 36 deletions progress/style.go
Original file line number Diff line number Diff line change
Expand Up @@ -168,27 +168,25 @@ type StyleOptions struct {
TimeOverallPrecision time.Duration // precision for overall time
}

var (
// StyleOptionsDefault defines sane defaults for the Options. Use this as an
// example to customize the Tracker rendering.
StyleOptionsDefault = StyleOptions{
DoneString: "done!",
ErrorString: "fail!",
ETAPrecision: time.Second,
ETAString: "~ETA",
PercentFormat: "%5.2f%%",
PercentIndeterminate: " ??? ",
Separator: " ... ",
SnipIndicator: "~",
SpeedPosition: PositionRight,
SpeedPrecision: time.Microsecond,
SpeedOverallFormatter: FormatNumber,
SpeedSuffix: "/s",
TimeDonePrecision: time.Millisecond,
TimeInProgressPrecision: time.Microsecond,
TimeOverallPrecision: time.Second,
}
)
// StyleOptionsDefault defines sane defaults for the Options. Use this as an
// example to customize the Tracker rendering.
var StyleOptionsDefault = StyleOptions{
DoneString: "done!",
ErrorString: "fail!",
ETAPrecision: time.Second,
ETAString: "~ETA",
PercentFormat: "%5.2f%%",
PercentIndeterminate: " ??? ",
Separator: " ... ",
SnipIndicator: "~",
SpeedPosition: PositionRight,
SpeedPrecision: time.Microsecond,
SpeedOverallFormatter: FormatNumber,
SpeedSuffix: "/s",
TimeDonePrecision: time.Millisecond,
TimeInProgressPrecision: time.Microsecond,
TimeOverallPrecision: time.Second,
}

// StyleVisibility controls what gets shown and what gets hidden.
type StyleVisibility struct {
Expand All @@ -204,18 +202,16 @@ type StyleVisibility struct {
Value bool // tracker value
}

var (
// StyleVisibilityDefault defines sane defaults for the Visibility.
StyleVisibilityDefault = StyleVisibility{
ETA: false,
ETAOverall: true,
Percentage: true,
Pinned: true,
Speed: false,
SpeedOverall: false,
Time: true,
Tracker: true,
TrackerOverall: false,
Value: true,
}
)
// StyleVisibilityDefault defines sane defaults for the Visibility.
var StyleVisibilityDefault = StyleVisibility{
ETA: false,
ETAOverall: true,
Percentage: true,
Pinned: true,
Speed: false,
SpeedOverall: false,
Time: true,
Tracker: true,
TrackerOverall: false,
Value: true,
}
Loading

0 comments on commit 13d3a1d

Please sign in to comment.