Skip to content

Commit dc7337a

Browse files
committed
Replace brew which-update
- Keep `brew which-update` as the CI-facing command because core CI now updates command-not-found entries from bottle metadata. - Drop the old bulk scan, stats and commit paths because the database is no longer refreshed by a scheduled repository commit. - Limit `executables_db.rb` updates to bottle JSON metadata and explicit formula removals. - Regenerate command docs, completions and Sorbet RBI for the narrower command interface.
1 parent 79a17df commit dc7337a

12 files changed

Lines changed: 250 additions & 653 deletions

File tree

.github/workflows/command-not-found-db-update.yml

Lines changed: 0 additions & 94 deletions
This file was deleted.

Library/Homebrew/dev-cmd/which-update.rb

Lines changed: 67 additions & 111 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
require "abstract_command"
88
require "executables_db"
9+
require "utils/github"
910

1011
module Homebrew
1112
module DevCmd
@@ -14,143 +15,98 @@ class WhichUpdate < AbstractCommand
1415
description <<~EOS
1516
Database update for `brew which-formula`.
1617
EOS
17-
switch "--stats",
18-
description: "Print statistics about the database contents (number of commands and formulae, " \
19-
"list of missing formulae)."
20-
switch "--commit",
21-
description: "Commit the changes using `git`."
22-
switch "--update-existing",
23-
description: "Update database entries with outdated formula versions."
24-
switch "--install-missing",
25-
description: "Install and update formulae that are missing from the database and don't have bottles."
26-
switch "--eval-all",
27-
description: "Evaluate all installed taps, rather than just the core tap."
28-
flag "--max-downloads=",
29-
description: "Specify a maximum number of formulae to download and update."
18+
flag "--bottle-json-dir=",
19+
description: "Use generated bottle JSON files in the given directory to update formula entries."
20+
flag "--removed-formulae-file=",
21+
description: "Remove database entries for formulae listed in the given file."
22+
flag "--pull-request=",
23+
description: "Update entries for formula changes in the given pull request number."
24+
flag "--repository=",
25+
depends_on: "--pull-request",
26+
description: "GitHub repository for `--pull-request` (default: `$GITHUB_REPOSITORY`)."
3027
flag "--summary-file=",
3128
description: "Output a summary of the changes to a file."
32-
conflicts "--stats", "--commit"
33-
conflicts "--stats", "--install-missing"
34-
conflicts "--stats", "--update-existing"
35-
conflicts "--stats", "--max-downloads"
3629
named_args :database, number: 1
3730
end
3831

3932
sig { override.void }
4033
def run
41-
if args.stats?
42-
stats source: args.named.fetch(0)
43-
else
44-
update_and_save! source: args.named.fetch(0),
45-
commit: args.commit?,
46-
update_existing: args.update_existing?,
47-
install_missing: args.install_missing?,
48-
max_downloads: args.max_downloads&.to_i,
49-
eval_all: args.eval_all?,
50-
summary_file: args.summary_file
34+
updated = update_and_save! source: args.named.fetch(0),
35+
bottle_json_dir: args.bottle_json_dir,
36+
removed_formulae_file: args.removed_formulae_file,
37+
pull_request: args.pull_request,
38+
repository: args.repository,
39+
summary_file: args.summary_file
40+
41+
if (github_output = ENV["GITHUB_OUTPUT"].presence)
42+
File.open(github_output, "a") { |file| file.puts "updated=#{updated}" }
5143
end
5244
end
5345

54-
sig { params(source: String).void }
55-
def stats(source:)
56-
opoo "The DB file doesn't exist." unless File.exist? source
57-
db = ExecutablesDB.new source
58-
59-
formulae = db.formula_names
60-
core = Formula.core_names
61-
62-
cmds_count = db.exes.values.reduce(0) { |s, exs| s + exs.binaries.size }
63-
64-
core_percentage = ((formulae & core).size * 1000 / core.size.to_f).round / 10.0
65-
66-
missing = (core - formulae).reject { |f| Formula[f].disabled? }
67-
puts <<~EOS
68-
#{formulae.size} formulae
69-
#{cmds_count} commands
70-
#{core_percentage}% (missing: #{missing * " "})
71-
EOS
72-
73-
unknown = formulae - Formula.full_names
74-
puts "\nUnknown formulae: #{unknown * ", "}." if unknown.any?
75-
nil
76-
end
77-
7846
sig {
7947
params(
80-
source: String,
81-
commit: T::Boolean,
82-
update_existing: T::Boolean,
83-
install_missing: T::Boolean,
84-
max_downloads: T.nilable(Integer),
85-
eval_all: T::Boolean,
86-
summary_file: T.nilable(String),
87-
).void
48+
source: String,
49+
bottle_json_dir: T.nilable(String),
50+
removed_formulae_file: T.nilable(String),
51+
pull_request: T.nilable(String),
52+
repository: T.nilable(String),
53+
summary_file: T.nilable(String),
54+
).returns(T::Boolean)
8855
}
89-
def update_and_save!(source:, commit: false, update_existing: false, install_missing: false,
90-
max_downloads: nil, eval_all: false, summary_file: nil)
56+
def update_and_save!(source:, bottle_json_dir: nil, removed_formulae_file: nil, pull_request: nil,
57+
repository: nil, summary_file: nil)
58+
source_path = Pathname(source)
59+
original_database = source_path.exist? ? source_path.read : nil
9160
db = ExecutablesDB.new source
92-
db.update!(update_existing:, install_missing:,
93-
max_downloads:, eval_all:)
94-
db.save!
9561

96-
if summary_file
97-
msg = summary_file_message(db.changes)
98-
File.open(summary_file, "a") do |file|
99-
file.puts(msg)
100-
end
62+
removed_formulae = if removed_formulae_file.blank? || !File.file?(removed_formulae_file)
63+
[]
64+
else
65+
File.readlines(removed_formulae_file, chomp: true).filter_map { |line| line.strip.presence }
10166
end
10267

103-
return if !commit || !db.changed?
104-
105-
msg = git_commit_message(db.changes)
106-
safe_system "git", "-C", db.root.to_s, "commit", "-m", msg, source
107-
end
108-
109-
sig { params(els: T::Array[String], verb: String).returns(String) }
110-
def english_list(els, verb)
111-
msg = +""
112-
msg << els.slice(0, 3)&.join(", ")
113-
msg << " and #{els.length - 3} more" if msg.length < 40 && els.length > 3
114-
"#{verb.capitalize} #{msg}"
115-
end
68+
if pull_request
69+
repository = repository.presence || ENV["GITHUB_REPOSITORY"].presence
70+
if repository.blank?
71+
raise UsageError,
72+
"`--repository` or `$GITHUB_REPOSITORY` is required with `--pull-request`."
73+
end
11674

117-
sig { params(changes: ExecutablesDB::Changes).returns(String) }
118-
def git_commit_message(changes)
119-
msg = []
120-
ExecutablesDB::Changes::TYPES.each do |action|
121-
names = changes.send(action)
122-
next if names.empty?
75+
owner, repo = repository.split("/", 2)
76+
if owner.blank? || repo.blank? || repo.include?("/")
77+
raise UsageError, "`--repository` must be in the form `owner/repo`."
78+
end
12379

124-
action = "bump version for" if action == :version_bump
125-
msg << english_list(names.to_a.sort, action.to_s)
126-
break
80+
GitHub::API.paginate_rest(GitHub.url_to("repos", owner, repo, "pulls", pull_request, "files")) do |files|
81+
T.cast(files, T::Array[T::Hash[String, T.untyped]]).each do |file|
82+
filename = file["filename"].to_s
83+
next if !filename.start_with?("Formula/") || !filename.end_with?(".rb")
84+
85+
case file["status"].to_s
86+
when "removed"
87+
removed_formulae << File.basename(filename, ".rb")
88+
when "renamed"
89+
removed_formulae << File.basename(file["previous_filename"].to_s, ".rb")
90+
end
91+
end
92+
end
12793
end
12894

129-
msg.join
130-
end
95+
db.update!(bottle_json_dir:, removed_formulae:)
96+
db.save!
97+
updated = original_database != source_path.read
13198

132-
sig { params(changes: ExecutablesDB::Changes).returns(String) }
133-
def summary_file_message(changes)
134-
msg = []
135-
ExecutablesDB::Changes::TYPES.each do |action|
136-
names = changes.send(action)
137-
next if names.empty?
99+
if summary_file
100+
File.open(summary_file, "a") do |file|
101+
file.puts <<~EOS
102+
## Database Update Summary
138103
139-
action_heading = action.to_s.split("_").map(&:capitalize).join(" ")
140-
msg << "### #{action_heading}"
141-
msg << ""
142-
names.to_a.sort.each do |name|
143-
msg << "- [`#{name}`](https://formulae.brew.sh/formula/#{name})"
104+
#{updated ? "Updated command-not-found database." : "No changes"}
105+
EOS
144106
end
145107
end
146108

147-
msg << "No changes" if msg.empty?
148-
149-
<<~MESSAGE
150-
## Database Update Summary
151-
152-
#{msg.join("\n")}
153-
MESSAGE
109+
updated
154110
end
155111
end
156112
end

0 commit comments

Comments
 (0)