package main import ( "bytes" "slices" "sync" "github.com/gosuri/uiprogress" "src.lwithers.me.uk/go/htpack/cmd/htpacker/packer" ) type uiProgress struct { p *uiprogress.Progress uncompressed, gzip, brotli *uiProgressBar } func newUiProgress(ftp packer.FilesToPack) *uiProgress { up := &uiProgress{ p: uiprogress.New(), } up.uncompressed = newUiProgressBar(up.p, len(ftp), "uncompressed") var nGzip, nBrotli int for _, f := range ftp { if !f.DisableCompression && !f.DisableGzip { nGzip++ } if !f.DisableCompression && !f.DisableBrotli { nBrotli++ } } if nGzip > 0 { up.gzip = newUiProgressBar(up.p, nGzip, "gzip") } if nBrotli > 0 { up.brotli = newUiProgressBar(up.p, nGzip, "brotli") } up.p.Start() return up } func (up *uiProgress) Count(_ int) { } func (up *uiProgress) Begin(filename, compression string) { up.bar(compression).begin(filename) } func (up *uiProgress) End(filename, compression string) { up.bar(compression).end(filename) } func (up *uiProgress) bar(compression string) *uiProgressBar { switch compression { case "uncompressed": return up.uncompressed case "gzip": return up.gzip case "brotli": return up.brotli } return nil } func (up *uiProgress) Complete() { up.p.Stop() } type uiProgressBar struct { bar *uiprogress.Bar lock sync.Mutex inflight []string } func newUiProgressBar(p *uiprogress.Progress, total int, compression string) *uiProgressBar { bar := &uiProgressBar{ bar: p.AddBar(total).AppendCompleted(), } var buf bytes.Buffer bar.bar.PrependFunc(func(*uiprogress.Bar) string { bar.lock.Lock() defer bar.lock.Unlock() buf.Reset() buf.WriteString(compression) if len(bar.inflight) > 0 { buf.WriteString(" (") for i, f := range bar.inflight { if i > 0 { buf.WriteString(", ") } buf.WriteString(f) } buf.WriteRune(')') } if buf.Len() < 40 { buf.WriteString(" ") buf.Truncate(40) } else if buf.Len() > 40 { buf.Truncate(39) buf.WriteString("…") } return buf.String() }) return bar } func (bar *uiProgressBar) begin(filename string) { if bar == nil { return } bar.lock.Lock() defer bar.lock.Unlock() bar.inflight = append(bar.inflight, filename) } func (bar *uiProgressBar) end(filename string) { if bar == nil { return } bar.lock.Lock() defer bar.lock.Unlock() bar.bar.Incr() if idx := slices.Index(bar.inflight, filename); idx != -1 { bar.inflight = slices.Delete(bar.inflight, idx, idx+1) } }