From 53fe6b518fe327b080f9ccc35b8b74a0e6d3f6aa Mon Sep 17 00:00:00 2001 From: Misty De Meo Date: Tue, 12 Jan 2021 23:46:39 -0800 Subject: [PATCH 1/4] Keg: allow overwriting same-formula conflicts 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. --- Library/Homebrew/keg.rb | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/Library/Homebrew/keg.rb b/Library/Homebrew/keg.rb index e2db8254fb..30aca75a1c 100644 --- a/Library/Homebrew/keg.rb +++ b/Library/Homebrew/keg.rb @@ -647,6 +647,18 @@ class Keg dst.delete if options[:overwrite] && (dst.exist? || dst.symlink?) dst.make_relative_symlink(src) rescue Errno::EEXIST => e + # We're linking a different version of the same formula + # Note that the AlreadyLinkedError check above *should* + # have caught this, but there are circumstances in which + # we end up with symlinks for a formula even though + # it seems to be missing an optlink. In that case, + # we should be clear to blow those away and replace + # them. + if dst.symlink? && Keg.for(dst).name == name + dst.unlink + retry + end + raise ConflictError.new(self, src.relative_path_from(path), dst, e) if dst.exist? if dst.symlink? From e01fa7d2aec5d07ec8b8d7cd6d7cb2d0f48ce9c1 Mon Sep 17 00:00:00 2001 From: Mike McQuaid Date: Wed, 13 Jan 2021 09:23:36 +0000 Subject: [PATCH 2/4] keg: tweak retry comment. --- Library/Homebrew/keg.rb | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/Library/Homebrew/keg.rb b/Library/Homebrew/keg.rb index 30aca75a1c..562c95cee8 100644 --- a/Library/Homebrew/keg.rb +++ b/Library/Homebrew/keg.rb @@ -647,13 +647,10 @@ class Keg dst.delete if options[:overwrite] && (dst.exist? || dst.symlink?) dst.make_relative_symlink(src) rescue Errno::EEXIST => e - # We're linking a different version of the same formula - # Note that the AlreadyLinkedError check above *should* - # have caught this, but there are circumstances in which - # we end up with symlinks for a formula even though - # it seems to be missing an optlink. In that case, - # we should be clear to blow those away and replace - # them. + # Retry if we're linking a different version of the same + # formula. The `AlreadyLinkedError` above won't catch + # this if a formula is missing an optlink. In that case, + # delete the symlink and retry. if dst.symlink? && Keg.for(dst).name == name dst.unlink retry From 66f0a35587fffb32f16e51daf3091cb8781a6e10 Mon Sep 17 00:00:00 2001 From: Mike McQuaid Date: Wed, 13 Jan 2021 09:28:13 +0000 Subject: [PATCH 3/4] keg: remove trailing whitespace. --- Library/Homebrew/keg.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Library/Homebrew/keg.rb b/Library/Homebrew/keg.rb index 562c95cee8..99c0e02559 100644 --- a/Library/Homebrew/keg.rb +++ b/Library/Homebrew/keg.rb @@ -647,7 +647,7 @@ class Keg dst.delete if options[:overwrite] && (dst.exist? || dst.symlink?) dst.make_relative_symlink(src) rescue Errno::EEXIST => e - # Retry if we're linking a different version of the same + # Retry if we're linking a different version of the same # formula. The `AlreadyLinkedError` above won't catch # this if a formula is missing an optlink. In that case, # delete the symlink and retry. From a2e0da89e4e1ae7f815210eb2d30d68114520e5c Mon Sep 17 00:00:00 2001 From: Misty De Meo Date: Wed, 13 Jan 2021 09:17:27 -0800 Subject: [PATCH 4/4] Keg: only instantiate Keg.for if target exists --- Library/Homebrew/keg.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Library/Homebrew/keg.rb b/Library/Homebrew/keg.rb index 99c0e02559..aa406c0bf8 100644 --- a/Library/Homebrew/keg.rb +++ b/Library/Homebrew/keg.rb @@ -651,7 +651,7 @@ class Keg # formula. The `AlreadyLinkedError` above won't catch # this if a formula is missing an optlink. In that case, # delete the symlink and retry. - if dst.symlink? && Keg.for(dst).name == name + if dst.symlink? && dst.exist? && Keg.for(dst).name == name dst.unlink retry end