Class: Log::ProgressBar

Inherits:
Object
  • Object
show all
Defined in:
lib/rbbt/util/log/progress.rb,
lib/rbbt/util/log/progress/util.rb,
lib/rbbt/util/log/progress/report.rb

Constant Summary collapse

BAR_MUTEX =
Mutex.new
BARS =
[]
REMOVE =
[]
SILENCED =
[]

Class Attribute Summary collapse

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(max = nil, options = {}) ⇒ ProgressBar

Returns a new instance of ProgressBar.



23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
# File 'lib/rbbt/util/log/progress.rb', line 23

def initialize(max = nil, options = {})
  options = Misc.add_defaults options, :depth => 0, :num_reports => 100, :io => STDERR, :severity => Log.severity, :frequency => 2
  depth, num_reports, desc, io, severity, file, bytes, frequency, process, callback = Misc.process_options options, :depth, :num_reports, :desc, :io, :severity, :file, :bytes, :frequency, :process, :callback

  @max = max
  @ticks = 0
  @frequency = frequency
  @last_time = nil
  @last_count = nil
  @last_percent = nil
  @depth = depth
  @desc = desc.nil? ? "" : desc.gsub(/\n/,' ')
  @file = file
  @bytes = bytes
  @process = process
  @callback = callback
end

Class Attribute Details

.default_fileObject

Returns the value of attribute default_file.



18
19
20
# File 'lib/rbbt/util/log/progress.rb', line 18

def default_file
  @default_file
end

Instance Attribute Details

#bytesObject

Returns the value of attribute bytes.



21
22
23
# File 'lib/rbbt/util/log/progress.rb', line 21

def bytes
  @bytes
end

#callbackObject

Returns the value of attribute callback.



21
22
23
# File 'lib/rbbt/util/log/progress.rb', line 21

def callback
  @callback
end

#depthObject

Returns the value of attribute depth.



21
22
23
# File 'lib/rbbt/util/log/progress.rb', line 21

def depth
  @depth
end

#descObject

Returns the value of attribute desc.



21
22
23
# File 'lib/rbbt/util/log/progress.rb', line 21

def desc
  @desc
end

#fileObject

Returns the value of attribute file.



21
22
23
# File 'lib/rbbt/util/log/progress.rb', line 21

def file
  @file
end

#frequencyObject

Returns the value of attribute frequency.



21
22
23
# File 'lib/rbbt/util/log/progress.rb', line 21

def frequency
  @frequency
end

#historyObject

Returns the value of attribute history.



12
13
14
# File 'lib/rbbt/util/log/progress/report.rb', line 12

def history
  @history
end

#maxObject

Returns the value of attribute max.



21
22
23
# File 'lib/rbbt/util/log/progress.rb', line 21

def max
  @max
end

#max_historyObject

Returns the value of attribute max_history.



12
13
14
# File 'lib/rbbt/util/log/progress/report.rb', line 12

def max_history
  @max_history
end

#mean_maxObject

Returns the value of attribute mean_max.



12
13
14
# File 'lib/rbbt/util/log/progress/report.rb', line 12

def mean_max
  @mean_max
end

#process(elem) ⇒ Object

Returns the value of attribute process.



21
22
23
# File 'lib/rbbt/util/log/progress.rb', line 21

def process
  @process
end

#ticksObject

Returns the value of attribute ticks.



21
22
23
# File 'lib/rbbt/util/log/progress.rb', line 21

def ticks
  @ticks
end

Class Method Details

.add_offset(value = 1) ⇒ Object



8
9
10
11
12
13
# File 'lib/rbbt/util/log/progress/util.rb', line 8

def self.add_offset(value = 1)
  value = 1 if TrueClass === value
  @@offset = offset + value.to_i
  @@offset = 0 if @@offset < 0
  @@offset
end

.cleanup_barsObject



39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
# File 'lib/rbbt/util/log/progress/util.rb', line 39

def self.cleanup_bars
  BAR_MUTEX.synchronize do
    REMOVE.each do |bar|
      index = BARS.index bar
      if index
        BARS.delete_at index
        BARS.each_with_index do |bar,i|
          bar.depth = i
        end
      end
      index = SILENCED.index bar
      if index
        SILENCED.delete_at index
        SILENCED.each_with_index do |bar,i|
          bar.depth = i
        end
      end
    end
    REMOVE.clear
    BARS.length
  end
end

.new_bar(max, options = {}) ⇒ Object



29
30
31
32
33
34
35
36
37
# File 'lib/rbbt/util/log/progress/util.rb', line 29

def self.new_bar(max, options = {})
  cleanup_bars
  BAR_MUTEX.synchronize do
    Log::LAST.replace "new_bar" if Log::LAST == "progress"
    options = Misc.add_defaults options, :depth => BARS.length + Log::ProgressBar.offset
    BARS << (bar = ProgressBar.new(max, options))
    bar
  end
end

.offsetObject



23
24
25
26
27
# File 'lib/rbbt/util/log/progress/util.rb', line 23

def self.offset
  @@offset ||= 0
  @@offset = 0 if @@offset < 0
  @@offset
end

.remove_bar(bar, error = false) ⇒ Object



62
63
64
65
66
67
68
69
70
71
72
73
74
75
# File 'lib/rbbt/util/log/progress/util.rb', line 62

def self.remove_bar(bar, error = false)
  BAR_MUTEX.synchronize do
    return if REMOVE.include? bar
  end
  if error
    bar.error if bar.respond_to? :error
  else
    bar.done if bar.respond_to? :done
  end
  BAR_MUTEX.synchronize do
    REMOVE << bar
  end
  Log::LAST.replace "remove_bar" if Log::LAST == "progress"
end

.remove_offset(value = 1) ⇒ Object



15
16
17
18
19
20
# File 'lib/rbbt/util/log/progress/util.rb', line 15

def self.remove_offset(value = 1)
  value = 1 if TrueClass === value
  @@offset = offset - value.to_i
  @@offset = 0 if @@offset < 0
  @@offset
end

.with_bar(max, options = {}) ⇒ Object



81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
# File 'lib/rbbt/util/log/progress/util.rb', line 81

def self.with_bar(max, options = {})
  bar = new_bar(max, options)
  res = nil
  begin
    error = false
    keep = false
    yield bar
  rescue KeepBar
    keep = true
  rescue
    error = true
    raise $!
  ensure
    remove_bar(bar, error) if bar
  end
end

Instance Method Details

#done(io = STDERR) ⇒ Object



197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
# File 'lib/rbbt/util/log/progress/report.rb', line 197

def done(io = STDERR)
  done_msg = Log.color(:magenta, "· ") << Log.color(:green, "done")
  if @start
    ellapsed = (Time.now - @start).to_i
  else
    ellapsed = 0
  end
  ellapsed = [ellapsed/3600, ellapsed/60 % 60, ellapsed % 60].map{|t| "%02i" % t }.join(':')
  done_msg << " " << Log.color(:blue, (@ticks).to_s) << " #{bytes ? 'bytes' : 'items'} in " << Log.color(:green, ellapsed)
  @last_count = 0
  @last_time = @start
  done_msg << " - " << thr_msg 
  done_msg << Log.color(:magenta, " · " << desc)
  print(io, Log.up_lines(@depth) << done_msg << Log.down_lines(@depth)) 

  Open.rm file if file and Open.exists?(file)

  @callback.call self if @callback
end

#error(io = STDERR) ⇒ Object



217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
# File 'lib/rbbt/util/log/progress/report.rb', line 217

def error(io = STDERR)
  done_msg = Log.color(:magenta, "· ") << Log.color(:red, "error")
  if @start
    ellapsed = (Time.now - @start).to_i
  else
    ellapsed = 0
  end
  ellapsed = [ellapsed/3600, ellapsed/60 % 60, ellapsed % 60].map{|t| "%02i" % t }.join(':')
  done_msg << " " << Log.color(:blue, (@ticks).to_s) << " in " << Log.color(:green, ellapsed)
  @last_count = 0
  @last_time = @start
  done_msg << " - " << thr_msg
  done_msg << Log.color(:magenta, " · " << desc)      
  print(io, Log.up_lines(@depth) << done_msg << Log.down_lines(@depth)) 

  Open.rm file if file and Open.exists?(file)

  begin
    @callback.call self
  rescue
    Log.debug "Callback failed for filed progress bar: #{$!.message}"
  end if @callback
end

#eta_msgObject



86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
# File 'lib/rbbt/util/log/progress/report.rb', line 86

def eta_msg
  percent = self.percent
  time = Time.now

  indicator = ""
  10.times{|i|
    if i < percent / 10 then
      indicator << Log.color(:yellow, ".")
    else
      indicator << " "
    end
  }

  indicator << " #{Log.color(:blue, percent.to_s << "%")}"

  used = time - @start
  if @mean_max and @mean_max > 0 and @mean > 0
    eta =  (@max - @ticks) / @mean
  else
    eta =  (@max - @ticks) / (@ticks/used)
  end

  used = Misc.format_seconds(used) 
  eta = [eta/3600, eta/60 % 60, eta % 60].map{|t| "%02i" % t }.join(':')

  #indicator << " #{Log.color :yellow, used} used #{Log.color :yellow, eta} left - #{Log.color :yellow, ticks.to_s} of #{Log.color :yellow, @max.to_s} #{bytes ? 'bytes' : 'items'}"
  indicator << " #{Log.color :yellow, eta} => #{Log.color :yellow, used} - #{Log.color :yellow, ticks.to_s} of #{Log.color :yellow, @max.to_s} #{bytes ? 'bytes' : 'items'}"

  indicator
end

#initObject



51
52
53
54
55
56
57
58
# File 'lib/rbbt/util/log/progress.rb', line 51

def init
  @ticks, @bytes = 0
  @last_time = @last_count = @last_percent = nil
  @history, @mean_max, @max_history = nil
  @start = @last_time = Time.now
  @last_count = 0
  report
end

#load(info) ⇒ Object



136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
# File 'lib/rbbt/util/log/progress/report.rb', line 136

def load(info)
  info.each do |key, value| 
    case key.to_sym
    when :start 
      @start = value
    when :last_time 
      @last_time = value
    when :last_count 
      @last_count = value
    when :last_percent 
      @last_percent = value
    when :desc 
      @desc = value
    when :ticks 
      @ticks = value
    when :max 
      @max = value
    when :mean 
      @mean = value
    end
  end
end

#percentObject



41
42
43
44
45
# File 'lib/rbbt/util/log/progress.rb', line 41

def percent
  return 0 if @ticks == 0
  return 100 if @max == 0
  (@ticks * 100) / @max
end

#pos(pos) ⇒ Object



84
85
86
87
# File 'lib/rbbt/util/log/progress.rb', line 84

def pos(pos)
  step = pos - (@ticks || 0)
  tick(step)
end


3
4
5
6
7
8
9
10
# File 'lib/rbbt/util/log/progress/report.rb', line 3

def print(io, str)
  return if Log.no_bar
  LOG_MUTEX.synchronize do
    STDERR.print str
    Log.logfile.puts str unless Log.logfile.nil?
    Log::LAST.replace "progress"
  end
end

#remove(error = false) ⇒ Object



77
78
79
# File 'lib/rbbt/util/log/progress/util.rb', line 77

def remove(error = false)
  Log::ProgressBar.remove_bar self, error
end

#report(io = STDERR) ⇒ Object



165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
# File 'lib/rbbt/util/log/progress/report.rb', line 165

def report(io = STDERR)
  if Log::LAST != "progress"
    bars = BARS
    if Log::LAST == "new_bar"
      Log::LAST.replace "progress"
      bar = bars.sort_by{|b| b.depth }.first
      print(io, Log.color(:magenta ,bar.report_msg) << "\n") 
    else
      length = Log::ProgressBar.cleanup_bars
      print(io, Log.color(:magenta, "···Progress\n"))
      bars.sort_by{|b| b.depth }.reverse.each do |bar|
        if SILENCED.include? bar
          print(io, Log.color(:magenta, "·\n")) 
        else
          print(io, Log.color(:magenta ,bar.report_msg) << "\n") 
        end
      end
    end
  else
    bars = BARS
  end
  bars << self unless BARS.include? self

  print(io, Log.up_lines(bars.length) << Log.color(:magenta, "···Progress\n") << Log.down_lines(bars.length+1)) if Log::ProgressBar.offset == 0
  print(io, Log.up_lines(@depth) << report_msg << "\n" << Log.down_lines(@depth - 1)) 
  @last_time = Time.now
  @last_count = ticks
  @last_percent = percent if max and max > 0
  Log::LAST.replace "progress"
  save if file
end

#report_msgObject



117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
# File 'lib/rbbt/util/log/progress/report.rb', line 117

def report_msg
  str = Log.color(:magenta, "·")
  if @ticks == 0
    if @max
      return str << " " << Log.color(:magenta, "waiting on #{@max} #{bytes ? 'bytes' : 'items'}") <<  Log.color(:magenta, " · " << desc)
    else
      return str << " " << Log.color(:magenta, "waiting - PID: #{Process.pid}") <<  Log.color(:magenta, " · " << desc)
    end
  end
  str << " " << thr_msg
  if max
    str << Log.color(:blue, " -- ") << eta_msg
  else
    str << Log.color(:blue, " -- ") << ticks.to_s << " #{bytes ? 'bytes' : 'items'}"
  end
  str <<  Log.color(:magenta, " · " << desc)
  str
end

#saveObject



159
160
161
162
163
# File 'lib/rbbt/util/log/progress/report.rb', line 159

def save
  info = {:start => @start, :last_time => @last_time, :last_count => @last_count, :last_percent => @last_percent, :desc => @desc, :ticks => @ticks, :max => @max, :mean => @mean}
  info.delete_if{|k,v| v.nil?}
  Open.write(file, info.to_yaml)
end

#thr_msgObject



13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
# File 'lib/rbbt/util/log/progress/report.rb', line 13

def thr_msg
  if @history.nil?
    @history ||= [[0, @start], [@ticks, Time.now] ]
  elsif @last_ticks != @ticks
    @history << [@ticks, Time.now]
    max_history ||= begin
                      max_history = case 
                                    when @ticks > 20
                                      count = @ticks - @last_count
                                      count = 1 if count == 0
                                      if @max
                                        times = @max / count
                                        num = times / 20
                                        num = 2 if num < 2
                                      else
                                        num = 10
                                      end
                                      count * num
                                    else
                                      20
                                    end
                      max_history = 30 if max_history > 30
                      max_history
                    end
    @history.shift if @history.length > max_history
  end

  @last_ticks = @ticks

  @mean_max ||= 0
  if @history.length > 3

    sticks, stime = @history.first
    ssticks, sstime = @history[-3]
    lticks, ltime = @history.last


    mean = @mean = (lticks - sticks).to_f / (ltime - stime)
    short_mean = (lticks - ssticks).to_f / (ltime - sstime)

    @mean_max = mean if mean > @mean_max
  end

  if short_mean
    thr = short_mean
  else
    thr = begin
            (@ticks || 1) / (Time.now - @start) 
          rescue
            1
          end
  end

  thr = 0.0000001 if thr == 0
  
  if mean.nil? or mean.to_i > 2
    str = "#{ Log.color :blue, thr.to_i.to_s } per sec."
    #str << " #{ Log.color :yellow, mean.to_i.to_s } avg. #{Log.color :yellow, @mean_max.to_i.to_s} max." if @mean_max > 0
  else
    if 1.0/thr < 1
      str = "#{ Log.color :blue, (1.0/thr).round(2).to_s } secs each"
    elsif 1.0/thr < 2
      str = "#{ Log.color :blue, (1.0/thr).round(1).to_s } secs each"
    else
      str = "#{ Log.color :blue, (1/thr).ceil.to_s } secs each"
    end
    #str << " #{ Log.color :yellow, (1/mean).ceil.to_s } avg. #{Log.color :yellow, (1/@mean_max).ceil.to_s} min." if @mean_max > 0
  end

  str
end

#tick(step = 1) ⇒ Object



60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
# File 'lib/rbbt/util/log/progress.rb', line 60

def tick(step = 1)
  return if Log.no_bar
  @ticks += step

  time = Time.now
  if @last_time.nil?
    @last_time = time
    @last_count = @ticks
    @start = time
    return
  end

  diff = time - @last_time
  report and return if diff >= @frequency
  return unless max and max > 0

  percent = self.percent
  if @last_percent.nil?
    @last_percent = percent
    return
  end
  report and return if percent > @last_percent and diff > 0.3
end