blob: 0833584355d367887983fc60ed59407d42e521c8 [file] [log] [blame] [edit]
// Package progress makes it possible to display download progress.
package progress
import (
"fmt"
"io"
"os"
"strings"
"golang.org/x/term"
"github.com/bazelbuild/bazelisk/config"
)
// Progress shows a download progress bar.
type progress struct {
header string
total int64
current int64
lastMessage string
}
func showProgress(config config.Config) bool {
// If stdout is a terminal, don't show progress.
if !term.IsTerminal(int(os.Stdout.Fd())) {
return false
}
// Check the config variable.
showProgress := config.Get("BAZELISK_SHOW_PROGRESS")
if len(showProgress) == 0 {
// Default to showing progress
return true
}
switch strings.ToLower(showProgress) {
case "":
return true // Default to on
case "yes":
return true
case "y":
return true
case "true":
return true
case "1":
return true
case "no":
return false
case "n":
return false
case "false":
return false
case "0":
return false
}
// TODO: default: error
return true
}
// Writer creates an io.Writer to print the progress.
func Writer(w io.Writer, header string, total int64, config config.Config) io.Writer {
if !showProgress(config) {
return w
}
prog := &progress{
header: header,
total: total,
}
out := io.MultiWriter(w, prog)
return out
}
// Finish writes final output after the progress bar is complete.
func Finish(config config.Config) {
if showProgress(config) {
// Add a newline after the progress bar
fmt.Println()
}
}
func (p *progress) Write(buf []byte) (int, error) {
l := len(buf)
p.current += int64(l)
p.ShowProgress()
return l, nil
}
// Writes the current download progress to stdout.
func (p *progress) ShowProgress() {
var message string
if p.total > 0 {
message = fmt.Sprintf("%s: %s out of %s (%s)",
p.header,
formatMb(p.current),
formatMb(p.total),
formatPercentage(p.current, p.total))
} else {
message = fmt.Sprintf("%s: %s",
p.header,
formatMb(p.current))
}
if message == p.lastMessage {
return
}
// Clear the line.
fmt.Printf("\r%s", strings.Repeat(" ", 39))
// Show a message, don't add a newline
fmt.Printf("\r%s", message)
p.lastMessage = message
}
func formatMb(size int64) string {
// TODO: Use units other than MB
inMb := size / (1024 * 1024)
return fmt.Sprintf("%d MB", inMb)
}
func formatPercentage(current, size int64) string {
percentage := current * 100 / size
return fmt.Sprintf("%d%%", percentage)
}