Keg: fix alias and versioned symlink handling.

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 commit is contained in:
Mike McQuaid 2021-01-14 16:02:06 +00:00
parent 9e26db3a55
commit 128aeba3a4
No known key found for this signature in database
GPG Key ID: 48A898132FD8EE70

View File

@ -301,28 +301,16 @@ class Keg
# versioned aliases are handled below
next if a.match?(/.+@./)
alias_opt_symlink = opt/a
if alias_opt_symlink.symlink? && alias_opt_symlink.exist?
alias_opt_symlink.delete if alias_opt_symlink.realpath == opt_record.realpath
elsif alias_opt_symlink.symlink? || alias_opt_symlink.exist?
alias_opt_symlink.delete
end
alias_linkedkegs_symlink = linkedkegs/a
alias_linkedkegs_symlink.delete if alias_linkedkegs_symlink.symlink? || alias_linkedkegs_symlink.exist?
remove_alias_symlink(opt/a, opt_record)
remove_alias_symlink(linkedkegs/a, linked_keg_record)
end
Pathname.glob("#{opt_record}@*").each do |a|
a = a.basename.to_s
next if aliases.include?(a)
alias_opt_symlink = opt/a
if alias_opt_symlink.symlink? && alias_opt_symlink.exist? && rack == alias_opt_symlink.realpath.parent
alias_opt_symlink.delete
end
alias_linkedkegs_symlink = linkedkegs/a
alias_linkedkegs_symlink.delete if alias_linkedkegs_symlink.symlink? || alias_linkedkegs_symlink.exist?
remove_alias_symlink(opt/a, rack)
remove_alias_symlink(linkedkegs/a, rack)
end
end
@ -341,6 +329,7 @@ class Keg
path.rmtree
path.parent.rmdir_if_possible
remove_opt_record if optlinked?
remove_linked_keg_record if linked?
remove_old_aliases
remove_oldname_opt_record
rescue Errno::EACCES, Errno::ENOTEMPTY
@ -377,12 +366,12 @@ class Keg
dst.uninstall_info if dst.to_s.match?(INFOFILE_RX)
dst.unlink
remove_old_aliases
Find.prune if src.directory?
end
end
unless options[:dry_run]
remove_old_aliases
remove_linked_keg_record if linked?
dirs.reverse_each(&:rmdir_if_possible)
end
@ -659,6 +648,14 @@ class Keg
raise LinkError.new(self, src.relative_path_from(path), dst, e)
end
def remove_alias_symlink(alias_symlink, alias_match_path)
if alias_symlink.symlink? && alias_symlink.exist?
alias_symlink.delete if alias_symlink.realpath == alias_match_path.realpath
elsif alias_symlink.symlink? || alias_symlink.exist?
alias_symlink.delete
end
end
protected
# symlinks the contents of path+relative_dir recursively into #{HOMEBREW_PREFIX}/relative_dir