dynamic_tree.go 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552
  1. package tree
  2. import (
  3. "errors"
  4. "fmt"
  5. "path/filepath"
  6. "strings"
  7. )
  8. const (
  9. TopType = "top"
  10. IntermediateType = "intermediate"
  11. BottomType = "bottom"
  12. SingleType = "single"
  13. )
  14. var ErrUnknownType = errors.New("unknown type")
  15. var ErrShouldBeBottom = errors.New("should be of type Bottom")
  16. var ErrChannelError = errors.New("channel errored")
  17. var ErrUnknownUnit = errors.New("unknown unit")
  18. var (
  19. NodeB = "│"
  20. NodeT = "├──"
  21. NodeL = "└──"
  22. NodePad = " "
  23. CloseLine = "\033[K\n"
  24. )
  25. type Node interface {
  26. SetUnit(string)
  27. GetUnit() ByteSize
  28. Size() int64
  29. Spawn(int) error
  30. Collect() error
  31. AddCollector(chan int64)
  32. SetLimits(int64, int64)
  33. Level() int
  34. Name() string
  35. Complete() bool
  36. Depth() int
  37. }
  38. //////////////////////////////
  39. /////////// Top //////////////
  40. //////////////////////////////
  41. type Top struct {
  42. path string
  43. size int64
  44. unit ByteSize
  45. tree []Node
  46. collect []<-chan int64
  47. minLimit int64
  48. maxLimit int64
  49. level int
  50. complete bool
  51. }
  52. func NewTop(path string) *Top {
  53. t := &Top{path: path, level: 0, unit: KB}
  54. return t
  55. }
  56. func (t *Top) SetUnit(unit string) {
  57. t.unit = parseUnit(unit)
  58. }
  59. func (t *Top) GetUnit() ByteSize {
  60. return t.unit
  61. }
  62. func (t *Top) Size() int64 {
  63. return t.size
  64. }
  65. func (t *Top) Spawn(maxLevel int) error {
  66. if t.Level() >= maxLevel {
  67. return ErrShouldBeBottom
  68. }
  69. files, err := ListDir(t.path)
  70. if err != nil {
  71. return err
  72. }
  73. for _, info := range files {
  74. switch mode := info.Mode(); {
  75. case mode.IsDir():
  76. var child Node
  77. var collect chan int64
  78. path := filepath.Join(t.path, info.Name())
  79. if isLastLevel(t, maxLevel) || !AnyDirectoryDownThere(path) {
  80. child, collect = t.newBottom(path)
  81. } else {
  82. child, collect = t.newIntermediate(path)
  83. }
  84. t.AddCollector(collect)
  85. go child.Spawn(maxLevel)
  86. case !mode.IsDir() && mode.IsRegular():
  87. t.size += info.Size()
  88. }
  89. }
  90. go t.Collect()
  91. return nil
  92. }
  93. func (t *Top) Collect() error {
  94. for s := range merge(t.collect) {
  95. t.size += s
  96. }
  97. t.complete = true
  98. return nil
  99. }
  100. func (t *Top) AddCollector(collect chan int64) {
  101. t.collect = append(t.collect, collect)
  102. }
  103. func (t *Top) SetLimits(min, max int64) {
  104. t.minLimit = min
  105. t.maxLimit = max
  106. }
  107. func (t *Top) Level() int {
  108. return t.level
  109. }
  110. func (t *Top) Name() string {
  111. return filepath.Base(t.path)
  112. }
  113. func (t *Top) Complete() bool {
  114. for _, child := range t.tree {
  115. if !child.Complete() {
  116. return false
  117. }
  118. }
  119. return true
  120. }
  121. func (t *Top) Depth() int {
  122. var depth int
  123. for _, child := range t.tree {
  124. if isIntoLimits(child.Size(), t.minLimit, t.maxLimit) {
  125. depth += child.Depth()
  126. }
  127. }
  128. return depth
  129. }
  130. func (t *Top) String() string {
  131. var out string
  132. var lines []string
  133. out += fmt.Sprintf("(%s) %s%s", fmtSize(t.Size(), t.GetUnit()), t.path, CloseLine)
  134. treeSize := 0
  135. for _, child := range t.tree {
  136. if isIntoLimits(child.Size(), t.minLimit, t.maxLimit) {
  137. lines = append(lines, fmt.Sprintf("%s", child))
  138. treeSize += 1
  139. }
  140. }
  141. for a := 0; a < treeSize-1; a++ {
  142. childLines := strings.Split(lines[a], "\n")
  143. out += fmt.Sprintf(" %s%s%s", NodeT, childLines[0], CloseLine)
  144. for b := 1; b < len(childLines); b++ {
  145. out += fmt.Sprintf(" %s%s%s", NodeB, childLines[b], CloseLine)
  146. }
  147. }
  148. childLines := strings.Split(lines[treeSize-1], "\n")
  149. out += fmt.Sprintf(" %s%s%s", NodeL, childLines[0], CloseLine)
  150. for a := 1; a < len(childLines); a++ {
  151. out += fmt.Sprintf("%s%s%s", " ", childLines[a], CloseLine)
  152. }
  153. return out
  154. }
  155. func (t *Top) addToTree(child Node) {
  156. t.tree = append(t.tree, child)
  157. }
  158. func (t *Top) newChild(path, kind string) (Node, chan int64) {
  159. switch {
  160. case kind == IntermediateType:
  161. i, collect := NewIntermediate(path, t)
  162. t.addToTree(i)
  163. return i, collect
  164. case kind == BottomType:
  165. b, collect := NewBottom(path, t)
  166. t.addToTree(b)
  167. return b, collect
  168. default:
  169. panic(ErrUnknownType)
  170. }
  171. }
  172. func (t *Top) newIntermediate(path string) (*Intermediate, chan int64) {
  173. child, collect := t.newChild(path, IntermediateType)
  174. return child.(*Intermediate), collect
  175. }
  176. func (t *Top) newBottom(path string) (*Bottom, chan int64) {
  177. child, collect := t.newChild(path, BottomType)
  178. return child.(*Bottom), collect
  179. }
  180. //////////////////////////////
  181. /////// Intermediate /////////
  182. //////////////////////////////
  183. type Intermediate struct {
  184. path string
  185. size int64
  186. unit ByteSize
  187. parent Node
  188. tree []Node
  189. collect []<-chan int64
  190. refer chan int64
  191. minLimit int64
  192. maxLimit int64
  193. level int
  194. complete bool
  195. }
  196. func NewIntermediate(path string, parent Node) (*Intermediate, chan int64) {
  197. refer := make(chan int64)
  198. i := &Intermediate{path: path, refer: refer, parent: parent}
  199. i.collect = make([]<-chan int64, 1)
  200. i.level = parent.Level() + 1
  201. i.unit = parent.GetUnit()
  202. return i, refer
  203. }
  204. func (i *Intermediate) SetUnit(unit string) {
  205. i.unit = parseUnit(unit)
  206. }
  207. func (i *Intermediate) GetUnit() ByteSize {
  208. return i.unit
  209. }
  210. func (i *Intermediate) Size() int64 {
  211. return i.size
  212. }
  213. func (i *Intermediate) Spawn(maxLevel int) error {
  214. if i.Level() >= maxLevel {
  215. return ErrShouldBeBottom
  216. }
  217. files, err := ListDir(i.path)
  218. if err != nil {
  219. return err
  220. }
  221. for _, info := range files {
  222. switch mode := info.Mode(); {
  223. case mode.IsDir():
  224. var child Node
  225. var collect chan int64
  226. path := filepath.Join(i.path, info.Name())
  227. if isLastLevel(i, maxLevel) || !AnyDirectoryDownThere(path) {
  228. child, collect = i.newBottom(path)
  229. } else {
  230. child, collect = i.newIntermediate(path)
  231. }
  232. i.AddCollector(collect)
  233. go child.Spawn(maxLevel)
  234. case !mode.IsDir() && mode.IsRegular():
  235. i.size += info.Size()
  236. i.refer <- info.Size()
  237. }
  238. }
  239. go i.Collect()
  240. return nil
  241. }
  242. func (i *Intermediate) Collect() error {
  243. for s := range merge(i.collect) {
  244. i.size += s
  245. i.refer <- s
  246. }
  247. i.complete = true
  248. return nil
  249. }
  250. func (i *Intermediate) AddCollector(collect chan int64) {
  251. i.collect = append(i.collect, collect)
  252. }
  253. func (i *Intermediate) SetLimits(min, max int64) {
  254. i.minLimit = min
  255. i.maxLimit = max
  256. }
  257. func (i *Intermediate) Level() int {
  258. return i.level
  259. }
  260. func (i *Intermediate) Name() string {
  261. return filepath.Base(i.path)
  262. }
  263. func (i *Intermediate) Complete() bool {
  264. for _, child := range i.tree {
  265. if !child.Complete() {
  266. return false
  267. }
  268. }
  269. return true
  270. }
  271. func (i *Intermediate) Depth() int {
  272. var depth int
  273. for _, child := range i.tree {
  274. if isIntoLimits(child.Size(), i.minLimit, i.maxLimit) {
  275. depth += child.Depth()
  276. }
  277. }
  278. return depth
  279. }
  280. func (i *Intermediate) String() string {
  281. var lines []string
  282. out := fmt.Sprintf("(%s) %s\n", fmtSize(i.Size(), i.GetUnit()), i.Name())
  283. treeSize := 0
  284. for _, child := range i.tree {
  285. if isIntoLimits(child.Size(), i.minLimit, i.maxLimit) {
  286. lines = append(lines, fmt.Sprintf("%s", child))
  287. treeSize += 1
  288. }
  289. }
  290. for a := 0; a < treeSize-1; a++ {
  291. childLines := strings.Split(lines[a], "\n")
  292. out += fmt.Sprintf("%s%s%s", NodePad, NodeT, childLines[0])
  293. for b := 1; b < len(childLines); b++ {
  294. out += fmt.Sprintf("%s%s%s", NodePad, NodeB, childLines[b])
  295. }
  296. }
  297. childLines := strings.Split(lines[treeSize-1], "\n")
  298. lenChildLines := len(childLines)
  299. if lenChildLines > 1 {
  300. out += fmt.Sprintf("%s%s%s", NodePad, NodeL, childLines[0])
  301. for a := 1; a < lenChildLines-2; a++ {
  302. out += fmt.Sprintf(" %s%s", NodePad, childLines[a])
  303. }
  304. out += fmt.Sprintf(" %s%s", NodePad, childLines[lenChildLines-1])
  305. } else {
  306. out += fmt.Sprintf("%s%s%s", NodePad, NodeL, childLines[0])
  307. }
  308. return out
  309. }
  310. func (i *Intermediate) addToTree(child Node) {
  311. i.tree = append(i.tree, child)
  312. }
  313. func (i *Intermediate) newChild(path, kind string) (Node, chan int64) {
  314. switch {
  315. case kind == IntermediateType:
  316. c, collect := NewIntermediate(path, i)
  317. i.addToTree(c)
  318. return c, collect
  319. case kind == BottomType:
  320. b, collect := NewBottom(path, i)
  321. i.addToTree(b)
  322. return b, collect
  323. default:
  324. panic(ErrUnknownType)
  325. }
  326. }
  327. func (i *Intermediate) newIntermediate(path string) (*Intermediate, chan int64) {
  328. child, collect := i.newChild(path, IntermediateType)
  329. return child.(*Intermediate), collect
  330. }
  331. func (i *Intermediate) newBottom(path string) (*Bottom, chan int64) {
  332. child, collect := i.newChild(path, BottomType)
  333. return child.(*Bottom), collect
  334. }
  335. //////////////////////////////
  336. ////////// Bottom ////////////
  337. //////////////////////////////
  338. type Bottom struct {
  339. path string
  340. size int64
  341. unit ByteSize
  342. parent Node
  343. walker Walker
  344. collect chan int64
  345. refer chan int64
  346. minLimit int64
  347. maxLimit int64
  348. level int
  349. complete bool
  350. }
  351. func NewBottom(path string, parent Node) (*Bottom, chan int64) {
  352. refer := make(chan int64)
  353. b := &Bottom{path: path, refer: refer, parent: parent, unit: parent.GetUnit()}
  354. b.level = parent.Level() + 1
  355. b.unit = parent.GetUnit()
  356. return b, refer
  357. }
  358. func (b *Bottom) SetUnit(unit string) {
  359. b.unit = parseUnit(unit)
  360. }
  361. func (b *Bottom) GetUnit() ByteSize {
  362. return b.unit
  363. }
  364. func (b *Bottom) Size() int64 {
  365. return b.size
  366. }
  367. func (b *Bottom) Spawn(maxLevel int) error {
  368. collect := make(chan int64)
  369. b.AddCollector(collect)
  370. b.walker = NewRealWalker(b.path, collect)
  371. go b.walker.Walk()
  372. go b.Collect()
  373. return nil
  374. }
  375. func (b *Bottom) Collect() error {
  376. for s := range b.collect {
  377. b.size += s
  378. b.refer <- s
  379. }
  380. b.complete = true
  381. return nil
  382. }
  383. func (b *Bottom) AddCollector(collect chan int64) {
  384. b.collect = collect
  385. }
  386. func (b *Bottom) SetLimits(min, max int64) {
  387. b.minLimit = min
  388. b.maxLimit = max
  389. }
  390. func (b *Bottom) Level() int {
  391. return b.level
  392. }
  393. func (b *Bottom) Name() string {
  394. return filepath.Base(b.path)
  395. }
  396. func (b *Bottom) Complete() bool {
  397. return b.complete
  398. }
  399. func (b *Bottom) Depth() int {
  400. return 1
  401. }
  402. func (b *Bottom) String() string {
  403. return fmt.Sprintf("(%s) %s", fmtSize(b.Size(), b.GetUnit()), b.Name())
  404. }
  405. //////////////////////////////
  406. ////////// Single ////////////
  407. //////////////////////////////
  408. type Single struct {
  409. path string
  410. size int64
  411. unit ByteSize
  412. walker Walker
  413. collect chan int64
  414. complete bool
  415. }
  416. func NewSingle(path string) *Single {
  417. s := &Single{path: path}
  418. collect := make(chan int64)
  419. s.AddCollector(collect)
  420. return s
  421. }
  422. func (s *Single) SetUnit(unit string) {
  423. s.unit = parseUnit(unit)
  424. }
  425. func (s *Single) GetUnit() ByteSize {
  426. return s.unit
  427. }
  428. func (s *Single) Size() int64 {
  429. return s.size
  430. }
  431. func (s *Single) Spawn(maxLevel int) error {
  432. s.walker = NewRealWalker(s.path, s.collect)
  433. go s.walker.Walk()
  434. go s.Collect()
  435. return nil
  436. }
  437. func (s *Single) Collect() error {
  438. for v := range s.collect {
  439. s.size += v
  440. }
  441. s.complete = true
  442. return nil
  443. }
  444. func (s *Single) AddCollector(collect chan int64) {
  445. s.collect = collect
  446. }
  447. func (s *Single) SetLimits(min, max int64) {
  448. // just ignore limits
  449. return
  450. }
  451. func (s *Single) Level() int {
  452. return 0
  453. }
  454. func (s *Single) Name() string {
  455. return filepath.Base(s.path)
  456. }
  457. func (s *Single) Complete() bool {
  458. return s.complete
  459. }
  460. func (s *Single) Depth() int {
  461. return 1
  462. }
  463. func (s *Single) String() string {
  464. return fmt.Sprintf("(%s) %s\n", fmtSize(s.Size(), s.GetUnit()), s.Name())
  465. }
  466. //////////////////////////////
  467. ////////// Walker ////////////
  468. //////////////////////////////
  469. type Walker interface {
  470. Walk()
  471. }