2021-03-16 14:43:22 +08:00
|
|
|
#!/usr/bin/env ruby
|
|
|
|
# frozen_string_literal: true
|
|
|
|
|
|
|
|
require "open3"
|
|
|
|
require "optparse"
|
|
|
|
require "pathname"
|
|
|
|
require "tmpdir"
|
2023-04-10 12:59:47 +08:00
|
|
|
require "json"
|
|
|
|
require "open-uri"
|
2021-03-16 14:43:22 +08:00
|
|
|
|
|
|
|
# Exit cleanup
|
|
|
|
TMP_DIR = Pathname.new(Dir.mktmpdir).freeze
|
|
|
|
at_exit { TMP_DIR.rmtree }
|
|
|
|
|
|
|
|
# Constants
|
|
|
|
ONLINE_ISSUE = "https://github.com/Homebrew/homebrew-cask/issues/88469"
|
|
|
|
CASK_REPOS = %w[homebrew-cask homebrew-cask-versions homebrew-cask-drivers].freeze
|
2023-04-10 12:59:47 +08:00
|
|
|
CASK_JSON_URL = "https://formulae.brew.sh/api/analytics/cask-install/365d.json"
|
|
|
|
|
|
|
|
# Download the file and save it to the specified directory
|
|
|
|
File.open("#{TMP_DIR}/cask.json", "wb") do |output_file|
|
|
|
|
URI.parse(CASK_JSON_URL).open do |input_file|
|
|
|
|
output_file.write(input_file.read)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
CASK_JSON = File.read("#{TMP_DIR}/cask.json").freeze
|
|
|
|
CASK_DATA = JSON.parse(CASK_JSON).freeze
|
2021-03-16 14:43:22 +08:00
|
|
|
|
|
|
|
# Helpers
|
|
|
|
def cask_name(cask_path)
|
|
|
|
cask_path.basename.sub(/\.rb$/, "")
|
|
|
|
end
|
|
|
|
|
|
|
|
def cask_url(tap_dir, cask_path)
|
|
|
|
tap_base = tap_dir.dirname.basename.to_path
|
|
|
|
cask_base = cask_path.basename.to_path
|
|
|
|
|
|
|
|
"https://github.com/Homebrew/#{tap_base}/blob/master/Casks/#{cask_base}"
|
|
|
|
end
|
|
|
|
|
2023-04-10 12:59:47 +08:00
|
|
|
def find_count(cask_name, data)
|
|
|
|
data["items"].find { |item| item["cask"] == cask_name.to_s }&.dig("count") || "0"
|
|
|
|
end
|
|
|
|
|
2021-03-16 14:43:22 +08:00
|
|
|
# Options
|
|
|
|
ARGV.push("--help") unless ARGV.include?("run")
|
|
|
|
|
|
|
|
OptionParser.new do |parser|
|
|
|
|
parser.banner = <<~BANNER
|
|
|
|
Generates lists of casks missing `zap` in official repos, and copies it to replace the information on #{ONLINE_ISSUE}
|
|
|
|
|
|
|
|
Usage:
|
|
|
|
#{File.basename($PROGRAM_NAME)} run
|
|
|
|
|
|
|
|
The argument 'run' is necessary to prevent running the script by mistake.
|
|
|
|
BANNER
|
|
|
|
end.parse!
|
|
|
|
|
|
|
|
# Grab all taps and casks
|
|
|
|
CASK_DIRS = CASK_REPOS.each_with_object([]) do |repo, tap_dirs|
|
|
|
|
clone_dir = TMP_DIR.join(repo)
|
|
|
|
casks_dir = clone_dir.join("Casks")
|
|
|
|
tap_dirs.push(casks_dir)
|
|
|
|
|
|
|
|
system("git", "clone", "--depth", "1", "https://github.com/Homebrew/#{repo}.git", clone_dir.to_path)
|
|
|
|
end.freeze
|
|
|
|
|
|
|
|
ALL_CASKS = CASK_DIRS.each_with_object({}) do |tap_dir, casks|
|
|
|
|
casks[tap_dir] = []
|
|
|
|
|
|
|
|
# Populate hash with tap directory paths as keys
|
|
|
|
# and cask file paths as values in array
|
|
|
|
tap_dir
|
|
|
|
.children
|
|
|
|
.shuffle
|
|
|
|
.select { _1.extname == ".rb" }
|
|
|
|
.each { casks[tap_dir].push(_1) }
|
|
|
|
end.freeze
|
|
|
|
|
|
|
|
CASKS_NO_ZAP = ALL_CASKS.each_with_object({}) do |(tap_dir, casks), without_zap|
|
|
|
|
without_zap[tap_dir] = []
|
|
|
|
|
2023-04-10 12:59:47 +08:00
|
|
|
# Populate hash with casks without a zap that are not discontinued
|
2021-03-16 14:43:22 +08:00
|
|
|
casks
|
2021-11-02 09:51:53 +08:00
|
|
|
.reject { |file| file.readlines.any? { _1.start_with?(/\s+(# No )?zap /) } }
|
2023-04-10 12:59:47 +08:00
|
|
|
.reject { |file| file.readlines.any? { _1.start_with?(/\s+discontinued /) } }
|
2021-03-16 14:43:22 +08:00
|
|
|
.each { without_zap[tap_dir].push(_1) }
|
|
|
|
|
|
|
|
# Reject tap directory if there are no casks without zap
|
|
|
|
without_zap.delete(tap_dir) if without_zap[tap_dir].empty?
|
|
|
|
end.freeze
|
|
|
|
|
|
|
|
CASK_LISTS = CASKS_NO_ZAP.each_with_object([]) do |(tap_dir, casks), message|
|
|
|
|
message.push("<details><summary>#{tap_dir.dirname.basename.to_path}</summary>")
|
|
|
|
message.push("") # Empty line so the markdown still works inside the HTML
|
|
|
|
|
2023-04-10 12:59:47 +08:00
|
|
|
# Sort casks by count
|
|
|
|
sorted_casks = casks.sort_by { |cask_file| -find_count(cask_name(cask_file), CASK_DATA).delete(",").to_i }
|
|
|
|
|
|
|
|
sorted_casks.each do |cask_file|
|
|
|
|
cask_name = cask_name(cask_file)
|
|
|
|
count = find_count(cask_name, CASK_DATA)
|
|
|
|
message.push("* [`#{cask_name}`](#{cask_url(tap_dir, cask_file)}) - Downloads: #{count}")
|
|
|
|
end
|
2021-03-16 14:43:22 +08:00
|
|
|
|
|
|
|
message.push("</details>")
|
|
|
|
end.freeze
|
|
|
|
|
|
|
|
Open3.capture2("/usr/bin/pbcopy", stdin_data: "#{CASK_LISTS.join("\n")}\n")
|
|
|
|
puts("Copied lists to clipboard. Replace the information in the issue.")
|
|
|
|
system("open", ONLINE_ISSUE)
|