mirror of
https://github.com/chromebrew/chromebrew.git
synced 2026-01-08 23:18:10 -05:00
117 lines
3.7 KiB
Ruby
117 lines
3.7 KiB
Ruby
require 'io/console'
|
|
require_relative 'color'
|
|
require_relative 'convert_size'
|
|
|
|
class ProgressBar
|
|
class InvalidSizeError < StandardError; end
|
|
|
|
attr_accessor :progress_bar_showing
|
|
|
|
def initialize (total_size)
|
|
# character used to fill the progress bar, one of the box-drawing character in unicode
|
|
@bar_char = "\u2501"
|
|
|
|
# color scheme of progress bar, can be changed
|
|
# see color.rb for more available colors
|
|
@bar_front_color = :lightcyan
|
|
@bar_bg_color = :gray
|
|
|
|
# all info blocks with space taken
|
|
@info_before_bar = { downloaded_size_in_str: 20 }
|
|
@info_after_bar = { percentage_in_str: 4, elapsed_time_in_str: 8 }
|
|
|
|
@percentage = @downloaded = 0
|
|
@total_size = total_size.to_f
|
|
|
|
@total_size_in_str = human_size(@total_size)
|
|
|
|
trap('WINCH') do
|
|
# reset width settings after terminal resized
|
|
# get terminal size, calculate the width of progress bar based on it
|
|
@terminal_h, @terminal_w = IO.console&.winsize || [ 25, 80 ]
|
|
@bar_width = @terminal_w -
|
|
@info_before_bar.merge(@info_after_bar).values.sum - # space that all info blocks takes
|
|
( @info_before_bar.merge(@info_after_bar).length * 2 ) # space for separator (whitespaces) between each info
|
|
end
|
|
|
|
Process.kill('WINCH', 0) # trigger the trap above
|
|
end
|
|
|
|
def set_downloaded_size (downloaded_size, invalid_size_error: true)
|
|
if downloaded_size > @total_size
|
|
# when the given downloaded size/total size is invalid (given downloaded size > given total size),
|
|
# set all info to unknown (except downloaded size)
|
|
@elapsed_time = @total_size = 0
|
|
@elapsed_time_in_str = '--:--:--'
|
|
|
|
@percentage = 100
|
|
@percentage_in_str = '---'
|
|
|
|
@total_size_in_str = ''
|
|
@downloaded_size_in_str = human_size(downloaded_size)
|
|
|
|
# raise error unless #{invalid_size_error} is set to false
|
|
if invalid_size_error
|
|
raise InvalidSizeError, 'The given downloaded size is larger than the total size'
|
|
else
|
|
return false
|
|
end
|
|
end
|
|
|
|
if @start_time
|
|
@elapsed_time = (Time.now - @start_time).to_i
|
|
else
|
|
# record start time, used for calculating elapsed time
|
|
@start_time = Time.now
|
|
@elapsed_time = 0
|
|
end
|
|
|
|
@elapsed_time_in_str = Time.at(@elapsed_time).utc.strftime('%H:%M:%S')
|
|
|
|
# calculate progress percentage, round to nearest 0.1
|
|
@percentage = ( ( downloaded_size / @total_size ) * 100 ).round(1)
|
|
@percentage_in_str = "#{@percentage.to_i}%"
|
|
|
|
# {downloaded size}/{total size}
|
|
@downloaded_size_in_str = "#{human_size(downloaded_size)}/#{@total_size_in_str}"
|
|
end
|
|
|
|
def show
|
|
return Thread.new do
|
|
@progress_bar_showing = true
|
|
|
|
print "\e[?25l" # hide cursor to prevent cursor flickering
|
|
|
|
while @progress_bar_showing
|
|
sleep 0.15 # update progress bar after each 0.15 seconds
|
|
|
|
completed_length = ( @bar_width * (@percentage / 100) ).to_i
|
|
uncompleted_length = @bar_width - completed_length
|
|
|
|
# print info and progress bar
|
|
@info_before_bar.each_pair do |varName, width|
|
|
printf "%*.*s ", width, width, instance_variable_get("@#{varName}")
|
|
end
|
|
|
|
# print progress bar with color code
|
|
print ( @bar_char * completed_length ).send(@bar_front_color),
|
|
( @bar_char * uncompleted_length ).send(@bar_bg_color)
|
|
|
|
@info_after_bar.each_pair do |varName, width|
|
|
printf " %*.*s", width, width, instance_variable_get("@#{varName}")
|
|
end
|
|
|
|
# stop when 100%
|
|
if @percentage >= 100
|
|
print "\e[2K\r" # clear previous line (progress bar)
|
|
break
|
|
else
|
|
print "\r"
|
|
end
|
|
end
|
|
ensure
|
|
print "\e[?25h" # restore cursor mode since we hide it before
|
|
end
|
|
end
|
|
end
|