tracker-group.js 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. 'use strict'
  2. var util = require('util')
  3. var TrackerBase = require('./tracker-base.js')
  4. var Tracker = require('./tracker.js')
  5. var TrackerStream = require('./tracker-stream.js')
  6. var TrackerGroup = module.exports = function (name) {
  7. TrackerBase.call(this, name)
  8. this.parentGroup = null
  9. this.trackers = []
  10. this.completion = {}
  11. this.weight = {}
  12. this.totalWeight = 0
  13. this.finished = false
  14. this.bubbleChange = bubbleChange(this)
  15. }
  16. util.inherits(TrackerGroup, TrackerBase)
  17. function bubbleChange (trackerGroup) {
  18. return function (name, completed, tracker) {
  19. trackerGroup.completion[tracker.id] = completed
  20. if (trackerGroup.finished) return
  21. trackerGroup.emit('change', name || trackerGroup.name, trackerGroup.completed(), trackerGroup)
  22. }
  23. }
  24. TrackerGroup.prototype.nameInTree = function () {
  25. var names = []
  26. var from = this
  27. while (from) {
  28. names.unshift(from.name)
  29. from = from.parentGroup
  30. }
  31. return names.join('/')
  32. }
  33. TrackerGroup.prototype.addUnit = function (unit, weight) {
  34. if (unit.addUnit) {
  35. var toTest = this
  36. while (toTest) {
  37. if (unit === toTest) {
  38. throw new Error(
  39. 'Attempted to add tracker group ' +
  40. unit.name + ' to tree that already includes it ' +
  41. this.nameInTree(this))
  42. }
  43. toTest = toTest.parentGroup
  44. }
  45. unit.parentGroup = this
  46. }
  47. this.weight[unit.id] = weight || 1
  48. this.totalWeight += this.weight[unit.id]
  49. this.trackers.push(unit)
  50. this.completion[unit.id] = unit.completed()
  51. unit.on('change', this.bubbleChange)
  52. if (!this.finished) this.emit('change', unit.name, this.completion[unit.id], unit)
  53. return unit
  54. }
  55. TrackerGroup.prototype.completed = function () {
  56. if (this.trackers.length === 0) return 0
  57. var valPerWeight = 1 / this.totalWeight
  58. var completed = 0
  59. for (var ii = 0; ii < this.trackers.length; ii++) {
  60. var trackerId = this.trackers[ii].id
  61. completed += valPerWeight * this.weight[trackerId] * this.completion[trackerId]
  62. }
  63. return completed
  64. }
  65. TrackerGroup.prototype.newGroup = function (name, weight) {
  66. return this.addUnit(new TrackerGroup(name), weight)
  67. }
  68. TrackerGroup.prototype.newItem = function (name, todo, weight) {
  69. return this.addUnit(new Tracker(name, todo), weight)
  70. }
  71. TrackerGroup.prototype.newStream = function (name, todo, weight) {
  72. return this.addUnit(new TrackerStream(name, todo), weight)
  73. }
  74. TrackerGroup.prototype.finish = function () {
  75. this.finished = true
  76. if (!this.trackers.length) this.addUnit(new Tracker(), 1, true)
  77. for (var ii = 0; ii < this.trackers.length; ii++) {
  78. var tracker = this.trackers[ii]
  79. tracker.finish()
  80. tracker.removeListener('change', this.bubbleChange)
  81. }
  82. this.emit('change', this.name, 1, this)
  83. }
  84. var buffer = ' '
  85. TrackerGroup.prototype.debug = function (depth) {
  86. depth = depth || 0
  87. var indent = depth ? buffer.substr(0, depth) : ''
  88. var output = indent + (this.name || 'top') + ': ' + this.completed() + '\n'
  89. this.trackers.forEach(function (tracker) {
  90. if (tracker instanceof TrackerGroup) {
  91. output += tracker.debug(depth + 1)
  92. } else {
  93. output += indent + ' ' + tracker.name + ': ' + tracker.completed() + '\n'
  94. }
  95. })
  96. return output
  97. }