Currently, `brew link` installs `*.info` files to
`#{HOMEBREW_PREFIX}/share/info/dir` using the `install_info` method.
However, some formulae (e.g., `Emacs`) also ship `*.info.gz` files,
which are only `symlink`ed but not installed.
This commit allows `*.info.gz` files to be installed during linking in
addition to the `*.info` files.
- Previously I thought that comments were fine to discourage people from
wasting their time trying to bump things that used `undef` that Sorbet
didn't support. But RuboCop is better at this since it'll complain if
the comments are unnecessary.
- Suggested in https://github.com/Homebrew/brew/pull/18018#issuecomment-2283369501.
- I've gone for a mixture of `rubocop:disable` for the files that can't
be `typed: strict` (use of undef, required before everything else, etc)
and `rubocop:todo` for everything else that should be tried to make
strictly typed. There's no functional difference between the two as
`rubocop:todo` is `rubocop:disable` with a different name.
- And I entirely disabled the cop for the docs/ directory since
`typed: strict` isn't going to gain us anything for some Markdown
linting config files.
- This means that now it's easier to track what needs to be done rather
than relying on checklists of files in our big Sorbet issue:
```shell
$ git grep 'typed: true # rubocop:todo Sorbet/StrictSigil' | wc -l
268
```
- And this is confirmed working for new files:
```shell
$ git status
On branch use-rubocop-for-sorbet-strict-sigils
Untracked files:
(use "git add <file>..." to include in what will be committed)
Library/Homebrew/bad.rb
Library/Homebrew/good.rb
nothing added to commit but untracked files present (use "git add" to track)
$ brew style
Offenses:
bad.rb:1:1: C: Sorbet/StrictSigil: Sorbet sigil should be at least strict got true.
^^^^^^^^^^^^^
1340 files inspected, 1 offense detected
```
This improves the load time of most brew commands. For an example of
one of the simplest commands this speeds up:
Without Bootsnap:
```
$ hyperfine 'git checkout master; brew help' 'git checkout optimise_requires; brew help'
Benchmark 1: git checkout master; brew help
Time (mean ± σ): 525.0 ms ± 35.8 ms [User: 229.9 ms, System: 113.1 ms]
Range (min … max): 465.3 ms … 576.6 ms 10 runs
Benchmark 2: git checkout optimise_requires; brew help
Time (mean ± σ): 383.3 ms ± 25.1 ms [User: 133.0 ms, System: 72.1 ms]
Range (min … max): 353.0 ms … 443.6 ms 10 runs
Summary
git checkout optimise_requires; brew help ran
1.37 ± 0.13 times faster than git checkout master; brew help
```
With Bootsnap:
```
$ hyperfine 'git checkout master; brew help' 'git checkout optimise_requires; brew help'
Benchmark 1: git checkout master; brew help
Time (mean ± σ): 386.0 ms ± 30.9 ms [User: 130.2 ms, System: 93.8 ms]
Range (min … max): 359.5 ms … 469.3 ms 10 runs
Benchmark 2: git checkout optimise_requires; brew help
Time (mean ± σ): 330.2 ms ± 32.4 ms [User: 93.4 ms, System: 73.0 ms]
Range (min … max): 302.9 ms … 413.9 ms 10 runs
Summary
git checkout optimise_requires; brew help ran
1.17 ± 0.15 times faster than git checkout master; brew help
```
This updates logic to add a `#scheme_and_version` method to be used
with `.sort_by` and `.max_by`. Using `Keg#version` by itself can be
inaccurate when different version schemes are present. This also
updates the behavior of `Formula#eligible_kegs_for_cleanup` to match
the previous behavior. We were dropping the wrong keg based on the
sort being reversed in a previous PR.
When a Keg is unlinked, brew-link gives a helpful message for how to proceed: adding the `--overwrite` flag.
For safety, it also recommends running in `--dry-run` mode first to see what would be deleted.
So a user's common flow would be:
1. run `brew link foo`
2. get error message with guidance
3. run `brew link --overwrite --dry-run foo`
4. inspect
5. run `brew link --overwrite foo`
In this flow, steps 3-5 are likely very common. Common enough that a user may use their shell history to re-populate their prompt with step 3's command, delete the `--dry-run` flag, and re-run. (The end goal, of course, is to link `foo`.)
The `--dry-run` flag needs to be removed from the command, of course. If it had been at the _end_ of the command, it would make the subsequent modification easier.
Instead of "up arrow, left-arrow a bunch, then backspace over --dry-run, hopefully not backspacing over the formula name", it would be easier for the user if the dry-run flag were already at the end of the command. Then the user can "up arrow, backspace a few times and hit enter".
What's more, if the last arg were `--dry-run`, a more advanced bash user could even use `!:-` to re-run the link command with all-but-the-last-arg.
This allows us to remove all the manual timestamp fiddling and lets
`gnu-tar` handle it for us instead (as-per the most recent
recommendations on https://reproducible-builds.org/docs/archives/).
Some formulae (e.g. `luv`) have a `lib/lua/5.1` subdirectory inside
their keg. Before this change, the `5.1` subdirectory is symlinked into
`HOMEBREW_PREFIX`.
This can result in `luarocks` installing things into a formula's keg,
which we don't want.
Let's fix that by making sure that `brew link` creates these
subdirectories instead of symlinking them. We already do this for
subdirectories of `share/lua`:
8dd96ae8ba/Library/Homebrew/keg.rb (L430)
Previously, `brew upgrade gcc@10` could get overzealous and remove the
`LinkedKeg` record for `gcc@9`. This is bad because we then think
`gcc@9` is unlinked when it is not and it causes a tonne of conflicts
when trying to link `gcc@9` again.
Instead, fix up the alias and versioned alias cleanup to be more
precise and only delete the symlinks that point to the current `rack`,
`opt_record` or `linked_keg_record` and unify the logic so it's
performed consistently.
While we're here:
- don't `remove_old_aliases` every time we try to unlink a directory
but just perform it once per `unlink` operation
- remove the linked keg record on `uninstall`
This is weird. We're seeing some installs where formulae
have no opt prefix and no linked keg record, *but* still
ended up linked into the prefix. Upgrades will blow up in
this case because the old symlinks won't get deleted and
Homebrew will report a nonsensical error message about
not being able to link over another link from the same
formula!
Since the optpath is either missing or pointing to the
wrong destination at this point, the checks for conflict
linking above will have failed. We should instead be safe
to simply blow away these conflicting symlinks and replace
them with the new targets.
Fixes https://github.com/Homebrew/homebrew-core/issues/68866.