Skip to content

Commit

Permalink
Add internal/units, remove go-units dependency
Browse files Browse the repository at this point in the history
We only use a single method, RAMInBytes, which can be easily implemented
locally.

Do that (based on docker/go-units#40, so the
implementation is fully backward-compatible, except for the addition
of treating -1), and remove docker/go-units dependency.

This implementation relies on strings.Cut() which is only available
since Go 1.18.

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
  • Loading branch information
kolyshkin committed Aug 18, 2022
1 parent 4a51b04 commit b617fe7
Show file tree
Hide file tree
Showing 14 changed files with 165 additions and 616 deletions.
1 change: 0 additions & 1 deletion go.mod
Expand Up @@ -8,7 +8,6 @@ require (
github.com/containerd/console v1.0.3
github.com/coreos/go-systemd/v22 v22.3.2
github.com/cyphar/filepath-securejoin v0.2.3
github.com/docker/go-units v0.4.0
github.com/godbus/dbus/v5 v5.1.0
github.com/moby/sys/mountinfo v0.6.2
github.com/mrunalp/fileutils v0.5.0
Expand Down
2 changes: 0 additions & 2 deletions go.sum
Expand Up @@ -14,8 +14,6 @@ github.com/cyphar/filepath-securejoin v0.2.3/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxG
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw=
github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
github.com/frankban/quicktest v1.14.0 h1:+cqqvzZV87b4adx/5ayVOaYZ2CrvM4ejQvUdBzPPUss=
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk=
Expand Down
95 changes: 95 additions & 0 deletions internal/units/units.go
@@ -0,0 +1,95 @@
package units

import (
"fmt"
"strconv"
"strings"
)

func RAMInBytes(val string) (int64, error) {
if val == "-1" {
return -1, nil
}

num, sfx, found := strings.Cut(val, " ")
if !found {
// No space between the number and the suffix.
sep := strings.LastIndexAny(val, "01234567890.")
if sep == -1 {
// There should be at least a digit.
return -1, fmt.Errorf("invalid value: %q", val)
}
num = val[:sep+1]
sfx = val[sep+1:]
}

size, err := strconv.ParseFloat(num, 64)
if err != nil {
return -1, err
}
// Backward compatibility: reject negative sizes.
if size < 0 {
return -1, fmt.Errorf("invalid value: %q", val)
}

if len(sfx) == 0 {
return int64(size), nil
}

// Process the suffix.
if len(sfx) > 3 { // Too long.
goto badSuffix
}
sfx = strings.ToLower(sfx)
// Trivial case: b suffix.
if sfx[0] == 'b' {
if len(sfx) > 1 { // no extra characters allowed after b.
goto badSuffix
}
return int64(size), nil
}

if mul := getMultiplier(sfx[0]); mul != 0 {
size *= float64(mul)
} else {
goto badSuffix
}

// The suffix may have extra "b" or "ib" (e.g. KiB or MB).
switch {
case len(sfx) == 2 && sfx[1] != 'b':
goto badSuffix
case len(sfx) == 3 && sfx[1:] != "ib":
goto badSuffix
}

return int64(size), nil

badSuffix:
return -1, fmt.Errorf("invalid suffix: '%s'", sfx)
}

const (
kb = 1024
mb = 1024 * kb
gb = 1024 * mb
tb = 1024 * gb
pb = 1024 * tb
)

func getMultiplier(suffix byte) int64 {
switch suffix {
case 'k':
return kb
case 'm':
return mb
case 'g':
return gb
case 't':
return tb
case 'p':
return pb
}

return 0
}
63 changes: 63 additions & 0 deletions internal/units/units_test.go
@@ -0,0 +1,63 @@
package units

import (
"reflect"
"runtime"
"strings"
"testing"
)

func TestRAMInBytes(t *testing.T) {
assertEqual(t, RAMInBytes, "-1", -1)
assertEqual(t, RAMInBytes, "32", 32)
assertEqual(t, RAMInBytes, "32b", 32)
assertEqual(t, RAMInBytes, "32B", 32)
assertEqual(t, RAMInBytes, "32k", 32*kb)
assertEqual(t, RAMInBytes, "32K", 32*kb)
assertEqual(t, RAMInBytes, "32kb", 32*kb)
assertEqual(t, RAMInBytes, "32Kb", 32*kb)
assertEqual(t, RAMInBytes, "32Kib", 32*kb)
assertEqual(t, RAMInBytes, "32KIB", 32*kb)
assertEqual(t, RAMInBytes, "32Mb", 32*mb)
assertEqual(t, RAMInBytes, "32Gb", 32*gb)
assertEqual(t, RAMInBytes, "32Tb", 32*tb)
assertEqual(t, RAMInBytes, "32Pb", 32*pb)
assertEqual(t, RAMInBytes, "32PB", 32*pb)
assertEqual(t, RAMInBytes, "32P", 32*pb)

assertEqual(t, RAMInBytes, "32.3", 32)
tmp := 32.3 * mb
assertEqual(t, RAMInBytes, "32.3 mb", int64(tmp))
tmp = 0.3 * mb
assertEqual(t, RAMInBytes, "0.3MB", int64(tmp))

assertError(t, RAMInBytes, "")
assertError(t, RAMInBytes, "hello")
assertError(t, RAMInBytes, "-32")
assertError(t, RAMInBytes, " 32 ")
assertError(t, RAMInBytes, "32m b")
assertError(t, RAMInBytes, "32bm")
}

type parseFn func(string) (int64, error)

func (fn parseFn) String() string {
fnName := runtime.FuncForPC(reflect.ValueOf(fn).Pointer()).Name()
return fnName[strings.LastIndex(fnName, ".")+1:]
}

func assertEqual(t *testing.T, fn parseFn, arg string, expected int64) {
t.Helper()
res, err := fn(arg)
if err != nil || res != expected {
t.Errorf("%s(\"%s\") -> expected '%d' but got '%d' with error '%v'", fn, arg, expected, res, err)
}
}

func assertError(t *testing.T, fn parseFn, arg string) {
t.Helper()
res, err := fn(arg)
if err == nil && res != -1 {
t.Errorf("%s(\"%s\") -> expected error but got '%d'", fn, arg, res)
}
}
20 changes: 7 additions & 13 deletions update.go
Expand Up @@ -7,14 +7,14 @@ import (
"os"
"strconv"

"github.com/opencontainers/runc/libcontainer/cgroups"
"github.com/opencontainers/runtime-spec/specs-go"
"github.com/sirupsen/logrus"
"github.com/urfave/cli"

"github.com/docker/go-units"
"github.com/opencontainers/runc/internal/units"
"github.com/opencontainers/runc/libcontainer/cgroups"
"github.com/opencontainers/runc/libcontainer/configs"
"github.com/opencontainers/runc/libcontainer/intelrdt"
"github.com/opencontainers/runtime-spec/specs-go"
"github.com/urfave/cli"
)

func i64Ptr(i int64) *int64 { return &i }
Expand Down Expand Up @@ -232,15 +232,9 @@ other options are ignored.
{"memory-reservation", r.Memory.Reservation},
} {
if val := context.String(pair.opt); val != "" {
var v int64

if val != "-1" {
v, err = units.RAMInBytes(val)
if err != nil {
return fmt.Errorf("invalid value for %s: %w", pair.opt, err)
}
} else {
v = -1
v, err := units.RAMInBytes(val)
if err != nil {
return fmt.Errorf("invalid value for %s: %w", pair.opt, err)
}
*pair.dest = v
}
Expand Down
67 changes: 0 additions & 67 deletions vendor/github.com/docker/go-units/CONTRIBUTING.md

This file was deleted.

0 comments on commit b617fe7

Please sign in to comment.