info: make verbose analytics use tabular output.
This copies (and slightly improves) the current `brew formula-analytics` output so `brew formula-analytics` can be adjusted to just output JSON.
This commit is contained in:
parent
4231197437
commit
0617dc1c1d
@ -1,11 +1,20 @@
|
|||||||
#: * `info`:
|
#: * `info`:
|
||||||
#: Display brief statistics for your Homebrew installation.
|
#: Display brief statistics for your Homebrew installation.
|
||||||
#:
|
#:
|
||||||
#: * `info` <formula> [`--verbose`]:
|
#: * `info` `--analytics` [`--days=`<days>] [`--category=`<category>]:
|
||||||
|
#: Display Homebrew analytics data (provided neither `HOMEBREW_NO_ANALYTICS`
|
||||||
|
#: or `HOMEBREW_NO_GITHUB_API` are set)
|
||||||
|
#:
|
||||||
|
#: The value for `days` must be `30`, `90` or `365`. The default is `30`.
|
||||||
|
#:
|
||||||
|
#: The value for `category` must be `install`, `install-on-request`,
|
||||||
|
#: `build-error` or `os-version`. The default is `install`.
|
||||||
|
#:
|
||||||
|
#: * `info` <formula> [`--analytics`]:
|
||||||
#: Display information about <formula> and analytics data (provided neither
|
#: Display information about <formula> and analytics data (provided neither
|
||||||
#: `HOMEBREW_NO_ANALYTICS` or `HOMEBREW_NO_GITHUB_API` are set)
|
#: `HOMEBREW_NO_ANALYTICS` or `HOMEBREW_NO_GITHUB_API` are set)
|
||||||
#:
|
#:
|
||||||
#: Pass `--verbose` to see more detailed analytics data.
|
#: Pass `--analytics` to see more detailed analytics data.
|
||||||
#:
|
#:
|
||||||
#: * `info` `--github` <formula>:
|
#: * `info` `--github` <formula>:
|
||||||
#: Open a browser to the GitHub History page for <formula>.
|
#: Open a browser to the GitHub History page for <formula>.
|
||||||
@ -47,7 +56,9 @@ module Homebrew
|
|||||||
|
|
||||||
def print_info
|
def print_info
|
||||||
if ARGV.named.empty?
|
if ARGV.named.empty?
|
||||||
if HOMEBREW_CELLAR.exist?
|
if ARGV.include?("--analytics")
|
||||||
|
output_analytics
|
||||||
|
elsif HOMEBREW_CELLAR.exist?
|
||||||
count = Formula.racks.length
|
count = Formula.racks.length
|
||||||
puts "#{count} #{"keg".pluralize(count)}, #{HOMEBREW_CELLAR.abv}"
|
puts "#{count} #{"keg".pluralize(count)}, #{HOMEBREW_CELLAR.abv}"
|
||||||
end
|
end
|
||||||
@ -184,42 +195,156 @@ module Homebrew
|
|||||||
caveats = Caveats.new(f)
|
caveats = Caveats.new(f)
|
||||||
ohai "Caveats", caveats.to_s unless caveats.empty?
|
ohai "Caveats", caveats.to_s unless caveats.empty?
|
||||||
|
|
||||||
output_analytics(f)
|
output_formula_analytics(f)
|
||||||
end
|
end
|
||||||
|
|
||||||
def output_analytics(f)
|
def formulae_api_json(endpoint)
|
||||||
return if ENV["HOMEBREW_NO_ANALYTICS"]
|
return if ENV["HOMEBREW_NO_ANALYTICS"] || ENV["HOMEBREW_NO_GITHUB_API"]
|
||||||
return if ENV["HOMEBREW_NO_GITHUB_API"]
|
|
||||||
|
|
||||||
formulae_json_url = "https://formulae.brew.sh/api/formula/#{f}.json"
|
output, = curl_output("--max-time", "3",
|
||||||
output, = curl_output("--max-time", "3", formulae_json_url)
|
"https://formulae.brew.sh/api/#{endpoint}")
|
||||||
return if output.empty?
|
return if output.blank?
|
||||||
|
|
||||||
json = begin
|
|
||||||
JSON.parse(output)
|
JSON.parse(output)
|
||||||
rescue JSON::ParserError
|
rescue JSON::ParserError
|
||||||
nil
|
nil
|
||||||
end
|
end
|
||||||
return if json.nil? || json.empty? || json["analytics"].empty?
|
|
||||||
|
def analytics_table(category, days, results, os_version: false)
|
||||||
|
oh1 "#{category} (#{days} days)"
|
||||||
|
total_count = results.values.inject("+")
|
||||||
|
formatted_total_count = format_count(total_count)
|
||||||
|
formatted_total_percent = format_percent(100)
|
||||||
|
|
||||||
|
index_header = "Index"
|
||||||
|
count_header = "Count"
|
||||||
|
percent_header = "Percent"
|
||||||
|
name_with_options_header = if os_version
|
||||||
|
"macOS Version"
|
||||||
|
else
|
||||||
|
"Name (with options)"
|
||||||
|
end
|
||||||
|
|
||||||
|
total_index_footer = "Total"
|
||||||
|
max_index_width = results.length.to_s.length
|
||||||
|
index_width = [
|
||||||
|
index_header.length,
|
||||||
|
total_index_footer.length,
|
||||||
|
max_index_width,
|
||||||
|
].max
|
||||||
|
count_width = [
|
||||||
|
count_header.length,
|
||||||
|
formatted_total_count.length,
|
||||||
|
].max
|
||||||
|
percent_width = [
|
||||||
|
percent_header.length,
|
||||||
|
formatted_total_percent.length,
|
||||||
|
].max
|
||||||
|
name_with_options_width = Tty.width -
|
||||||
|
index_width -
|
||||||
|
count_width -
|
||||||
|
percent_width -
|
||||||
|
10 # spacing and lines
|
||||||
|
|
||||||
|
formatted_index_header =
|
||||||
|
format "%#{index_width}s", index_header
|
||||||
|
formatted_name_with_options_header =
|
||||||
|
format "%-#{name_with_options_width}s",
|
||||||
|
name_with_options_header[0..name_with_options_width-1]
|
||||||
|
formatted_count_header =
|
||||||
|
format "%#{count_width}s", count_header
|
||||||
|
formatted_percent_header =
|
||||||
|
format "%#{percent_width}s", percent_header
|
||||||
|
puts "#{formatted_index_header} | #{formatted_name_with_options_header} | "\
|
||||||
|
"#{formatted_count_header} | #{formatted_percent_header}"
|
||||||
|
|
||||||
|
columns_line = "#{"-"*index_width}:|-#{"-"*name_with_options_width}-|-"\
|
||||||
|
"#{"-"*count_width}:|-#{"-"*percent_width}:"
|
||||||
|
puts columns_line
|
||||||
|
|
||||||
|
index = 0
|
||||||
|
results.each do |name_with_options, count|
|
||||||
|
index += 1
|
||||||
|
formatted_index = format "%0#{max_index_width}d", index
|
||||||
|
formatted_index = format "%-#{index_width}s", formatted_index
|
||||||
|
formatted_name_with_options =
|
||||||
|
format "%-#{name_with_options_width}s",
|
||||||
|
name_with_options[0..name_with_options_width-1]
|
||||||
|
formatted_count = format "%#{count_width}s", format_count(count)
|
||||||
|
formatted_percent = if total_count.zero?
|
||||||
|
format "%#{percent_width}s", format_percent(0)
|
||||||
|
else
|
||||||
|
format "%#{percent_width}s",
|
||||||
|
format_percent((count.to_i * 100) / total_count.to_f)
|
||||||
|
end
|
||||||
|
puts "#{formatted_index} | #{formatted_name_with_options} | " \
|
||||||
|
"#{formatted_count} | #{formatted_percent}%"
|
||||||
|
next if index > 10
|
||||||
|
end
|
||||||
|
return unless results.length > 1
|
||||||
|
|
||||||
|
formatted_total_footer =
|
||||||
|
format "%-#{index_width}s", total_index_footer
|
||||||
|
formatted_blank_footer =
|
||||||
|
format "%-#{name_with_options_width}s", ""
|
||||||
|
formatted_total_count_footer =
|
||||||
|
format "%#{count_width}s", formatted_total_count
|
||||||
|
formatted_total_percent_footer =
|
||||||
|
format "%#{percent_width}s", formatted_total_percent
|
||||||
|
puts "#{formatted_total_footer} | #{formatted_blank_footer} | "\
|
||||||
|
"#{formatted_total_count_footer} | #{formatted_total_percent_footer}%"
|
||||||
|
end
|
||||||
|
|
||||||
|
def output_analytics
|
||||||
|
days = ARGV.value("days") || "30"
|
||||||
|
valid_days = %w[30 90 365]
|
||||||
|
unless valid_days.include?(days)
|
||||||
|
raise ArgumentError("Days must be one of #{valid_days.join(", ")}!")
|
||||||
|
end
|
||||||
|
|
||||||
|
category = ARGV.value("category") || "install"
|
||||||
|
valid_categories = %w[install install-on-request build-error os-version]
|
||||||
|
unless valid_categories.include?(category)
|
||||||
|
raise ArgumentError("Categories must be one of #{valid_categories.join(", ")}")
|
||||||
|
end
|
||||||
|
|
||||||
|
json = formulae_api_json("analytics/#{category}/#{days}d.json")
|
||||||
|
return if json.blank? || json["items"].blank?
|
||||||
|
|
||||||
|
os_version = category == "os-version"
|
||||||
|
results = {}
|
||||||
|
json["items"].each do |item|
|
||||||
|
key = if os_version
|
||||||
|
item["os_version"]
|
||||||
|
else
|
||||||
|
item["formula"]
|
||||||
|
end
|
||||||
|
results[key] = item["count"].tr(",", "").to_i
|
||||||
|
end
|
||||||
|
analytics_table(category, days, results, os_version: os_version)
|
||||||
|
end
|
||||||
|
|
||||||
|
def output_formula_analytics(f)
|
||||||
|
json = formulae_api_json("formula/#{f}.json")
|
||||||
|
return if json.blank? || json["analytics"].blank?
|
||||||
|
|
||||||
|
full_analytics = ARGV.include?("--analytics") || ARGV.verbose?
|
||||||
|
|
||||||
ohai "Analytics"
|
ohai "Analytics"
|
||||||
if ARGV.verbose?
|
|
||||||
json["analytics"].each do |category, value|
|
json["analytics"].each do |category, value|
|
||||||
value.each do |range, results|
|
analytics = []
|
||||||
oh1 "#{category} (#{range})"
|
|
||||||
results.each do |name_with_options, count|
|
value.each do |days, results|
|
||||||
puts "#{name_with_options}: #{number_readable(count)}"
|
days = days.to_i
|
||||||
|
if full_analytics
|
||||||
|
analytics_table(category, days, results)
|
||||||
|
else
|
||||||
|
total_count = results.values.inject("+")
|
||||||
|
analytics << "#{number_readable(total_count)} (#{days} days)"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
json["analytics"].each do |category, value|
|
puts "#{category}: #{analytics.join(", ")}" unless full_analytics
|
||||||
analytics = value.map do |range, results|
|
|
||||||
"#{number_readable(results.values.inject("+"))} (#{range})"
|
|
||||||
end
|
|
||||||
puts "#{category}: #{analytics.join(", ")}"
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -247,4 +372,12 @@ module Homebrew
|
|||||||
|
|
||||||
"#{dep.name} #{dep.option_tags.map { |o| "--#{o}" }.join(" ")}"
|
"#{dep.name} #{dep.option_tags.map { |o| "--#{o}" }.join(" ")}"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def format_count(count)
|
||||||
|
count.to_s.reverse.gsub(/(\d{3})(?=\d)/, '\\1,').reverse
|
||||||
|
end
|
||||||
|
|
||||||
|
def format_percent(percent)
|
||||||
|
format "%.2f", percent
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
@ -23,6 +23,13 @@ end
|
|||||||
describe Homebrew do
|
describe Homebrew do
|
||||||
let(:remote) { "https://github.com/Homebrew/homebrew-core" }
|
let(:remote) { "https://github.com/Homebrew/homebrew-core" }
|
||||||
|
|
||||||
|
specify "::analytics_table" do
|
||||||
|
results = { ack: 10, wget: 100 }
|
||||||
|
expect { subject.analytics_table("install", "30", results) }
|
||||||
|
.to output(/110 | 100.00%/).to_stdout
|
||||||
|
.and not_to_output.to_stderr
|
||||||
|
end
|
||||||
|
|
||||||
specify "::github_remote_path" do
|
specify "::github_remote_path" do
|
||||||
expect(subject.github_remote_path(remote, "Formula/git.rb"))
|
expect(subject.github_remote_path(remote, "Formula/git.rb"))
|
||||||
.to eq("https://github.com/Homebrew/homebrew-core/blob/master/Formula/git.rb")
|
.to eq("https://github.com/Homebrew/homebrew-core/blob/master/Formula/git.rb")
|
||||||
|
@ -187,7 +187,7 @@ RSpec::Matchers.define :a_json_string do
|
|||||||
begin
|
begin
|
||||||
JSON.parse(actual)
|
JSON.parse(actual)
|
||||||
true
|
true
|
||||||
rescue JSON::ParseError
|
rescue JSON::ParserError
|
||||||
false
|
false
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -199,11 +199,20 @@ With `--verbose` or `-v`, many commands print extra debugging information. Note
|
|||||||
* `info`:
|
* `info`:
|
||||||
Display brief statistics for your Homebrew installation.
|
Display brief statistics for your Homebrew installation.
|
||||||
|
|
||||||
* `info` *`formula`* [`--verbose`]:
|
* `info` `--analytics` [`--days=`*`days`*] [`--category=`*`category`*]:
|
||||||
|
Display Homebrew analytics data (provided neither `HOMEBREW_NO_ANALYTICS`
|
||||||
|
or `HOMEBREW_NO_GITHUB_API` are set)
|
||||||
|
|
||||||
|
The value for `days` must be `30`, `90` or `365`. The default is `30`.
|
||||||
|
|
||||||
|
The value for `category` must be `install`, `install-on-request`,
|
||||||
|
`build-error` or `os-version`. The default is `install`.
|
||||||
|
|
||||||
|
* `info` *`formula`* [`--analytics`]:
|
||||||
Display information about *`formula`* and analytics data (provided neither
|
Display information about *`formula`* and analytics data (provided neither
|
||||||
`HOMEBREW_NO_ANALYTICS` or `HOMEBREW_NO_GITHUB_API` are set)
|
`HOMEBREW_NO_ANALYTICS` or `HOMEBREW_NO_GITHUB_API` are set)
|
||||||
|
|
||||||
Pass `--verbose` to see more detailed analytics data.
|
Pass `--analytics` to see more detailed analytics data.
|
||||||
|
|
||||||
* `info` `--github` *`formula`*:
|
* `info` `--github` *`formula`*:
|
||||||
Open a browser to the GitHub History page for *`formula`*.
|
Open a browser to the GitHub History page for *`formula`*.
|
||||||
|
@ -208,11 +208,21 @@ Open \fIformula\fR\'s homepage in a browser\.
|
|||||||
Display brief statistics for your Homebrew installation\.
|
Display brief statistics for your Homebrew installation\.
|
||||||
.
|
.
|
||||||
.TP
|
.TP
|
||||||
\fBinfo\fR \fIformula\fR [\fB\-\-verbose\fR]
|
\fBinfo\fR \fB\-\-analytics\fR [\fB\-\-days=\fR\fIdays\fR] [\fB\-\-category=\fR\fIcategory\fR]
|
||||||
|
Display Homebrew analytics data (provided neither \fBHOMEBREW_NO_ANALYTICS\fR or \fBHOMEBREW_NO_GITHUB_API\fR are set)
|
||||||
|
.
|
||||||
|
.IP
|
||||||
|
The value for \fBdays\fR must be \fB30\fR, \fB90\fR or \fB365\fR\. The default is \fB30\fR\.
|
||||||
|
.
|
||||||
|
.IP
|
||||||
|
The value for \fBcategory\fR must be \fBinstall\fR, \fBinstall\-on\-request\fR, \fBbuild\-error\fR or \fBos\-version\fR\. The default is \fBinstall\fR\.
|
||||||
|
.
|
||||||
|
.TP
|
||||||
|
\fBinfo\fR \fIformula\fR [\fB\-\-analytics\fR]
|
||||||
Display information about \fIformula\fR and analytics data (provided neither \fBHOMEBREW_NO_ANALYTICS\fR or \fBHOMEBREW_NO_GITHUB_API\fR are set)
|
Display information about \fIformula\fR and analytics data (provided neither \fBHOMEBREW_NO_ANALYTICS\fR or \fBHOMEBREW_NO_GITHUB_API\fR are set)
|
||||||
.
|
.
|
||||||
.IP
|
.IP
|
||||||
Pass \fB\-\-verbose\fR to see more detailed analytics data\.
|
Pass \fB\-\-analytics\fR to see more detailed analytics data\.
|
||||||
.
|
.
|
||||||
.TP
|
.TP
|
||||||
\fBinfo\fR \fB\-\-github\fR \fIformula\fR
|
\fBinfo\fR \fB\-\-github\fR \fIformula\fR
|
||||||
|
Loading…
x
Reference in New Issue
Block a user