add link_overwrite DSL
Sometimes we accidentally install files outside prefix. After we fix that, users will get nasty link conflict error. So we create a whitelist here to allow overwriting certain files. e.g. link_overwrite "bin/foo", "lib/bar" link_overwrite "share/man/man1/baz-*" During FormulaInstaller#link, the whitelist conflict files will be backup into HOMEBREW_CACHE/Backup
This commit is contained in:
parent
6362b5fdba
commit
09c810c7f4
@ -11,6 +11,7 @@ require "install_renamed"
|
||||
require "pkg_version"
|
||||
require "tap"
|
||||
require "formula_renames"
|
||||
require "keg"
|
||||
|
||||
# A formula provides instructions and metadata for Homebrew to install a piece
|
||||
# of software. Every Homebrew formula is a {Formula}.
|
||||
@ -330,7 +331,6 @@ class Formula
|
||||
# The currently installed version for this formula. Will raise an exception
|
||||
# if the formula is not installed.
|
||||
def installed_version
|
||||
require "keg"
|
||||
Keg.new(installed_prefix).version
|
||||
end
|
||||
|
||||
@ -657,6 +657,30 @@ class Formula
|
||||
self.class.skip_clean_paths.include? to_check
|
||||
end
|
||||
|
||||
# Sometimes we accidentally install files outside prefix. After we fix that,
|
||||
# users will get nasty link conflict error. So we create a whitelist here to
|
||||
# allow overwriting certain files. e.g.
|
||||
# link_overwrite "bin/foo", "lib/bar"
|
||||
# link_overwrite "share/man/man1/baz-*"
|
||||
def link_overwrite?(path)
|
||||
# Don't overwrite files not created by Homebrew.
|
||||
return false unless path.stat.uid == File.stat(HOMEBREW_BREW_FILE).uid
|
||||
# Don't overwrite files belong to other keg.
|
||||
begin
|
||||
Keg.for(path)
|
||||
rescue NotAKegError, Errno::ENOENT
|
||||
# file doesn't belong to any keg.
|
||||
else
|
||||
return false
|
||||
end
|
||||
to_check = path.relative_path_from(HOMEBREW_PREFIX).to_s
|
||||
self.class.link_overwrite_paths.any? do |p|
|
||||
p == to_check ||
|
||||
to_check.start_with?(p.chomp("/") + "/") ||
|
||||
/^#{Regexp.escape(p).gsub('\*', ".*?")}$/ === to_check
|
||||
end
|
||||
end
|
||||
|
||||
def skip_cxxstdlib_check?
|
||||
false
|
||||
end
|
||||
@ -1351,5 +1375,14 @@ class Formula
|
||||
def test(&block)
|
||||
define_method(:test, &block)
|
||||
end
|
||||
|
||||
def link_overwrite(*paths)
|
||||
paths.flatten!
|
||||
link_overwrite_paths.merge(paths)
|
||||
end
|
||||
|
||||
def link_overwrite_paths
|
||||
@link_overwrite_paths ||= Set.new
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@ -589,9 +589,20 @@ class FormulaInstaller
|
||||
keg.remove_linked_keg_record
|
||||
end
|
||||
|
||||
link_overwrite_backup = {} # dict: conflict file -> backup file
|
||||
backup_dir = HOMEBREW_CACHE/"Backup"
|
||||
|
||||
begin
|
||||
keg.link
|
||||
rescue Keg::ConflictError => e
|
||||
conflict_file = e.dst
|
||||
if formula.link_overwrite?(conflict_file) && !link_overwrite_backup.key?(conflict_file)
|
||||
backup_file = backup_dir/conflict_file.relative_path_from(HOMEBREW_PREFIX).to_s
|
||||
backup_file.parent.mkpath
|
||||
conflict_file.rename backup_file
|
||||
link_overwrite_backup[conflict_file] = backup_file
|
||||
retry
|
||||
end
|
||||
onoe "The `brew link` step did not complete successfully"
|
||||
puts "The formula built, but is not symlinked into #{HOMEBREW_PREFIX}"
|
||||
puts e
|
||||
@ -616,10 +627,24 @@ class FormulaInstaller
|
||||
puts e
|
||||
puts e.backtrace if debug?
|
||||
@show_summary_heading = true
|
||||
ignore_interrupts { keg.unlink }
|
||||
ignore_interrupts do
|
||||
keg.unlink
|
||||
link_overwrite_backup.each do |conflict_file, backup_file|
|
||||
conflict_file.parent.mkpath
|
||||
backup_file.rename conflict_file
|
||||
end
|
||||
end
|
||||
Homebrew.failed = true
|
||||
raise
|
||||
end
|
||||
|
||||
unless link_overwrite_backup.empty?
|
||||
opoo "These files were overwritten during `brew link` step:"
|
||||
puts link_overwrite_backup.keys
|
||||
puts
|
||||
puts "They are backup in #{backup_dir}"
|
||||
@show_summary_heading = true
|
||||
end
|
||||
end
|
||||
|
||||
def install_plist
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user