package config import ( "fmt" "math" "strconv" "strings" ) func parseBool(value string) (bool, error) { switch strings.ToLower(strings.TrimSpace(value)) { case "1", "t", "true", "y", "yes", "on": return true, nil case "0", "f", "false", "n", "no", "off": return false, nil default: return false, fmt.Errorf("must be a boolean") } } func parseInt64(value string, min int64) (int64, error) { parsed, err := strconv.ParseInt(strings.TrimSpace(value), 10, 64) if err != nil { return 0, fmt.Errorf("must be an integer") } if parsed < min { return 0, fmt.Errorf("must be at least %d", min) } return parsed, nil } func parseInt(value string, min int) (int, error) { parsed64, err := parseInt64(value, int64(min)) if err != nil { return 0, err } if parsed64 > int64(^uint(0)>>1) { return 0, fmt.Errorf("is too large") } return int(parsed64), nil } const bytesPerGigabyte = 1024 * 1024 * 1024 func parseGigabytes(value string, min float64) (int64, error) { raw := strings.TrimSpace(value) lower := strings.ToLower(raw) if strings.HasSuffix(lower, "gb") { raw = strings.TrimSpace(raw[:len(raw)-2]) } parsed, err := strconv.ParseFloat(raw, 64) if err != nil { return 0, fmt.Errorf("must be a number of GB") } if parsed < min { return 0, fmt.Errorf("must be at least %s", trimTrailingZeros(min)) } bytes := parsed * bytesPerGigabyte if bytes > math.MaxInt64 { return 0, fmt.Errorf("is too large") } return int64(math.Round(bytes)), nil } func formatGigabytesFromBytes(bytes int64) string { if bytes <= 0 { return "0" } value := float64(bytes) / bytesPerGigabyte return trimTrailingZeros(value) } func trimTrailingZeros(value float64) string { text := strconv.FormatFloat(value, 'f', 3, 64) text = strings.TrimRight(text, "0") text = strings.TrimRight(text, ".") if text == "" { return "0" } return text } func formatBool(value bool) string { if value { return "true" } return "false" }