Skip to content

Commit

Permalink
Merge pull request #8577 from nandahkrishna/livecheck-json-progress
Browse files Browse the repository at this point in the history
livecheck: progress bar for JSON output
  • Loading branch information
nandahkrishna committed Sep 18, 2020
2 parents c540939 + 56a8f8f commit 65e51da
Show file tree
Hide file tree
Showing 35 changed files with 1,304 additions and 37 deletions.
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,6 @@
**/vendor/bundle/ruby/*/gems/rubocop-0*/
**/vendor/bundle/ruby/*/gems/rubocop-ast-*/
**/vendor/bundle/ruby/*/gems/ruby-prof-*/
**/vendor/bundle/ruby/*/gems/ruby-progressbar-*/
**/vendor/bundle/ruby/*/gems/simplecov-*/
**/vendor/bundle/ruby/*/gems/simplecov-html-*/
**/vendor/bundle/ruby/*/gems/sorbet-*/
Expand Down
12 changes: 7 additions & 5 deletions Library/Homebrew/dev-cmd/livecheck.rb
Original file line number Diff line number Diff line change
Expand Up @@ -26,15 +26,17 @@ def livecheck_args
switch "--full-name",
description: "Print formulae with fully-qualified names."
flag "--tap=",
description: "Check the formulae within the given tap, specified as <user>`/`<repo>."
switch "--installed",
description: "Check formulae that are currently installed."
switch "--json",
description: "Output informations in JSON format."
description: "Check formulae within the given tap, specified as <user>`/`<repo>."
switch "--all",
description: "Check all available formulae."
switch "--installed",
description: "Check formulae that are currently installed."
switch "--newer-only",
description: "Show the latest version only if it's newer than the formula."
switch "--json",
description: "Output information in JSON format."
switch "-q", "--quiet",
description: "Suppress warnings, don't print a progress bar for JSON output."
conflicts "--debug", "--json"
conflicts "--tap=", "--all", "--installed"
end
Expand Down
37 changes: 35 additions & 2 deletions Library/Homebrew/livecheck/livecheck.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# frozen_string_literal: true

require "livecheck/strategy"
require "ruby-progressbar"

module Homebrew
# The `Livecheck` module consists of methods used by the `brew livecheck`
Expand Down Expand Up @@ -66,6 +67,27 @@ def livecheck_formulae(formulae_to_check, args)
@livecheck_strategy_names.freeze

has_a_newer_upstream_version = false

if args.json? && !args.quiet? && $stderr.tty?
total_formulae = if formulae_to_check == Formula
formulae_to_check.count
else
formulae_to_check.length
end

Tty.with($stderr) do |stderr|
stderr.puts Formatter.headline("Running checks", color: :blue)
end

progress = ProgressBar.create(
total: total_formulae,
progress_mark: "#",
remainder_mark: ".",
format: " %t: [%B] %c/%C ",
output: $stderr,
)
end

formulae_checked = formulae_to_check.sort.map.with_index do |formula, i|
if args.debug? && i.positive?
puts <<~EOS
Expand All @@ -78,7 +100,7 @@ def livecheck_formulae(formulae_to_check, args)
skip_result = skip_conditions(formula, args: args)
next skip_result if skip_result != false

formula.head.downloader.shutup! if formula.head?
formula.head&.downloader&.shutup!

current = if formula.head?
formula.any_installed_version.version.commit
Expand Down Expand Up @@ -136,6 +158,7 @@ def livecheck_formulae(formulae_to_check, args)
has_a_newer_upstream_version ||= true

if args.json?
progress&.increment
info.except!(:meta) unless args.verbose?
next info
end
Expand All @@ -146,6 +169,7 @@ def livecheck_formulae(formulae_to_check, args)
Homebrew.failed = true

if args.json?
progress&.increment
status_hash(formula, "error", [e.to_s], args: args)
elsif !args.quiet?
onoe "#{Tty.blue}#{formula_name(formula, args: args)}#{Tty.reset}: #{e}"
Expand All @@ -157,7 +181,16 @@ def livecheck_formulae(formulae_to_check, args)
puts "No newer upstream versions."
end

puts JSON.generate(formulae_checked.compact) if args.json?
return unless args.json?

if progress
progress.finish
Tty.with($stderr) do |stderr|
stderr.print "#{Tty.up}#{Tty.erase_line}" * 2
end
end

puts JSON.generate(formulae_checked.compact)
end

# Returns the fully-qualified name of a formula if the full_name argument is
Expand Down
19 changes: 19 additions & 0 deletions Library/Homebrew/utils/tty.rb
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,15 @@ def truncate(string)
no_underline: 24,
}.freeze

SPECIAL_CODES = {
up: "1A",
down: "1B",
right: "1C",
left: "1D",
erase_line: "K",
erase_char: "P",
}.freeze

CODES = COLOR_CODES.merge(STYLE_CODES).freeze

def append_to_escape_sequence(code)
Expand All @@ -77,6 +86,16 @@ def reset_escape_sequence!
end
end

SPECIAL_CODES.each do |name, code|
define_singleton_method(name) do
if @stream.tty?
"\033[#{code}"
else
""
end
end
end

def to_s
return "" unless color?

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# frozen_string_literal: true

require 'ruby-progressbar/output'
require 'ruby-progressbar/outputs/tty'
require 'ruby-progressbar/outputs/non_tty'
require 'ruby-progressbar/timer'
require 'ruby-progressbar/progress'
require 'ruby-progressbar/throttle'
require 'ruby-progressbar/calculators/length'
require 'ruby-progressbar/calculators/running_average'
require 'ruby-progressbar/components'
require 'ruby-progressbar/format'
require 'ruby-progressbar/base'
require 'ruby-progressbar/refinements' if Module.
private_instance_methods.
include?(:using)

class ProgressBar
def self.create(*args)
ProgressBar::Base.new(*args)
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
require 'forwardable'

class ProgressBar
class Base
extend Forwardable

def_delegators :output,
:clear,
:log,
:refresh

def_delegators :progressable,
:progress,
:total

def initialize(options = {})
self.autostart = options.fetch(:autostart, true)
self.autofinish = options.fetch(:autofinish, true)
self.finished = false

self.timer = Timer.new(options)
self.progressable = Progress.new(options)

options = options.merge(:timer => timer,
:progress => progressable)

self.title_comp = Components::Title.new(options)
self.bar = Components::Bar.new(options)
self.percentage = Components::Percentage.new(options)
self.rate = Components::Rate.new(options)
self.time = Components::Time.new(options)

self.output = Output.detect(options.merge(:bar => self))
@format = Format::String.new(output.resolve_format(options[:format]))

start :at => options[:starting_at] if autostart
end

def start(options = {})
timer.start
update_progress(:start, options)
end

def finish
return if finished?

output.with_refresh do
self.finished = true
progressable.finish
timer.stop
end
end

def pause
output.with_refresh { timer.pause } unless paused?
end

def stop
output.with_refresh { timer.stop } unless stopped?
end

def resume
output.with_refresh { timer.resume } if stopped?
end

def reset
output.with_refresh do
self.finished = false
progressable.reset
timer.reset
end
end

def stopped?
timer.stopped? || finished?
end

alias paused? stopped?

def finished?
finished || (autofinish && progressable.finished?)
end

def started?
timer.started?
end

def decrement
update_progress(:decrement)
end

def increment
update_progress(:increment)
end

def progress=(new_progress)
update_progress(:progress=, new_progress)
end

def total=(new_total)
update_progress(:total=, new_total)
end

def progress_mark=(mark)
output.refresh_with_format_change { bar.progress_mark = mark }
end

def remainder_mark=(mark)
output.refresh_with_format_change { bar.remainder_mark = mark }
end

def title
title_comp.title
end

def title=(title)
output.refresh_with_format_change { title_comp.title = title }
end

def to_s(new_format = nil)
self.format = new_format if new_format

Format::Formatter.process(@format, output.length, self)
end

# rubocop:disable Metrics/AbcSize, Metrics/LineLength
def to_h
{
'output_stream' => output.__send__(:stream),
'length' => output.length,
'title' => title_comp.title,
'progress_mark' => bar.progress_mark,
'remainder_mark' => bar.remainder_mark,
'progress' => progressable.progress,
'total' => progressable.total,
'percentage' => progressable.percentage_completed_with_precision.to_f,
'elapsed_time_in_seconds' => time.__send__(:timer).elapsed_seconds,
'estimated_time_remaining_in_seconds' => time.__send__(:estimated_seconds_remaining),
'base_rate_of_change' => rate.__send__(:base_rate),
'scaled_rate_of_change' => rate.__send__(:scaled_rate),
'unknown_progress_animation_steps' => bar.upa_steps,
'throttle_rate' => output.__send__(:throttle).rate,
'started?' => started?,
'stopped?' => stopped?,
'finished?' => finished?
}
end
# rubocop:enable Metrics/AbcSize, Metrics/LineLength

def inspect
"#<ProgressBar:#{progress}/#{total || 'unknown'}>"
end

def format=(other)
output.refresh_with_format_change do
@format = Format::String.new(other || output.default_format)
end
end

alias format format=

protected

attr_accessor :output,
:timer,
:progressable,
:title_comp,
:bar,
:percentage,
:rate,
:time,
:autostart,
:autofinish,
:finished

def update_progress(*args)
output.with_refresh do
progressable.__send__(*args)
timer.stop if finished?
end
end
end
end

0 comments on commit 65e51da

Please sign in to comment.