scout-gear 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,240 @@
1
+ require 'yaml'
2
+ module Log
3
+ class ProgressBar
4
+ def print(io, str)
5
+ return if Log.no_bar
6
+ STDERR.print str
7
+ Log.logfile.puts str unless Log.logfile.nil?
8
+ Log::LAST.replace "progress"
9
+ end
10
+
11
+ attr_accessor :history, :mean_max, :max_history
12
+ def thr_msg
13
+ if @history.nil?
14
+ @history ||= [[0, @start], [@ticks, Time.now] ]
15
+ elsif @last_ticks != @ticks
16
+ @history << [@ticks, Time.now]
17
+ max_history ||= begin
18
+ max_history = case
19
+ when @ticks > 20
20
+ count = @ticks - @last_count
21
+ count = 1 if count == 0
22
+ if @max
23
+ times = @max / count
24
+ num = times / 20
25
+ num = 2 if num < 2
26
+ else
27
+ num = 10
28
+ end
29
+ count * num
30
+ else
31
+ 20
32
+ end
33
+ max_history = 30 if max_history > 30
34
+ max_history
35
+ end
36
+ @history.shift if @history.length > max_history
37
+ end
38
+
39
+ @last_ticks = @ticks
40
+
41
+ @mean_max ||= 0
42
+ if @history.length > 3
43
+
44
+ sticks, stime = @history.first
45
+ ssticks, sstime = @history[-3]
46
+ lticks, ltime = @history.last
47
+
48
+
49
+ mean = @mean = (lticks - sticks).to_f / (ltime - stime)
50
+ short_mean = (lticks - ssticks).to_f / (ltime - sstime)
51
+
52
+ @mean_max = mean if mean > @mean_max
53
+ end
54
+
55
+ if short_mean
56
+ thr = short_mean
57
+ else
58
+ thr = begin
59
+ (@ticks || 1) / (Time.now - @start)
60
+ rescue
61
+ 1
62
+ end
63
+ end
64
+
65
+ thr = 0.0000001 if thr == 0
66
+
67
+ if mean.nil? or mean.to_i > 2
68
+ str = "#{ Log.color :blue, thr.to_i.to_s } per sec."
69
+ #str << " #{ Log.color :yellow, mean.to_i.to_s } avg. #{Log.color :yellow, @mean_max.to_i.to_s} max." if @mean_max > 0
70
+ else
71
+ if 1.0/thr < 1
72
+ str = "#{ Log.color :blue, (1.0/thr).round(2).to_s } secs each"
73
+ elsif 1.0/thr < 2
74
+ str = "#{ Log.color :blue, (1.0/thr).round(1).to_s } secs each"
75
+ else
76
+ str = "#{ Log.color :blue, (1/thr).ceil.to_s } secs each"
77
+ end
78
+ #str << " #{ Log.color :yellow, (1/mean).ceil.to_s } avg. #{Log.color :yellow, (1/@mean_max).ceil.to_s} min." if @mean_max > 0
79
+ end
80
+
81
+ str
82
+ end
83
+
84
+
85
+ def eta_msg
86
+ percent = self.percent
87
+ time = Time.now
88
+
89
+ indicator = ""
90
+ 10.times{|i|
91
+ if i < percent / 10 then
92
+ indicator << Log.color(:yellow, ".")
93
+ else
94
+ indicator << " "
95
+ end
96
+ }
97
+
98
+ indicator << " #{Log.color(:blue, percent.to_s << "%")}"
99
+
100
+ used = time - @start
101
+ if @mean_max and @mean_max > 0 and @mean > 0
102
+ eta = (@max - @ticks) / @mean
103
+ else
104
+ eta = (@max - @ticks) / (@ticks/used)
105
+ end
106
+
107
+ used = Misc.format_seconds(used)
108
+ eta = [eta/3600, eta/60 % 60, eta % 60].map{|t| "%02i" % t }.join(':')
109
+
110
+ #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'}"
111
+ 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'}"
112
+
113
+ indicator
114
+ end
115
+
116
+ def report_msg
117
+ str = Log.color(:magenta, "·")
118
+ if @ticks == 0
119
+ if @max
120
+ return str << " " << Log.color(:magenta, "waiting on #{@max} #{bytes ? 'bytes' : 'items'}") << Log.color(:magenta, " · " << desc)
121
+ else
122
+ return str << " " << Log.color(:magenta, "waiting - PID: #{Process.pid}") << Log.color(:magenta, " · " << desc)
123
+ end
124
+ end
125
+ str << " " << thr_msg
126
+ if max
127
+ str << Log.color(:blue, " -- ") << eta_msg
128
+ else
129
+ str << Log.color(:blue, " -- ") << ticks.to_s << " #{bytes ? 'bytes' : 'items'}"
130
+ end
131
+ str << Log.color(:magenta, " · " << desc)
132
+ str
133
+ end
134
+
135
+ def load(info)
136
+ info.each do |key, value|
137
+ case key.to_sym
138
+ when :start
139
+ @start = value
140
+ when :last_time
141
+ @last_time = value
142
+ when :last_count
143
+ @last_count = value
144
+ when :last_percent
145
+ @last_percent = value
146
+ when :desc
147
+ @desc = value
148
+ when :ticks
149
+ @ticks = value
150
+ when :max
151
+ @max = value
152
+ when :mean
153
+ @mean = value
154
+ end
155
+ end
156
+ end
157
+
158
+ def save
159
+ info = {:start => @start, :last_time => @last_time, :last_count => @last_count, :last_percent => @last_percent, :desc => @desc, :ticks => @ticks, :max => @max, :mean => @mean}
160
+ info.delete_if{|k,v| v.nil?}
161
+ File.write(file, info.to_yaml)
162
+ end
163
+
164
+ def report(io = STDERR)
165
+ if Log::LAST != "progress"
166
+ bars = BARS
167
+ if Log::LAST == "new_bar"
168
+ Log::LAST.replace "progress"
169
+ bar = bars.sort_by{|b| b.depth }.first
170
+ print(io, Log.color(:magenta ,bar.report_msg) << "\n")
171
+ else
172
+ length = Log::ProgressBar.cleanup_bars
173
+ print(io, Log.color(:magenta, "···Progress\n"))
174
+ bars.sort_by{|b| b.depth }.reverse.each do |bar|
175
+ if SILENCED.include? bar
176
+ print(io, Log.color(:magenta, "·\n"))
177
+ else
178
+ print(io, Log.color(:magenta ,bar.report_msg) << "\n")
179
+ end
180
+ end
181
+ end
182
+ else
183
+ bars = BARS
184
+ end
185
+ bars << self unless BARS.include? self
186
+
187
+ print(io, Log.up_lines(bars.length) << Log.color(:magenta, "···Progress\n") << Log.down_lines(bars.length+1)) if Log::ProgressBar.offset == 0
188
+ print(io, Log.up_lines(@depth) << report_msg << "\n" << Log.down_lines(@depth - 1))
189
+ @last_time = Time.now
190
+ @last_count = ticks
191
+ @last_percent = percent if max and max > 0
192
+ Log::LAST.replace "progress"
193
+ save if file
194
+ end
195
+
196
+ def done(io = STDERR)
197
+ done_msg = Log.color(:magenta, "· ") << Log.color(:green, "done")
198
+ if @start
199
+ ellapsed = (Time.now - @start).to_i
200
+ else
201
+ ellapsed = 0
202
+ end
203
+ ellapsed = [ellapsed/3600, ellapsed/60 % 60, ellapsed % 60].map{|t| "%02i" % t }.join(':')
204
+ done_msg << " " << Log.color(:blue, (@ticks).to_s) << " #{bytes ? 'bytes' : 'items'} in " << Log.color(:green, ellapsed)
205
+ @last_count = 0
206
+ @last_time = @start
207
+ done_msg << " - " << thr_msg
208
+ done_msg << Log.color(:magenta, " · " << desc)
209
+ print(io, Log.up_lines(@depth) << done_msg << Log.down_lines(@depth))
210
+
211
+ FileUtils.rm file if file and File.exists?(file)
212
+
213
+ @callback.call self if @callback
214
+ end
215
+
216
+ def error(io = STDERR)
217
+ done_msg = Log.color(:magenta, "· ") << Log.color(:red, "error")
218
+ if @start
219
+ ellapsed = (Time.now - @start).to_i
220
+ else
221
+ ellapsed = 0
222
+ end
223
+ ellapsed = [ellapsed/3600, ellapsed/60 % 60, ellapsed % 60].map{|t| "%02i" % t }.join(':')
224
+ done_msg << " " << Log.color(:blue, (@ticks).to_s) << " in " << Log.color(:green, ellapsed)
225
+ @last_count = 0
226
+ @last_time = @start
227
+ done_msg << " - " << thr_msg
228
+ done_msg << Log.color(:magenta, " · " << desc)
229
+ print(io, Log.up_lines(@depth) << done_msg << Log.down_lines(@depth))
230
+
231
+ File.rm file if file and File.exist?(file)
232
+
233
+ begin
234
+ @callback.call self
235
+ rescue
236
+ Log.debug "Callback failed for filed progress bar: #{$!.message}"
237
+ end if @callback
238
+ end
239
+ end
240
+ end
@@ -0,0 +1,100 @@
1
+ require_relative '../../exceptions'
2
+ module Log
3
+ class ProgressBar
4
+ BAR_MUTEX = Mutex.new
5
+ BARS = []
6
+ REMOVE = []
7
+ SILENCED = []
8
+
9
+ def self.add_offset(value = 1)
10
+ value = 1 if TrueClass === value
11
+ @@offset = offset + value.to_i
12
+ @@offset = 0 if @@offset < 0
13
+ @@offset
14
+ end
15
+
16
+ def self.remove_offset(value = 1)
17
+ value = 1 if TrueClass === value
18
+ @@offset = offset - value.to_i
19
+ @@offset = 0 if @@offset < 0
20
+ @@offset
21
+ end
22
+
23
+
24
+ def self.offset
25
+ @@offset ||= 0
26
+ @@offset = 0 if @@offset < 0
27
+ @@offset
28
+ end
29
+
30
+ def self.new_bar(max, options = {})
31
+ cleanup_bars
32
+ BAR_MUTEX.synchronize do
33
+ Log::LAST.replace "new_bar" if Log::LAST == "progress"
34
+ options = IndiferentHash.add_defaults options, :depth => BARS.length + Log::ProgressBar.offset
35
+ BARS << (bar = ProgressBar.new(max, options))
36
+ bar
37
+ end
38
+ end
39
+
40
+ def self.cleanup_bars
41
+ BAR_MUTEX.synchronize do
42
+ REMOVE.each do |bar|
43
+ index = BARS.index bar
44
+ if index
45
+ BARS.delete_at index
46
+ BARS.each_with_index do |bar,i|
47
+ bar.depth = i
48
+ end
49
+ end
50
+ index = SILENCED.index bar
51
+ if index
52
+ SILENCED.delete_at index
53
+ SILENCED.each_with_index do |bar,i|
54
+ bar.depth = i
55
+ end
56
+ end
57
+ end
58
+ REMOVE.clear
59
+ BARS.length
60
+ end
61
+ end
62
+
63
+ def self.remove_bar(bar, error = false)
64
+ BAR_MUTEX.synchronize do
65
+ return if REMOVE.include? bar
66
+ end
67
+ if error
68
+ bar.error if bar.respond_to? :error
69
+ else
70
+ bar.done if bar.respond_to? :done
71
+ end
72
+ BAR_MUTEX.synchronize do
73
+ REMOVE << bar
74
+ end
75
+ Log::LAST.replace "remove_bar" if Log::LAST == "progress"
76
+ end
77
+
78
+ def remove(error = false)
79
+ Log::ProgressBar.remove_bar self, error
80
+ end
81
+
82
+ def self.with_bar(max, options = {})
83
+ bar = new_bar(max, options)
84
+ res = nil
85
+ begin
86
+ error = false
87
+ keep = false
88
+ yield bar
89
+ rescue KeepBar
90
+ keep = true
91
+ rescue
92
+ error = true
93
+ raise $!
94
+ ensure
95
+ remove_bar(bar, error) if bar
96
+ end
97
+ end
98
+ end
99
+ end
100
+
@@ -0,0 +1,102 @@
1
+ require_relative 'progress/util'
2
+ require_relative 'progress/report'
3
+ module Log
4
+
5
+ def self.no_bar=(value)
6
+ @@no_bar = value
7
+ end
8
+
9
+ def self.no_bar
10
+ @@no_bar = false unless defined?(@@no_bar)
11
+ @@no_bar || ENV["RBBT_NO_PROGRESS"] == "true"
12
+ end
13
+
14
+ class ProgressBar
15
+
16
+ class << self
17
+ attr_accessor :default_file
18
+ end
19
+
20
+ attr_accessor :max, :ticks, :frequency, :depth, :desc, :file, :bytes, :process, :callback
21
+
22
+ def initialize(max = nil, options = {})
23
+ depth, num_reports, desc, io, severity, file, bytes, frequency, process, callback =
24
+ IndiferentHash.process_options options, :depth, :num_reports, :desc, :io, :severity, :file, :bytes, :frequency, :process, :callback,
25
+ :depth => 0, :num_reports => 100, :io => STDERR, :severity => Log.severity, :frequency => 2
26
+
27
+ @max = max
28
+ @ticks = 0
29
+ @frequency = frequency
30
+ @last_time = nil
31
+ @last_count = nil
32
+ @last_percent = nil
33
+ @depth = depth
34
+ @desc = desc.nil? ? "" : desc.gsub(/\n/,' ')
35
+ @file = file
36
+ @bytes = bytes
37
+ @process = process
38
+ @callback = callback
39
+ end
40
+
41
+ def percent
42
+ return 0 if @ticks == 0
43
+ return 100 if @max == 0
44
+ (@ticks * 100) / @max
45
+ end
46
+
47
+ def file
48
+ @file || ProgressBar.default_file
49
+ end
50
+
51
+ def init
52
+ @ticks, @bytes = 0
53
+ @last_time = @last_count = @last_percent = nil
54
+ @history, @mean_max, @max_history = nil
55
+ @start = @last_time = Time.now
56
+ @last_count = 0
57
+ report
58
+ end
59
+
60
+ def tick(step = 1)
61
+ return if Log.no_bar
62
+ @ticks += step
63
+
64
+ time = Time.now
65
+ if @last_time.nil?
66
+ @last_time = time
67
+ @last_count = @ticks
68
+ @start = time
69
+ return
70
+ end
71
+
72
+ diff = time - @last_time
73
+ report and return if diff >= @frequency
74
+ return unless max and max > 0
75
+
76
+ percent = self.percent
77
+ if @last_percent.nil?
78
+ @last_percent = percent
79
+ return
80
+ end
81
+ report && return if percent > @last_percent and diff > 0.3
82
+ end
83
+
84
+ def pos(pos)
85
+ step = pos - (@ticks || 0)
86
+ tick(step)
87
+ end
88
+
89
+ def process(elem)
90
+ case res = @process.call(elem)
91
+ when FalseClass
92
+ nil
93
+ when TrueClass
94
+ tick
95
+ when Integer
96
+ pos(res)
97
+ when Float
98
+ pos(res * max)
99
+ end
100
+ end
101
+ end
102
+ end