Merge pull request #5756 from crosbymichael/move-units-to-pkg

Move duration and size to units pkg
This commit is contained in:
Victor Vieux 2014-05-14 11:36:14 -07:00
commit bc22c9948c
11 changed files with 165 additions and 140 deletions

View file

@ -28,6 +28,7 @@ import (
"github.com/dotcloud/docker/nat" "github.com/dotcloud/docker/nat"
"github.com/dotcloud/docker/pkg/signal" "github.com/dotcloud/docker/pkg/signal"
"github.com/dotcloud/docker/pkg/term" "github.com/dotcloud/docker/pkg/term"
"github.com/dotcloud/docker/pkg/units"
"github.com/dotcloud/docker/registry" "github.com/dotcloud/docker/registry"
"github.com/dotcloud/docker/runconfig" "github.com/dotcloud/docker/runconfig"
"github.com/dotcloud/docker/utils" "github.com/dotcloud/docker/utils"
@ -884,14 +885,14 @@ func (cli *DockerCli) CmdHistory(args ...string) error {
fmt.Fprintf(w, "%s\t", utils.TruncateID(outID)) fmt.Fprintf(w, "%s\t", utils.TruncateID(outID))
} }
fmt.Fprintf(w, "%s ago\t", utils.HumanDuration(time.Now().UTC().Sub(time.Unix(out.GetInt64("Created"), 0)))) fmt.Fprintf(w, "%s ago\t", units.HumanDuration(time.Now().UTC().Sub(time.Unix(out.GetInt64("Created"), 0))))
if *noTrunc { if *noTrunc {
fmt.Fprintf(w, "%s\t", out.Get("CreatedBy")) fmt.Fprintf(w, "%s\t", out.Get("CreatedBy"))
} else { } else {
fmt.Fprintf(w, "%s\t", utils.Trunc(out.Get("CreatedBy"), 45)) fmt.Fprintf(w, "%s\t", utils.Trunc(out.Get("CreatedBy"), 45))
} }
fmt.Fprintf(w, "%s\n", utils.HumanSize(out.GetInt64("Size"))) fmt.Fprintf(w, "%s\n", units.HumanSize(out.GetInt64("Size")))
} else { } else {
if *noTrunc { if *noTrunc {
fmt.Fprintln(w, outID) fmt.Fprintln(w, outID)
@ -1249,7 +1250,7 @@ func (cli *DockerCli) CmdImages(args ...string) error {
} }
if !*quiet { if !*quiet {
fmt.Fprintf(w, "%s\t%s\t%s\t%s ago\t%s\n", repo, tag, outID, utils.HumanDuration(time.Now().UTC().Sub(time.Unix(out.GetInt64("Created"), 0))), utils.HumanSize(out.GetInt64("VirtualSize"))) fmt.Fprintf(w, "%s\t%s\t%s\t%s ago\t%s\n", repo, tag, outID, units.HumanDuration(time.Now().UTC().Sub(time.Unix(out.GetInt64("Created"), 0))), units.HumanSize(out.GetInt64("VirtualSize")))
} else { } else {
fmt.Fprintln(w, outID) fmt.Fprintln(w, outID)
} }
@ -1323,7 +1324,7 @@ func (cli *DockerCli) printTreeNode(noTrunc bool, image *engine.Env, prefix stri
imageID = utils.TruncateID(image.Get("Id")) imageID = utils.TruncateID(image.Get("Id"))
} }
fmt.Fprintf(cli.out, "%s%s Virtual Size: %s", prefix, imageID, utils.HumanSize(image.GetInt64("VirtualSize"))) fmt.Fprintf(cli.out, "%s%s Virtual Size: %s", prefix, imageID, units.HumanSize(image.GetInt64("VirtualSize")))
if image.GetList("RepoTags")[0] != "<none>:<none>" { if image.GetList("RepoTags")[0] != "<none>:<none>" {
fmt.Fprintf(cli.out, " Tags: %s\n", strings.Join(image.GetList("RepoTags"), ", ")) fmt.Fprintf(cli.out, " Tags: %s\n", strings.Join(image.GetList("RepoTags"), ", "))
} else { } else {
@ -1408,12 +1409,12 @@ func (cli *DockerCli) CmdPs(args ...string) error {
outCommand = utils.Trunc(outCommand, 20) outCommand = utils.Trunc(outCommand, 20)
} }
ports.ReadListFrom([]byte(out.Get("Ports"))) ports.ReadListFrom([]byte(out.Get("Ports")))
fmt.Fprintf(w, "%s\t%s\t%s\t%s ago\t%s\t%s\t%s\t", outID, out.Get("Image"), outCommand, utils.HumanDuration(time.Now().UTC().Sub(time.Unix(out.GetInt64("Created"), 0))), out.Get("Status"), api.DisplayablePorts(ports), strings.Join(outNames, ",")) fmt.Fprintf(w, "%s\t%s\t%s\t%s ago\t%s\t%s\t%s\t", outID, out.Get("Image"), outCommand, units.HumanDuration(time.Now().UTC().Sub(time.Unix(out.GetInt64("Created"), 0))), out.Get("Status"), api.DisplayablePorts(ports), strings.Join(outNames, ","))
if *size { if *size {
if out.GetInt("SizeRootFs") > 0 { if out.GetInt("SizeRootFs") > 0 {
fmt.Fprintf(w, "%s (virtual %s)\n", utils.HumanSize(out.GetInt64("SizeRw")), utils.HumanSize(out.GetInt64("SizeRootFs"))) fmt.Fprintf(w, "%s (virtual %s)\n", units.HumanSize(out.GetInt64("SizeRw")), units.HumanSize(out.GetInt64("SizeRootFs")))
} else { } else {
fmt.Fprintf(w, "%s\n", utils.HumanSize(out.GetInt64("SizeRw"))) fmt.Fprintf(w, "%s\n", units.HumanSize(out.GetInt64("SizeRw")))
} }
} else { } else {
fmt.Fprint(w, "\n") fmt.Fprint(w, "\n")

View file

@ -8,7 +8,7 @@ import (
"strings" "strings"
"github.com/dotcloud/docker/pkg/libcontainer" "github.com/dotcloud/docker/pkg/libcontainer"
"github.com/dotcloud/docker/utils" "github.com/dotcloud/docker/pkg/units"
) )
type Action func(*libcontainer.Container, interface{}, string) error type Action func(*libcontainer.Container, interface{}, string) error
@ -75,7 +75,7 @@ func memory(container *libcontainer.Container, context interface{}, value string
return fmt.Errorf("cannot set cgroups when they are disabled") return fmt.Errorf("cannot set cgroups when they are disabled")
} }
v, err := utils.RAMInBytes(value) v, err := units.RAMInBytes(value)
if err != nil { if err != nil {
return err return err
} }
@ -88,7 +88,7 @@ func memoryReservation(container *libcontainer.Container, context interface{}, v
return fmt.Errorf("cannot set cgroups when they are disabled") return fmt.Errorf("cannot set cgroups when they are disabled")
} }
v, err := utils.RAMInBytes(value) v, err := units.RAMInBytes(value)
if err != nil { if err != nil {
return err return err
} }

View file

@ -2,9 +2,10 @@ package daemon
import ( import (
"fmt" "fmt"
"github.com/dotcloud/docker/utils"
"sync" "sync"
"time" "time"
"github.com/dotcloud/docker/pkg/units"
) )
type State struct { type State struct {
@ -22,12 +23,12 @@ func (s *State) String() string {
defer s.RUnlock() defer s.RUnlock()
if s.Running { if s.Running {
return fmt.Sprintf("Up %s", utils.HumanDuration(time.Now().UTC().Sub(s.StartedAt))) return fmt.Sprintf("Up %s", units.HumanDuration(time.Now().UTC().Sub(s.StartedAt)))
} }
if s.FinishedAt.IsZero() { if s.FinishedAt.IsZero() {
return "" return ""
} }
return fmt.Sprintf("Exited (%d) %s ago", s.ExitCode, utils.HumanDuration(time.Now().UTC().Sub(s.FinishedAt))) return fmt.Sprintf("Exited (%d) %s ago", s.ExitCode, units.HumanDuration(time.Now().UTC().Sub(s.FinishedAt)))
} }
func (s *State) IsRunning() bool { func (s *State) IsRunning() bool {

2
pkg/units/MAINTAINERS Normal file
View file

@ -0,0 +1,2 @@
Michael Crosby <michael@crosbymichael.com> (@crosbymichael)
Victor Vieux <vieux@docker.com> (@vieux)

31
pkg/units/duration.go Normal file
View file

@ -0,0 +1,31 @@
package units
import (
"fmt"
"time"
)
// HumanDuration returns a human-readable approximation of a duration
// (eg. "About a minute", "4 hours ago", etc.)
func HumanDuration(d time.Duration) string {
if seconds := int(d.Seconds()); seconds < 1 {
return "Less than a second"
} else if seconds < 60 {
return fmt.Sprintf("%d seconds", seconds)
} else if minutes := int(d.Minutes()); minutes == 1 {
return "About a minute"
} else if minutes < 60 {
return fmt.Sprintf("%d minutes", minutes)
} else if hours := int(d.Hours()); hours == 1 {
return "About an hour"
} else if hours < 48 {
return fmt.Sprintf("%d hours", hours)
} else if hours < 24*7*2 {
return fmt.Sprintf("%d days", hours/24)
} else if hours < 24*30*3 {
return fmt.Sprintf("%d weeks", hours/24/7)
} else if hours < 24*365*2 {
return fmt.Sprintf("%d months", hours/24/30)
}
return fmt.Sprintf("%f years", d.Hours()/24/365)
}

56
pkg/units/size.go Normal file
View file

@ -0,0 +1,56 @@
package units
import (
"fmt"
"regexp"
"strconv"
"strings"
)
// HumanSize returns a human-readable approximation of a size
// using SI standard (eg. "44kB", "17MB")
func HumanSize(size int64) string {
i := 0
var sizef float64
sizef = float64(size)
units := []string{"B", "kB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"}
for sizef >= 1000.0 {
sizef = sizef / 1000.0
i++
}
return fmt.Sprintf("%.4g %s", sizef, units[i])
}
// Parses a human-readable string representing an amount of RAM
// in bytes, kibibytes, mebibytes or gibibytes, and returns the
// number of bytes, or -1 if the string is unparseable.
// Units are case-insensitive, and the 'b' suffix is optional.
func RAMInBytes(size string) (bytes int64, err error) {
re, error := regexp.Compile("^(\\d+)([kKmMgG])?[bB]?$")
if error != nil {
return -1, error
}
matches := re.FindStringSubmatch(size)
if len(matches) != 3 {
return -1, fmt.Errorf("Invalid size: '%s'", size)
}
memLimit, error := strconv.ParseInt(matches[1], 10, 0)
if error != nil {
return -1, error
}
unit := strings.ToLower(matches[2])
if unit == "k" {
memLimit *= 1024
} else if unit == "m" {
memLimit *= 1024 * 1024
} else if unit == "g" {
memLimit *= 1024 * 1024 * 1024
}
return memLimit, nil
}

54
pkg/units/size_test.go Normal file
View file

@ -0,0 +1,54 @@
package units
import (
"strings"
"testing"
)
func TestHumanSize(t *testing.T) {
size := strings.Trim(HumanSize(1000), " \t")
expect := "1 kB"
if size != expect {
t.Errorf("1000 -> expected '%s', got '%s'", expect, size)
}
size = strings.Trim(HumanSize(1024), " \t")
expect = "1.024 kB"
if size != expect {
t.Errorf("1024 -> expected '%s', got '%s'", expect, size)
}
}
func TestRAMInBytes(t *testing.T) {
assertRAMInBytes(t, "32", false, 32)
assertRAMInBytes(t, "32b", false, 32)
assertRAMInBytes(t, "32B", false, 32)
assertRAMInBytes(t, "32k", false, 32*1024)
assertRAMInBytes(t, "32K", false, 32*1024)
assertRAMInBytes(t, "32kb", false, 32*1024)
assertRAMInBytes(t, "32Kb", false, 32*1024)
assertRAMInBytes(t, "32Mb", false, 32*1024*1024)
assertRAMInBytes(t, "32Gb", false, 32*1024*1024*1024)
assertRAMInBytes(t, "", true, -1)
assertRAMInBytes(t, "hello", true, -1)
assertRAMInBytes(t, "-32", true, -1)
assertRAMInBytes(t, " 32 ", true, -1)
assertRAMInBytes(t, "32 mb", true, -1)
assertRAMInBytes(t, "32m b", true, -1)
assertRAMInBytes(t, "32bm", true, -1)
}
func assertRAMInBytes(t *testing.T, size string, expectError bool, expectedBytes int64) {
actualBytes, err := RAMInBytes(size)
if (err != nil) && !expectError {
t.Errorf("Unexpected error parsing '%s': %s", size, err)
}
if (err == nil) && expectError {
t.Errorf("Expected to get an error parsing '%s', but got none (bytes=%d)", size, actualBytes)
}
if actualBytes != expectedBytes {
t.Errorf("Expected '%s' to parse as %d bytes, got %d", size, expectedBytes, actualBytes)
}
}

View file

@ -10,6 +10,7 @@ import (
"github.com/dotcloud/docker/opts" "github.com/dotcloud/docker/opts"
flag "github.com/dotcloud/docker/pkg/mflag" flag "github.com/dotcloud/docker/pkg/mflag"
"github.com/dotcloud/docker/pkg/sysinfo" "github.com/dotcloud/docker/pkg/sysinfo"
"github.com/dotcloud/docker/pkg/units"
"github.com/dotcloud/docker/utils" "github.com/dotcloud/docker/utils"
) )
@ -120,7 +121,7 @@ func parseRun(cmd *flag.FlagSet, args []string, sysInfo *sysinfo.SysInfo) (*Conf
var flMemory int64 var flMemory int64
if *flMemoryString != "" { if *flMemoryString != "" {
parsedMemory, err := utils.RAMInBytes(*flMemoryString) parsedMemory, err := units.RAMInBytes(*flMemoryString)
if err != nil { if err != nil {
return nil, nil, cmd, err return nil, nil, cmd, err
} }

View file

@ -3,10 +3,12 @@ package utils
import ( import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"github.com/dotcloud/docker/pkg/term"
"io" "io"
"strings" "strings"
"time" "time"
"github.com/dotcloud/docker/pkg/term"
"github.com/dotcloud/docker/pkg/units"
) )
type JSONError struct { type JSONError struct {
@ -41,11 +43,11 @@ func (p *JSONProgress) String() string {
if p.Current <= 0 && p.Total <= 0 { if p.Current <= 0 && p.Total <= 0 {
return "" return ""
} }
current := HumanSize(int64(p.Current)) current := units.HumanSize(int64(p.Current))
if p.Total <= 0 { if p.Total <= 0 {
return fmt.Sprintf("%8v", current) return fmt.Sprintf("%8v", current)
} }
total := HumanSize(int64(p.Total)) total := units.HumanSize(int64(p.Total))
percentage := int(float64(p.Current)/float64(p.Total)*100) / 2 percentage := int(float64(p.Current)/float64(p.Total)*100) / 2
if width > 110 { if width > 110 {
pbBox = fmt.Sprintf("[%s>%s] ", strings.Repeat("=", percentage), strings.Repeat(" ", 50-percentage)) pbBox = fmt.Sprintf("[%s>%s] ", strings.Repeat("=", percentage), strings.Repeat(" ", 50-percentage))

View file

@ -16,7 +16,6 @@ import (
"os" "os"
"os/exec" "os/exec"
"path/filepath" "path/filepath"
"regexp"
"runtime" "runtime"
"strconv" "strconv"
"strings" "strings"
@ -84,79 +83,6 @@ func Errorf(format string, a ...interface{}) {
logf("error", format, a...) logf("error", format, a...)
} }
// HumanDuration returns a human-readable approximation of a duration
// (eg. "About a minute", "4 hours ago", etc.)
func HumanDuration(d time.Duration) string {
if seconds := int(d.Seconds()); seconds < 1 {
return "Less than a second"
} else if seconds < 60 {
return fmt.Sprintf("%d seconds", seconds)
} else if minutes := int(d.Minutes()); minutes == 1 {
return "About a minute"
} else if minutes < 60 {
return fmt.Sprintf("%d minutes", minutes)
} else if hours := int(d.Hours()); hours == 1 {
return "About an hour"
} else if hours < 48 {
return fmt.Sprintf("%d hours", hours)
} else if hours < 24*7*2 {
return fmt.Sprintf("%d days", hours/24)
} else if hours < 24*30*3 {
return fmt.Sprintf("%d weeks", hours/24/7)
} else if hours < 24*365*2 {
return fmt.Sprintf("%d months", hours/24/30)
}
return fmt.Sprintf("%f years", d.Hours()/24/365)
}
// HumanSize returns a human-readable approximation of a size
// using SI standard (eg. "44kB", "17MB")
func HumanSize(size int64) string {
i := 0
var sizef float64
sizef = float64(size)
units := []string{"B", "kB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"}
for sizef >= 1000.0 {
sizef = sizef / 1000.0
i++
}
return fmt.Sprintf("%.4g %s", sizef, units[i])
}
// Parses a human-readable string representing an amount of RAM
// in bytes, kibibytes, mebibytes or gibibytes, and returns the
// number of bytes, or -1 if the string is unparseable.
// Units are case-insensitive, and the 'b' suffix is optional.
func RAMInBytes(size string) (bytes int64, err error) {
re, error := regexp.Compile("^(\\d+)([kKmMgG])?[bB]?$")
if error != nil {
return -1, error
}
matches := re.FindStringSubmatch(size)
if len(matches) != 3 {
return -1, fmt.Errorf("Invalid size: '%s'", size)
}
memLimit, error := strconv.ParseInt(matches[1], 10, 0)
if error != nil {
return -1, error
}
unit := strings.ToLower(matches[2])
if unit == "k" {
memLimit *= 1024
} else if unit == "m" {
memLimit *= 1024 * 1024
} else if unit == "g" {
memLimit *= 1024 * 1024 * 1024
}
return memLimit, nil
}
func Trunc(s string, maxlen int) string { func Trunc(s string, maxlen int) string {
if len(s) <= maxlen { if len(s) <= maxlen {
return s return s

View file

@ -6,7 +6,6 @@ import (
"io" "io"
"io/ioutil" "io/ioutil"
"os" "os"
"strings"
"testing" "testing"
) )
@ -271,54 +270,6 @@ func TestCompareKernelVersion(t *testing.T) {
-1) -1)
} }
func TestHumanSize(t *testing.T) {
size := strings.Trim(HumanSize(1000), " \t")
expect := "1 kB"
if size != expect {
t.Errorf("1000 -> expected '%s', got '%s'", expect, size)
}
size = strings.Trim(HumanSize(1024), " \t")
expect = "1.024 kB"
if size != expect {
t.Errorf("1024 -> expected '%s', got '%s'", expect, size)
}
}
func TestRAMInBytes(t *testing.T) {
assertRAMInBytes(t, "32", false, 32)
assertRAMInBytes(t, "32b", false, 32)
assertRAMInBytes(t, "32B", false, 32)
assertRAMInBytes(t, "32k", false, 32*1024)
assertRAMInBytes(t, "32K", false, 32*1024)
assertRAMInBytes(t, "32kb", false, 32*1024)
assertRAMInBytes(t, "32Kb", false, 32*1024)
assertRAMInBytes(t, "32Mb", false, 32*1024*1024)
assertRAMInBytes(t, "32Gb", false, 32*1024*1024*1024)
assertRAMInBytes(t, "", true, -1)
assertRAMInBytes(t, "hello", true, -1)
assertRAMInBytes(t, "-32", true, -1)
assertRAMInBytes(t, " 32 ", true, -1)
assertRAMInBytes(t, "32 mb", true, -1)
assertRAMInBytes(t, "32m b", true, -1)
assertRAMInBytes(t, "32bm", true, -1)
}
func assertRAMInBytes(t *testing.T, size string, expectError bool, expectedBytes int64) {
actualBytes, err := RAMInBytes(size)
if (err != nil) && !expectError {
t.Errorf("Unexpected error parsing '%s': %s", size, err)
}
if (err == nil) && expectError {
t.Errorf("Expected to get an error parsing '%s', but got none (bytes=%d)", size, actualBytes)
}
if actualBytes != expectedBytes {
t.Errorf("Expected '%s' to parse as %d bytes, got %d", size, expectedBytes, actualBytes)
}
}
func TestParseHost(t *testing.T) { func TestParseHost(t *testing.T) {
var ( var (
defaultHttpHost = "127.0.0.1" defaultHttpHost = "127.0.0.1"