Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,10 @@
themeOpt = flag.String("theme", defaultThemeName(), "color themes: dark, light, ansi")
styleOpt = flag.String("style", defaultStyleName(), "style: unicode, ascii")

availThreshold = flag.String("avail-threshold", "10G,1G", "specifies the coloring threshold (yellow, red) of the avail column, must be integer with optional SI prefixes")
availThreshold = flag.String("avail-threshold", "10G,1G", "specifies the coloring threshold (yellow, red) of the avail column, must be integer with prefixes, combine it with --si to use SI instead of IEC conventions")
usageThreshold = flag.String("usage-threshold", "0.5,0.9", "specifies the coloring threshold (yellow, red) of the usage bars as a floating point number from 0 to 1")

prefixSI = flag.Bool("si", false, "use SI units (powers of 1000) instead of IEC units (powers of 1024)")
inodes = flag.Bool("inodes", false, "list inode information instead of block usage")
jsonOutput = flag.Bool("json", false, "output all devices in JSON format")
warns = flag.Bool("warnings", false, "output all warnings to STDERR")
Expand Down Expand Up @@ -265,8 +266,9 @@
fmt.Fprintln(os.Stderr, fmt.Errorf("error parsing avail-threshold: invalid option '%s'", *availThreshold))
os.Exit(1)
}

for _, threshold := range availbilityThresholds {

Check failure on line 270 in main.go

View workflow job for this annotation

GitHub Actions / build (^1, ubuntu-latest)

declared and not used: threshold

Check failure on line 270 in main.go

View workflow job for this annotation

GitHub Actions / build (^1, macos-latest)

declared and not used: threshold
_, err = stringToSize(threshold)
_, err = stringToSize(thresold, *prefixSI)

Check failure on line 271 in main.go

View workflow job for this annotation

GitHub Actions / build (^1, ubuntu-latest)

undefined: thresold

Check failure on line 271 in main.go

View workflow job for this annotation

GitHub Actions / build (^1, macos-latest)

undefined: thresold
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a simple typo in threshold.

if err != nil {
fmt.Fprintln(os.Stderr, "error parsing avail-threshold:", err)
os.Exit(1)
Expand Down
8 changes: 7 additions & 1 deletion man.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,11 +65,17 @@ If duf doesn't detect your terminal's colors correctly, you can set a theme:

$ duf --theme light

duf highlights the availability & usage columns in red, green, or yellow, depending on how much space is still available. You can set your own thresholds:
duf highlights the availability & usage columns in red, green, or yellow, depending on how much space is still available. Use --si to use SI instead of IEC conventions units. You can set your own thresholds:

$ duf --avail-threshold="10G,1G"
$ duf --usage-threshold="0.5,0.9"

Valid prefixes are: k, M, G, T, P, E, Z, Y, but k are replaced with K when using SI units format.

To use SI units (powers of 1000) instead of IEC units (powers of 1024), use:

$ duf --si

If you prefer your output as JSON:

$ duf --json
Expand Down
101 changes: 48 additions & 53 deletions table.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ package main

import (
"fmt"
"math"
"os"
"regexp"
"strconv"
"strings"

Expand Down Expand Up @@ -147,16 +147,16 @@ func printTable(title string, m []Mount, opts TableOptions) {

// sizeTransformer makes a size human-readable.
func sizeTransformer(val interface{}) string {
return sizeToString(val.(uint64))
return sizeToString(val.(uint64), *prefixSI)
}

// spaceTransformer makes a size human-readable and applies a color coding.
func spaceTransformer(val interface{}) string {
free := val.(uint64)

s := termenv.String(sizeToString(free))
redAvail, _ := stringToSize(strings.Split(*availThreshold, ",")[1])
yellowAvail, _ := stringToSize(strings.Split(*availThreshold, ",")[0])
s := termenv.String(sizeToString(free, *prefixSI))
redAvail, _ := stringToSize(strings.Split(*availThreshold, ",")[1], *prefixSI)
yellowAvail, _ := stringToSize(strings.Split(*availThreshold, ",")[0], *prefixSI)
switch {
case free < redAvail:
s = s.Foreground(theme.colorRed)
Expand Down Expand Up @@ -242,65 +242,60 @@ func tableWidth(cols []int, separators bool) int {
return twidth
}

// sizeToString prettifies sizes.
func sizeToString(size uint64) (str string) {
b := float64(size)
func sizeToString(bytes uint64, SI bool) string {
size := float64(bytes)

switch {
case size >= 1<<60:
str = fmt.Sprintf("%.1fE", b/(1<<60))
case size >= 1<<50:
str = fmt.Sprintf("%.1fP", b/(1<<50))
case size >= 1<<40:
str = fmt.Sprintf("%.1fT", b/(1<<40))
case size >= 1<<30:
str = fmt.Sprintf("%.1fG", b/(1<<30))
case size >= 1<<20:
str = fmt.Sprintf("%.1fM", b/(1<<20))
case size >= 1<<10:
str = fmt.Sprintf("%.1fK", b/(1<<10))
default:
str = fmt.Sprintf("%dB", size)
unit := float64(1024)
prefixes := []string{"Ki", "Mi", "Gi", "Ti", "Pi", "Ei", "Zi", "Yi"}

if SI {
unit = float64(1000)
prefixes = []string{"k", "M", "G", "T", "P", "E", "Z", "Y"}
}

return
if size < unit {
return fmt.Sprintf("%d B", bytes)
}

exp := int(math.Log(size) / math.Log(unit))
prefix := prefixes[exp-1]
value := size / math.Pow(unit, float64(exp))

return fmt.Sprintf("%.1f%sB", value, prefix)
}

// stringToSize transforms an SI size into a number.
func stringToSize(s string) (size uint64, err error) {
regex := regexp.MustCompile(`^(\d+)([KMGTPE]?)$`)
matches := regex.FindStringSubmatch(s)
if len(matches) == 0 {
return 0, fmt.Errorf("'%s' is not valid, must have integer with optional SI prefix", s)
func stringToSize(s string, SI bool) (uint64, error) {
var prefix string
var num float64
if _, err := fmt.Sscanf(s, "%f%s", &num, &prefix); err != nil {
return 0, err
}

num, err := strconv.ParseUint(matches[1], 10, 64)
if err != nil {
return 0, err
if prefix == "" {
return uint64(num), nil
}

unit := float64(1024)
prefixes := []string{"", "k", "M", "G", "T", "P", "E", "Z", "Y"}
if SI {
unit = float64(1000)
prefixes[1] = "K"
}
if matches[2] != "" {
prefix := matches[2]
switch prefix {
case "K":
size = num << 10
case "M":
size = num << 20
case "G":
size = num << 30
case "T":
size = num << 40
case "P":
size = num << 50
case "E":
size = num << 60
default:
err = fmt.Errorf("prefix '%s' not allowed, valid prefixes are K, M, G, T, P, E", prefix)
return

var exp int
for i, p := range prefixes {
if p == prefix {
exp = i
break
}
} else {
size = num
}
return

if exp == 0 {
return 0, fmt.Errorf("prefix '%s' not allowed, valid prefixes are k, M, G, T, P, E, Z, Y and K with SI format", prefix)
}

return uint64(num * math.Pow(unit, float64(exp))), nil
}

// stringToColumn converts a column name to its index.
Expand Down
Loading