123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121 |
- package sizer
- import (
- "fmt"
- "github.com/gosuri/uilive"
- )
- // Ruspa is the asynchronous worker that is in charge of collecting
- // the underlying sizes and relay the total to the eventual parent.
- type Ruspa struct {
- INode *INode
- Send chan StatusReport
- Recv chan StatusReport
- Done chan StatusReport
- Opened map[string]*Ruspa
- }
- // NewRuspa inits a new Ruspa
- func NewRuspa(inode *INode, collect chan StatusReport) *Ruspa {
- var r Ruspa
- r.INode = inode
- r.Recv = make(chan StatusReport)
- if collect == nil {
- r.Send = make(chan StatusReport)
- } else {
- r.Send = collect
- }
- r.Done = make(chan StatusReport)
- r.Opened = make(map[string]*Ruspa)
- return &r
- }
- // Scava starts a worker on the given INode.
- func (w *Ruspa) Scava(done chan StatusReport) {
- Console.Debugln("Scava: ", w.INode.Path)
- children, err := ls(w.INode.Path)
- if err != nil {
- w.Send <- StatusReport{path: w.INode.Path, err: err}
- }
- for _, childPath := range children {
- kind, size, err := IdentifyType(childPath)
- if err != nil {
- w.Send <- StatusReport{path: childPath, err: err}
- }
- childINode := NewINode(kind, size, childPath)
- w.INode.Children.Append(childINode)
- switch {
- case kind == FileType:
- Console.Debugln("[file]", w.INode.Path, " ~> ", childINode.Path)
- w.Send <- StatusReport{path: childPath, size: size}
- case kind == DirType:
- Console.Debugln("[dir]", w.INode.Path, " ~> ", childINode.Path)
- cw := NewRuspa(childINode, w.Recv)
- w.Opened[childPath] = cw
- go cw.Scava(w.Done)
- // go cw.Ammucchia(w.Done)
- }
- }
- if len(w.Opened) == 0 {
- done <- StatusReport{path: w.INode.Path}
- } else {
- go w.Ammucchia(done)
- }
- }
- // Ammucchia gathers the size of the underlying Ruspa workers
- // and adds to the INode size.
- func (w *Ruspa) Ammucchia(done chan StatusReport) {
- for len(w.Opened) > 0 {
- select {
- case report := <-w.Recv:
- if report.err != nil {
- Console.Debugln(Red(report.err))
- }
- if report.err == nil {
- w.INode.Size += report.size
- }
- case leaf := <-w.Done:
- Console.Debugln("Done:", leaf.path)
- delete(w.Opened, leaf.path)
- }
- }
- Console.Debugln(w.INode.Path, ": Completed. Exiting...")
- done <- StatusReport{path: w.INode.Path, size: w.INode.Size}
- }
- // Pesa starts the worker for current inode and returns the channel
- // to listen to get the size.
- func (i *INode) Pesa(done chan StatusReport) chan StatusReport {
- result := make(chan StatusReport)
- w := NewRuspa(i, result)
- go w.Scava(done)
- // go w.Ammucchia(done)
- return result
- }
- // NastroConvogliatore starts a Pesa on a given path and displays
- // the current value of the size.
- func NastroConvogliatore(path string) {
- pathINode, err := INodeFromPath(path)
- if err != nil {
- Console.Fatalln("Failed creating inode:", err)
- }
- Console.Debugln("Starting Pesa on path:", path)
- done := make(chan StatusReport)
- result := pathINode.Pesa(done)
- writer := uilive.New()
- writer.Start()
- fmt.Fprintf(writer, "%s\n", Green("Starting..."))
- for {
- select {
- case res := <-result:
- fmt.Fprintf(writer, "%s: %d\n", res.path, res.size)
- case res := <-done:
- fmt.Fprintf(writer, "%s: %d\n", res.path, res.size)
- writer.Stop()
- return
- }
- }
- }
|