lib/tasks/task_helper.rb
# frozen_string_literal: true

# Write the given objects to the standard output – except if Rake is configured
# to be quiet.
#
# This is useful when running tests (when Rake is configured to be quiet),
# to avoid spamming the output with extra informations.
def rake_puts(*args)
  if Rake.verbose
    puts(*args)
  end
end

def rake_print(*args)
  if Rake.verbose
    print(*args)
  end
end

# Display progress of a long-running Rake task.
#
# Usage:
#
# ```
# progress = ProgressReport.new(100)
# (0..100).times do
#   progress.inc
# end
# progress.finish
# ````
class ProgressReport
  def initialize(total)
    @start = Time.zone.now
    rake_puts
    set_progress(total: total, count: 0)
  end

  def inc(amount = 1)
    set_progress(count: @count + amount)
    if @per_10_000 % 10 == 0
      print_progress
    end
  end

  def set(count)
    set_progress(count: count)

    if @per_10_000 % 10 == 0
      print_progress
    end
  end

  def finish
    if @count > 0 && @per_10_000 != 10_000
      set_progress(total: @count)
      print_progress
    end
    rake_puts
  end

  private

  def set_progress(total: nil, count: nil)
    if total.present?
      @total = total
    end
    if count.present?
      @count = count
      @total = [@count, @total].max
    end
    if @total&.nonzero?
      @per_10_000 = 10_000 * @count / @total
    end
  end

  def print_progress
    elapsed = Time.zone.now - @start
    percent = format('%5.1f%%', @per_10_000 / 100.0)
    total = @total.to_s
    count = @count.to_s.rjust(total.length)
    rake_print("\r#{percent} (#{count}/#{total}) [#{format_duration(elapsed)}/#{format_duration(elapsed * 10_000.0 / @per_10_000)}]")
  end

  def format_duration(seconds)
    if seconds.finite?
      Time.zone.at(seconds).utc.strftime('%H:%M:%S')
    else
      '--:--:--'
    end
  end
end
