Skip to content

Commit

Permalink
Move duration and size to units pkg
Browse files Browse the repository at this point in the history
Docker-DCO-1.1-Signed-off-by: Michael Crosby <[email protected]> (github: crosbymichael)
  • Loading branch information
crosbymichael committed May 13, 2014
1 parent 0d78799 commit d33b465
Show file tree
Hide file tree
Showing 11 changed files with 165 additions and 140 deletions.
15 changes: 8 additions & 7 deletions api/client/commands.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import (
"github.com/dotcloud/docker/nat"
"github.com/dotcloud/docker/pkg/signal"
"github.com/dotcloud/docker/pkg/term"
"github.com/dotcloud/docker/pkg/units"
"github.com/dotcloud/docker/registry"
"github.com/dotcloud/docker/runconfig"
"github.com/dotcloud/docker/utils"
Expand Down Expand Up @@ -884,14 +885,14 @@ func (cli *DockerCli) CmdHistory(args ...string) error {
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 {
fmt.Fprintf(w, "%s\t", out.Get("CreatedBy"))
} else {
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 {
if *noTrunc {
fmt.Fprintln(w, outID)
Expand Down Expand Up @@ -1249,7 +1250,7 @@ func (cli *DockerCli) CmdImages(args ...string) error {
}

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 {
fmt.Fprintln(w, outID)
}
Expand Down Expand Up @@ -1323,7 +1324,7 @@ func (cli *DockerCli) printTreeNode(noTrunc bool, image *engine.Env, prefix stri
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>" {
fmt.Fprintf(cli.out, " Tags: %s\n", strings.Join(image.GetList("RepoTags"), ", "))
} else {
Expand Down Expand Up @@ -1408,12 +1409,12 @@ func (cli *DockerCli) CmdPs(args ...string) error {
outCommand = utils.Trunc(outCommand, 20)
}
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 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 {
fmt.Fprintf(w, "%s\n", utils.HumanSize(out.GetInt64("SizeRw")))
fmt.Fprintf(w, "%s\n", units.HumanSize(out.GetInt64("SizeRw")))
}
} else {
fmt.Fprint(w, "\n")
Expand Down
6 changes: 3 additions & 3 deletions daemon/execdriver/native/configuration/parse.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import (
"strings"

"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
Expand Down Expand Up @@ -75,7 +75,7 @@ func memory(container *libcontainer.Container, context interface{}, value string
return fmt.Errorf("cannot set cgroups when they are disabled")
}

v, err := utils.RAMInBytes(value)
v, err := units.RAMInBytes(value)
if err != nil {
return err
}
Expand All @@ -88,7 +88,7 @@ func memoryReservation(container *libcontainer.Container, context interface{}, v
return fmt.Errorf("cannot set cgroups when they are disabled")
}

v, err := utils.RAMInBytes(value)
v, err := units.RAMInBytes(value)
if err != nil {
return err
}
Expand Down
7 changes: 4 additions & 3 deletions daemon/state.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@ package daemon

import (
"fmt"
"github.com/dotcloud/docker/utils"
"sync"
"time"

"github.com/dotcloud/docker/pkg/units"
)

type State struct {
Expand All @@ -22,12 +23,12 @@ func (s *State) String() string {
defer s.RUnlock()

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() {
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 {
Expand Down
2 changes: 2 additions & 0 deletions pkg/units/MAINTAINERS
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Michael Crosby <[email protected]> (@crosbymichael)
Victor Vieux <[email protected]> (@vieux)
31 changes: 31 additions & 0 deletions pkg/units/duration.go
Original file line number Diff line number Diff line change
@@ -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 changes: 56 additions & 0 deletions pkg/units/size.go
Original file line number Diff line number Diff line change
@@ -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 changes: 54 additions & 0 deletions pkg/units/size_test.go
Original file line number Diff line number Diff line change
@@ -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)
}
}
3 changes: 2 additions & 1 deletion runconfig/parse.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"github.com/dotcloud/docker/opts"
flag "github.com/dotcloud/docker/pkg/mflag"
"github.com/dotcloud/docker/pkg/sysinfo"
"github.com/dotcloud/docker/pkg/units"
"github.com/dotcloud/docker/utils"
)

Expand Down Expand Up @@ -119,7 +120,7 @@ func parseRun(cmd *flag.FlagSet, args []string, sysInfo *sysinfo.SysInfo) (*Conf

var flMemory int64
if *flMemoryString != "" {
parsedMemory, err := utils.RAMInBytes(*flMemoryString)
parsedMemory, err := units.RAMInBytes(*flMemoryString)
if err != nil {
return nil, nil, cmd, err
}
Expand Down
8 changes: 5 additions & 3 deletions utils/jsonmessage.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,12 @@ package utils
import (
"encoding/json"
"fmt"
"github.com/dotcloud/docker/pkg/term"
"io"
"strings"
"time"

"github.com/dotcloud/docker/pkg/term"
"github.com/dotcloud/docker/pkg/units"
)

type JSONError struct {
Expand Down Expand Up @@ -41,11 +43,11 @@ func (p *JSONProgress) String() string {
if p.Current <= 0 && p.Total <= 0 {
return ""
}
current := HumanSize(int64(p.Current))
current := units.HumanSize(int64(p.Current))
if p.Total <= 0 {
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
if width > 110 {
pbBox = fmt.Sprintf("[%s>%s] ", strings.Repeat("=", percentage), strings.Repeat(" ", 50-percentage))
Expand Down
74 changes: 0 additions & 74 deletions utils/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ import (
"os"
"os/exec"
"path/filepath"
"regexp"
"runtime"
"strconv"
"strings"
Expand Down Expand Up @@ -83,79 +82,6 @@ func Errorf(format string, a ...interface{}) {
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 {
if len(s) <= maxlen {
return s
Expand Down
Loading

0 comments on commit d33b465

Please sign in to comment.