Compare commits

...

3 commits

Author SHA1 Message Date
ce417a1df6
Introduce unit for size and add tests 2020-03-03 14:22:12 +01:00
b0851a268c
Remove unused function 2020-03-03 14:21:06 +01:00
3db212b3c6
Report the right size to Top 2020-03-03 14:16:54 +01:00
4 changed files with 222 additions and 78 deletions

View file

@ -14,9 +14,21 @@ const (
SingleType = "single" SingleType = "single"
) )
type ByteSize uint
const (
B ByteSize = 1 << (10 * iota)
KB
MB
GB
TB
PB
)
var ErrUnknownType = errors.New("unknown type") var ErrUnknownType = errors.New("unknown type")
var ErrShouldBeBottom = errors.New("should be of type Bottom") var ErrShouldBeBottom = errors.New("should be of type Bottom")
var ErrChannelError = errors.New("channel errored") var ErrChannelError = errors.New("channel errored")
var ErrUnknownUnit = errors.New("unknown unit")
var ( var (
NodeB = "│" NodeB = "│"
NodeT = "├──" NodeT = "├──"
@ -25,6 +37,8 @@ var (
) )
type Node interface { type Node interface {
SetUnit(string)
GetUnit() ByteSize
Size() int64 Size() int64
Spawn(int) error Spawn(int) error
Collect() error Collect() error
@ -36,8 +50,50 @@ func isLastLevel(node Node, maxLevel int) bool {
return maxLevel-1 == node.Level() return maxLevel-1 == node.Level()
} }
func isBeforeLastLevel(node Node, maxLevel int) bool { func setUnit(unit string) ByteSize {
return maxLevel-1 > node.Level() switch unit {
case "B":
return B
case "KB":
return KB
case "MB":
return MB
case "GB":
return GB
case "TB":
return TB
case "PB":
// I reckon this will never happen, but you never know
return PB
default:
panic(ErrUnknownUnit)
}
}
func fmtUnit(unit ByteSize) string {
switch unit {
case B:
return "B"
case KB:
return "KB"
case MB:
return "MB"
case GB:
return "GB"
case TB:
return "TB"
case PB:
// I reckon this will never happen, but you never know
return "PB"
default:
panic(ErrUnknownUnit)
}
}
func fmtSize(size int64, unit ByteSize) string {
var dimension float64
dimension = float64(size) / float64(unit)
return fmt.Sprintf("%.2f %s", dimension, fmtUnit(unit))
} }
////////////////////////////// //////////////////////////////
@ -47,17 +103,26 @@ func isBeforeLastLevel(node Node, maxLevel int) bool {
type Top struct { type Top struct {
path string path string
size int64 size int64
unit ByteSize
tree []Node tree []Node
collect chan int64 collect chan int64
level int level int
} }
func NewTop(path string) *Top { func NewTop(path string) *Top {
t := &Top{path: path, level: 0} t := &Top{path: path, level: 0, unit: KB}
t.collect = make(chan int64) t.collect = make(chan int64)
return t return t
} }
func (t *Top) SetUnit(unit string) {
t.unit = setUnit(unit)
}
func (t *Top) GetUnit() ByteSize {
return t.unit
}
func (t *Top) Size() int64 { func (t *Top) Size() int64 {
return t.size return t.size
} }
@ -114,7 +179,7 @@ func (t *Top) Name() string {
func (t *Top) String() string { func (t *Top) String() string {
var out string var out string
var lines []string var lines []string
out += fmt.Sprintf("(%d) %s\n", t.Size(), t.path) out += fmt.Sprintf("(%s) %s\n", fmtSize(t.Size(), t.GetUnit()), t.path)
treeSize := len(t.tree) treeSize := len(t.tree)
for _, child := range t.tree { for _, child := range t.tree {
lines = append(lines, fmt.Sprintf("%s", child)) lines = append(lines, fmt.Sprintf("%s", child))
@ -129,7 +194,7 @@ func (t *Top) String() string {
childLines := strings.Split(lines[treeSize-1], "\n") childLines := strings.Split(lines[treeSize-1], "\n")
out += fmt.Sprintf(" %s%s\n", NodeL, childLines[0]) out += fmt.Sprintf(" %s%s\n", NodeL, childLines[0])
for a := 1; a < len(childLines); a++ { for a := 1; a < len(childLines); a++ {
out += fmt.Sprintf(" %s%s\n", NodePad, childLines[a]) out += fmt.Sprintf("%s%s\n", " ", childLines[a])
} }
return out return out
} }
@ -168,6 +233,7 @@ func (t *Top) newBottom(path string) *Bottom {
type Intermediate struct { type Intermediate struct {
path string path string
size int64 size int64
unit ByteSize
parent Node parent Node
tree []Node tree []Node
collect chan int64 collect chan int64
@ -179,9 +245,18 @@ func NewIntermediate(path string, parent Node) *Intermediate {
i := &Intermediate{path: path, refer: parent.Collector(), parent: parent} i := &Intermediate{path: path, refer: parent.Collector(), parent: parent}
i.collect = make(chan int64) i.collect = make(chan int64)
i.level = parent.Level() + 1 i.level = parent.Level() + 1
i.unit = parent.GetUnit()
return i return i
} }
func (i *Intermediate) SetUnit(unit string) {
i.unit = setUnit(unit)
}
func (i *Intermediate) GetUnit() ByteSize {
return i.unit
}
func (i *Intermediate) Size() int64 { func (i *Intermediate) Size() int64 {
return i.size return i.size
} }
@ -221,7 +296,7 @@ func (i *Intermediate) Spawn(maxLevel int) error {
func (i *Intermediate) Collect() error { func (i *Intermediate) Collect() error {
for s := range i.collect { for s := range i.collect {
i.size += s i.size += s
i.refer <- i.size i.refer <- s
} }
close(i.refer) close(i.refer)
return nil return nil
@ -241,7 +316,7 @@ func (i *Intermediate) Name() string {
func (i *Intermediate) String() string { func (i *Intermediate) String() string {
var lines []string var lines []string
out := fmt.Sprintf("(%d) %s\n", i.Size(), i.Name()) out := fmt.Sprintf("(%s) %s\n", fmtSize(i.Size(), i.GetUnit()), i.Name())
treeSize := len(i.tree) treeSize := len(i.tree)
for _, child := range i.tree { for _, child := range i.tree {
lines = append(lines, fmt.Sprintf("%s", child)) lines = append(lines, fmt.Sprintf("%s", child))
@ -260,9 +335,9 @@ func (i *Intermediate) String() string {
if lenChildLines > 1 { if lenChildLines > 1 {
out += fmt.Sprintf("%s%s%s\n", NodePad, NodeL, childLines[0]) out += fmt.Sprintf("%s%s%s\n", NodePad, NodeL, childLines[0])
for a := 1; a < lenChildLines-2; a++ { for a := 1; a < lenChildLines-2; a++ {
out += fmt.Sprintf("%s%s%s\n", NodePad, NodePad, childLines[a]) out += fmt.Sprintf(" %s%s\n", NodePad, childLines[a])
} }
out += fmt.Sprintf("%s%s%s", NodePad, NodePad, childLines[lenChildLines-1]) out += fmt.Sprintf(" %s%s", NodePad, childLines[lenChildLines-1])
} else { } else {
out += fmt.Sprintf("%s%s%s", NodePad, NodeL, childLines[0]) out += fmt.Sprintf("%s%s%s", NodePad, NodeL, childLines[0])
} }
@ -303,6 +378,7 @@ func (i *Intermediate) newBottom(path string) *Bottom {
type Bottom struct { type Bottom struct {
path string path string
size int64 size int64
unit ByteSize
parent Node parent Node
walker Walker walker Walker
collect chan int64 collect chan int64
@ -311,12 +387,21 @@ type Bottom struct {
} }
func NewBottom(path string, parent Node) *Bottom { func NewBottom(path string, parent Node) *Bottom {
b := &Bottom{path: path, refer: parent.Collector(), parent: parent} b := &Bottom{path: path, refer: parent.Collector(), parent: parent, unit: parent.GetUnit()}
b.collect = make(chan int64) b.collect = make(chan int64)
b.level = parent.Level() + 1 b.level = parent.Level() + 1
b.unit = parent.GetUnit()
return b return b
} }
func (b *Bottom) SetUnit(unit string) {
b.unit = setUnit(unit)
}
func (b *Bottom) GetUnit() ByteSize {
return b.unit
}
func (b *Bottom) Size() int64 { func (b *Bottom) Size() int64 {
return b.size return b.size
} }
@ -330,7 +415,7 @@ func (b *Bottom) Spawn(maxLevel int) error {
func (b *Bottom) Collect() error { func (b *Bottom) Collect() error {
for s := range b.collect { for s := range b.collect {
b.size += s b.size += s
b.refer <- b.size b.refer <- s
} }
close(b.refer) close(b.refer)
return nil return nil
@ -349,7 +434,7 @@ func (b *Bottom) Name() string {
} }
func (b *Bottom) String() string { func (b *Bottom) String() string {
return fmt.Sprintf("(%d) %s", b.Size(), b.Name()) return fmt.Sprintf("(%s) %s", fmtSize(b.Size(), b.GetUnit()), b.Name())
} }
////////////////////////////// //////////////////////////////

View file

@ -3,74 +3,69 @@ package main
import ( import (
"fmt" "fmt"
"testing" "testing"
"time"
) )
const result = `(0) / const result = `(0.00 KB) /
(0) i1 (0.00 KB) i1
(0) i1s1 (0.00 KB) i1s1
(0) i1s1b1 (0.00 KB) i1s1b1
(0) i1s1b2 (0.00 KB) i1s1b2
(0) i1s1b3 (0.00 KB) i1s1b3
(0) i1s1b3 (0.00 KB) i1s2
(0) i1s2 (0.00 KB) i1s2b1
(0) i1s2b1 (0.00 KB) i1s2b2
(0) i1s2b2 (0.00 KB) i1s3
(0) i1s2b2 (0.00 KB) i1s3s1
(0) i1s3 (0.00 KB) i1s3s1b1
(0) i1s3s1 (0.00 KB) i1s3s1b2
(0) i1s3s1b1 (0.00 KB) i1s3s1b3
(0) i1s3s1b2 (0.00 KB) i1s3b1
(0) i1s3s1b3 (0.00 KB) i1s4
(0) i1s3s1b3 (0.00 KB) i1s4b1
(0) i1s3b1 (0.00 KB) i2
(0) i1s3b1 (0.00 KB) i2b1
(0) i1s4 (0.00 KB) i2b2
(0) i1s4b1 (0.00 KB) i3
(0) i2 (0.00 KB) i3s1
(0) i2b1 (0.00 KB) i3s1b1
(0) i2b2 (0.00 KB) i3s2
(0) i2b2 (0.00 KB) i3s2b1
(0) i3 (0.00 KB) i3s2b2
(0) i3s1 (0.00 KB) i3s3
(0) i3s1b1 (0.00 KB) i3s3b1
(0) i3s1b1
(0) i3s2
(0) i3s2b1
(0) i3s2b2
(0) i3s2b2
(0) i3s3
(0) i3s3b1
` `
func createTree() *Top { func createTree() *Top {
t := NewTop("/") t := NewTop("/")
i1 := t.newChild("i1", IntermediateType).(*Intermediate) t.SetUnit("KB")
i2 := t.newChild("i2", IntermediateType).(*Intermediate) i1 := t.newIntermediate("i1")
i3 := t.newChild("i3", IntermediateType).(*Intermediate) i2 := t.newIntermediate("i2")
i1s1 := i1.newChild("i1s1", IntermediateType).(*Intermediate) i3 := t.newIntermediate("i3")
i1s2 := i1.newChild("i1s2", IntermediateType).(*Intermediate) i1s1 := i1.newIntermediate("i1s1")
i1s3 := i1.newChild("i1s3", IntermediateType).(*Intermediate) i1s2 := i1.newIntermediate("i1s2")
i1s4 := i1.newChild("i1s4", IntermediateType).(*Intermediate) i1s3 := i1.newIntermediate("i1s3")
i3s1 := i3.newChild("i3s1", IntermediateType).(*Intermediate) i1s4 := i1.newIntermediate("i1s4")
i3s2 := i3.newChild("i3s2", IntermediateType).(*Intermediate) i3s1 := i3.newIntermediate("i3s1")
i3s3 := i3.newChild("i3s3", IntermediateType).(*Intermediate) i3s2 := i3.newIntermediate("i3s2")
_ = i1s1.newChild("i1s1b1", BottomType).(*Bottom) i3s3 := i3.newIntermediate("i3s3")
_ = i1s1.newChild("i1s1b2", BottomType).(*Bottom) _ = i1s1.newBottom("i1s1b1")
_ = i1s1.newChild("i1s1b3", BottomType).(*Bottom) _ = i1s1.newBottom("i1s1b2")
_ = i1s2.newChild("i1s2b1", BottomType).(*Bottom) _ = i1s1.newBottom("i1s1b3")
_ = i1s2.newChild("i1s2b2", BottomType).(*Bottom) _ = i1s2.newBottom("i1s2b1")
i1s3s1 := i1s3.newChild("i1s3s1", IntermediateType).(*Intermediate) _ = i1s2.newBottom("i1s2b2")
_ = i1s3.newChild("i1s3b1", BottomType).(*Bottom) i1s3s1 := i1s3.newIntermediate("i1s3s1")
_ = i1s4.newChild("i1s4b1", BottomType).(*Bottom) _ = i1s3.newBottom("i1s3b1")
_ = i2.newChild("i2b1", BottomType).(*Bottom) _ = i1s4.newBottom("i1s4b1")
_ = i2.newChild("i2b2", BottomType).(*Bottom) _ = i2.newBottom("i2b1")
_ = i3s1.newChild("i3s1b1", BottomType).(*Bottom) _ = i2.newBottom("i2b2")
_ = i3s2.newChild("i3s2b1", BottomType).(*Bottom) _ = i3s1.newBottom("i3s1b1")
_ = i3s2.newChild("i3s2b2", BottomType).(*Bottom) _ = i3s2.newBottom("i3s2b1")
_ = i3s3.newChild("i3s3b1", BottomType).(*Bottom) _ = i3s2.newBottom("i3s2b2")
_ = i1s3s1.newChild("i1s3s1b1", BottomType).(*Bottom) _ = i3s3.newBottom("i3s3b1")
_ = i1s3s1.newChild("i1s3s1b2", BottomType).(*Bottom) _ = i1s3s1.newBottom("i1s3s1b1")
_ = i1s3s1.newChild("i1s3s1b3", BottomType).(*Bottom) _ = i1s3s1.newBottom("i1s3s1b2")
_ = i1s3s1.newBottom("i1s3s1b3")
return t return t
} }
@ -79,6 +74,31 @@ func TestString(t *testing.T) {
tree := createTree() tree := createTree()
repr := fmt.Sprintf("%s", tree) repr := fmt.Sprintf("%s", tree)
if repr != result { if repr != result {
t.Errorf("%s", repr) t.Errorf("repr:\n%s\n\nresult:\n%s", repr, result)
}
}
func TestSize(t *testing.T) {
root := NewTop(".")
i := NewIntermediate("i", root)
b := NewBottom("b", i)
go func() {
ch := b.Collector()
ch <- 1024
}()
go b.Collect()
go i.Collect()
go root.Collect()
time.Sleep(time.Second)
if bsize := b.Size(); bsize != 1024 {
t.Errorf("b -> wrong size: %d\n", bsize)
}
if isize := i.Size(); isize != 1024 {
t.Errorf("i -> wrong size: %d\n", isize)
}
if tsize := root.Size(); tsize != 1024 {
t.Errorf("t -> wrong size: %d\n", tsize)
} }
} }

36
main.go
View file

@ -6,14 +6,50 @@ import (
"time" "time"
) )
type UnitValue struct {
unit string
}
func (u *UnitValue) String() string {
return u.unit
}
func (u *UnitValue) Set(value string) error {
switch value {
case "B":
u.unit = "B"
return nil
case "KB":
u.unit = "KB"
return nil
case "MB":
u.unit = "MB"
return nil
case "GB":
u.unit = "GB"
return nil
case "TB":
u.unit = "TB"
return nil
case "PB":
u.unit = "PB"
return nil
default:
return ErrUnknownUnit
}
}
func main() { func main() {
var path string var path string
var depth int var depth int
var unit = &UnitValue{unit: "KB"}
flag.StringVar(&path, "path", ".", "Path from where to start the walk from") flag.StringVar(&path, "path", ".", "Path from where to start the walk from")
flag.IntVar(&depth, "depth", 0, "Depth to display") flag.IntVar(&depth, "depth", 0, "Depth to display")
flag.Var(unit, "unit", "Unit in which to report size")
flag.Parse() flag.Parse()
t := NewTop(path) t := NewTop(path)
t.SetUnit(unit.String())
go t.Spawn(depth) go t.Spawn(depth)
go t.Collect() go t.Collect()
for { for {

View file

@ -11,10 +11,13 @@ type RealWalker struct {
} }
func (r *RealWalker) walkFunc(path string, info os.FileInfo, err error) error { func (r *RealWalker) walkFunc(path string, info os.FileInfo, err error) error {
if !info.IsDir() {
switch mode := info.Mode(); { switch mode := info.Mode(); {
case mode.IsRegular(): case mode.IsRegular():
r.report <- info.Size() r.report <- info.Size()
} }
}
return nil return nil
} }