Compare commits

..

No commits in common. "d00a7fa2c04ada007f74d828a14b122f8863975c" and "ce417a1df65bbc86cd84ccef9770570df5666f7a" have entirely different histories.

7 changed files with 155 additions and 260 deletions

View file

@ -1,4 +1,4 @@
package tree
package main
import (
"os"

View file

@ -1,4 +1,4 @@
package tree
package main
import (
"io/ioutil"

View file

@ -1,4 +1,4 @@
package tree
package main
import (
"errors"
@ -14,6 +14,17 @@ 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")
@ -31,10 +42,58 @@ type Node interface {
Size() int64
Spawn(int) error
Collect() error
AddCollector(chan int64)
Collector() chan int64
Level() int
Name() string
Complete() bool
}
func isLastLevel(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))
}
//////////////////////////////
@ -42,17 +101,17 @@ type Node interface {
//////////////////////////////
type Top struct {
path string
size int64
unit ByteSize
tree []Node
collect []<-chan int64
level int
complete bool
path string
size int64
unit ByteSize
tree []Node
collect chan int64
level int
}
func NewTop(path string) *Top {
t := &Top{path: path, level: 0, unit: KB}
t.collect = make(chan int64)
return t
}
@ -81,34 +140,32 @@ func (t *Top) Spawn(maxLevel int) error {
switch mode := info.Mode(); {
case mode.IsDir():
var child Node
var collect chan int64
path := filepath.Join(t.path, info.Name())
if isLastLevel(t, maxLevel) || !AnyDirectoryDownThere(path) {
child, collect = t.newBottom(path)
child = t.newBottom(path)
} else {
child, collect = t.newIntermediate(path)
child = t.newIntermediate(path)
}
t.AddCollector(collect)
go child.Spawn(maxLevel)
defer func() {
go child.Collect()
}()
case !mode.IsDir() && mode.IsRegular():
t.size += info.Size()
t.collect <- info.Size()
}
}
go t.Collect()
return nil
}
func (t *Top) Collect() error {
for s := range merge(t.collect) {
for s := range t.collect {
t.size += s
}
t.complete = true
return nil
}
func (t *Top) AddCollector(collect chan int64) {
t.collect = append(t.collect, collect)
func (t *Top) Collector() chan int64 {
return t.collect
}
func (t *Top) Level() int {
@ -119,15 +176,6 @@ func (t *Top) Name() string {
return filepath.Base(t.path)
}
func (t *Top) Complete() bool {
for _, child := range t.tree {
if !child.Complete() {
return false
}
}
return true
}
func (t *Top) String() string {
var out string
var lines []string
@ -155,29 +203,27 @@ func (t *Top) addToTree(child Node) {
t.tree = append(t.tree, child)
}
func (t *Top) newChild(path, kind string) (Node, chan int64) {
func (t *Top) newChild(path, kind string) Node {
switch {
case kind == IntermediateType:
i, collect := NewIntermediate(path, t)
i := NewIntermediate(path, t)
t.addToTree(i)
return i, collect
return i
case kind == BottomType:
b, collect := NewBottom(path, t)
b := NewBottom(path, t)
t.addToTree(b)
return b, collect
return b
default:
panic(ErrUnknownType)
}
}
func (t *Top) newIntermediate(path string) (*Intermediate, chan int64) {
child, collect := t.newChild(path, IntermediateType)
return child.(*Intermediate), collect
func (t *Top) newIntermediate(path string) *Intermediate {
return t.newChild(path, IntermediateType).(*Intermediate)
}
func (t *Top) newBottom(path string) (*Bottom, chan int64) {
child, collect := t.newChild(path, BottomType)
return child.(*Bottom), collect
func (t *Top) newBottom(path string) *Bottom {
return t.newChild(path, BottomType).(*Bottom)
}
//////////////////////////////
@ -185,24 +231,22 @@ func (t *Top) newBottom(path string) (*Bottom, chan int64) {
//////////////////////////////
type Intermediate struct {
path string
size int64
unit ByteSize
parent Node
tree []Node
collect []<-chan int64
refer chan int64
level int
complete bool
path string
size int64
unit ByteSize
parent Node
tree []Node
collect chan int64
refer chan int64
level int
}
func NewIntermediate(path string, parent Node) (*Intermediate, chan int64) {
refer := make(chan int64)
i := &Intermediate{path: path, refer: refer, parent: parent}
i.collect = make([]<-chan int64, 1)
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, refer
return i
}
func (i *Intermediate) SetUnit(unit string) {
@ -231,36 +275,35 @@ func (i *Intermediate) Spawn(maxLevel int) error {
switch mode := info.Mode(); {
case mode.IsDir():
var child Node
var collect chan int64
path := filepath.Join(i.path, info.Name())
if isLastLevel(i, maxLevel) || !AnyDirectoryDownThere(path) {
child, collect = i.newBottom(path)
child = i.newBottom(path)
} else {
child, collect = i.newIntermediate(path)
child = i.newIntermediate(path)
}
i.AddCollector(collect)
go child.Spawn(maxLevel)
defer func() {
go child.Collect()
}()
case !mode.IsDir() && mode.IsRegular():
i.size += info.Size()
i.refer <- info.Size()
i.collect <- info.Size()
}
}
go i.Collect()
return nil
}
func (i *Intermediate) Collect() error {
for s := range merge(i.collect) {
for s := range i.collect {
i.size += s
i.refer <- s
}
i.complete = true
close(i.refer)
return nil
}
func (i *Intermediate) AddCollector(collect chan int64) {
i.collect = append(i.collect, collect)
func (i *Intermediate) Collector() chan int64 {
return i.collect
}
func (i *Intermediate) Level() int {
@ -271,15 +314,6 @@ func (i *Intermediate) Name() string {
return filepath.Base(i.path)
}
func (i *Intermediate) Complete() bool {
for _, child := range i.tree {
if !child.Complete() {
return false
}
}
return true
}
func (i *Intermediate) String() string {
var lines []string
out := fmt.Sprintf("(%s) %s\n", fmtSize(i.Size(), i.GetUnit()), i.Name())
@ -314,29 +348,27 @@ func (i *Intermediate) addToTree(child Node) {
i.tree = append(i.tree, child)
}
func (i *Intermediate) newChild(path, kind string) (Node, chan int64) {
func (i *Intermediate) newChild(path, kind string) Node {
switch {
case kind == IntermediateType:
c, collect := NewIntermediate(path, i)
c := NewIntermediate(path, i)
i.addToTree(c)
return c, collect
return c
case kind == BottomType:
b, collect := NewBottom(path, i)
b := NewBottom(path, i)
i.addToTree(b)
return b, collect
return b
default:
panic(ErrUnknownType)
}
}
func (i *Intermediate) newIntermediate(path string) (*Intermediate, chan int64) {
child, collect := i.newChild(path, IntermediateType)
return child.(*Intermediate), collect
func (i *Intermediate) newIntermediate(path string) *Intermediate {
return i.newChild(path, IntermediateType).(*Intermediate)
}
func (i *Intermediate) newBottom(path string) (*Bottom, chan int64) {
child, collect := i.newChild(path, BottomType)
return child.(*Bottom), collect
func (i *Intermediate) newBottom(path string) *Bottom {
return i.newChild(path, BottomType).(*Bottom)
}
//////////////////////////////
@ -344,23 +376,22 @@ func (i *Intermediate) newBottom(path string) (*Bottom, chan int64) {
//////////////////////////////
type Bottom struct {
path string
size int64
unit ByteSize
parent Node
walker Walker
collect chan int64
refer chan int64
level int
complete bool
path string
size int64
unit ByteSize
parent Node
walker Walker
collect chan int64
refer chan int64
level int
}
func NewBottom(path string, parent Node) (*Bottom, chan int64) {
refer := make(chan int64)
b := &Bottom{path: path, refer: refer, parent: parent, unit: parent.GetUnit()}
func NewBottom(path string, parent Node) *Bottom {
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, refer
return b
}
func (b *Bottom) SetUnit(unit string) {
@ -376,11 +407,8 @@ func (b *Bottom) Size() int64 {
}
func (b *Bottom) Spawn(maxLevel int) error {
collect := make(chan int64)
b.AddCollector(collect)
b.walker = NewRealWalker(b.path, collect)
b.walker = NewRealWalker(b.path, b.collect)
go b.walker.Walk()
go b.Collect()
return nil
}
@ -389,12 +417,12 @@ func (b *Bottom) Collect() error {
b.size += s
b.refer <- s
}
b.complete = true
close(b.refer)
return nil
}
func (b *Bottom) AddCollector(collect chan int64) {
b.collect = collect
func (b *Bottom) Collector() chan int64 {
return b.collect
}
func (b *Bottom) Level() int {
@ -405,10 +433,6 @@ func (b *Bottom) Name() string {
return filepath.Base(b.path)
}
func (b *Bottom) Complete() bool {
return b.complete
}
func (b *Bottom) String() string {
return fmt.Sprintf("(%s) %s", fmtSize(b.Size(), b.GetUnit()), b.Name())
}
@ -418,27 +442,10 @@ func (b *Bottom) String() string {
//////////////////////////////
type Single struct {
path string
size int64
unit ByteSize
walker Walker
collect chan int64
complete bool
}
func NewSingle(path string) *Single {
s := &Single{path: path}
collect := make(chan int64)
s.AddCollector(collect)
return s
}
func (s *Single) SetUnit(unit string) {
s.unit = setUnit(unit)
}
func (s *Single) GetUnit() ByteSize {
return s.unit
path string
size int64
walker Walker
collect chan int64
}
func (s *Single) Size() int64 {
@ -448,7 +455,6 @@ func (s *Single) Size() int64 {
func (s *Single) Spawn(maxLevel int) error {
s.walker = NewRealWalker(s.path, s.collect)
go s.walker.Walk()
go s.Collect()
return nil
}
@ -456,28 +462,21 @@ func (s *Single) Collect() error {
for v := range s.collect {
s.size += v
}
s.complete = true
return nil
}
func (s *Single) AddCollector(collect chan int64) {
s.collect = collect
func (s *Single) Collector() chan int64 {
return s.collect
}
func (s *Single) Level() int {
return 0
}
func (s *Single) Name() string {
return filepath.Base(s.path)
}
func (s *Single) Complete() bool {
return s.complete
}
func (s *Single) String() string {
return fmt.Sprintf("(%s) %s\n", fmtSize(s.Size(), s.GetUnit()), s.Name())
func NewSingle(path string) *Single {
s := &Single{path: path}
s.collect = make(chan int64)
return s
}
//////////////////////////////

View file

@ -1,4 +1,4 @@
package tree
package main
import (
"fmt"

View file

@ -4,8 +4,6 @@ import (
"flag"
"fmt"
"time"
"git.lattuga.net/blallo/ruspa/tree"
)
type UnitValue struct {
@ -37,36 +35,28 @@ func (u *UnitValue) Set(value string) error {
u.unit = "PB"
return nil
default:
return tree.ErrUnknownUnit
return ErrUnknownUnit
}
}
func main() {
var path string
var depth int
var root tree.Node
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()
if depth == 0 || !tree.AnyDirectoryDownThere(path) {
root = tree.NewSingle(path)
} else {
root = tree.NewTop(path)
}
root.SetUnit(unit.String())
go root.Spawn(depth)
t := NewTop(path)
t.SetUnit(unit.String())
go t.Spawn(depth)
go t.Collect()
for {
select {
case <-time.After(500 * time.Millisecond):
fmt.Printf("\033[H\033[2J")
fmt.Println(root)
if root.Complete() {
return
}
fmt.Println(t)
}
}
}

View file

@ -1,4 +1,4 @@
package tree
package main
import (
"os"
@ -23,7 +23,6 @@ func (r *RealWalker) walkFunc(path string, info os.FileInfo, err error) error {
func (r *RealWalker) Walk() {
filepath.Walk(r.path, r.walkFunc)
close(r.report)
}
func NewRealWalker(path string, report chan int64) *RealWalker {

View file

@ -1,93 +0,0 @@
package tree
import (
"fmt"
"sync"
)
type ByteSize uint
const (
B ByteSize = 1 << (10 * iota)
KB
MB
GB
TB
PB
)
func isLastLevel(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))
}
func merge(cs []<-chan int64) <-chan int64 {
var wg sync.WaitGroup
out := make(chan int64)
// Start an output goroutine for each input channel in cs. output
// copies values from c to out until c is closed, then calls wg.Done.
output := func(c <-chan int64) {
for n := range c {
out <- n
}
wg.Done()
}
wg.Add(len(cs))
for _, c := range cs {
go output(c)
}
// Start a goroutine to close out once all the output goroutines are
// done. This must start after the wg.Add call.
go func() {
wg.Wait()
close(out)
}()
return out
}