dynamic_tree.go 10 KB

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