- Make every statically-poked method public and call it directly,
keeping `public_send` only for dynamically-named public methods.
- Read and write state through public `attr_*` accessors instead of
instance variable reflection.
- Enable `Homebrew/NoSendInTests` and
`Homebrew/NoInstanceVariableAccessInTests` now the test suite is
clean, so neither pattern creeps back in.
- Keep rare justified disables, e.g. `Module#remove_const` is
private core Ruby and raw memoisation state has no accessor.
Cask renames leave an alias symlink in the Caskroom (today old token ->
new directory; an earlier migration era created the inverse
arrangement). Uninstall removed only broken symlinks named after the
cask's declared old_tokens, so any other arrangement - uninstalling by
the old token, or an alias left by the earlier era - left a dangling
symlink behind: brew list --cask still showed the name while
brew uninstall of it failed with "Cask ... is not installed". Scan the
Caskroom for broken symlinks pointing at the removed directory instead,
whichever of the linked names was uninstalled, and clean up on the
purge_caskroom_path force path too.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- store deterministic language deltas in public and internal API data
- select URLs, checksums and artifacts without loading cask Ruby
- retain source fallback for older API data and legacy flight blocks
- preserve artifacts when receipts or metadata are missing
- share recovery between migration, upgrade and reinstall
- verify rewritten JSON before deleting legacy metadata
- Extract cask containers during queued fetches so installs spend less
serial time in the staging phase.
- Keep receipt writing and artifact installation in the normal install
path so installed state does not change early.
- Skip queued extraction when unpack dependencies are still missing so
dependency installation ordering stays intact.
`Cask::Installer#backup` renamed the staged version directory to
`<version>.upgrading` for rollback safety, raising `Errno::ENOENT`
("No such file or directory @ rb_file_s_rename") and aborting the
whole `brew upgrade` when that directory was already gone — a common
state for `auto_updates` casks that self-updated out-of-band, or after
an interrupted `brew upgrade`/`brew cleanup`. Guard the rename so a
missing staged path is a no-op instead of a fatal error.
Closes#22998.
Signed-off-by: Gaál György <gb12335@gmail.com>
- Use a minimal post-install snapshot for supported casks.
- Read receipt-owned version and artifacts from `INSTALL_RECEIPT.json`.
- Leave uninstall flight block caskfiles as Ruby until ported.
- Avoid loading simple `homebrew/cask` entries when `brew fetch --cask`
can resolve URL, version and checksum data from `CaskStruct`.
- Reuse that API-backed download construction for internal-API casks
during installer download enqueueing.
- Keep source-backed cask loading for language-specific casks and other
caskfile-only install paths.
- Ensure `join` is called on a Pathname of `config.appdir`, because
`config.appdir` is typed in `cask/config.rbi` as a String, but in the
real method sig can be either a String or a Pathname.
- `Formulary.cache.delete` can take a String or a Pathname, but Sorbet
only sees the String type, so call `to_s` on the argument passed to
it.
- Stub the `bzip2` formula fetch/install dispatched by the bzip2
container's unpack strategy, so the test no longer pours a real
bottle whose GitHub Packages manifest fetch flaked with
`Couldn't find manifest matching bottle checksum`
- Keep `UnpackStrategy::Bzip2#dependencies` intact and force the
dependency to resolve as missing so the container-driven
dependency-resolution path stays covered deterministically
- `HOMEBREW_ALLOWED_TAPS`, `HOMEBREW_FORBIDDEN_TAPS` and `trust.json`
matched taps by `user/repository` name only, which `brew tap
user/repository <url>` trivially spoofed by pointing that name at an
arbitrary remote
- match a `user/repository` name only against a tap on its default
GitHub remote; a tap with a custom remote must now be referenced by
its remote URL, so non-GitHub taps are listed and trusted by URL
- evaluate the allow/forbid gate against the requested clone remote so
the bypass is caught before cloning
- gate the implicit official-tap exemption behind `implicitly_official?`
so an official-named tap is only auto-allowed/trusted when its content
comes from the API or it uses an official (or `HOMEBREW_CORE_GIT_REMOTE`)
remote, not when pointed at an untrusted custom remote
- refuse per-item trust for custom-remote taps; trust the whole tap by
URL instead
- Since https://github.com/sorbet/sorbet/commit/d9d4b57b3fde3907d739ed85d340e64f75f2a7b8
Sorbet types `described_class` more correctly than assuming `T.untyped`.
- Switched back via having Copilot CLI (GPT 5.3 Codex) write me a
script to change all of the `klass` references into full class names,
and then running RuboCop's autocorrector having removed the `explicit`
style. The explicit style was deemed too verbose in
0c1321f1b1, hence why we went with
`let(:klass)`.
- This is much less verbose than the full class name, while preserving
Sorbet typing of the tests fully.
- Avoid splitting cask source fetches from combined upgrade fetches
- Keep language-specific caskfiles on a prefetch queue only when needed
- Hide `Downloading Cask files` unless that queue will fetch new files
- Reduce slow command specs because repeated `brew` subprocesses were
dominating the profile more than the tested Homebrew behaviour.
- Preserve coverage by moving option and error branches into direct
command-object specs where a full process adds no useful signal.
- Keep shell-specific coverage by folding Bash command checks into one
subprocess harness for each affected Bash path.
- Combine formula and cask happy paths in `fetch`, `outdated` and
`upgrade`, so one process still checks both package types.
- Keep `cmd/install` source, bottle, keg-only and `--HEAD` coverage,
with `--HEAD` separate because the option applies to the whole call.
- Stub expensive `svn`, DMG mount and signal-wait paths so the specs
cover Homebrew decisions without invoking slow external work.
- Restore `brew extract` monkey patches when specs run in-process, so
dependency and formula requirement caches do not leak across examples.
- Document the integration-test limit in `AGENTS.md` so future command
specs bias towards fast in-process coverage.
- The "explicit" setting on the `RSpec/DescribedClass` cop is still
enabled, because `described_class` is bad for Sorbet typing, but
instead of applying its autocorrections to specify the full class name
everywhere that `described_class` was used, use
`let(:klass) { Foo }` so that the repetition per-test isn't massive in
tests that use it a lot (say, >5 times).
- Changes made with Copilot CLI, agent mode, Claude Opus 4.7.
- Support `depends_on :linux` for casks and formulae.
- Fast-path support checks for Linux-only software.
- Document the Linux-only dependency semantics.
- Cover Linux-only and conflicting OS guard paths.
- stop `gimp` on Linux before source reloads fail
- avoid queued downloads for unsupported API-backed casks
- cover `fetch` and `enqueue_downloads` with regression tests
- Now that we've enabled `--experimental-rspec-mode` [1], let's start
using Sorbet in tests at its basic `typed: false` level for now.
- This will ease the migration to `typed: true` of any or all tests we
want to do in the future.
[1]: https://github.com/Homebrew/brew/pull/21742
- Improve the error message when a cask or formula is forbidden by an
environment variable (fixes#17880)
- Move the `forbidden_tap_check` and `forbidden_cask_and_formula_check`
methods to the top of the `install` method, so that they are checked
before the main cask is downloaded.
We already had `HOMEBREW_FORBIDDEN_LICENSES` but this commit adds
`HOMEBREW_FORBIDDEN_CASKS`, `HOMEBREW_FORBIDDEN_FORMULAE` and
`HOMEBREW_FORBIDDEN_TAPS` for also forbidding those.
Relatedly, add `HOMEBREW_FORBIDDEN_OWNER` and
`HOMEBREW_FORBIDDEN_OWNER_CONTACT` to allow customising these
messages.
There were no existing tests for `HOMEBREW_FORBIDDEN_LICENSES` so have
added more tests for all of these checks.
Co-authored-by: Bo Anderson <mail@boanderson.me>
Previously, the behavior was to warn users that a cask was already
installed and then skip modifying the installed version. This is
different to how we handled things with formulas. For them we would
upgrade any already installed formulas. This just brings casks in line
with what we already do with formulas.
Changes:
- cmd/install: Upgrade already installed casks if HOMEBREW_NO_INSTALL_UPGRADE
is not set
- env_config: Update wording of HOMEBREW_NO_INSTALL_UPGRADE to include casks
- remove error that was only used to alert about already installed casks
Note:
- The upgrade command for casks defaults to --greedy when you pass named casks
to the command which means that this will always default to that behavior
since you must specify the name of the cask when installing.
Set metadata when we load casks from the source API.
Set `@tap_git_head` manually.
Also, allow `auto_update` to receive false.
This is only done for consistency.
Stop double printing the `kext` caveat.
Handle Array elements correctly when substituting
path elements in artifacts. This affected how the
Uninstall Signal keys were evaluated (they are
represented as arrays of arrays).
A sha256 hash of the previous download is stored and compared with
new downloads before updating :latest casks. This prevents unnecessary
reinstalls when the cask hasn't been updated.
Move download path to cask from installer to prevent unnecessary
redownloads of casks.
The problem occurred when calling `brew reinstall` on a cask
with an out of date caskfile.
To solve the problem Cask::Installer#uninstall_existing_cask has been changed to
catch a possible CaskInvalidError when trying to load outdated
caskfiles using Cask::CaskLoader#load.