list: warn about broken Caskroom symlinks

The bare cask listing is ls(1) of the Caskroom directory, so a broken
symlink there (e.g. a dangling cask rename alias) lists exactly like an
installed cask while loading and uninstalling it fail. brew cleanup has
removed such symlinks since 3ddc196f11, but until it runs the listing
misleads with no hint of the problem, and when broken symlinks are the
only Caskroom entries the listing prints nothing at all while brew
uninstall of the listed name errors. Warn on stderr, naming the broken
symlinks and pointing at brew cleanup, without changing stdout output.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Anthony Holland
2026-07-21 13:08:19 +12:00
co-authored by Claude Fable 5
parent 3cd4b81833
commit 94392d0307
2 changed files with 25 additions and 3 deletions
+17 -3
View File
@@ -229,9 +229,12 @@ module Homebrew
system_command! "ls", args: [*ls_args, HOMEBREW_CELLAR], print_stdout: true
puts if $stdout.tty? && !args.formula?
end
if !args.formula? && Cask::Caskroom.any_casks_installed?
ohai "Casks" if $stdout.tty? && !args.cask?
system_command! "ls", args: [*ls_args, Cask::Caskroom.path], print_stdout: true
unless args.formula?
if Cask::Caskroom.any_casks_installed?
ohai "Casks" if $stdout.tty? && !args.cask?
system_command! "ls", args: [*ls_args, Cask::Caskroom.path], print_stdout: true
end
warn_about_broken_caskroom_symlinks
end
else
kegs, casks = args.named.to_kegs_to_casks
@@ -249,6 +252,17 @@ module Homebrew
private
# A broken symlink in the Caskroom (e.g. a dangling cask rename alias) lists
# like an installed cask but cannot load or uninstall, so flag it.
sig { void }
def warn_about_broken_caskroom_symlinks
broken_symlinks = Cask::Caskroom.path.glob("*").select { |child| child.symlink? && !child.exist? }
return if broken_symlinks.empty?
opoo "Broken Caskroom symlinks (`brew cleanup` removes them): " \
"#{broken_symlinks.map(&:basename).sort.join(", ")}"
end
sig { params(name: String).returns(T.nilable(String)) }
def pinned_formula_entry(name)
pin_path = HOMEBREW_PINNED_KEGS/name
+8
View File
@@ -229,6 +229,14 @@ RSpec.describe Homebrew::Cmd::List do
cask.unpin
end
it "warns about broken Caskroom symlinks" do
Cask::Caskroom.path.mkpath
FileUtils.ln_s "missing-cask", Cask::Caskroom.path/"dangling-alias"
expect { described_class.new(["--cask"]).run }
.to output(/Broken Caskroom symlinks \(`brew cleanup` removes them\): dangling-alias/).to_stderr
end
it "fails only for explicitly named missing pinned packages", :cask do
install_formula_version "testball", "0.1"
(HOMEBREW_PREFIX/"var/homebrew/pinned").mkpath