config: gather system configuration concurrently

This commit is contained in:
Douglas Eichelberger
2026-07-06 13:06:36 -07:00
parent 988192e555
commit 6955480c07
7 changed files with 103 additions and 21 deletions
+12 -4
View File
@@ -62,14 +62,22 @@ class DevelopmentTools
Version::NULL
end
sig { returns(T.nilable(String)) }
def clang_version_output
@clang_version_output ||= T.let(
if (path = locate("clang"))
`#{path} --version`
end, T.nilable(String)
)
end
# Get the Clang version.
#
# @api public
sig { returns(Version) }
def clang_version
@clang_version ||= T.let(
if (path = locate("clang")) &&
(build_version = `#{path} --version`[/(?:clang|LLVM) version (\d+\.\d(?:\.\d)?)/, 1])
if (build_version = clang_version_output&.[](/(?:clang|LLVM) version (\d+\.\d(?:\.\d)?)/, 1))
Version.new(build_version)
else
Version::NULL
@@ -83,8 +91,7 @@ class DevelopmentTools
sig { returns(Version) }
def clang_build_version
@clang_build_version ||= T.let(
if (path = locate("clang")) &&
(build_version = `#{path} --version`[%r{clang(-| version [^ ]+ \(tags/RELEASE_)(\d{2,})}, 2])
if (build_version = clang_version_output&.[](%r{clang(-| version [^ ]+ \(tags/RELEASE_)(\d{2,})}, 2))
Version.new(build_version)
else
Version::NULL
@@ -134,6 +141,7 @@ class DevelopmentTools
sig { void }
def clear_version_cache
@clang_version_output = T.let(nil, T.nilable(String))
@clang_version = @clang_build_version = T.let(nil, T.nilable(Version))
@gcc_version = T.let({}, T.nilable(T::Hash[String, Version]))
end
@@ -104,10 +104,8 @@ module OS
end
sig { params(out: T.any(File, StringIO, IO)).void }
def dump_verbose_config(out = $stdout)
kernel = Utils.safe_popen_read("uname", "-mors").chomp
super
out.puts "Kernel: #{kernel}"
def linux_config(out = $stdout)
out.puts "Kernel: #{Utils.safe_popen_read("uname", "-mors").chomp}"
out.puts "OS: #{OS::Linux.os_version}"
if OS.wsl?
out.puts "WSL: #{OS::Linux.wsl_version}"
@@ -122,6 +120,11 @@ module OS
out.puts "#{f}: #{formula_linked_version(f)}"
end
end
sig { returns(T::Array[Symbol]) }
def config_sections
super + [:linux_config]
end
end
end
end
@@ -62,8 +62,7 @@ module OS
end
sig { params(out: T.any(File, StringIO, IO)).void }
def dump_verbose_config(out = $stdout)
super
def macos_config(out = $stdout)
out.puts "macOS: #{MacOS.full_version}-#{kernel}"
out.puts "CLT: #{clt || "N/A"}"
out.puts "Xcode: #{xcode || "N/A"}"
@@ -73,6 +72,11 @@ module OS
end
out.puts "Rosetta 2: #{::Hardware::CPU.in_rosetta2?}" if ::Hardware::CPU.physical_cpu_arm64?
end
sig { returns(T::Array[Symbol]) }
def config_sections
super + [:macos_config]
end
end
end
end
+13
View File
@@ -45,6 +45,19 @@ class GitRepository
popen_git("show", "-s", "--format=%cr", "HEAD")
end
# Gets the full commit hash of the HEAD commit, the relative date of the
# last commit and the currently checked-out branch (or HEAD if the
# repository is in a detached HEAD state) in a single Git invocation.
sig { returns([T.nilable(String), T.nilable(String), T.nilable(String)]) }
def head_info
output = popen_git("show", "-s", "--format=%H%n%cr%n%D", "HEAD")
return [nil, nil, nil] if output.nil?
head, last_committed, refs = output.lines(chomp: true)
branch = refs&.[](/\AHEAD -> ([^,\n]+)/, 1) || "HEAD"
[head, last_committed, branch]
end
# Gets the name of the currently checked-out branch, or HEAD if the repository is in a detached HEAD state.
sig { params(safe: T::Boolean).returns(T.nilable(String)) }
def branch_name(safe: false)
+37 -11
View File
@@ -42,19 +42,27 @@ module SystemConfig
GitRepository.new(HOMEBREW_REPOSITORY)
end
sig { returns([T.nilable(String), T.nilable(String), T.nilable(String)]) }
def homebrew_head_info
@homebrew_head_info ||= T.let(
homebrew_repo.head_info,
T.nilable([T.nilable(String), T.nilable(String), T.nilable(String)]),
)
end
sig { returns(String) }
def branch
homebrew_repo.branch_name || "(none)"
homebrew_head_info[2] || "(none)"
end
sig { returns(String) }
def head
homebrew_repo.head_ref || "(none)"
homebrew_head_info[0] || "(none)"
end
sig { returns(String) }
def last_commit
homebrew_repo.last_committed || "never"
homebrew_head_info[1] || "never"
end
sig { returns(String) }
@@ -127,10 +135,11 @@ module SystemConfig
if tap.installed?
out.puts "#{tap_name} origin: #{tap.remote}" if tap.remote != tap.default_remote
out.puts "#{tap_name} HEAD: #{tap.git_head || "(none)"}"
out.puts "#{tap_name} last commit: #{tap.git_last_commit || "never"}"
head, last_commit, branch = tap.git_repository.head_info
out.puts "#{tap_name} HEAD: #{head || "(none)"}"
out.puts "#{tap_name} last commit: #{last_commit || "never"}"
default_branches = %w[main master].freeze
out.puts "#{tap_name} branch: #{tap.git_branch || "(none)"}" if default_branches.exclude?(tap.git_branch)
out.puts "#{tap_name} branch: #{branch || "(none)"}" if default_branches.exclude?(branch)
end
json_file = Homebrew::API::HOMEBREW_CACHE_API/json_file_name
@@ -194,12 +203,29 @@ module SystemConfig
end
sig { params(out: T.any(File, StringIO, IO)).void }
def dump_verbose_config(out = $stdout)
homebrew_config(out)
core_tap_config(out)
homebrew_env_config(out)
def hardware_config(out = $stdout)
hardware = self.hardware
out.puts hardware if hardware
host_software_config(out)
end
sig { returns(T::Array[Symbol]) }
def config_sections
[:homebrew_config, :core_tap_config, :homebrew_env_config, :hardware_config, :host_software_config]
end
sig { params(out: T.any(File, StringIO, IO)).void }
def dump_verbose_config(out = $stdout)
# Most sections shell out for their values (Git, compilers, curl,
# etc.), so render them concurrently and print them in order.
threads = config_sections.map do |section|
Thread.new do
Thread.current.report_on_exception = false
io = StringIO.new
public_send(section, io)
io.string
end
end
threads.each { |thread| out.print thread.value }
end
end
end
+15
View File
@@ -69,6 +69,21 @@ RSpec.describe Homebrew::Cmd::Config do
expect(output.string).to include("Windows: Windows 11 Pro (25H2) [26200.8457]\n")
end
it "prints config sections in order" do
output = StringIO.new
allow(SystemConfig).to receive(:config_sections).and_return([:homebrew_config, :host_software_config])
allow(SystemConfig).to receive(:homebrew_config) do |io|
sleep(0.01)
io.puts "first"
end
allow(SystemConfig).to receive(:host_software_config) { |io| io.puts "second" }
SystemConfig.dump_verbose_config(output)
expect(output.string).to eq("first\nsecond\n")
end
it "does not print HOMEBREW_EVAL_ALL unless it is directly set" do
output = StringIO.new
@@ -47,6 +47,19 @@ RSpec.describe GitRepository do
end
end
describe "#head_info" do
it "returns the HEAD commit hash, relative commit time and branch name in one Git invocation" do
expect(git_repo.head_info).to eq([git_repo.head_ref, git_repo.last_committed, branch_name])
clone_path.cd do
safe_system Utils::Git.git, "checkout", "--quiet", "--detach"
end
expect(git_repo.head_info[2]).to eq("HEAD")
expect(described_class.new(repo_root/"nonexistent").head_info).to eq([nil, nil, nil])
end
end
describe "when the origin has a branch and tag with the same name" do
it "disambiguates branch_name, origin_branch_name, and default_origin_branch?" do
expect(git_repo.branch_name).to eq(branch_name)