Bug #2731
closedFileUtils.copy prints error message in $DEBUG mode when destination doesn't exist
Description
=begin
Trying to copy a file with Ruby:
$ touch source
$ ls destination
ls: destination: No such file or directory
$ ruby -rfileutils -d -e 'FileUtils.copy "source", "destination"'
Exception `Errno::ENOENT' at /usr/local/lib/ruby/1.9.1/fileutils.rb:1429 - No such file or directory - destination
$ ls destination
destination
While the copy succeeds, it prints this confusing message. I don't expect libraries to issue exceptions when performing standard operations. This affects the FileUtils methods install, mv, cp_r, and cp; but the problem is in Entry_#fu_same? (around lib/fileutils.rb:1426):
def fu_same?(a, b) #:nodoc:
if fu_have_st_ino?
st1 = File.stat(a)
st2 = File.stat(b)
st1.dev == st2.dev and st1.ino == st2.ino
else
File.expand_path(a) == File.expand_path(b)
end
rescue Errno::ENOENT
return false
end
So, File.stat(b) is checked even if b doesn't exist. The resulting error message is even explicitely captured and hidden by the rescue. For the methods in question, it is a common case that the destination file doesn't exist.
Here's a version that doesn't rely on exceptions:
def fu_same?(a, b) #:nodoc:
return false if !File.exist?(a) || !File.exist?(b)
if fu_have_st_ino?
st1 = File.stat(a)
st2 = File.stat(b)
st1.dev == st2.dev and st1.ino == st2.ino
else
File.expand_path(a) == File.expand_path(b)
end
end
The problem exists across Ruby versions from 1.8.6 to 1.9.2dev.
=end
Updated by mame (Yusuke Endoh) over 14 years ago
- Status changed from Open to Rejected
=begin
Hi,
2010/2/10 Kornelius Kalnbach redmine@ruby-lang.org:
Trying to copy a file with Ruby:
$ touch source
$ ls destination
ls: destination: No such file or directory
$ ruby -rfileutils -d -e 'FileUtils.copy "source", "destination"'
Exception `Errno::ENOENT' at /usr/local/lib/ruby/1.9.1/fileutils.rb:1429 - No such file or directory - destination
$ ls destination
destinationWhile the copy succeeds, it prints this confusing message.
You say, library must not use an exception for internal implementation?
The convension is uneasy and too uncomfortable for library authors.
In old convension, an exception might be for exceptional condition.
But currently, it has many use cases not only to represent exceptional
condition but also to represent normal condition (e.g., StopIteration),
to control execution (e.g., DSL), etc.
So this is not a bug and I close the ticket.
Rather, we should reconsider the purpose and behavior of $DEBUG.
Currently, it is worthless in effect.
--
Yusuke ENDOH mame@tsg.ne.jp
=end
Updated by murphy (Kornelius Kalnbach) over 14 years ago
=begin
On 11.04.10 16:08, Yusuke Endoh wrote:
You say, library must not use an exception for internal implementation?
The convension is uneasy and too uncomfortable for library authors.In old convension, an exception might be for exceptional condition.
But currently, it has many use cases not only to represent exceptional
condition but also to represent normal condition (e.g., StopIteration),
to control execution (e.g., DSL), etc.
You're right. I agree that it's not a bug, more like an inconvenient
behavior. The patch might still be an improvement.
The only workaround I know is:
debug, $DEBUG = $DEBUG, false
FileUtils.copy source, destination
$DEBUG = debug
I don't like such constructs because they look ugly (aka "noise").
So this is not a bug and I close the ticket.
Rather, we should reconsider the purpose and behavior of $DEBUG.
Currently, it is worthless in effect.
Spontaneous idea: Setting $DEBUG to an Exception class or an array of
such classes to specify which exception you want to debug. Improving
Rubys debugging capabilities can't hurt.
[murphy]
=end