| // 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) |
| } |