`@on_os_blocks_exist` was written in `Cask::DSL` and `OnSystem` but never
read, and the `:on_os_blocks_exist?` entry in `Cask::DSL::DSL_METHODS` only
produced a dead delegator (no `on_os_blocks_exist?` reader exists). Remove the
DSL entry, the write-only flag and the stale explanatory comment.
Claude-Session: https://claude.ai/code/session_011BgWRBydtdkvt8ocqH4nj9
Main added the `configure_glibc_runtime` and `configure_clang_system`
install-steps DSL methods (#23201, #23190). They are formula-facing DSL with
no in-repo caller, like their siblings, so mark them `@api internal` to keep
brew deadcode idempotent.
Claude-Session: https://claude.ai/code/session_011BgWRBydtdkvt8ocqH4nj9
Main kept and extended code the branch had removed as dead: `match.rb` now
calls `Vulnerability#cve_ids`/`#details` and the OSV `@details` field, so
restore main's `vulns/vulnerability.rb` and `utils/repology.rb` rather than
the branch's stale removals.
Main also added `advisory_url`, `fix_urls`, `distributions` and a refactored
`query_api` that are covered by specs but have no production caller yet; mark
each `# deadcode:keep` so the branch stays idempotent.
Claude-Session: https://claude.ai/code/session_011BgWRBydtdkvt8ocqH4nj9
Main's "Make tests use public APIs and enable their cops" commit added public
`attr_*` accessors (and a `Homebrew/NoSendInTests` cop) so specs avoid
`instance_variable_get`/`send`. Those accessors have no production caller, so
`brew deadcode` flags them: mark each `# deadcode:keep` noting it exists for
test ergonomics. Do the same for the restored `Trust.trusted_formula_file?`/
`trusted_cask_file?` wrappers (kept so `trust_spec` need not `send`).
Also re-add the sandbox refactor `# deadcode:keep` markers (lost when taking
main's reordered sandbox.rb), annotate the new `install_gzipped_executable`
install-steps DSL method `@api internal`, and disable `NoSendInTests` in
`deadcode_spec` (which unit-tests the command's private methods).
Claude-Session: https://claude.ai/code/session_011BgWRBydtdkvt8ocqH4nj9
GitHub code search confirms none of these are used by formulae or casks in
any tap, and they have no in-repo or dynamic callers (only their own specs):
- Cask::DSL::Version#unstable?
- CxxStdlib#type_string
- Cask::Artifact::Moved.english_description
- Tab#cxxstdlib
- Tab#head_version
Remove the methods and their now-orphaned spec coverage. (`kernel_major_version`
is kept: homebrew-core's `llvm` formulae call it.)
Claude-Session: https://claude.ai/code/session_011BgWRBydtdkvt8ocqH4nj9
The `--[no-]quarantine` switches that dispatched this predicate (via
`env: :cask_opts_quarantine`) were removed in the Homebrew 6 deprecations,
leaving it with no callers. Remove it rather than keeping it annotated.
Claude-Session: https://claude.ai/code/session_011BgWRBydtdkvt8ocqH4nj9
`macos_compatible?`, `linux_compatible?`, `x86_64_compatible?` and
`arm64_compatible?` are reached only through in-repo dynamic dispatch
(`public_send(:"#{platform}_compatible?")` / `:"#{arch}_compatible?"` in
github_runner_matrix.rb), not from formulae in other taps, so mark them
`# deadcode:keep` rather than `@api internal`.
Claude-Session: https://claude.ai/code/session_011BgWRBydtdkvt8ocqH4nj9
`binarydir` is reached only through dynamic dispatch within this repository
(`config.public_send(self.class.dirmethod)` in `Cask::Artifact::Relocated`),
never from casks in other taps, so it is not part of the cross-repo API
surface. Mark it `# deadcode:keep` rather than `@api internal`.
Claude-Session: https://claude.ai/code/session_011BgWRBydtdkvt8ocqH4nj9
After rebasing onto the latest main:
- main added the `terminate_process` and `configure_gcc_runtime` install-steps
DSL methods, which are called only from formulae/casks; annotate them
`@api internal` like the sibling DSL methods.
- main marked `gio_querymodules` with an `# odeprecated` comment (rather than
an `@api internal` annotation), so teach `brew deadcode` to honor
`# odeprecated`/`# odisabled` comment markers above a definition, not just
`odeprecated`/`odisabled` calls in its body. Declarative DSL methods
deprecated this way are then kept without needing an `@api` annotation.
Claude-Session: https://claude.ai/code/session_011BgWRBydtdkvt8ocqH4nj9
These instance variables are assigned but never read, yet removing them
cleanly would cascade beyond a single line (dropping constructor parameters
and their call sites, or a dangling DSL delegator). Leave an analysis comment
at each site rather than making that call here:
- GitHub::API::Error#@github_message (utils/github/api.rb)
- FormulaAuditor#@spdx_license_data / #@spdx_exception_data (formula_auditor.rb)
- OnSystem#@on_os_blocks_exist (on_system.rb) and its dead `:on_os_blocks_exist?`
entry in Cask::DSL::DSL_METHODS (cask/dsl.rb)
Claude-Session: https://claude.ai/code/session_011BgWRBydtdkvt8ocqH4nj9
These instance variables are assigned but never read anywhere, so their
writes are dead code. Spoom's `brew deadcode` only models methods and
constants, not instance variables, so it cannot flag these.
- Cask::Caveats#@discontinued
- Cask::URL#@data, #@revisions, #@trust_cert (values already kept in `specs`)
- Homebrew::Vulns::Vulnerability#@details
- Homebrew::API::JSONDownloadStrategy#@stale_seconds and
Homebrew::API::JSONDownload#@stale_seconds (code reads `meta[:stale_seconds]`)
- APIHashable#@old_homebrew_cellar (never restored; the cellar is not patched)
- CurlDownloadStrategy#@last_modified (only the local variable is read)
- Formula#@fully_loaded_formula
- SoftwareSpec#@depends_on_macos_set_in_block (flag never queried)
- RuboCop::Cop::FormulaCop @registry (dead class-level assignment)
Claude-Session: https://claude.ai/code/session_011BgWRBydtdkvt8ocqH4nj9
Running `brew deadcode` again flagged more definitions. Most were false
positives: cross-repo formula/cask/ENV/hardware/service DSL and
dynamically dispatched methods that I had restored from `main` while
fixing earlier breakage but not yet annotated. Annotate them `@api
internal` (or `# deadcode:keep` where a dynamic caller is involved) so
the command no longer reports them.
Also fix a real regression: `prof/vernier_fork_guard.rb` had its
`without_running_collector`/`stop_running_collector` methods removed even
though they are called from a `Kernel.module_eval` string (invisible to
Spoom), which broke `brew prof --vernier`. Restore them.
Remove genuinely dead definitions (invoked only by specs, or not at all)
and the specs that only covered them: `Utils::Git.count_coauthors`,
`GitHub.search_merged_pull_requests_in_user_or_organisation`,
`GitHub.count_repository_commits` and its `repo_commits_for_user` helper
(orphaned when `brew contributions` was refactored),
`Repology.query_api`, `GemSetup.install_gem!` and its `ohai_if_defined`
helper, `FormulaInfo#bottle_tags`, `FormulaWrapper#plist?`, and the
unused `Bundle::Checker::CheckStep` type alias.
`brew deadcode --dry-run` now reports no dead code to remove.
Claude-Session: https://claude.ai/code/session_011BgWRBydtdkvt8ocqH4nj9
`__setobj__` implements the `Delegator` interface (called by
`Delegator#initialize`), so mark its signature `override` rather than
using a `# deadcode:keep` comment. `brew deadcode` keeps it either way,
but `override` documents the intent precisely and Sorbet verifies it.
Claude-Session: https://claude.ai/code/session_011BgWRBydtdkvt8ocqH4nj9
Running `brew deadcode` (and the removal already committed with the
command) stripped code that Spoom cannot see callers for because it is
dispatched dynamically or called by formulae/casks in other repositories.
Restore those definitions and keep them from being flagged again:
- Teach the command to keep RuboCop `on_*`/`after_*` callbacks and
`RESTRICT_ON_*` scope constants, and extend the Spoom monkey-patch to
drop dangling `private_constant`/`public_constant` calls.
- Keep dynamically dispatched internals with `# deadcode:keep`/
`keep-matching` (diagnostic checks, `SystemConfig` sections, install
steps DSL, node-pattern predicates, `Delegator#__setobj__`, module
setters, `env_config` cask options).
- Annotate cross-repo formula/cask/ENV/hardware/service DSL with
`@api public`/`@api internal` so it is documented and retained.
- Remove specs that only covered genuinely dead code, move test-only
reset helpers to `test/support/helper/services.rb`, and fix specs that
referenced restored or changed definitions.
Claude-Session: https://claude.ai/code/session_011BgWRBydtdkvt8ocqH4nj9
Bump vendored Spoom to 1.8.4 and preload a monkey-patch into the
`spoom deadcode remove` subprocess that backports two removal fixes
opened upstream but not yet in a released gem:
- Shopify/spoom#980: removal no longer eats a preceding heredoc.
- Shopify/spoom#981: a `private_constant`/`public_constant` referencing
a removed constant is removed alongside it.
The patch reopens `NodeRemover` via a prepended module and is loaded only
in the removal subprocess (via `ruby -r`), never into brew itself. Delete
the patch and its wiring once the vendored Spoom includes both fixes.
Claude-Session: https://claude.ai/code/session_01XcY6NJn468hSt2n4WVkfoK
Spoom reports command classes under `cmd/` and `dev-cmd/` as dead
because they are invoked by name rather than referenced in Ruby (and
`ShellCommand` ones are backed by Bash), so `brew deadcode` was removing
whole command classes such as `VendorInstall`. Keep any class that
subclasses `AbstractCommand` under those directories, while still
allowing removal of dead methods and constants defined within them.
Claude-Session: https://claude.ai/code/session_01XcY6NJn468hSt2n4WVkfoK
Adds a `brew deadcode` dev-cmd that finds and removes dead code identified
by Spoom, excluding test code so that definitions referenced only by their
specs are also treated as dead. Definitions documented with `# @api public`
or `# @api internal`, or defined with an `override` signature, are always
kept, since Spoom cannot see their dynamic, subclass or cross-tap (e.g.
homebrew-core) callers.
Removes the dead code it identified, restoring false positives (dynamically
dispatched diagnostic checks and cask stanza classes, TestRunnerFormula
platform predicates, livecheck skip conditions, TopologicalHash tsort
methods and YARD docstring plugin methods). homebrew-core-used helpers such
as kernel_major_version, deny_network_access!, require_root and
detected_python_shebang are restored and annotated `# @api internal`.
Test-only cache resets are relocated into the specs that need them.
The hook spec now verifies via a side effect that the hook never
executes, rather than only that `git clone` succeeds. Comments no
longer say "user-configured" since `-c core.hooksPath` overrides
every configuration scope.
A global `core.hooksPath` (e.g. set by `git lfs install`) breaks
`brew tap` and `brew update`: hooks run with Homebrew's filtered
`PATH`, which lacks `git-lfs`, so every tap clone or update fails.
Pass `-c core.hooksPath=/dev/null` to tap and update Git operations,
as `package/scripts/postinstall` already does for the installer.
Requested in #21621.
These instance variables are assigned but never read:
- `@stale_seconds` and `@target` in `Homebrew::API::JSONDownloadStrategy`
and `Homebrew::API::JSONDownload`; the value is used via `meta[:target]`/
`meta[:stale_seconds]` and the `target`/`stale_seconds` arguments, not the
ivars. (`JSONDownloadStrategy#initialize` then only called `super`, so drop
it too.)
- `@old_homebrew_cellar` in `APIHashable`, which is saved during API
generation but never restored (only the prefix, home and git config are).
Claude-Session: https://claude.ai/code/session_011BgWRBydtdkvt8ocqH4nj9
brew bundle's parallel scheduler avoids running two entries in the same
batch when their recursive declared dependencies overlap, but implicit
dependencies added at formula-instantiation time (e.g. bubblewrap and
its dependents on Linux, when the sandbox executable isn't installed
yet) aren't declared on any formula, so two otherwise-unrelated
formulae can both silently need to fetch the same bottle at once. Since
DownloadLock's flock is non-blocking, the loser dies instead of
waiting.
Add DependencyCollector#implicit_dependency_names (empty by default,
overridden on Linux to report bubblewrap/gcc/glibc when they'd
currently be added), and fold it into every entry's recursive
dependency set before computing overlaps, so entries needing the same
implicit dependency are serialized like any other shared dependency.
See https://github.com/Homebrew/brew/issues/23328