Codebase list golang-github-vbauerster-mpb / 6e5802d _examples / barExtenderRev / main.go
6e5802d

Tree @6e5802d (Download .tar.gz)

main.go @6e5802draw · history · blame

package main

import (
	"fmt"
	"io"
	"math/rand"
	"sync/atomic"
	"time"

	"github.com/vbauerster/mpb/v7"
	"github.com/vbauerster/mpb/v7/decor"
)

var curTask uint32
var doneTasks uint32

type task struct {
	id    int
	total int
	bar   *mpb.Bar
}

func main() {
	numTasks := 4

	var total int
	var filler mpb.BarFiller
	tasks := make([]*task, numTasks)

	for i := 0; i < numTasks; i++ {
		task := &task{
			id:    i,
			total: rand.Intn(101) + 100,
		}
		total += task.total
		filler = middleware(filler, task.id)
		tasks[i] = task
	}

	filler = newLineMiddleware(filler)

	p := mpb.New()

	for i := 0; i < numTasks; i++ {
		var waitBar *mpb.Bar
		if i != 0 {
			waitBar = tasks[i-1].bar
		}
		total := tasks[i].total
		bar := p.AddBar(int64(total),
			mpb.BarExtenderRev(filler),
			mpb.BarQueueAfter(waitBar, false),
			mpb.PrependDecorators(
				decor.Name("current:", decor.WCSyncWidthR),
			),
			mpb.AppendDecorators(
				decor.Percentage(decor.WCSyncWidth),
			),
		)
		tasks[i].bar = bar
	}

	tb := p.AddBar(int64(total),
		mpb.PrependDecorators(
			decor.Any(func(st decor.Statistics) string {
				var done uint32
				if st.Completed {
					done = uint32(len(tasks))
				} else {
					done = atomic.LoadUint32(&doneTasks)
				}
				return fmt.Sprintf("TOTAL(%d/%d)", done, len(tasks))
			}, decor.WCSyncWidthR),
		),
		mpb.AppendDecorators(
			decor.Percentage(decor.WCSyncWidth),
		),
	)

	for _, t := range tasks {
		atomic.StoreUint32(&curTask, uint32(t.id))
		complete(tb, t)
		atomic.AddUint32(&doneTasks, 1)
	}

	p.Wait()
}

func middleware(base mpb.BarFiller, id int) mpb.BarFiller {
	var done bool
	fn := func(w io.Writer, _ int, st decor.Statistics) {
		if !done {
			cur := atomic.LoadUint32(&curTask) == uint32(id)
			if !st.Completed && cur {
				fmt.Fprintf(w, "=> Taksk %02d\n", id)
				return
			} else if !cur {
				fmt.Fprintf(w, "   Taksk %02d\n", id)
				return
			} else {
				done = cur
			}
		}
		fmt.Fprintf(w, "   Taksk %02d: Done!\n", id)
	}
	if id == 0 {
		return mpb.BarFillerFunc(fn)
	}
	return mpb.BarFillerFunc(func(w io.Writer, reqWidth int, st decor.Statistics) {
		fn(w, reqWidth, st)
		base.Fill(w, reqWidth, st)
	})
}

func newLineMiddleware(base mpb.BarFiller) mpb.BarFiller {
	return mpb.BarFillerFunc(func(w io.Writer, reqWidth int, st decor.Statistics) {
		fmt.Fprintln(w)
		base.Fill(w, reqWidth, st)
	})
}

func complete(tb *mpb.Bar, t *task) {
	bar := t.bar
	max := 100 * time.Millisecond
	for !bar.Completed() {
		n := rand.Int63n(10) + 1
		bar.IncrInt64(n)
		tb.IncrInt64(n)
		time.Sleep(time.Duration(rand.Intn(10)+1) * max / 10)
	}
	bar.Wait()
}