aboutsummaryrefslogtreecommitdiffstats
path: root/Library
diff options
context:
space:
mode:
authorXu Cheng2015-08-23 16:35:51 +0800
committerXu Cheng2015-08-23 21:43:03 +0800
commit09c810c7f428b838b9b327d1c92f87ebc6e76447 (patch)
treeadc834ec2a403f27783fc3632385b7c6a2f7005d /Library
parent6362b5fdba1aeb9f23fe80c80df8fdfd80d7f57a (diff)
downloadbrew-09c810c7f428b838b9b327d1c92f87ebc6e76447.tar.bz2
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
Diffstat (limited to 'Library')
-rw-r--r--Library/Homebrew/formula.rb35
-rw-r--r--Library/Homebrew/formula_installer.rb27
2 files changed, 60 insertions, 2 deletions
diff --git a/Library/Homebrew/formula.rb b/Library/Homebrew/formula.rb
index 278cf6595..8fba7803b 100644
--- a/Library/Homebrew/formula.rb
+++ b/Library/Homebrew/formula.rb
@@ -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
diff --git a/Library/Homebrew/formula_installer.rb b/Library/Homebrew/formula_installer.rb
index 550fd93ad..3c19f7a14 100644
--- a/Library/Homebrew/formula_installer.rb
+++ b/Library/Homebrew/formula_installer.rb
@@ -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