Created
September 6, 2012 20:21
-
-
Save mistydemeo/3660108 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require 'fileutils' | |
require 'tmpdir' | |
# FileUtils.mv | |
# | |
# Ruby 1.8.7's FileUtils.mv calls File.rename on the src. However, File.rename | |
# raises Errno::EXDEV when src and dst exist on separate devices. The fallback | |
# is to perform a copy instead of a rename. | |
# | |
# However, there is a bug in 1.8.7's implementation. If src is a symlink or a | |
# directory containing a symlink, and the target of that symlink has not yet been | |
# copied, the copy will fail, because copy_metadata calls File.utime on the | |
# symlink. File.utime resolves symlinks, and because the target does yet exist, | |
# it raises Errno::ENOENT. | |
# | |
# This was fixed in Ruby here: | |
# https://github.com/ruby/ruby/commit/7d89ecdc523aab7b9908501b6743da2c26a53825 | |
# ***NOTE***: This is an entirely different problem than the one that prompted | |
# the introduction of HOMEBREW_TEMP. In that case, the BSD mv(1) command bails | |
# out if we're moving a symlink across volumes when the target has *already* | |
# been moved. We only see this when Pathname#install_p is fed a symlink directly, | |
# as that is the only case in which we exec mv(1) rather than using FileUtils.mv. | |
if RUBY_VERSION.to_f < 1.9 | |
class FileUtils::Entry_ | |
def copy_metadata(path) | |
st = lstat() | |
if !st.symlink? | |
File.utime st.atime, st.mtime, path | |
end | |
begin | |
if st.symlink? | |
begin | |
File.lchown st.uid, st.gid, path | |
rescue NotImplementedError | |
end | |
else | |
File.chown st.uid, st.gid, path | |
end | |
rescue Errno::EPERM | |
# clear setuid/setgid | |
if st.symlink? | |
begin | |
File.lchmod st.mode & 01777, path | |
rescue NotImplementedError | |
end | |
else | |
File.chmod st.mode & 01777, path | |
end | |
else | |
if st.symlink? | |
begin | |
File.lchmod st.mode, path | |
rescue NotImplementedError | |
end | |
else | |
File.chmod st.mode, path | |
end | |
end | |
end | |
end | |
end | |
begin | |
Kernel.system "diskutil erasevolume HFS+ 'fileutilstmp' $(hdiutil attach -nomount ram://1024)" | |
Dir.mktmpdir do |dir| | |
Dir.chdir dir do | |
FileUtils.mkdir 'foo' | |
FileUtils.mkdir 'bar' | |
FileUtils.ln_s '../bar', 'foo/bar' | |
begin | |
FileUtils.mv 'foo', '/Volumes/fileutilstmp' | |
rescue Errno::ENOENT | |
puts "Ruby 1.8.7's FileUtils.mv blows." | |
end | |
end | |
end | |
ensure | |
Kernel.system "umount", "/Volumes/fileutilstmp" | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment