Bug #2731

FileUtils.copy prints error message in $DEBUG mode when destination doesn't exist

Added by murphy (Kornelius Kalnbach) over 2 years ago. Updated about 1 year ago.

[ruby-core:28141]
Status:Rejected Start date:02/10/2010
Priority:Normal Due date:
Assignee:- % Done:

0%

Category:-
Target version:-
ruby -v:ruby 1.9.2dev (2010-02-04 trunk 26573) [i386-darwin10.2.0]

Description

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.

Associated revisions

Revision 27317
Added by nobu (Nobuyoshi Nakada) about 2 years ago

* lib/fileutils.rb (fu_each_src_dest): ensure src is accessible. * lib/fileutils.rb (fu_same): use File.identical? to get rid of exceptions. [ruby-core:28141] * lib/fileutils.rb (fu_have_st_ino): no longer used.

History

Updated by mame (Yusuke Endoh) about 2 years ago

  • Status changed from Open to Rejected
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
> destination
>
> While 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>

Updated by murphy (Kornelius Kalnbach) about 2 years ago

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]

Also available in: Atom PDF