]> gitweb.michael.orlitzky.com - dead/whatever-dl.git/blob - vendor/ruby-progressbar/progressbar.rb
507082d6aa6be82dc03df26edcf2396ebe316cc6
[dead/whatever-dl.git] / vendor / ruby-progressbar / progressbar.rb
1 #
2 # Ruby/ProgressBar - a text progress bar library
3 #
4 # Copyright (C) 2001-2005 Satoru Takabayashi <satoru@namazu.org>
5 # All rights reserved.
6 # This is free software with ABSOLUTELY NO WARRANTY.
7 #
8 # You can redistribute it and/or modify it under the terms
9 # of Ruby's license.
10 #
11
12 class ProgressBar
13 VERSION = "0.9"
14
15 def initialize (title, total, out = STDERR)
16 @title = title
17 @total = total
18 @out = out
19 @terminal_width = 80
20 @bar_mark = "o"
21 @current = 0
22 @previous = 0
23 @finished_p = false
24 @start_time = Time.now
25 @previous_time = @start_time
26 @title_width = 14
27 @format = "%-#{@title_width}s %3d%% %s %s"
28 @format_arguments = [:title, :percentage, :bar, :stat]
29 clear
30 show
31 end
32 attr_reader :title
33 attr_reader :current
34 attr_reader :total
35 attr_accessor :start_time
36
37 private
38 def fmt_bar
39 bar_width = do_percentage * @terminal_width / 100
40 sprintf("|%s%s|",
41 @bar_mark * bar_width,
42 " " * (@terminal_width - bar_width))
43 end
44
45 def fmt_percentage
46 do_percentage
47 end
48
49 def fmt_stat
50 if @finished_p then elapsed else eta end
51 end
52
53 def fmt_stat_for_file_transfer
54 if @finished_p then
55 sprintf("%s %s %s", bytes, transfer_rate, elapsed)
56 else
57 sprintf("%s %s %s", bytes, transfer_rate, eta)
58 end
59 end
60
61 def fmt_title
62 @title[0,(@title_width - 1)] + ":"
63 end
64
65 def convert_bytes (bytes)
66 if bytes < 1024
67 sprintf("%6dB", bytes)
68 elsif bytes < 1024 * 1000 # 1000kb
69 sprintf("%5.1fKB", bytes.to_f / 1024)
70 elsif bytes < 1024 * 1024 * 1000 # 1000mb
71 sprintf("%5.1fMB", bytes.to_f / 1024 / 1024)
72 else
73 sprintf("%5.1fGB", bytes.to_f / 1024 / 1024 / 1024)
74 end
75 end
76
77 def transfer_rate
78 bytes_per_second = @current.to_f / (Time.now - @start_time)
79 sprintf("%s/s", convert_bytes(bytes_per_second))
80 end
81
82 def bytes
83 convert_bytes(@current)
84 end
85
86 def format_time (t)
87 t = t.to_i
88 sec = t % 60
89 min = (t / 60) % 60
90 hour = t / 3600
91 sprintf("%02d:%02d:%02d", hour, min, sec);
92 end
93
94 # ETA stands for Estimated Time of Arrival.
95 def eta
96 if @current == 0
97 "ETA: --:--:--"
98 else
99 elapsed = Time.now - @start_time
100 eta = elapsed * @total / @current - elapsed;
101 sprintf("ETA: %s", format_time(eta))
102 end
103 end
104
105 def elapsed
106 elapsed = Time.now - @start_time
107 sprintf("Time: %s", format_time(elapsed))
108 end
109
110 def eol
111 if @finished_p then "\n" else "\r" end
112 end
113
114 def do_percentage
115 if @total.zero?
116 100
117 else
118 @current * 100 / @total
119 end
120 end
121
122 def get_width
123 # FIXME: I don't know how portable it is.
124 default_width = 80
125 begin
126 tiocgwinsz = 0x5413
127 data = [0, 0, 0, 0].pack("SSSS")
128 if @out.ioctl(tiocgwinsz, data) >= 0 then
129 rows, cols, xpixels, ypixels = data.unpack("SSSS")
130 if cols >= 0 then cols else default_width end
131 else
132 default_width
133 end
134 rescue Exception
135 default_width
136 end
137 end
138
139 def show
140 arguments = @format_arguments.map {|method|
141 method = sprintf("fmt_%s", method)
142 send(method)
143 }
144 line = sprintf(@format, *arguments)
145
146 width = get_width
147 if line.length == width - 1
148 @out.print(line + eol)
149 @out.flush
150 elsif line.length >= width
151 @terminal_width = [@terminal_width - (line.length - width + 1), 0].max
152 if @terminal_width == 0 then @out.print(line + eol) else show end
153 else # line.length < width - 1
154 @terminal_width += width - line.length + 1
155 show
156 end
157 @previous_time = Time.now
158 end
159
160 def show_if_needed
161 if @total.zero?
162 cur_percentage = 100
163 prev_percentage = 0
164 else
165 cur_percentage = (@current * 100 / @total).to_i
166 prev_percentage = (@previous * 100 / @total).to_i
167 end
168
169 # Use "!=" instead of ">" to support negative changes
170 if cur_percentage != prev_percentage ||
171 Time.now - @previous_time >= 1 || @finished_p
172 show
173 end
174 end
175
176 public
177 def clear
178 @out.print "\r"
179 @out.print(" " * (get_width - 1))
180 @out.print "\r"
181 end
182
183 def finish
184 @current = @total
185 @finished_p = true
186 show
187 end
188
189 def finished?
190 @finished_p
191 end
192
193 def file_transfer_mode
194 @format_arguments = [:title, :percentage, :bar, :stat_for_file_transfer]
195 end
196
197 def format= (format)
198 @format = format
199 end
200
201 def format_arguments= (arguments)
202 @format_arguments = arguments
203 end
204
205 def halt
206 @finished_p = true
207 show
208 end
209
210 def inc (step = 1)
211 @current += step
212 @current = @total if @current > @total
213 show_if_needed
214 @previous = @current
215 end
216
217 def set (count)
218 if count < 0 || count > @total
219 raise "invalid count: #{count} (total: #{@total})"
220 end
221 @current = count
222 show_if_needed
223 @previous = @current
224 end
225
226 def inspect
227 "#<ProgressBar:#{@current}/#{@total}>"
228 end
229 end
230
231 class ReversedProgressBar < ProgressBar
232 def do_percentage
233 100 - super
234 end
235 end
236