lib/sus/output/progress.rb
# frozen_string_literal: true # Released under the MIT License. # Copyright, 2021-2024, by Samuel Williams. require_relative "bar" require_relative "status" require_relative "lines" module Sus module Output class Progress def self.now ::Process.clock_gettime(Process::CLOCK_MONOTONIC) end def initialize(output, total = 0, minimum_output_duration: 1.0) @output = output @subject = subject @start_time = Progress.now if @output.interactive? @bar = Bar.new @lines = Lines.new(@output) @lines[0] = @bar end @current = 0 @total = total end attr :subject attr :current attr :total def duration Progress.now - @start_time end def progress @current.to_f / @total.to_f end def remaining @total - @current end def average_duration if @current > 0 duration / @current end end def estimated_remaining_time if average_duration = self.average_duration average_duration * remaining end end # Increase the amont of work done. def increment(amount = 1) @current += amount @bar&.update(@current, @total, self.to_s) @lines&.redraw(0) return self end # Increase the total size of the progress. def expand(amount = 1) @total += amount @bar&.update(@current, @total, self.to_s) @lines&.redraw(0) return self end def report(index, context, state) @lines&.[]=(index+1, Status.new(state, context)) return self end def clear @lines&.clear end def to_s if estimated_remaining_time = self.estimated_remaining_time "#{@current}/#{@total} completed in #{formatted_duration(self.duration)}, #{formatted_duration(estimated_remaining_time)} remaining" else "#{@current}/#{@total} completed" end end private def formatted_duration(duration) seconds = duration.floor if seconds < 60.0 return "#{seconds}s" end minutes = (duration / 60.0).floor seconds = (seconds - (minutes * 60)).round if minutes < 60.0 return "#{minutes}m#{seconds}s" end hours = (minutes / 60.0).floor minutes = (minutes - (hours * 60)).round if hours < 24.0 return "#{hours}h#{minutes}m" end days = (hours / 24.0).floor hours = (hours - (days * 24)).round return "#{days}d#{hours}h" end end end end