mirror of
https://github.com/rclone/rclone
synced 2024-12-29 22:26:24 +01:00
3553cc4a5f
Before this change backend types were printing incorrectly as the name of the type, not what was defined by the Type() method. This was not working due to not calling the Type() method. However this needed to be defined on a non-pointer type due to the way the options are handled.
189 lines
4.4 KiB
Go
189 lines
4.4 KiB
Go
package fs
|
|
|
|
// CountSuffix is parsed by flag with k/M/G decimal suffixes
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"math"
|
|
"sort"
|
|
"strconv"
|
|
"strings"
|
|
)
|
|
|
|
// CountSuffix is an int64 with a friendly way of printing setting
|
|
type CountSuffix int64
|
|
|
|
// Common multipliers for SizeSuffix
|
|
const (
|
|
CountSuffixBase CountSuffix = 1
|
|
Kilo = 1000 * CountSuffixBase
|
|
Mega = 1000 * Kilo
|
|
Giga = 1000 * Mega
|
|
Tera = 1000 * Giga
|
|
Peta = 1000 * Tera
|
|
Exa = 1000 * Peta
|
|
)
|
|
const (
|
|
// CountSuffixMax is the largest CountSuffix multiplier
|
|
CountSuffixMax = Exa
|
|
// CountSuffixMaxValue is the largest value that can be used to create CountSuffix
|
|
CountSuffixMaxValue = math.MaxInt64
|
|
// CountSuffixMinValue is the smallest value that can be used to create CountSuffix
|
|
CountSuffixMinValue = math.MinInt64
|
|
)
|
|
|
|
// Turn CountSuffix into a string and a suffix
|
|
func (x CountSuffix) string() (string, string) {
|
|
scaled := float64(0)
|
|
suffix := ""
|
|
switch {
|
|
case x < 0:
|
|
return "off", ""
|
|
case x == 0:
|
|
return "0", ""
|
|
case x < Kilo:
|
|
scaled = float64(x)
|
|
suffix = ""
|
|
case x < Mega:
|
|
scaled = float64(x) / float64(Kilo)
|
|
suffix = "k"
|
|
case x < Giga:
|
|
scaled = float64(x) / float64(Mega)
|
|
suffix = "M"
|
|
case x < Tera:
|
|
scaled = float64(x) / float64(Giga)
|
|
suffix = "G"
|
|
case x < Peta:
|
|
scaled = float64(x) / float64(Tera)
|
|
suffix = "T"
|
|
case x < Exa:
|
|
scaled = float64(x) / float64(Peta)
|
|
suffix = "P"
|
|
default:
|
|
scaled = float64(x) / float64(Exa)
|
|
suffix = "E"
|
|
}
|
|
if math.Floor(scaled) == scaled {
|
|
return fmt.Sprintf("%.0f", scaled), suffix
|
|
}
|
|
return fmt.Sprintf("%.3f", scaled), suffix
|
|
}
|
|
|
|
// String turns CountSuffix into a string
|
|
func (x CountSuffix) String() string {
|
|
val, suffix := x.string()
|
|
return val + suffix
|
|
}
|
|
|
|
// Unit turns CountSuffix into a string with a unit
|
|
func (x CountSuffix) Unit(unit string) string {
|
|
val, suffix := x.string()
|
|
if val == "off" {
|
|
return val
|
|
}
|
|
var suffixUnit string
|
|
if suffix != "" && unit != "" {
|
|
suffixUnit = suffix + unit
|
|
} else {
|
|
suffixUnit = suffix + unit
|
|
}
|
|
return val + " " + suffixUnit
|
|
}
|
|
|
|
func (x *CountSuffix) multiplierFromSymbol(s byte) (found bool, multiplier float64) {
|
|
switch s {
|
|
case 'k', 'K':
|
|
return true, float64(Kilo)
|
|
case 'm', 'M':
|
|
return true, float64(Mega)
|
|
case 'g', 'G':
|
|
return true, float64(Giga)
|
|
case 't', 'T':
|
|
return true, float64(Tera)
|
|
case 'p', 'P':
|
|
return true, float64(Peta)
|
|
case 'e', 'E':
|
|
return true, float64(Exa)
|
|
default:
|
|
return false, float64(CountSuffixBase)
|
|
}
|
|
}
|
|
|
|
// Set a CountSuffix
|
|
func (x *CountSuffix) Set(s string) error {
|
|
if len(s) == 0 {
|
|
return errors.New("empty string")
|
|
}
|
|
if strings.ToLower(s) == "off" {
|
|
*x = -1
|
|
return nil
|
|
}
|
|
suffix := s[len(s)-1]
|
|
suffixLen := 1
|
|
multiplierFound := false
|
|
var multiplier float64
|
|
switch suffix {
|
|
case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '.':
|
|
suffixLen = 0
|
|
multiplier = float64(Kilo)
|
|
case 'b', 'B':
|
|
if len(s) > 1 {
|
|
suffix = s[len(s)-2]
|
|
if multiplierFound, multiplier = x.multiplierFromSymbol(suffix); multiplierFound {
|
|
suffixLen = 2
|
|
}
|
|
} else {
|
|
multiplier = float64(CountSuffixBase)
|
|
}
|
|
default:
|
|
if multiplierFound, multiplier = x.multiplierFromSymbol(suffix); !multiplierFound {
|
|
return fmt.Errorf("bad suffix %q", suffix)
|
|
}
|
|
}
|
|
s = s[:len(s)-suffixLen]
|
|
value, err := strconv.ParseFloat(s, 64)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if value < 0 {
|
|
return fmt.Errorf("size can't be negative %q", s)
|
|
}
|
|
value *= multiplier
|
|
*x = CountSuffix(value)
|
|
return nil
|
|
}
|
|
|
|
// Type of the value
|
|
func (x CountSuffix) Type() string {
|
|
return "CountSuffix"
|
|
}
|
|
|
|
// Scan implements the fmt.Scanner interface
|
|
func (x *CountSuffix) Scan(s fmt.ScanState, ch rune) error {
|
|
token, err := s.Token(true, nil)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return x.Set(string(token))
|
|
}
|
|
|
|
// CountSuffixList is a slice CountSuffix values
|
|
type CountSuffixList []CountSuffix
|
|
|
|
func (l CountSuffixList) Len() int { return len(l) }
|
|
func (l CountSuffixList) Swap(i, j int) { l[i], l[j] = l[j], l[i] }
|
|
func (l CountSuffixList) Less(i, j int) bool { return l[i] < l[j] }
|
|
|
|
// Sort sorts the list
|
|
func (l CountSuffixList) Sort() {
|
|
sort.Sort(l)
|
|
}
|
|
|
|
// UnmarshalJSON makes sure the value can be parsed as a string or integer in JSON
|
|
func (x *CountSuffix) UnmarshalJSON(in []byte) error {
|
|
return UnmarshalJSONFlag(in, x, func(i int64) error {
|
|
*x = CountSuffix(i)
|
|
return nil
|
|
})
|
|
}
|