Fix every finding surfaced by the canonical .golangci.yml with golangci-lint v2.12.2 (refs #61), behavior-preserving throughout: - err113: dynamic errors replaced with package-level sentinels and %w wrapping; direct comparisons converted to errors.Is - goprintffuncname: printf-style helpers renamed with an f suffix (ui.Writer message methods, cli.ReportErrorf, database.Fatalf, vaultik stdoutf) and all call sites updated - revive: stuttering type names renamed (blob.Handler, blob.WithReader, blob.ChunkPosition, storage.URL, storage.Info), doc comments added, unused parameters blanked, package comments added - contextcheck/noctx: ctx threaded through blob.Packer (AddChunk/Flush/FinalizeBlob/PackChunks) and scanner call sites; context-aware exec and sql variants used - funlen/cyclop/gocognit/nestif/dupl: oversized or duplicated functions split into focused helpers across production and test code - paralleltest/tparallel/thelper/usetesting/testpackage: tests parallelized where safe (global log.Initialize kept in the serial phase), helpers marked, t.TempDir adopted, external test packages where only exported API is used - gosec: integer conversions clamped or justified, header timeouts added, remaining findings suppressed with per-site justifications - mnd/goconst/lll/wsl_v5/nlreturn/noinlineerr/errcheck and other mechanical findings fixed directly Remove the deprecated log.LogOptions alias (callers migrated to log.Options). make check is green.
88 lines
2.1 KiB
Go
88 lines
2.1 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".
|
|
//
|
|
//nolint:recvcheck // UnmarshalYAML requires a pointer; String/Int64 are value reads
|
|
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
|
|
}
|