link: add --force and --dry-run options

`brew link` can now be made to delete any conflicting files using
the --force argument. It also has a --dry-run option, similar to
git clean -n, which will list any files which would be deleted
without touching the filesystem.

Closes Homebrew/homebrew#11811.

Signed-off-by: Misty De Meo <mistydemeo@gmail.com>
This commit is contained in:
Misty De Meo 2012-06-17 16:54:20 -05:00
parent dd9ef7b71b
commit 743b5e6feb
5 changed files with 55 additions and 16 deletions

View File

@ -186,11 +186,18 @@ For the full command list, see the COMMANDS section.
If `--git` is passed, Homebrew will create a Git repository, useful for If `--git` is passed, Homebrew will create a Git repository, useful for
creating patches to the software. creating patches to the software.
* `ln`, `link` <formula>: * `ln`, `link [--force] [--dry-run]` <formula>:
Symlink all of <formula>'s installed files into the Homebrew prefix. This Symlink all of <formula>'s installed files into the Homebrew prefix. This
is done automatically when you install formula, but can be useful for DIY is done automatically when you install formula, but can be useful for DIY
installations. installations.
If `--force` is passed, Homebrew will delete files which already exist in
the prefix while linking.
If `--dry-run` or `-n` is passed, Homebrew will list all files which would
be deleted by `brew link --force`, but will not actually link or delete
any files.
* `ls, list [--unbrewed] [--versions]` [<formulae>]: * `ls, list [--unbrewed] [--versions]` [<formulae>]:
Without any arguments, list all installed formulae. Without any arguments, list all installed formulae.

View File

@ -9,14 +9,30 @@ module Homebrew extend self
abort "Cowardly refusing to `sudo brew link'" abort "Cowardly refusing to `sudo brew link'"
end end
if ARGV.force?
mode = :force
elsif ARGV.include?("--dry-run") || ARGV.include?("-n")
mode = :dryrun
else
mode = nil
end
ARGV.kegs.each do |keg| ARGV.kegs.each do |keg|
if keg.linked_keg_record.directory? and keg.linked_keg_record.realpath == keg if keg.linked_keg_record.directory? and keg.linked_keg_record.realpath == keg
opoo "Already linked: #{keg}" opoo "Already linked: #{keg}"
next next
end end
if mode == :dryrun
print "Would remove:\n" do
keg.link(mode)
end
next
end
print "Linking #{keg}... " do print "Linking #{keg}... " do
puts "#{keg.link} symlinks created" puts "#{keg.link(mode)} symlinks created"
end end
end end
end end

View File

@ -347,6 +347,11 @@ class Pathname
raise <<-EOS.undent raise <<-EOS.undent
Could not symlink file: #{src.expand_path} Could not symlink file: #{src.expand_path}
Target #{self} already exists. You may need to delete it. Target #{self} already exists. You may need to delete it.
To force the link and delete this file, do:
brew link -f formula_name
To list all files that would be deleted:
brew link -n formula_name
EOS EOS
elsif !dirname.writable? elsif !dirname.writable?
raise <<-EOS.undent raise <<-EOS.undent

View File

@ -58,7 +58,7 @@ class Keg < Pathname
linked_keg_record.directory? and self == linked_keg_record.realpath linked_keg_record.directory? and self == linked_keg_record.realpath
end end
def link def link mode=nil
raise "Cannot link #{fname}\nAnother version is already linked: #{linked_keg_record.realpath}" if linked_keg_record.directory? raise "Cannot link #{fname}\nAnother version is already linked: #{linked_keg_record.realpath}" if linked_keg_record.directory?
$n=0 $n=0
@ -70,12 +70,12 @@ class Keg < Pathname
# yeah indeed, you have to force anything you need in the main tree into # yeah indeed, you have to force anything you need in the main tree into
# these dirs REMEMBER that *NOT* everything needs to be in the main tree # these dirs REMEMBER that *NOT* everything needs to be in the main tree
link_dir('etc') {:mkpath} link_dir('etc', mode) {:mkpath}
link_dir('bin') {:skip_dir} link_dir('bin', mode) {:skip_dir}
link_dir('sbin') {:skip_dir} link_dir('sbin', mode) {:skip_dir}
link_dir('include') {:link} link_dir('include', mode) {:link}
link_dir('share') do |path| link_dir('share', mode) do |path|
case path.to_s case path.to_s
when 'locale/locale.alias' then :skip_file when 'locale/locale.alias' then :skip_file
when INFOFILE_RX then ENV['HOMEBREW_KEEP_INFO'] ? :info : :skip_file when INFOFILE_RX then ENV['HOMEBREW_KEEP_INFO'] ? :info : :skip_file
@ -86,7 +86,7 @@ class Keg < Pathname
end end
end end
link_dir('lib') do |path| link_dir('lib', mode) do |path|
case path.to_s case path.to_s
when 'charset.alias' then :skip_file when 'charset.alias' then :skip_file
# pkg-config database gets explicitly created # pkg-config database gets explicitly created
@ -106,7 +106,7 @@ class Keg < Pathname
end end
end end
linked_keg_record.make_relative_symlink(self) linked_keg_record.make_relative_symlink(self) unless mode == :dryrun
return $n + $d return $n + $d
end end
@ -127,16 +127,21 @@ protected
puts "Won't resolve conflicts for symlink #{dst} as it doesn't resolve into the Cellar" if ARGV.verbose? puts "Won't resolve conflicts for symlink #{dst} as it doesn't resolve into the Cellar" if ARGV.verbose?
end end
def make_relative_symlink dst, src def make_relative_symlink dst, src, mode=nil
if dst.exist? and dst.realpath == src.realpath if dst.exist? and dst.realpath == src.realpath
puts "Skipping; already exists: #{dst}" if ARGV.verbose? puts "Skipping; already exists: #{dst}" if ARGV.verbose?
# cf. git-clean -n: list files to delete, don't really link or delete
elsif mode == :dryrun
puts dst if dst.exist?
return
else else
dst.delete if mode == :force && dst.exist?
dst.make_relative_symlink src dst.make_relative_symlink src
end end
end end
# symlinks the contents of self+foo recursively into /usr/local/foo # symlinks the contents of self+foo recursively into /usr/local/foo
def link_dir foo def link_dir foo, mode=nil
root = self+foo root = self+foo
return unless root.exist? return unless root.exist?
@ -154,10 +159,10 @@ protected
Find.prune Find.prune
when :info when :info
next if File.basename(src) == 'dir' # skip historical local 'dir' files next if File.basename(src) == 'dir' # skip historical local 'dir' files
make_relative_symlink dst, src make_relative_symlink dst, src, mode
dst.install_info dst.install_info
else else
make_relative_symlink dst, src make_relative_symlink dst, src, mode
end end
elsif src.directory? elsif src.directory?
# if the dst dir already exists, then great! walk the rest of the tree tho # if the dst dir already exists, then great! walk the rest of the tree tho

View File

@ -1,7 +1,7 @@
.\" generated with Ronn/v0.7.3 .\" generated with Ronn/v0.7.3
.\" http://github.com/rtomayko/ronn/tree/0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3
. .
.TH "BREW" "1" "March 2012" "Homebrew" "brew" .TH "BREW" "1" "June 2012" "Homebrew" "brew"
. .
.SH "NAME" .SH "NAME"
\fBbrew\fR \- The missing package manager for OS X \fBbrew\fR \- The missing package manager for OS X
@ -208,9 +208,15 @@ Download and patch \fIformula\fR, then open a shell\. This allows the user to ru
If \fB\-\-git\fR is passed, Homebrew will create a Git repository, useful for creating patches to the software\. If \fB\-\-git\fR is passed, Homebrew will create a Git repository, useful for creating patches to the software\.
. .
.TP .TP
\fBln\fR, \fBlink\fR \fIformula\fR \fBln\fR, \fBlink [\-\-force] [\-\-dry\-run]\fR \fIformula\fR
Symlink all of \fIformula\fR\'s installed files into the Homebrew prefix\. This is done automatically when you install formula, but can be useful for DIY installations\. Symlink all of \fIformula\fR\'s installed files into the Homebrew prefix\. This is done automatically when you install formula, but can be useful for DIY installations\.
. .
.IP
If \fB\-\-force\fR is passed, Homebrew will delete files which already exist in the prefix while linking\.
.
.IP
If \fB\-\-dry\-run\fR or \fB\-n\fR is passed, Homebrew will list all files which would be deleted by \fBbrew link \-\-force\fR, but will not actually link or delete any files\.
.
.TP .TP
\fBls, list [\-\-unbrewed] [\-\-versions]\fR [\fIformulae\fR] \fBls, list [\-\-unbrewed] [\-\-versions]\fR [\fIformulae\fR]
Without any arguments, list all installed formulae\. Without any arguments, list all installed formulae\.