435c0d9fc8
This PR switches the Nomad repository from using govendor to Go modules for managing dependencies. Aspects of the Nomad workflow remain pretty much the same. The usual Makefile targets should continue to work as they always did. The API submodule simply defers to the parent Nomad version on the repository, keeping the semantics of API versioning that currently exists.
174 lines
4.2 KiB
Go
174 lines
4.2 KiB
Go
package humanize
|
|
|
|
import (
|
|
"fmt"
|
|
"math/big"
|
|
"strings"
|
|
"unicode"
|
|
)
|
|
|
|
var (
|
|
bigIECExp = big.NewInt(1024)
|
|
|
|
// BigByte is one byte in bit.Ints
|
|
BigByte = big.NewInt(1)
|
|
// BigKiByte is 1,024 bytes in bit.Ints
|
|
BigKiByte = (&big.Int{}).Mul(BigByte, bigIECExp)
|
|
// BigMiByte is 1,024 k bytes in bit.Ints
|
|
BigMiByte = (&big.Int{}).Mul(BigKiByte, bigIECExp)
|
|
// BigGiByte is 1,024 m bytes in bit.Ints
|
|
BigGiByte = (&big.Int{}).Mul(BigMiByte, bigIECExp)
|
|
// BigTiByte is 1,024 g bytes in bit.Ints
|
|
BigTiByte = (&big.Int{}).Mul(BigGiByte, bigIECExp)
|
|
// BigPiByte is 1,024 t bytes in bit.Ints
|
|
BigPiByte = (&big.Int{}).Mul(BigTiByte, bigIECExp)
|
|
// BigEiByte is 1,024 p bytes in bit.Ints
|
|
BigEiByte = (&big.Int{}).Mul(BigPiByte, bigIECExp)
|
|
// BigZiByte is 1,024 e bytes in bit.Ints
|
|
BigZiByte = (&big.Int{}).Mul(BigEiByte, bigIECExp)
|
|
// BigYiByte is 1,024 z bytes in bit.Ints
|
|
BigYiByte = (&big.Int{}).Mul(BigZiByte, bigIECExp)
|
|
)
|
|
|
|
var (
|
|
bigSIExp = big.NewInt(1000)
|
|
|
|
// BigSIByte is one SI byte in big.Ints
|
|
BigSIByte = big.NewInt(1)
|
|
// BigKByte is 1,000 SI bytes in big.Ints
|
|
BigKByte = (&big.Int{}).Mul(BigSIByte, bigSIExp)
|
|
// BigMByte is 1,000 SI k bytes in big.Ints
|
|
BigMByte = (&big.Int{}).Mul(BigKByte, bigSIExp)
|
|
// BigGByte is 1,000 SI m bytes in big.Ints
|
|
BigGByte = (&big.Int{}).Mul(BigMByte, bigSIExp)
|
|
// BigTByte is 1,000 SI g bytes in big.Ints
|
|
BigTByte = (&big.Int{}).Mul(BigGByte, bigSIExp)
|
|
// BigPByte is 1,000 SI t bytes in big.Ints
|
|
BigPByte = (&big.Int{}).Mul(BigTByte, bigSIExp)
|
|
// BigEByte is 1,000 SI p bytes in big.Ints
|
|
BigEByte = (&big.Int{}).Mul(BigPByte, bigSIExp)
|
|
// BigZByte is 1,000 SI e bytes in big.Ints
|
|
BigZByte = (&big.Int{}).Mul(BigEByte, bigSIExp)
|
|
// BigYByte is 1,000 SI z bytes in big.Ints
|
|
BigYByte = (&big.Int{}).Mul(BigZByte, bigSIExp)
|
|
)
|
|
|
|
var bigBytesSizeTable = map[string]*big.Int{
|
|
"b": BigByte,
|
|
"kib": BigKiByte,
|
|
"kb": BigKByte,
|
|
"mib": BigMiByte,
|
|
"mb": BigMByte,
|
|
"gib": BigGiByte,
|
|
"gb": BigGByte,
|
|
"tib": BigTiByte,
|
|
"tb": BigTByte,
|
|
"pib": BigPiByte,
|
|
"pb": BigPByte,
|
|
"eib": BigEiByte,
|
|
"eb": BigEByte,
|
|
"zib": BigZiByte,
|
|
"zb": BigZByte,
|
|
"yib": BigYiByte,
|
|
"yb": BigYByte,
|
|
// Without suffix
|
|
"": BigByte,
|
|
"ki": BigKiByte,
|
|
"k": BigKByte,
|
|
"mi": BigMiByte,
|
|
"m": BigMByte,
|
|
"gi": BigGiByte,
|
|
"g": BigGByte,
|
|
"ti": BigTiByte,
|
|
"t": BigTByte,
|
|
"pi": BigPiByte,
|
|
"p": BigPByte,
|
|
"ei": BigEiByte,
|
|
"e": BigEByte,
|
|
"z": BigZByte,
|
|
"zi": BigZiByte,
|
|
"y": BigYByte,
|
|
"yi": BigYiByte,
|
|
}
|
|
|
|
var ten = big.NewInt(10)
|
|
|
|
func humanateBigBytes(s, base *big.Int, sizes []string) string {
|
|
if s.Cmp(ten) < 0 {
|
|
return fmt.Sprintf("%d B", s)
|
|
}
|
|
c := (&big.Int{}).Set(s)
|
|
val, mag := oomm(c, base, len(sizes)-1)
|
|
suffix := sizes[mag]
|
|
f := "%.0f %s"
|
|
if val < 10 {
|
|
f = "%.1f %s"
|
|
}
|
|
|
|
return fmt.Sprintf(f, val, suffix)
|
|
|
|
}
|
|
|
|
// BigBytes produces a human readable representation of an SI size.
|
|
//
|
|
// See also: ParseBigBytes.
|
|
//
|
|
// BigBytes(82854982) -> 83 MB
|
|
func BigBytes(s *big.Int) string {
|
|
sizes := []string{"B", "kB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"}
|
|
return humanateBigBytes(s, bigSIExp, sizes)
|
|
}
|
|
|
|
// BigIBytes produces a human readable representation of an IEC size.
|
|
//
|
|
// See also: ParseBigBytes.
|
|
//
|
|
// BigIBytes(82854982) -> 79 MiB
|
|
func BigIBytes(s *big.Int) string {
|
|
sizes := []string{"B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB", "YiB"}
|
|
return humanateBigBytes(s, bigIECExp, sizes)
|
|
}
|
|
|
|
// ParseBigBytes parses a string representation of bytes into the number
|
|
// of bytes it represents.
|
|
//
|
|
// See also: BigBytes, BigIBytes.
|
|
//
|
|
// ParseBigBytes("42 MB") -> 42000000, nil
|
|
// ParseBigBytes("42 mib") -> 44040192, nil
|
|
func ParseBigBytes(s string) (*big.Int, error) {
|
|
lastDigit := 0
|
|
hasComma := false
|
|
for _, r := range s {
|
|
if !(unicode.IsDigit(r) || r == '.' || r == ',') {
|
|
break
|
|
}
|
|
if r == ',' {
|
|
hasComma = true
|
|
}
|
|
lastDigit++
|
|
}
|
|
|
|
num := s[:lastDigit]
|
|
if hasComma {
|
|
num = strings.Replace(num, ",", "", -1)
|
|
}
|
|
|
|
val := &big.Rat{}
|
|
_, err := fmt.Sscanf(num, "%f", val)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
extra := strings.ToLower(strings.TrimSpace(s[lastDigit:]))
|
|
if m, ok := bigBytesSizeTable[extra]; ok {
|
|
mv := (&big.Rat{}).SetInt(m)
|
|
val.Mul(val, mv)
|
|
rv := &big.Int{}
|
|
rv.Div(val.Num(), val.Denom())
|
|
return rv, nil
|
|
}
|
|
|
|
return nil, fmt.Errorf("unhandled size name: %v", extra)
|
|
}
|