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"
)
type ByteSize uint
const (
B ByteSize = 1 << (10 * iota)
KB
MB
GB
TB
PB
)
var ErrUnknownType = errors.New("unknown type")
var ErrShouldBeBottom = errors.New("should be of type Bottom")
var ErrChannelError = errors.New("channel errored")
var ErrUnknownUnit = errors.New("unknown unit")
var (
NodeB = "│"
NodeT = "├──"
@ -25,6 +37,8 @@ var (
)
type Node interface {
SetUnit(string)
GetUnit() ByteSize
Size() int64
Spawn(int) error
Collect() error
@ -36,8 +50,50 @@ func isLastLevel(node Node, maxLevel int) bool {
return maxLevel-1 == node.Level()
}
func isBeforeLastLevel(node Node, maxLevel int) bool {
return maxLevel-1 > node.Level()
func setUnit(unit string) ByteSize {
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 {
path string
size int64
unit ByteSize
tree []Node
collect chan int64
level int
}
func NewTop(path string) *Top {
t := &Top{path: path, level: 0}
t := &Top{path: path, level: 0, unit: KB}
t.collect = make(chan int64)
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 {
return t.size
}
@ -114,7 +179,7 @@ func (t *Top) Name() string {
func (t *Top) String() string {
var out 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)
for _, child := range t.tree {
lines = append(lines, fmt.Sprintf("%s", child))
@ -129,7 +194,7 @@ func (t *Top) String() string {
childLines := strings.Split(lines[treeSize-1], "\n")
out += fmt.Sprintf(" %s%s\n", NodeL, childLines[0])
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
}
@ -168,6 +233,7 @@ func (t *Top) newBottom(path string) *Bottom {
type Intermediate struct {
path string
size int64
unit ByteSize
parent Node
tree []Node
collect chan int64
@ -179,9 +245,18 @@ func NewIntermediate(path string, parent Node) *Intermediate {
i := &Intermediate{path: path, refer: parent.Collector(), parent: parent}
i.collect = make(chan int64)
i.level = parent.Level() + 1
i.unit = parent.GetUnit()
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 {
return i.size
}
@ -221,7 +296,7 @@ func (i *Intermediate) Spawn(maxLevel int) error {
func (i *Intermediate) Collect() error {
for s := range i.collect {
i.size += s
i.refer <- i.size
i.refer <- s
}
close(i.refer)
return nil
@ -241,7 +316,7 @@ func (i *Intermediate) Name() string {
func (i *Intermediate) String() 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)
for _, child := range i.tree {
lines = append(lines, fmt.Sprintf("%s", child))
@ -260,9 +335,9 @@ func (i *Intermediate) String() string {
if lenChildLines > 1 {
out += fmt.Sprintf("%s%s%s\n", NodePad, NodeL, childLines[0])
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 {
out += fmt.Sprintf("%s%s%s", NodePad, NodeL, childLines[0])
}
@ -303,6 +378,7 @@ func (i *Intermediate) newBottom(path string) *Bottom {
type Bottom struct {
path string
size int64
unit ByteSize
parent Node
walker Walker
collect chan int64
@ -311,12 +387,21 @@ type Bottom struct {
}
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.level = parent.Level() + 1
b.unit = parent.GetUnit()
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 {
return b.size
}
@ -330,7 +415,7 @@ func (b *Bottom) Spawn(maxLevel int) error {
func (b *Bottom) Collect() error {
for s := range b.collect {
b.size += s
b.refer <- b.size
b.refer <- s
}
close(b.refer)
return nil
@ -349,7 +434,7 @@ func (b *Bottom) Name() 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 (
"fmt"
"testing"
"time"
)
const result = `(0) /
(0) i1
(0) i1s1
(0) i1s1b1
(0) i1s1b2
(0) i1s1b3
(0) i1s1b3
(0) i1s2
(0) i1s2b1
(0) i1s2b2
(0) i1s2b2
(0) i1s3
(0) i1s3s1
(0) i1s3s1b1
(0) i1s3s1b2
(0) i1s3s1b3
(0) i1s3s1b3
(0) i1s3b1
(0) i1s3b1
(0) i1s4
(0) i1s4b1
(0) i2
(0) i2b1
(0) i2b2
(0) i2b2
(0) i3
(0) i3s1
(0) i3s1b1
(0) i3s1b1
(0) i3s2
(0) i3s2b1
(0) i3s2b2
(0) i3s2b2
(0) i3s3
(0) i3s3b1
const result = `(0.00 KB) /
(0.00 KB) i1
(0.00 KB) i1s1
(0.00 KB) i1s1b1
(0.00 KB) i1s1b2
(0.00 KB) i1s1b3
(0.00 KB) i1s2
(0.00 KB) i1s2b1
(0.00 KB) i1s2b2
(0.00 KB) i1s3
(0.00 KB) i1s3s1
(0.00 KB) i1s3s1b1
(0.00 KB) i1s3s1b2
(0.00 KB) i1s3s1b3
(0.00 KB) i1s3b1
(0.00 KB) i1s4
(0.00 KB) i1s4b1
(0.00 KB) i2
(0.00 KB) i2b1
(0.00 KB) i2b2
(0.00 KB) i3
(0.00 KB) i3s1
(0.00 KB) i3s1b1
(0.00 KB) i3s2
(0.00 KB) i3s2b1
(0.00 KB) i3s2b2
(0.00 KB) i3s3
(0.00 KB) i3s3b1
`
func createTree() *Top {
t := NewTop("/")
i1 := t.newChild("i1", IntermediateType).(*Intermediate)
i2 := t.newChild("i2", IntermediateType).(*Intermediate)
i3 := t.newChild("i3", IntermediateType).(*Intermediate)
i1s1 := i1.newChild("i1s1", IntermediateType).(*Intermediate)
i1s2 := i1.newChild("i1s2", IntermediateType).(*Intermediate)
i1s3 := i1.newChild("i1s3", IntermediateType).(*Intermediate)
i1s4 := i1.newChild("i1s4", IntermediateType).(*Intermediate)
i3s1 := i3.newChild("i3s1", IntermediateType).(*Intermediate)
i3s2 := i3.newChild("i3s2", IntermediateType).(*Intermediate)
i3s3 := i3.newChild("i3s3", IntermediateType).(*Intermediate)
_ = i1s1.newChild("i1s1b1", BottomType).(*Bottom)
_ = i1s1.newChild("i1s1b2", BottomType).(*Bottom)
_ = i1s1.newChild("i1s1b3", BottomType).(*Bottom)
_ = i1s2.newChild("i1s2b1", BottomType).(*Bottom)
_ = i1s2.newChild("i1s2b2", BottomType).(*Bottom)
i1s3s1 := i1s3.newChild("i1s3s1", IntermediateType).(*Intermediate)
_ = i1s3.newChild("i1s3b1", BottomType).(*Bottom)
_ = i1s4.newChild("i1s4b1", BottomType).(*Bottom)
_ = i2.newChild("i2b1", BottomType).(*Bottom)
_ = i2.newChild("i2b2", BottomType).(*Bottom)
_ = i3s1.newChild("i3s1b1", BottomType).(*Bottom)
_ = i3s2.newChild("i3s2b1", BottomType).(*Bottom)
_ = i3s2.newChild("i3s2b2", BottomType).(*Bottom)
_ = i3s3.newChild("i3s3b1", BottomType).(*Bottom)
_ = i1s3s1.newChild("i1s3s1b1", BottomType).(*Bottom)
_ = i1s3s1.newChild("i1s3s1b2", BottomType).(*Bottom)
_ = i1s3s1.newChild("i1s3s1b3", BottomType).(*Bottom)
t.SetUnit("KB")
i1 := t.newIntermediate("i1")
i2 := t.newIntermediate("i2")
i3 := t.newIntermediate("i3")
i1s1 := i1.newIntermediate("i1s1")
i1s2 := i1.newIntermediate("i1s2")
i1s3 := i1.newIntermediate("i1s3")
i1s4 := i1.newIntermediate("i1s4")
i3s1 := i3.newIntermediate("i3s1")
i3s2 := i3.newIntermediate("i3s2")
i3s3 := i3.newIntermediate("i3s3")
_ = i1s1.newBottom("i1s1b1")
_ = i1s1.newBottom("i1s1b2")
_ = i1s1.newBottom("i1s1b3")
_ = i1s2.newBottom("i1s2b1")
_ = i1s2.newBottom("i1s2b2")
i1s3s1 := i1s3.newIntermediate("i1s3s1")
_ = i1s3.newBottom("i1s3b1")
_ = i1s4.newBottom("i1s4b1")
_ = i2.newBottom("i2b1")
_ = i2.newBottom("i2b2")
_ = i3s1.newBottom("i3s1b1")
_ = i3s2.newBottom("i3s2b1")
_ = i3s2.newBottom("i3s2b2")
_ = i3s3.newBottom("i3s3b1")
_ = i1s3s1.newBottom("i1s3s1b1")
_ = i1s3s1.newBottom("i1s3s1b2")
_ = i1s3s1.newBottom("i1s3s1b3")
return t
}
@ -79,6 +74,31 @@ func TestString(t *testing.T) {
tree := createTree()
repr := fmt.Sprintf("%s", tree)
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"
)
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() {
var path string
var depth int
var unit = &UnitValue{unit: "KB"}
flag.StringVar(&path, "path", ".", "Path from where to start the walk from")
flag.IntVar(&depth, "depth", 0, "Depth to display")
flag.Var(unit, "unit", "Unit in which to report size")
flag.Parse()
t := NewTop(path)
t.SetUnit(unit.String())
go t.Spawn(depth)
go t.Collect()
for {

View file

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