diff --git a/Library/Homebrew/bottle.rb b/Library/Homebrew/bottle.rb index af967aab12625..613a87d8f4b20 100644 --- a/Library/Homebrew/bottle.rb +++ b/Library/Homebrew/bottle.rb @@ -192,6 +192,14 @@ def installed_size resource.installed_size end + sig { returns(T.nilable(T::Array[String])) } + def path_exec_files + resource = github_packages_manifest_resource + return unless resource&.downloaded? + + resource.path_exec_files + end + sig { returns(Filename) } def filename Filename.create(T.cast(resource.owner, Formula), @tag, @spec.rebuild) diff --git a/Library/Homebrew/cmd/info.rb b/Library/Homebrew/cmd/info.rb index e75b849363afe..fbc10c9edee47 100644 --- a/Library/Homebrew/cmd/info.rb +++ b/Library/Homebrew/cmd/info.rb @@ -53,6 +53,7 @@ class NameSize < T::Struct switch "--github", description: "Open the GitHub source page for and in a browser. " \ "To view the history locally: `brew log -p` or " + # odeprecated replace this with --verbose on next release switch "--fetch-manifest", description: "Fetch GitHub Packages manifest for extra information when is not installed." flag "--json", @@ -70,7 +71,7 @@ class NameSize < T::Struct depends_on: "--json", description: "Include the variations hash in each formula's JSON output." switch "-v", "--verbose", - description: "Show more verbose analytics data for ." + description: "Show more verbose data for ." switch "--formula", "--formulae", description: "Treat all named arguments as formulae." switch "--cask", "--casks", @@ -524,7 +525,7 @@ def info_formula(formula) puts "Not installed" if (bottle = formula.bottle) begin - bottle.fetch_tab(quiet: !args.debug?) if args.fetch_manifest? + bottle.fetch_tab(quiet: !args.debug?) if args.fetch_manifest? || args.verbose? bottle_size = bottle.bottle_size installed_size = bottle.installed_size puts "Bottle Size: #{Formatter.disk_usage_readable(bottle_size)}" if bottle_size @@ -596,6 +597,22 @@ def info_formula(formula) Options.dump_for_formula formula end + if args.verbose? + binaries_keg = kegs.find(&:linked?) || kegs.last + binaries = if binaries_keg + binary_files = [binaries_keg/"bin", binaries_keg/"sbin"].select(&:directory?).flat_map do |dir| + dir.children.select { |child| child.file? && child.executable? } + end + binary_files.map { |path| path.basename.to_s } + elsif (path_exec_files = formula.bottle&.path_exec_files) + path_exec_files.map { |path| File.basename(path) } + end + if binaries.present? + binaries = binaries.sort.uniq + ohai "Binaries", Formatter.columns(binaries) + end + end + caveats = Caveats.new(formula) if (caveats_string = caveats.to_s.presence) ohai "Caveats", caveats_string diff --git a/Library/Homebrew/resource.rb b/Library/Homebrew/resource.rb index 9d7a69e4db986..3e738c36a28bf 100644 --- a/Library/Homebrew/resource.rb +++ b/Library/Homebrew/resource.rb @@ -411,6 +411,11 @@ def installed_size manifest_annotations["sh.brew.bottle.installed_size"]&.to_i end + sig { returns(T.nilable(T::Array[String])) } + def path_exec_files + manifest_annotations["sh.brew.path_exec_files"]&.split(",") + end + sig { override.returns(String) } def download_queue_type = "Bottle Manifest" diff --git a/Library/Homebrew/test/cmd/info_spec.rb b/Library/Homebrew/test/cmd/info_spec.rb index 42e5af770b5a8..765a8a2cb4a29 100644 --- a/Library/Homebrew/test/cmd/info_spec.rb +++ b/Library/Homebrew/test/cmd/info_spec.rb @@ -239,6 +239,104 @@ .and not_to_output.to_stderr end + it "prints a Binaries section listing executables in bin and sbin with --verbose" do + info = described_class.new(["--verbose"]) + formula = formula("testball") do + url "https://brew.sh/testball-0.1.tar.gz" + homepage "https://brew.sh/testball" + desc "Some test" + end + + keg_path = HOMEBREW_CELLAR/"testball/0.1" + (keg_path/"bin").mkpath + (keg_path/"sbin").mkpath + ["bin/testball", "bin/another", "sbin/daemon"].each do |rel| + file = keg_path/rel + file.write("#!/bin/sh\n") + file.chmod(0755) + end + tab = Tab.empty + tab.tabfile = keg_path/AbstractTab::FILENAME + tab.write + + allow(info).to receive(:github_info).with(formula).and_return("https://example.com/testball.rb") + allow(formula).to receive(:core_formula?).and_return(false) + + expect { info.send(:info_formula, formula) } + .to output(a_string_including("==> Binaries\nanother\ndaemon\ntestball\n")).to_stdout + .and not_to_output.to_stderr + end + + it "prints a Binaries section from the bottle manifest when the formula is not installed with --verbose" do + info = described_class.new(["--verbose"]) + formula = formula("testball") do + url "https://brew.sh/testball-0.1.tar.gz" + homepage "https://brew.sh/testball" + desc "Some test" + end + + bottle = instance_double( + Bottle, + path_exec_files: ["bin/testball", "bin/another", "sbin/daemon"], + bottle_size: nil, + installed_size: nil, + ) + allow(bottle).to receive(:fetch_tab) + allow(formula).to receive_messages(bottle:, core_formula?: false) + allow(info).to receive(:github_info).with(formula).and_return("https://example.com/testball.rb") + + expect { info.send(:info_formula, formula) } + .to output(a_string_including("==> Binaries\nanother\ndaemon\ntestball\n")).to_stdout + .and not_to_output.to_stderr + end + + it "omits the Binaries section without --verbose" do + info = described_class.new([]) + formula = formula("testball") do + url "https://brew.sh/testball-0.1.tar.gz" + homepage "https://brew.sh/testball" + desc "Some test" + end + + keg_path = HOMEBREW_CELLAR/"testball/0.1" + (keg_path/"bin").mkpath + binary = keg_path/"bin/testball" + binary.write("#!/bin/sh\n") + binary.chmod(0755) + tab = Tab.empty + tab.tabfile = keg_path/AbstractTab::FILENAME + tab.write + + allow(info).to receive(:github_info).with(formula).and_return("https://example.com/testball.rb") + allow(formula).to receive(:core_formula?).and_return(false) + + expect { info.send(:info_formula, formula) } + .to not_to_output(/==> Binaries/).to_stdout + .and not_to_output.to_stderr + end + + it "omits the Binaries section when no executables are installed" do + info = described_class.new(["--verbose"]) + formula = formula("testball") do + url "https://brew.sh/testball-0.1.tar.gz" + homepage "https://brew.sh/testball" + desc "Some test" + end + + keg_path = HOMEBREW_CELLAR/"testball/0.1" + (keg_path/"lib").mkpath + tab = Tab.empty + tab.tabfile = keg_path/AbstractTab::FILENAME + tab.write + + allow(info).to receive(:github_info).with(formula).and_return("https://example.com/testball.rb") + allow(formula).to receive(:core_formula?).and_return(false) + + expect { info.send(:info_formula, formula) } + .to not_to_output(/==> Binaries/).to_stdout + .and not_to_output.to_stderr + end + describe "::installation_status" do it "prints on-request installs explicitly" do expect(described_class.installation_status(instance_double(Tab, installed_on_request: true)))