check / check (push) Successful in 12m47s
Linting and testing become the lint and test phases of the Dockerfile, and the build stage depends on both. Dockerfile.lint, CHECK_EPOCH and the tests that checked them are removed. Every docker build in script/ passes --no-cache, and script/cibuild runs script/bootstrap first. A host without Go gets the go.mod version from script/install-go in .tool/go, which bootstrap, the Makefile, fmt, fmt-check, precommit and release add to PATH; fmt-check skips .tool. The image takes its version from the VERSION build arg or git describe, dev without .git. This repo's own entries follow the canonical content in .gitignore and .editorconfig. The golangci-lint v2.14.0 findings are fixed. The rules in CLAUDE.md move into AGENTS.md. IsDevVersion counts "unknown". Model: opus-5-5
86 lines
2.0 KiB
Go
86 lines
2.0 KiB
Go
package config
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"math"
|
|
|
|
"github.com/dustin/go-humanize"
|
|
)
|
|
|
|
var (
|
|
errSizeType = errors.New("size must be a number or string")
|
|
errSizeTooLarge = errors.New("size exceeds maximum supported value")
|
|
)
|
|
|
|
// Size represents a byte size that can be specified in configuration files.
|
|
// It can unmarshal from both numeric values (interpreted as bytes) and
|
|
// human-readable strings like "10MB", "2.5GB", or "1TB".
|
|
type Size int64
|
|
|
|
// UnmarshalYAML implements yaml.Unmarshaler for Size, allowing it to be
|
|
// parsed from YAML configuration files. It accepts both numeric values
|
|
// (interpreted as bytes) and string values with units (e.g., "10MB").
|
|
func (s *Size) UnmarshalYAML(unmarshal func(any) error) error {
|
|
// Try to unmarshal as int64 first
|
|
var intVal int64
|
|
|
|
err := unmarshal(&intVal)
|
|
if err == nil {
|
|
*s = Size(intVal)
|
|
|
|
return nil
|
|
}
|
|
|
|
// Try to unmarshal as string
|
|
var strVal string
|
|
|
|
err = unmarshal(&strVal)
|
|
if err != nil {
|
|
return errSizeType
|
|
}
|
|
|
|
// Parse the string using go-humanize
|
|
bytes, err := humanize.ParseBytes(strVal)
|
|
if err != nil {
|
|
return fmt.Errorf("invalid size format: %w", err)
|
|
}
|
|
|
|
if bytes > math.MaxInt64 {
|
|
return fmt.Errorf("%w: %s", errSizeTooLarge, strVal)
|
|
}
|
|
|
|
*s = Size(bytes)
|
|
|
|
return nil
|
|
}
|
|
|
|
// Int64 returns the size as int64 bytes.
|
|
// This is useful when the size needs to be passed to APIs that expect
|
|
// a numeric byte count.
|
|
func (s Size) Int64() int64 {
|
|
return int64(s)
|
|
}
|
|
|
|
// String returns the size as a human-readable string.
|
|
// For example, 1048576 bytes would be formatted as "1.0 MB".
|
|
// This implements the fmt.Stringer interface.
|
|
func (s Size) String() string {
|
|
//nolint:gosec // G115: sizes are non-negative by construction
|
|
return humanize.Bytes(uint64(s))
|
|
}
|
|
|
|
// ParseSize parses a size string into a Size value
|
|
func ParseSize(s string) (Size, error) {
|
|
bytes, err := humanize.ParseBytes(s)
|
|
if err != nil {
|
|
return 0, fmt.Errorf("invalid size format: %w", err)
|
|
}
|
|
|
|
if bytes > math.MaxInt64 {
|
|
return 0, fmt.Errorf("%w: %s", errSizeTooLarge, s)
|
|
}
|
|
|
|
return Size(bytes), nil
|
|
}
|