brew: `brew upgrade` misbehaves when a formula's dependency is renamed
- Ran
brew updateand retried your prior step? - Ran
brew doctor, fixed as many issues as possible and retried your prior step? - Confirmed this is problem with Homebrew/brew and not specific formulae? If it’s a formulae-specific problem please file this issue at https://github.com/Homebrew/homebrew-core/issues/new
Here’s my brew config and brew doctor output.
Summary
If a formula (that is depended on by another installed formula) is renamed, brew update tries to install it on top of the old one and fails during the brew link step.
Steps to Reproduce
Run these commands:
brew tap cartr/rename-bug-demo
brew install dependent
You’ll get two new formulae installed: somepackage (which is GNU Hello) and dependent which depends on it. Next, run these to switch to a branch where somepackage has been renamed to somepackage4 and upgrade:
cd /usr/local/Homebrew/Library/Taps/cartr/homebrew-rename-bug-demo
git config --add remote.origin.fetch "+refs/heads/*:refs/remotes/origin/*" && git fetch
git checkout add-four
brew upgrade
Expected Result
The upgrade completes successfully, migrating somepackage to somepackage4.
Actual Result
bash-3.2$ brew upgrade
Warning: You are using a pre-release version of Xcode.
You may encounter build failures or other breakages.
Please create pull-requests instead of filing issues.
==> Upgrading 1 outdated package, with result:
cartr/rename-bug-demo/somepackage4 2.10_1
==> Upgrading cartr/rename-bug-demo/somepackage4
==> Downloading http://ftpmirror.gnu.org/hello/hello-2.10.tar.gz
==> Downloading from http://mirrors.kernel.org/gnu/hello/hello-2.10.tar.gz
######################################################################## 100.0%
==> ./configure --disable-silent-rules --prefix=/usr/local/Cellar/somepackage4/2.10_1
==> make install
Error: The `brew link` step did not complete successfully
The formula built, but is not symlinked into /usr/local
Could not symlink bin/hello
Target /usr/local/bin/hello
is a symlink belonging to somepackage. You can unlink it:
brew unlink somepackage
To force the link and overwrite all conflicting files:
brew link --overwrite somepackage4
To list all files that would be deleted:
brew link --overwrite --dry-run somepackage4
Possible conflicting files are:
/usr/local/bin/hello -> /usr/local/Cellar/somepackage/2.10_1/bin/hello
/usr/local/share/info/hello.info -> /usr/local/Cellar/somepackage/2.10_1/share/info/hello.info
/usr/local/share/man/man1/hello.1 -> /usr/local/Cellar/somepackage/2.10_1/share/man/man1/hello.1
==> Summary
🍺 /usr/local/Cellar/somepackage4/2.10_1: 10 files, 124.4K, built in 41 seconds
somepackage remains installed in its original location. somepackage4 is installed but unlinked.
About this issue
- Original URL
- State: closed
- Created 7 years ago
- Comments: 21 (20 by maintainers)
Commits related to this issue
- upgrade: unlink kegs of renamed formulae For each formula to be uninstalled, find all linked kegs that were installed with that formula (even if it had a different name at the time) and unlink them. ... — committed to alyssais/brew by alyssais 7 years ago
- update-report: migrate all formulae every time. Unmigrated formulae cause hard-to-debug issues and relying on detection on Git alone is faster but not comprehensive. Instead, iterate through renamed,... — committed to MikeMcQuaid/brew by MikeMcQuaid 7 years ago
If gcc48 and gcc@4.8 both exist at the time update runs, then a migration will not be performed. So as we’ve folded the non-core taps into homebrew/core, every time the import PR into core was merged before the deletion PR in the original tap, anyone who updated in between will not have been migrated. In most cases, the import PR and deletion PR occurred nearly simultaneously, but there were cases where they were separated by hours or days. Also, anyone who did any ill-timed updates via
git fetchandgit reset, or viagit pull, instead of viabrew update, is potentially affected regardless of our timing of the merges.So the poor man’s mitigation without changing any code, if you think you may have been impacted, is to run
brew list | xargs -tn1 brew migrateand see if anything happens. In terms of code changes, we need to modify update so that it handles any migrations that were never attempted even though the target formulae already exist now.The worst case scenario is that a user has installed both the source and target. This is entirely possible because if I had
gcc48installed, and it didn’t get migrated togcc@4.8for me, then I could have chosen to installgcc@4.8at any time since then. I think we need a doctor check to detect this case, which manifests as both the left side and right side of a formula rename existing at the same time, with both left and right side being directories. When both exist, but the left side is a symlink, it was a normal migration. If the left side is a directory not a symlink, then it’s a double installation, or a failed migration, both of which would be problems doctor should report.If/when https://github.com/Homebrew/brew/pull/2359 ships, it will also be possible for a double installation to simply be a migration that hasn’t been completed yet. Also, if that PR ships, double installations will be subject to migration attempts, possibly trying to move the exact same version on top of itself.
Ideally, we would also have something preventing double installations from ever happening by not allowing them to proceed, but currently there is nothing to prevent them regardless of whether the migration bug reported here gets fixed. Of course, they’ll be far less likely once this is fixed, but they will still currently be possible either way.
Note the gcc48 -> gcc@4.8 isn’t present in the update report.
Okay, I think I’ve got this: