package progress import ( "fmt" "time" ) // humanSize formats a byte count by abbreviating it: divide by // 1024 while the value is at least one unit and a larger unit remains, then bump // to the next unit when the quotient is >=922 (so 0.9Mi shows instead of 922Ki). // The unit ladder is capped at Gi, so a terabyte prints // as "1024.0GiB". When human is false it prints the raw integer with a B suffix. func humanSize(n int64, human bool) string { if !human { return fmt.Sprintf("%dB", n) } const unit = 1024 if n < unit { return fmt.Sprintf("%dB", n) } // "KMG" caps the ladder at Gi (the units {"","Ki","Mi","Gi"}). const suffixes = "KMG" div, exp := int64(unit), 0 for v := n / unit; v >= unit && exp+1 < len(suffixes); v /= unit { div *= unit exp++ } // Bump to the next unit when the quotient is >=922 and a unit remains, so // 922*1024 bytes reads as 0.9MiB rather than 922KiB. if q := n / div; q >= 922 && exp+1 < len(suffixes) { div *= unit exp++ } val := float64(n) / float64(div) suffix := suffixes[exp] // One decimal for small mantissas and for anything that overflowed the // capped Gi unit (1024.0GiB and up); a bare integer otherwise (e.g. 20MiB). if val < 10 || exp == len(suffixes)-1 && val >= unit { return fmt.Sprintf("%.1f%ciB", val, suffix) } return fmt.Sprintf("%.0f%ciB", val, suffix) } // secfmt renders a duration as "1h2m3s", appending each unit only when it is // nonzero (but still showing seconds when the whole input is 0): // 3600s->"1h", 120s->"2m", 3720s->"1h2m". A non-positive or absurd // duration renders as "--". func secfmt(d time.Duration) string { s := int64(d.Seconds()) if s < 0 || d > 99*time.Hour { return "--" } h, m, sec := s/3600, (s%3600)/60, s%60 var str string if h > 0 { str += fmt.Sprintf("%dh", h) } if m > 0 { str += fmt.Sprintf("%dm", m) } if sec > 0 || s == 0 { str += fmt.Sprintf("%ds", sec) } return str } // percent returns completed/total as a 0-100 integer, or 0 when total is unknown. func percent(completed, total int64) int { if total <= 0 { return 0 } return int(completed * 100 / total) }