Trapping errors.

Discussion in 'Ruby' started by Hugh Sasse, Oct 31, 2005.

  1. Hugh Sasse

    Hugh Sasse Guest

    begin
    #...
    rescue => e
    #...
    end

    will trap e if it is a StandardError. SystemCallErrrors are
    supposed to handle Errorcodes from the OS. All of these are
    subclasses of Exception. So why do I get this failure under Cygwin:

    $ ruby BACKUP.RB "C:\\" "D:\\buzz_c"
    cp -rp C:\ D:\buzz_c
    /usr/lib/ruby/1.8/new_fileutils.rb:1251:in `initialize': Device or resource busy
    - C:\/WINDOWS/WIN386.SWP (Errno::EBUSY)
    from /usr/lib/ruby/1.8/new_fileutils.rb:1251:in `copy_file'
    from /usr/lib/ruby/1.8/new_fileutils.rb:1221:in `copy'
    from /usr/lib/ruby/1.8/new_fileutils.rb:455:in `copy_entry'
    from /usr/lib/ruby/1.8/new_fileutils.rb:1314:in `traverse'
    from /usr/lib/ruby/1.8/new_fileutils.rb:453:in `copy_entry'
    from /usr/lib/ruby/1.8/new_fileutils.rb:424:in `cp_r'
    from /usr/lib/ruby/1.8/new_fileutils.rb:1385:in `fu_each_src_dest'
    from /usr/lib/ruby/1.8/new_fileutils.rb:1401:in `fu_each_src_dest0'
    from /usr/lib/ruby/1.8/new_fileutils.rb:1383:in `fu_each_src_dest'
    from /usr/lib/ruby/1.8/new_fileutils.rb:422:in `cp_r'
    from BACKUP.RB:27

    hgs@buzz ~/downloads

    when my modified FileUtils.cp_r has

    begin
    copy_entry ...
    rescue Exception => e
    logger.error("backup"){"Error was #{e}")
    end

    (essentially. Theres a bit more to it than that, but the details
    shouldn't matter for my question.) So why can't I rescue it? (I'm
    trying to log, and skip files I can't backup so at least I get most
    of the files, and know which ones I have not.)

    Anyone also reading ruby-core will realize that my patch didn't work
    in practice.

    Thank you,
    Hugh
     
    Hugh Sasse, Oct 31, 2005
    #1
    1. Advertising

  2. Hugh Sasse <> wrote:
    > begin
    > #...
    > rescue => e
    > #...
    > end
    >
    > will trap e if it is a StandardError. SystemCallErrrors are
    > supposed to handle Errorcodes from the OS. All of these are
    > subclasses of Exception. So why do I get this failure under Cygwin:
    >
    > $ ruby BACKUP.RB "C:\\" "D:\\buzz_c"
    > cp -rp C:\ D:\buzz_c
    > /usr/lib/ruby/1.8/new_fileutils.rb:1251:in `initialize': Device or
    > resource busy - C:\/WINDOWS/WIN386.SWP (Errno::EBUSY)
    > from /usr/lib/ruby/1.8/new_fileutils.rb:1251:in `copy_file'
    > from /usr/lib/ruby/1.8/new_fileutils.rb:1221:in `copy'
    > from /usr/lib/ruby/1.8/new_fileutils.rb:455:in `copy_entry'
    > from /usr/lib/ruby/1.8/new_fileutils.rb:1314:in `traverse'
    > from /usr/lib/ruby/1.8/new_fileutils.rb:453:in `copy_entry'
    > from /usr/lib/ruby/1.8/new_fileutils.rb:424:in `cp_r'
    > from /usr/lib/ruby/1.8/new_fileutils.rb:1385:in
    > `fu_each_src_dest' from
    > /usr/lib/ruby/1.8/new_fileutils.rb:1401:in `fu_each_src_dest0'
    > from /usr/lib/ruby/1.8/new_fileutils.rb:1383:in
    > `fu_each_src_dest' from
    > /usr/lib/ruby/1.8/new_fileutils.rb:422:in `cp_r' from BACKUP.RB:27
    >
    > hgs@buzz ~/downloads
    >
    > when my modified FileUtils.cp_r has
    >
    > begin
    > copy_entry ...
    > rescue Exception => e
    > logger.error("backup"){"Error was #{e}")
    > end
    >
    > (essentially. Theres a bit more to it than that, but the details
    > shouldn't matter for my question.) So why can't I rescue it? (I'm
    > trying to log, and skip files I can't backup so at least I get most
    > of the files, and know which ones I have not.)


    Maybe it's in another thread. Or your code is actually not between "begin"
    and "rescue" but outside of that.

    Kind regards

    robert
     
    Robert Klemme, Nov 1, 2005
    #2
    1. Advertising

  3. Hugh Sasse

    Hugh Sasse Guest

    On Tue, 1 Nov 2005, Robert Klemme wrote:

    > Hugh Sasse <> wrote:
    > > begin
    > > #...
    > > rescue => e
    > > #...
    > > end
    > >
    > > will trap e if it is a StandardError. SystemCallErrrors are
    > > supposed to handle Errorcodes from the OS. All of these are
    > > subclasses of Exception. So why do I get this failure under Cygwin:
    > >
    > > $ ruby BACKUP.RB "C:\\" "D:\\buzz_c"
    > > cp -rp C:\ D:\buzz_c
    > > /usr/lib/ruby/1.8/new_fileutils.rb:1251:in `initialize': Device or
    > > resource busy - C:\/WINDOWS/WIN386.SWP (Errno::EBUSY)
    > > from /usr/lib/ruby/1.8/new_fileutils.rb:1251:in `copy_file'
    > > from /usr/lib/ruby/1.8/new_fileutils.rb:1221:in `copy'
    > > from /usr/lib/ruby/1.8/new_fileutils.rb:455:in `copy_entry'
    > > from /usr/lib/ruby/1.8/new_fileutils.rb:1314:in `traverse'
    > > from /usr/lib/ruby/1.8/new_fileutils.rb:453:in `copy_entry'
    > > from /usr/lib/ruby/1.8/new_fileutils.rb:424:in `cp_r'
    > > from /usr/lib/ruby/1.8/new_fileutils.rb:1385:in
    > > `fu_each_src_dest' from
    > > /usr/lib/ruby/1.8/new_fileutils.rb:1401:in `fu_each_src_dest0'
    > > from /usr/lib/ruby/1.8/new_fileutils.rb:1383:in
    > > `fu_each_src_dest' from
    > > /usr/lib/ruby/1.8/new_fileutils.rb:422:in `cp_r' from BACKUP.RB:27
    > >
    > > hgs@buzz ~/downloads
    > >
    > > when my modified FileUtils.cp_r has
    > >
    > > begin
    > > copy_entry ...
    > > rescue Exception => e
    > > logger.error("backup"){"Error was #{e}")
    > > end
    > >
    > > (essentially. Theres a bit more to it than that, but the details
    > > shouldn't matter for my question.) So why can't I rescue it? (I'm
    > > trying to log, and skip files I can't backup so at least I get most
    > > of the files, and know which ones I have not.)

    >
    > Maybe it's in another thread. Or your code is actually not between "begin"
    > and "rescue" but outside of that.


    there's no threading in there, and I'm pretty certain it is within
    that, because it is in the call to copy_entry

    >
    > Kind regards
    >
    > robert
    >


    The modified fileutils is (heavily pruned) below
    I've changed cp_r.

    Hugh

    #
    # = fileutils.rb
    #
    # Copyright (c) 2000-2005 Minero Aoki <>
    #
    # This program is free software.
    # You can distribute/modify this program under the same terms of ruby.
    #
    # == module FileUtils
    #
    # Namespace for several file utility methods for copying, moving, removing, etc.
    #
    # === Module Functions
    #
    # [...]
    # cp_r(src, dest, options) {|s,d,e|...}
    # cp_r(list, dir, options) {|s,d,e|...}
    # [...]
    #
    # The <tt>options</tt> parameter is a hash of options, taken from the list
    # <tt>:force</tt>, <tt>:noop</tt>, <tt>:preserve</tt>, and <tt>:verbose</tt>.
    # <tt>:noop</tt> means that no changes are made. The other two are obvious.
    # Each method documents the options that it honours.
    #
    # All methods that have the concept of a "source" file or directory can take
    # either one file or a list of files in that argument. See the method
    # documentation for examples.
    #
    # There are some `low level' methods, which do not accept any option:
    #
    # copy_entry(src, dest, preserve = false, dereference = false)
    # copy_file(src, dest, preserve = false, dereference = true)
    # [...]
    #
    # == module FileUtils::Verbose
    #
    # This module has all methods of FileUtils module, but it outputs messages
    # before acting. This equates to passing the <tt>:verbose</tt> flag to methods
    # in FileUtils.
    #
    # == module FileUtils::NoWrite
    #
    # This module has all methods of FileUtils module, but never changes
    # files/directories. This equates to passing the <tt>:noop</tt> flag to methods
    # in FileUtils.
    #
    # == module FileUtils::DryRun
    #
    # This module has all methods of FileUtils module, but never changes
    # files/directories. This equates to passing the <tt>:noop</tt> and
    # <tt>:verbose</tt> flags to methods in FileUtils.
    #

    module FileUtils

    def self.private_module_function(name) #:nodoc:
    module_function name
    private_class_method name
    end

    # This hash table holds command options.
    OPT_TABLE = {} #:nodoc: internal use only

    # [...]

    def fu_mkdir(path, mode) #:nodoc:
    path = path.sub(%r</\z>, '')
    if mode
    Dir.mkdir path, mode
    File.chmod mode, path
    else
    Dir.mkdir path
    end
    end
    private_module_function :fu_mkdir

    # [...]

    #
    # Options: preserve noop verbose dereference_root
    #
    # Copies +src+ to +dest+. If +src+ is a directory, this method copies
    # all its contents recursively. If +dest+ is a directory, copies
    # +src+ to +dest/src+.
    #
    # +src+ can be a list of files.
    #
    # # Installing ruby library "mylib" under the site_ruby
    # FileUtils.rm_r site_ruby + '/mylib', :force
    # FileUtils.cp_r 'lib/', site_ruby + '/mylib'
    #
    # # Examples of copying several files to target directory.
    # FileUtils.cp_r %w(mail.rb field.rb debug/), site_ruby + '/tmail'
    # FileUtils.cp_r Dir.glob('*.rb'), '/home/aamine/lib/ruby', :noop => true, :verbose => true
    #
    # # If you want to copy all contents of a directory instead of the
    # # directory itself, c.f. src/x -> dest/x, src/y -> dest/y,
    # # use following code.
    # FileUtils.cp_r 'src/.', 'dest' # cp_r('src', 'dest') makes src/dest,
    # # but this doesn't.
    #
    def cp_r(src, dest, options = {})
    fu_check_options options, :preserve, :noop, :verbose, :dereference_root
    fu_output_message "cp -r#{options[:preserve] ? 'p' : ''} #{[src,dest].flatten.join ' '}" if options[:verbose]
    return if options[:noop]
    options[:dereference_root] = true unless options.key?:)dereference_root)
    fu_each_src_dest(src, dest) do |s, d|
    begin
    copy_entry s, d, options[:preserve], options[:dereference_root]
    rescue Exception => e
    stop = true
    if block_given?
    stop = yield s,d,e
    end
    raise if stop
    end
    end
    end
    module_function :cp_r

    OPT_TABLE['cp_r'] = %w( noop verbose preserve dereference_root )

    #
    # Copies a file system entry +src+ to +dest+.
    # If +src+ is a directory, this method copies its contents recursively.
    # This method preserves file types, c.f. symlink, directory...
    # (FIFO, device files and etc. are not supported yet)
    #
    # Both of +src+ and +dest+ must be a path name.
    # +src+ must exist, +dest+ must not exist.
    #
    # If +preserve+ is true, this method preserves owner, group, permissions
    # and modified time.
    #
    # If +dereference_root+ is true, this method dereference tree root.
    #
    def copy_entry(src, dest, preserve = false, dereference_root = false)
    Entry_.new(src, nil, dereference_root).traverse do |ent|
    destent = Entry_.new(dest, ent.rel, false)
    ent.copy destent.path
    ent.copy_metadata destent.path if preserve
    end
    end
    module_function :copy_entry

    #
    # Copies file contents of +src+ to +dest+.
    # Both of +src+ and +dest+ must be a path name.
    #
    def copy_file(src, dest, preserve = false, dereference = true)
    ent = Entry_.new(src, nil, dereference)
    ent.copy_file dest
    ent.copy_metadata dest if preserve
    end
    module_function :copy_file

    # [...]


    class Entry_ #:nodoc: internal use only
    include StreamUtils_

    def initialize(a, b = nil, deref = false)
    @prefix = @rel = @path = nil
    if b
    @prefix = a
    @rel = b
    else
    @path = a
    end
    @deref = deref
    @stat = nil
    @lstat = nil
    end

    def inspect
    "\#<#{self.class} #{path()}>"
    end

    def path
    if @path
    @path.to_str
    else
    join(@prefix, @rel)
    end
    end

    def prefix
    @prefix || @path
    end

    def rel
    @rel
    end

    def dereference?
    @deref
    end

    def exist?
    lstat! ? true : false
    end

    def file?
    s = lstat!
    s and s.file?
    end

    def directory?
    s = lstat!
    s and s.directory?
    end

    def symlink?
    s = lstat!
    s and s.symlink?
    end

    def chardev?
    s = lstat!
    s and s.chardev?
    end

    def blockdev?
    s = lstat!
    s and s.blockdev?
    end

    def socket?
    s = lstat!
    s and s.socket?
    end

    def pipe?
    s = lstat!
    s and s.pipe?
    end

    S_IF_DOOR = 0xD000

    def door?
    s = lstat!
    s and (s.mode & 0xF000 == S_IF_DOOR)
    end

    def entries
    Dir.entries(path())\
    .reject {|n| n == '.' or n == '..' }\
    .map {|n| Entry_.new(prefix(), join(rel(), n.untaint)) }
    end

    def stat
    return @stat if @stat
    if lstat() and lstat().symlink?
    @stat = File.stat(path())
    else
    @stat = lstat()
    end
    @stat
    end

    def stat!
    return @stat if @stat
    if lstat! and lstat!.symlink?
    @stat = File.stat(path())
    else
    @stat = lstat!
    end
    @stat
    rescue SystemCallError
    nil
    end

    def lstat
    if dereference?
    @lstat ||= File.stat(path())
    else
    @lstat ||= File.lstat(path())
    end
    end

    def lstat!
    lstat()
    rescue SystemCallError
    nil
    end

    def chmod(mode)
    if symlink?
    File.lchmod mode, path() if have_lchmod?
    else
    File.chmod mode, path()
    end
    end

    def chown(uid, gid)
    if symlink?
    File.lchown uid, gid, path() if have_lchown?
    else
    File.chown uid, gid, path()
    end
    end

    def copy(dest)
    case
    when file?
    copy_file dest
    when directory?
    begin
    Dir.mkdir dest
    rescue
    raise unless File.directory?(dest)
    end
    when symlink?
    File.symlink File.readlink(path()), dest
    when chardev?
    raise "cannot handle device file" unless File.respond_to?:)mknod)
    mknod dest, ?c, 0666, lstat().rdev
    when blockdev?
    raise "cannot handle device file" unless File.respond_to?:)mknod)
    mknod dest, ?b, 0666, lstat().rdev
    when socket?
    raise "cannot handle socket" unless File.respond_to?:)mknod)
    mknod dest, nil, lstat().mode, 0
    when pipe?
    raise "cannot handle FIFO" unless File.respond_to?:)mkfifo)
    mkfifo dest, 0666
    when door?
    raise "cannot handle door: #{path()}"
    else
    raise "unknown file type: #{path()}"
    end
    end

    def copy_file(dest)
    st = stat()
    File.open(path(), 'rb') {|r|
    File.open(dest, 'wb', st.mode) {|w|
    fu_copy_stream0 r, w, (fu_blksize(st) || fu_default_blksize())
    }
    }
    end

    def copy_metadata(path)
    st = lstat()
    File.utime st.atime, st.mtime, path
    begin
    File.chown st.uid, st.gid, path
    rescue Errno::EPERM
    # clear setuid/setgid
    File.chmod st.mode & 01777, path
    else
    File.chmod st.mode, path
    end
    end

    # [...]

    def platform_support
    return yield unless fu_windows?
    first_time_p = true
    begin
    yield
    rescue Errno::ENOENT
    raise
    rescue => err
    if first_time_p
    first_time_p = false
    begin
    File.chmod 0700, path() # Windows does not have symlink
    retry
    rescue SystemCallError
    end
    end
    raise err
    end
    end

    def preorder_traverse
    stack = [self]
    while ent = stack.pop
    yield ent
    stack.concat ent.entries.reverse if ent.directory?
    end
    end

    alias traverse preorder_traverse

    def postorder_traverse
    if directory?
    entries().each do |ent|
    ent.postorder_traverse do |e|
    yield e
    end
    end
    end
    yield self
    end


    # [...]

    def join(dir, base)
    return dir.to_str if not base or base == '.'
    return base.to_str if not dir or dir == '.'
    File.join(dir, base)
    end
    end # class Entry_

    def fu_list(arg) #:nodoc:
    [arg].flatten.map {|path| path.to_str }
    end
    private_module_function :fu_list

    def fu_each_src_dest(src, dest) #:nodoc:
    fu_each_src_dest0(src, dest) do |s, d|
    raise ArgumentError, "same file: #{s} and #{d}" if fu_same?(s, d)
    yield s, d
    end
    end
    private_module_function :fu_each_src_dest

    def fu_each_src_dest0(src, dest) #:nodoc:
    if src.is_a?(Array)
    src.each do |s|
    s = s.to_str
    yield s, File.join(dest, File.basename(s))
    end
    else
    src = src.to_str
    if File.directory?(dest)
    yield src, File.join(dest, File.basename(src))
    else
    yield src, dest.to_str
    end
    end
    end
    private_module_function :fu_each_src_dest0

    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
    private_module_function :fu_same?

    def fu_have_st_ino? #:nodoc:
    not fu_windows?
    end
    private_module_function :fu_have_st_ino?

    def fu_check_options(options, *optdecl) #:nodoc:
    h = options.dup
    optdecl.each do |name|
    h.delete name
    end
    raise ArgumentError, "no such option: #{h.keys.join(' ')}" unless h.empty?
    end
    private_module_function :fu_check_options

    def fu_update_option(args, new) #:nodoc:
    if args.last.is_a?(Hash)
    args[-1] = args.last.dup.update(new)
    else
    args.push new
    end
    args
    end
    private_module_function :fu_update_option

    @fileutils_output = $stderr
    @fileutils_label = ''

    def fu_output_message(msg) #:nodoc:
    @fileutils_output ||= $stderr
    @fileutils_label ||= ''
    @fileutils_output.puts @fileutils_label + msg
    end
    private_module_function :fu_output_message

    #
    # Returns an Array of method names which have any options.
    #
    # p FileUtils.commands #=> ["chmod", "cp", "cp_r", "install", ...]
    #
    def FileUtils.commands
    OPT_TABLE.keys
    end

    #
    # Returns an Array of option names.
    #
    # p FileUtils.options #=> ["noop", "force", "verbose", "preserve", "mode"]
    #
    def FileUtils.options
    OPT_TABLE.values.flatten.uniq
    end

    #
    # Returns true if the method +mid+ have an option +opt+.
    #
    # p FileUtils.have_option?:)cp, :noop) #=> true
    # p FileUtils.have_option?:)rm, :force) #=> true
    # p FileUtils.have_option?:)rm, :perserve) #=> false
    #
    def FileUtils.have_option?(mid, opt)
    li = OPT_TABLE[mid.to_s] or raise ArgumentError, "no such method: #{mid}"
    li.include?(opt.to_s)
    end

    #
    # Returns an Array of option names of the method +mid+.
    #
    # p FileUtils.options:)rm) #=> ["noop", "verbose", "force"]
    #
    def FileUtils.options_of(mid)
    OPT_TABLE[mid.to_s]
    end

    # [...]

    end
     
    Hugh Sasse, Nov 1, 2005
    #3
  4. Hugh Sasse

    Hugh Sasse Guest

    I see my changes to fileutils are now in the Ruby CVS.
    However, even with
    rescue Exception, SystemCallError => e
    or
    rescue Exception, Errno::EACCES, Errno::EBUSY => e

    I still cannot trap this error. From the call stack this part of
    the code is being used, so why won't the error cause ruby to go back
    up the callstack until it finds this rescue clause?

    Hugh

    On Tue, 1 Nov 2005, Hugh Sasse wrote:

    > On Tue, 1 Nov 2005, Robert Klemme wrote:
    >
    > > Hugh Sasse <> wrote:
    > > > begin
    > > > #...
    > > > rescue => e
    > > > #...
    > > > end
    > > >
    > > > will trap e if it is a StandardError. SystemCallErrrors are
    > > > supposed to handle Errorcodes from the OS. All of these are
    > > > subclasses of Exception. So why do I get this failure under Cygwin:
    > > >
    > > > $ ruby BACKUP.RB "C:\\" "D:\\buzz_c"
    > > > cp -rp C:\ D:\buzz_c
    > > > /usr/lib/ruby/1.8/new_fileutils.rb:1251:in `initialize': Device or
    > > > resource busy - C:\/WINDOWS/WIN386.SWP (Errno::EBUSY)
    > > > from /usr/lib/ruby/1.8/new_fileutils.rb:1251:in `copy_file'
    > > > from /usr/lib/ruby/1.8/new_fileutils.rb:1221:in `copy'
    > > > from /usr/lib/ruby/1.8/new_fileutils.rb:455:in `copy_entry'
    > > > from /usr/lib/ruby/1.8/new_fileutils.rb:1314:in `traverse'
    > > > from /usr/lib/ruby/1.8/new_fileutils.rb:453:in `copy_entry'
    > > > from /usr/lib/ruby/1.8/new_fileutils.rb:424:in `cp_r'
    > > > from /usr/lib/ruby/1.8/new_fileutils.rb:1385:in
    > > > `fu_each_src_dest' from
    > > > /usr/lib/ruby/1.8/new_fileutils.rb:1401:in `fu_each_src_dest0'
    > > > from /usr/lib/ruby/1.8/new_fileutils.rb:1383:in
    > > > `fu_each_src_dest' from
    > > > /usr/lib/ruby/1.8/new_fileutils.rb:422:in `cp_r' from BACKUP.RB:27
    > > >
    > > > hgs@buzz ~/downloads
    > > >
    > > > when my modified FileUtils.cp_r has
    > > >
    > > > begin
    > > > copy_entry ...
    > > > rescue Exception => e
    > > > logger.error("backup"){"Error was #{e}")
    > > > end
    > > >
    > > > (essentially. Theres a bit more to it than that, but the details
    > > > shouldn't matter for my question.) So why can't I rescue it? (I'm
    > > > trying to log, and skip files I can't backup so at least I get most
    > > > of the files, and know which ones I have not.)

    > >
    > > Maybe it's in another thread. Or your code is actually not between "begin"
    > > and "rescue" but outside of that.

    >
    > there's no threading in there, and I'm pretty certain it is within
    > that, because it is in the call to copy_entry
    >
    > >
    > > Kind regards
    > >
    > > robert
    > >

    >
    > The modified fileutils is (heavily pruned) below
    > I've changed cp_r.
    >
    > Hugh
    >
    > #
    > # = fileutils.rb
    > #
    > # Copyright (c) 2000-2005 Minero Aoki <>
    > #
    > # This program is free software.
    > # You can distribute/modify this program under the same terms of ruby.
    > #
    > # == module FileUtils
    > #
    > # Namespace for several file utility methods for copying, moving, removing, etc.
    > #
    > # === Module Functions
    > #
    > # [...]
    > # cp_r(src, dest, options) {|s,d,e|...}
    > # cp_r(list, dir, options) {|s,d,e|...}
    > # [...]
    > #
    > # The <tt>options</tt> parameter is a hash of options, taken from the list
    > # <tt>:force</tt>, <tt>:noop</tt>, <tt>:preserve</tt>, and <tt>:verbose</tt>.
    > # <tt>:noop</tt> means that no changes are made. The other two are obvious.
    > # Each method documents the options that it honours.
    > #
    > # All methods that have the concept of a "source" file or directory can take
    > # either one file or a list of files in that argument. See the method
    > # documentation for examples.
    > #
    > # There are some `low level' methods, which do not accept any option:
    > #
    > # copy_entry(src, dest, preserve = false, dereference = false)
    > # copy_file(src, dest, preserve = false, dereference = true)
    > # [...]
    > #
    > # == module FileUtils::Verbose
    > #
    > # This module has all methods of FileUtils module, but it outputs messages
    > # before acting. This equates to passing the <tt>:verbose</tt> flag to methods
    > # in FileUtils.
    > #
    > # == module FileUtils::NoWrite
    > #
    > # This module has all methods of FileUtils module, but never changes
    > # files/directories. This equates to passing the <tt>:noop</tt> flag to methods
    > # in FileUtils.
    > #
    > # == module FileUtils::DryRun
    > #
    > # This module has all methods of FileUtils module, but never changes
    > # files/directories. This equates to passing the <tt>:noop</tt> and
    > # <tt>:verbose</tt> flags to methods in FileUtils.
    > #
    >
    > module FileUtils
    >
    > def self.private_module_function(name) #:nodoc:
    > module_function name
    > private_class_method name
    > end
    >
    > # This hash table holds command options.
    > OPT_TABLE = {} #:nodoc: internal use only
    >
    > # [...]
    >
    > def fu_mkdir(path, mode) #:nodoc:
    > path = path.sub(%r</\z>, '')
    > if mode
    > Dir.mkdir path, mode
    > File.chmod mode, path
    > else
    > Dir.mkdir path
    > end
    > end
    > private_module_function :fu_mkdir
    >
    > # [...]
    >
    > #
    > # Options: preserve noop verbose dereference_root
    > #
    > # Copies +src+ to +dest+. If +src+ is a directory, this method copies
    > # all its contents recursively. If +dest+ is a directory, copies
    > # +src+ to +dest/src+.
    > #
    > # +src+ can be a list of files.
    > #
    > # # Installing ruby library "mylib" under the site_ruby
    > # FileUtils.rm_r site_ruby + '/mylib', :force
    > # FileUtils.cp_r 'lib/', site_ruby + '/mylib'
    > #
    > # # Examples of copying several files to target directory.
    > # FileUtils.cp_r %w(mail.rb field.rb debug/), site_ruby + '/tmail'
    > # FileUtils.cp_r Dir.glob('*.rb'), '/home/aamine/lib/ruby', :noop => true, :verbose => true
    > #
    > # # If you want to copy all contents of a directory instead of the
    > # # directory itself, c.f. src/x -> dest/x, src/y -> dest/y,
    > # # use following code.
    > # FileUtils.cp_r 'src/.', 'dest' # cp_r('src', 'dest') makes src/dest,
    > # # but this doesn't.
    > #
    > def cp_r(src, dest, options = {})
    > fu_check_options options, :preserve, :noop, :verbose, :dereference_root
    > fu_output_message "cp -r#{options[:preserve] ? 'p' : ''} #{[src,dest].flatten.join ' '}" if options[:verbose]
    > return if options[:noop]
    > options[:dereference_root] = true unless options.key?:)dereference_root)
    > fu_each_src_dest(src, dest) do |s, d|
    > begin
    > copy_entry s, d, options[:preserve], options[:dereference_root]
    > rescue Exception => e
    > stop = true
    > if block_given?
    > stop = yield s,d,e
    > end
    > raise if stop
    > end
    > end
    > end
    > module_function :cp_r
    >
    > OPT_TABLE['cp_r'] = %w( noop verbose preserve dereference_root )
    >
    > #
    > # Copies a file system entry +src+ to +dest+.
    > # If +src+ is a directory, this method copies its contents recursively.
    > # This method preserves file types, c.f. symlink, directory...
    > # (FIFO, device files and etc. are not supported yet)
    > #
    > # Both of +src+ and +dest+ must be a path name.
    > # +src+ must exist, +dest+ must not exist.
    > #
    > # If +preserve+ is true, this method preserves owner, group, permissions
    > # and modified time.
    > #
    > # If +dereference_root+ is true, this method dereference tree root.
    > #
    > def copy_entry(src, dest, preserve = false, dereference_root = false)
    > Entry_.new(src, nil, dereference_root).traverse do |ent|
    > destent = Entry_.new(dest, ent.rel, false)
    > ent.copy destent.path
    > ent.copy_metadata destent.path if preserve
    > end
    > end
    > module_function :copy_entry
    >
    > #
    > # Copies file contents of +src+ to +dest+.
    > # Both of +src+ and +dest+ must be a path name.
    > #
    > def copy_file(src, dest, preserve = false, dereference = true)
    > ent = Entry_.new(src, nil, dereference)
    > ent.copy_file dest
    > ent.copy_metadata dest if preserve
    > end
    > module_function :copy_file
    >
    > # [...]
    >
    >
    > class Entry_ #:nodoc: internal use only
    > include StreamUtils_
    >
    > def initialize(a, b = nil, deref = false)
    > @prefix = @rel = @path = nil
    > if b
    > @prefix = a
    > @rel = b
    > else
    > @path = a
    > end
    > @deref = deref
    > @stat = nil
    > @lstat = nil
    > end
    >
    > def inspect
    > "\#<#{self.class} #{path()}>"
    > end
    >
    > def path
    > if @path
    > @path.to_str
    > else
    > join(@prefix, @rel)
    > end
    > end
    >
    > def prefix
    > @prefix || @path
    > end
    >
    > def rel
    > @rel
    > end
    >
    > def dereference?
    > @deref
    > end
    >
    > def exist?
    > lstat! ? true : false
    > end
    >
    > def file?
    > s = lstat!
    > s and s.file?
    > end
    >
    > def directory?
    > s = lstat!
    > s and s.directory?
    > end
    >
    > def symlink?
    > s = lstat!
    > s and s.symlink?
    > end
    >
    > def chardev?
    > s = lstat!
    > s and s.chardev?
    > end
    >
    > def blockdev?
    > s = lstat!
    > s and s.blockdev?
    > end
    >
    > def socket?
    > s = lstat!
    > s and s.socket?
    > end
    >
    > def pipe?
    > s = lstat!
    > s and s.pipe?
    > end
    >
    > S_IF_DOOR = 0xD000
    >
    > def door?
    > s = lstat!
    > s and (s.mode & 0xF000 == S_IF_DOOR)
    > end
    >
    > def entries
    > Dir.entries(path())\
    > .reject {|n| n == '.' or n == '..' }\
    > .map {|n| Entry_.new(prefix(), join(rel(), n.untaint)) }
    > end
    >
    > def stat
    > return @stat if @stat
    > if lstat() and lstat().symlink?
    > @stat = File.stat(path())
    > else
    > @stat = lstat()
    > end
    > @stat
    > end
    >
    > def stat!
    > return @stat if @stat
    > if lstat! and lstat!.symlink?
    > @stat = File.stat(path())
    > else
    > @stat = lstat!
    > end
    > @stat
    > rescue SystemCallError
    > nil
    > end
    >
    > def lstat
    > if dereference?
    > @lstat ||= File.stat(path())
    > else
    > @lstat ||= File.lstat(path())
    > end
    > end
    >
    > def lstat!
    > lstat()
    > rescue SystemCallError
    > nil
    > end
    >
    > def chmod(mode)
    > if symlink?
    > File.lchmod mode, path() if have_lchmod?
    > else
    > File.chmod mode, path()
    > end
    > end
    >
    > def chown(uid, gid)
    > if symlink?
    > File.lchown uid, gid, path() if have_lchown?
    > else
    > File.chown uid, gid, path()
    > end
    > end
    >
    > def copy(dest)
    > case
    > when file?
    > copy_file dest
    > when directory?
    > begin
    > Dir.mkdir dest
    > rescue
    > raise unless File.directory?(dest)
    > end
    > when symlink?
    > File.symlink File.readlink(path()), dest
    > when chardev?
    > raise "cannot handle device file" unless File.respond_to?:)mknod)
    > mknod dest, ?c, 0666, lstat().rdev
    > when blockdev?
    > raise "cannot handle device file" unless File.respond_to?:)mknod)
    > mknod dest, ?b, 0666, lstat().rdev
    > when socket?
    > raise "cannot handle socket" unless File.respond_to?:)mknod)
    > mknod dest, nil, lstat().mode, 0
    > when pipe?
    > raise "cannot handle FIFO" unless File.respond_to?:)mkfifo)
    > mkfifo dest, 0666
    > when door?
    > raise "cannot handle door: #{path()}"
    > else
    > raise "unknown file type: #{path()}"
    > end
    > end
    >
    > def copy_file(dest)
    > st = stat()
    > File.open(path(), 'rb') {|r|
    > File.open(dest, 'wb', st.mode) {|w|
    > fu_copy_stream0 r, w, (fu_blksize(st) || fu_default_blksize())
    > }
    > }
    > end
    >
    > def copy_metadata(path)
    > st = lstat()
    > File.utime st.atime, st.mtime, path
    > begin
    > File.chown st.uid, st.gid, path
    > rescue Errno::EPERM
    > # clear setuid/setgid
    > File.chmod st.mode & 01777, path
    > else
    > File.chmod st.mode, path
    > end
    > end
    >
    > # [...]
    >
    > def platform_support
    > return yield unless fu_windows?
    > first_time_p = true
    > begin
    > yield
    > rescue Errno::ENOENT
    > raise
    > rescue => err
    > if first_time_p
    > first_time_p = false
    > begin
    > File.chmod 0700, path() # Windows does not have symlink
    > retry
    > rescue SystemCallError
    > end
    > end
    > raise err
    > end
    > end
    >
    > def preorder_traverse
    > stack = [self]
    > while ent = stack.pop
    > yield ent
    > stack.concat ent.entries.reverse if ent.directory?
    > end
    > end
    >
    > alias traverse preorder_traverse
    >
    > def postorder_traverse
    > if directory?
    > entries().each do |ent|
    > ent.postorder_traverse do |e|
    > yield e
    > end
    > end
    > end
    > yield self
    > end
    >
    >
    > # [...]
    >
    > def join(dir, base)
    > return dir.to_str if not base or base == '.'
    > return base.to_str if not dir or dir == '.'
    > File.join(dir, base)
    > end
    > end # class Entry_
    >
    > def fu_list(arg) #:nodoc:
    > [arg].flatten.map {|path| path.to_str }
    > end
    > private_module_function :fu_list
    >
    > def fu_each_src_dest(src, dest) #:nodoc:
    > fu_each_src_dest0(src, dest) do |s, d|
    > raise ArgumentError, "same file: #{s} and #{d}" if fu_same?(s, d)
    > yield s, d
    > end
    > end
    > private_module_function :fu_each_src_dest
    >
    > def fu_each_src_dest0(src, dest) #:nodoc:
    > if src.is_a?(Array)
    > src.each do |s|
    > s = s.to_str
    > yield s, File.join(dest, File.basename(s))
    > end
    > else
    > src = src.to_str
    > if File.directory?(dest)
    > yield src, File.join(dest, File.basename(src))
    > else
    > yield src, dest.to_str
    > end
    > end
    > end
    > private_module_function :fu_each_src_dest0
    >
    > 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
    > private_module_function :fu_same?
    >
    > def fu_have_st_ino? #:nodoc:
    > not fu_windows?
    > end
    > private_module_function :fu_have_st_ino?
    >
    > def fu_check_options(options, *optdecl) #:nodoc:
    > h = options.dup
    > optdecl.each do |name|
    > h.delete name
    > end
    > raise ArgumentError, "no such option: #{h.keys.join(' ')}" unless h.empty?
    > end
    > private_module_function :fu_check_options
    >
    > def fu_update_option(args, new) #:nodoc:
    > if args.last.is_a?(Hash)
    > args[-1] = args.last.dup.update(new)
    > else
    > args.push new
    > end
    > args
    > end
    > private_module_function :fu_update_option
    >
    > @fileutils_output = $stderr
    > @fileutils_label = ''
    >
    > def fu_output_message(msg) #:nodoc:
    > @fileutils_output ||= $stderr
    > @fileutils_label ||= ''
    > @fileutils_output.puts @fileutils_label + msg
    > end
    > private_module_function :fu_output_message
    >
    > #
    > # Returns an Array of method names which have any options.
    > #
    > # p FileUtils.commands #=> ["chmod", "cp", "cp_r", "install", ...]
    > #
    > def FileUtils.commands
    > OPT_TABLE.keys
    > end
    >
    > #
    > # Returns an Array of option names.
    > #
    > # p FileUtils.options #=> ["noop", "force", "verbose", "preserve", "mode"]
    > #
    > def FileUtils.options
    > OPT_TABLE.values.flatten.uniq
    > end
    >
    > #
    > # Returns true if the method +mid+ have an option +opt+.
    > #
    > # p FileUtils.have_option?:)cp, :noop) #=> true
    > # p FileUtils.have_option?:)rm, :force) #=> true
    > # p FileUtils.have_option?:)rm, :perserve) #=> false
    > #
    > def FileUtils.have_option?(mid, opt)
    > li = OPT_TABLE[mid.to_s] or raise ArgumentError, "no such method: #{mid}"
    > li.include?(opt.to_s)
    > end
    >
    > #
    > # Returns an Array of option names of the method +mid+.
    > #
    > # p FileUtils.options:)rm) #=> ["noop", "verbose", "force"]
    > #
    > def FileUtils.options_of(mid)
    > OPT_TABLE[mid.to_s]
    > end
    >
    > # [...]
    >
    > end
    >
    >
     
    Hugh Sasse, Nov 2, 2005
    #4
  5. Hugh Sasse wrote:
    > I see my changes to fileutils are now in the Ruby CVS.
    > However, even with
    > rescue Exception, SystemCallError => e
    > or
    > rescue Exception, Errno::EACCES, Errno::EBUSY => e
    >
    > I still cannot trap this error. From the call stack this part of
    > the code is being used, so why won't the error cause ruby to go back
    > up the callstack until it finds this rescue clause?


    Maybe there's another rescue clause that is closer to the place where the
    exception is thrown...

    robert

    >
    > Hugh
    >
    > On Tue, 1 Nov 2005, Hugh Sasse wrote:
    >
    >> On Tue, 1 Nov 2005, Robert Klemme wrote:
    >>
    >>> Hugh Sasse <> wrote:
    >>>> begin
    >>>> #...
    >>>> rescue => e
    >>>> #...
    >>>> end
    >>>>
    >>>> will trap e if it is a StandardError. SystemCallErrrors are
    >>>> supposed to handle Errorcodes from the OS. All of these are
    >>>> subclasses of Exception. So why do I get this failure under
    >>>> Cygwin:
    >>>>
    >>>> $ ruby BACKUP.RB "C:\\" "D:\\buzz_c"
    >>>> cp -rp C:\ D:\buzz_c
    >>>> /usr/lib/ruby/1.8/new_fileutils.rb:1251:in `initialize': Device or
    >>>> resource busy - C:\/WINDOWS/WIN386.SWP (Errno::EBUSY)
    >>>> from /usr/lib/ruby/1.8/new_fileutils.rb:1251:in `copy_file'
    >>>> from /usr/lib/ruby/1.8/new_fileutils.rb:1221:in `copy'
    >>>> from /usr/lib/ruby/1.8/new_fileutils.rb:455:in `copy_entry'
    >>>> from /usr/lib/ruby/1.8/new_fileutils.rb:1314:in `traverse'
    >>>> from /usr/lib/ruby/1.8/new_fileutils.rb:453:in `copy_entry'
    >>>> from /usr/lib/ruby/1.8/new_fileutils.rb:424:in `cp_r'
    >>>> from /usr/lib/ruby/1.8/new_fileutils.rb:1385:in
    >>>> `fu_each_src_dest' from
    >>>> /usr/lib/ruby/1.8/new_fileutils.rb:1401:in
    >>>> `fu_each_src_dest0' from
    >>>> /usr/lib/ruby/1.8/new_fileutils.rb:1383:in
    >>>> `fu_each_src_dest' from /usr/lib/ruby/1.8/new_fileutils.rb:422:in
    >>>> `cp_r' from BACKUP.RB:27
    >>>>
    >>>> hgs@buzz ~/downloads
    >>>>
    >>>> when my modified FileUtils.cp_r has
    >>>>
    >>>> begin
    >>>> copy_entry ...
    >>>> rescue Exception => e
    >>>> logger.error("backup"){"Error was #{e}")
    >>>> end
    >>>>
    >>>> (essentially. Theres a bit more to it than that, but the details
    >>>> shouldn't matter for my question.) So why can't I rescue it? (I'm
    >>>> trying to log, and skip files I can't backup so at least I get most
    >>>> of the files, and know which ones I have not.)
    >>>
    >>> Maybe it's in another thread. Or your code is actually not between
    >>> "begin" and "rescue" but outside of that.

    >>
    >> there's no threading in there, and I'm pretty certain it is within
    >> that, because it is in the call to copy_entry
    >>
    >>>
    >>> Kind regards
    >>>
    >>> robert
    >>>

    >>
    >> The modified fileutils is (heavily pruned) below
    >> I've changed cp_r.
    >>
    >> Hugh
    >>
    >> #
    >> # = fileutils.rb
    >> #
    >> # Copyright (c) 2000-2005 Minero Aoki <>
    >> #
    >> # This program is free software.
    >> # You can distribute/modify this program under the same terms of
    >> ruby. #
    >> # == module FileUtils
    >> #
    >> # Namespace for several file utility methods for copying, moving,
    >> removing, etc. #
    >> # === Module Functions
    >> #
    >> # [...]
    >> # cp_r(src, dest, options) {|s,d,e|...}
    >> # cp_r(list, dir, options) {|s,d,e|...}
    >> # [...]
    >> #
    >> # The <tt>options</tt> parameter is a hash of options, taken from
    >> the list # <tt>:force</tt>, <tt>:noop</tt>, <tt>:preserve</tt>, and
    >> <tt>:verbose</tt>. # <tt>:noop</tt> means that no changes are made.
    >> The other two are obvious. # Each method documents the options that
    >> it honours. #
    >> # All methods that have the concept of a "source" file or directory
    >> can take # either one file or a list of files in that argument. See
    >> the method # documentation for examples.
    >> #
    >> # There are some `low level' methods, which do not accept any option:
    >> #
    >> # copy_entry(src, dest, preserve = false, dereference = false)
    >> # copy_file(src, dest, preserve = false, dereference = true)
    >> # [...]
    >> #
    >> # == module FileUtils::Verbose
    >> #
    >> # This module has all methods of FileUtils module, but it outputs
    >> messages # before acting. This equates to passing the
    >> <tt>:verbose</tt> flag to methods # in FileUtils.
    >> #
    >> # == module FileUtils::NoWrite
    >> #
    >> # This module has all methods of FileUtils module, but never changes
    >> # files/directories. This equates to passing the <tt>:noop</tt>
    >> flag to methods # in FileUtils.
    >> #
    >> # == module FileUtils::DryRun
    >> #
    >> # This module has all methods of FileUtils module, but never changes
    >> # files/directories. This equates to passing the <tt>:noop</tt> and
    >> # <tt>:verbose</tt> flags to methods in FileUtils.
    >> #
    >>
    >> module FileUtils
    >>
    >> def self.private_module_function(name) #:nodoc:
    >> module_function name
    >> private_class_method name
    >> end
    >>
    >> # This hash table holds command options.
    >> OPT_TABLE = {} #:nodoc: internal use only
    >>
    >> # [...]
    >>
    >> def fu_mkdir(path, mode) #:nodoc:
    >> path = path.sub(%r</\z>, '')
    >> if mode
    >> Dir.mkdir path, mode
    >> File.chmod mode, path
    >> else
    >> Dir.mkdir path
    >> end
    >> end
    >> private_module_function :fu_mkdir
    >>
    >> # [...]
    >>
    >> #
    >> # Options: preserve noop verbose dereference_root
    >> #
    >> # Copies +src+ to +dest+. If +src+ is a directory, this method
    >> copies # all its contents recursively. If +dest+ is a directory,
    >> copies # +src+ to +dest/src+.
    >> #
    >> # +src+ can be a list of files.
    >> #
    >> # # Installing ruby library "mylib" under the site_ruby
    >> # FileUtils.rm_r site_ruby + '/mylib', :force
    >> # FileUtils.cp_r 'lib/', site_ruby + '/mylib'
    >> #
    >> # # Examples of copying several files to target directory.
    >> # FileUtils.cp_r %w(mail.rb field.rb debug/), site_ruby +
    >> '/tmail' # FileUtils.cp_r Dir.glob('*.rb'),
    >> '/home/aamine/lib/ruby', :noop => true, :verbose => true #
    >> # # If you want to copy all contents of a directory instead of
    >> the # # directory itself, c.f. src/x -> dest/x, src/y -> dest/y,
    >> # # use following code.
    >> # FileUtils.cp_r 'src/.', 'dest' # cp_r('src', 'dest') makes
    >> src/dest, # # but this
    >> doesn't. #
    >> def cp_r(src, dest, options = {})
    >> fu_check_options options, :preserve, :noop, :verbose,
    >> :dereference_root fu_output_message "cp -r#{options[:preserve] ?
    >> 'p' : ''} #{[src,dest].flatten.join ' '}" if options[:verbose]
    >> return if options[:noop] options[:dereference_root] = true
    >> unless options.key?:)dereference_root) fu_each_src_dest(src,
    >> dest) do |s, d| begin
    >> copy_entry s, d, options[:preserve],
    >> options[:dereference_root] rescue Exception => e
    >> stop = true
    >> if block_given?
    >> stop = yield s,d,e
    >> end
    >> raise if stop
    >> end
    >> end
    >> end
    >> module_function :cp_r
    >>
    >> OPT_TABLE['cp_r'] = %w( noop verbose preserve dereference_root )
    >>
    >> #
    >> # Copies a file system entry +src+ to +dest+.
    >> # If +src+ is a directory, this method copies its contents
    >> recursively. # This method preserves file types, c.f. symlink,
    >> directory... # (FIFO, device files and etc. are not supported yet)
    >> #
    >> # Both of +src+ and +dest+ must be a path name.
    >> # +src+ must exist, +dest+ must not exist.
    >> #
    >> # If +preserve+ is true, this method preserves owner, group,
    >> permissions # and modified time.
    >> #
    >> # If +dereference_root+ is true, this method dereference tree root.
    >> #
    >> def copy_entry(src, dest, preserve = false, dereference_root =
    >> false) Entry_.new(src, nil, dereference_root).traverse do |ent|
    >> destent = Entry_.new(dest, ent.rel, false)
    >> ent.copy destent.path
    >> ent.copy_metadata destent.path if preserve
    >> end
    >> end
    >> module_function :copy_entry
    >>
    >> #
    >> # Copies file contents of +src+ to +dest+.
    >> # Both of +src+ and +dest+ must be a path name.
    >> #
    >> def copy_file(src, dest, preserve = false, dereference = true)
    >> ent = Entry_.new(src, nil, dereference)
    >> ent.copy_file dest
    >> ent.copy_metadata dest if preserve
    >> end
    >> module_function :copy_file
    >>
    >> # [...]
    >>
    >>
    >> class Entry_ #:nodoc: internal use only
    >> include StreamUtils_
    >>
    >> def initialize(a, b = nil, deref = false)
    >> @prefix = @rel = @path = nil
    >> if b
    >> @prefix = a
    >> @rel = b
    >> else
    >> @path = a
    >> end
    >> @deref = deref
    >> @stat = nil
    >> @lstat = nil
    >> end
    >>
    >> def inspect
    >> "\#<#{self.class} #{path()}>"
    >> end
    >>
    >> def path
    >> if @path
    >> @path.to_str
    >> else
    >> join(@prefix, @rel)
    >> end
    >> end
    >>
    >> def prefix
    >> @prefix || @path
    >> end
    >>
    >> def rel
    >> @rel
    >> end
    >>
    >> def dereference?
    >> @deref
    >> end
    >>
    >> def exist?
    >> lstat! ? true : false
    >> end
    >>
    >> def file?
    >> s = lstat!
    >> s and s.file?
    >> end
    >>
    >> def directory?
    >> s = lstat!
    >> s and s.directory?
    >> end
    >>
    >> def symlink?
    >> s = lstat!
    >> s and s.symlink?
    >> end
    >>
    >> def chardev?
    >> s = lstat!
    >> s and s.chardev?
    >> end
    >>
    >> def blockdev?
    >> s = lstat!
    >> s and s.blockdev?
    >> end
    >>
    >> def socket?
    >> s = lstat!
    >> s and s.socket?
    >> end
    >>
    >> def pipe?
    >> s = lstat!
    >> s and s.pipe?
    >> end
    >>
    >> S_IF_DOOR = 0xD000
    >>
    >> def door?
    >> s = lstat!
    >> s and (s.mode & 0xF000 == S_IF_DOOR)
    >> end
    >>
    >> def entries
    >> Dir.entries(path())\
    >> .reject {|n| n == '.' or n == '..' }\
    >> .map {|n| Entry_.new(prefix(), join(rel(), n.untaint)) }
    >> end
    >>
    >> def stat
    >> return @stat if @stat
    >> if lstat() and lstat().symlink?
    >> @stat = File.stat(path())
    >> else
    >> @stat = lstat()
    >> end
    >> @stat
    >> end
    >>
    >> def stat!
    >> return @stat if @stat
    >> if lstat! and lstat!.symlink?
    >> @stat = File.stat(path())
    >> else
    >> @stat = lstat!
    >> end
    >> @stat
    >> rescue SystemCallError
    >> nil
    >> end
    >>
    >> def lstat
    >> if dereference?
    >> @lstat ||= File.stat(path())
    >> else
    >> @lstat ||= File.lstat(path())
    >> end
    >> end
    >>
    >> def lstat!
    >> lstat()
    >> rescue SystemCallError
    >> nil
    >> end
    >>
    >> def chmod(mode)
    >> if symlink?
    >> File.lchmod mode, path() if have_lchmod?
    >> else
    >> File.chmod mode, path()
    >> end
    >> end
    >>
    >> def chown(uid, gid)
    >> if symlink?
    >> File.lchown uid, gid, path() if have_lchown?
    >> else
    >> File.chown uid, gid, path()
    >> end
    >> end
    >>
    >> def copy(dest)
    >> case
    >> when file?
    >> copy_file dest
    >> when directory?
    >> begin
    >> Dir.mkdir dest
    >> rescue
    >> raise unless File.directory?(dest)
    >> end
    >> when symlink?
    >> File.symlink File.readlink(path()), dest
    >> when chardev?
    >> raise "cannot handle device file" unless
    >> File.respond_to?:)mknod) mknod dest, ?c, 0666, lstat().rdev
    >> when blockdev?
    >> raise "cannot handle device file" unless
    >> File.respond_to?:)mknod) mknod dest, ?b, 0666, lstat().rdev
    >> when socket?
    >> raise "cannot handle socket" unless File.respond_to?:)mknod)
    >> mknod dest, nil, lstat().mode, 0
    >> when pipe?
    >> raise "cannot handle FIFO" unless File.respond_to?:)mkfifo)
    >> mkfifo dest, 0666
    >> when door?
    >> raise "cannot handle door: #{path()}"
    >> else
    >> raise "unknown file type: #{path()}"
    >> end
    >> end
    >>
    >> def copy_file(dest)
    >> st = stat()
    >> File.open(path(), 'rb') {|r|
    >> File.open(dest, 'wb', st.mode) {|w|
    >> fu_copy_stream0 r, w, (fu_blksize(st) ||
    >> fu_default_blksize()) }
    >> }
    >> end
    >>
    >> def copy_metadata(path)
    >> st = lstat()
    >> File.utime st.atime, st.mtime, path
    >> begin
    >> File.chown st.uid, st.gid, path
    >> rescue Errno::EPERM
    >> # clear setuid/setgid
    >> File.chmod st.mode & 01777, path
    >> else
    >> File.chmod st.mode, path
    >> end
    >> end
    >>
    >> # [...]
    >>
    >> def platform_support
    >> return yield unless fu_windows?
    >> first_time_p = true
    >> begin
    >> yield
    >> rescue Errno::ENOENT
    >> raise
    >> rescue => err
    >> if first_time_p
    >> first_time_p = false
    >> begin
    >> File.chmod 0700, path() # Windows does not have symlink
    >> retry
    >> rescue SystemCallError
    >> end
    >> end
    >> raise err
    >> end
    >> end
    >>
    >> def preorder_traverse
    >> stack = [self]
    >> while ent = stack.pop
    >> yield ent
    >> stack.concat ent.entries.reverse if ent.directory?
    >> end
    >> end
    >>
    >> alias traverse preorder_traverse
    >>
    >> def postorder_traverse
    >> if directory?
    >> entries().each do |ent|
    >> ent.postorder_traverse do |e|
    >> yield e
    >> end
    >> end
    >> end
    >> yield self
    >> end
    >>
    >>
    >> # [...]
    >>
    >> def join(dir, base)
    >> return dir.to_str if not base or base == '.'
    >> return base.to_str if not dir or dir == '.'
    >> File.join(dir, base)
    >> end
    >> end # class Entry_
    >>
    >> def fu_list(arg) #:nodoc:
    >> [arg].flatten.map {|path| path.to_str }
    >> end
    >> private_module_function :fu_list
    >>
    >> def fu_each_src_dest(src, dest) #:nodoc:
    >> fu_each_src_dest0(src, dest) do |s, d|
    >> raise ArgumentError, "same file: #{s} and #{d}" if fu_same?(s,
    >> d) yield s, d
    >> end
    >> end
    >> private_module_function :fu_each_src_dest
    >>
    >> def fu_each_src_dest0(src, dest) #:nodoc:
    >> if src.is_a?(Array)
    >> src.each do |s|
    >> s = s.to_str
    >> yield s, File.join(dest, File.basename(s))
    >> end
    >> else
    >> src = src.to_str
    >> if File.directory?(dest)
    >> yield src, File.join(dest, File.basename(src))
    >> else
    >> yield src, dest.to_str
    >> end
    >> end
    >> end
    >> private_module_function :fu_each_src_dest0
    >>
    >> 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
    >> private_module_function :fu_same?
    >>
    >> def fu_have_st_ino? #:nodoc:
    >> not fu_windows?
    >> end
    >> private_module_function :fu_have_st_ino?
    >>
    >> def fu_check_options(options, *optdecl) #:nodoc:
    >> h = options.dup
    >> optdecl.each do |name|
    >> h.delete name
    >> end
    >> raise ArgumentError, "no such option: #{h.keys.join(' ')}"
    >> unless h.empty? end
    >> private_module_function :fu_check_options
    >>
    >> def fu_update_option(args, new) #:nodoc:
    >> if args.last.is_a?(Hash)
    >> args[-1] = args.last.dup.update(new)
    >> else
    >> args.push new
    >> end
    >> args
    >> end
    >> private_module_function :fu_update_option
    >>
    >> @fileutils_output = $stderr
    >> @fileutils_label = ''
    >>
    >> def fu_output_message(msg) #:nodoc:
    >> @fileutils_output ||= $stderr
    >> @fileutils_label ||= ''
    >> @fileutils_output.puts @fileutils_label + msg
    >> end
    >> private_module_function :fu_output_message
    >>
    >> #
    >> # Returns an Array of method names which have any options.
    >> #
    >> # p FileUtils.commands #=> ["chmod", "cp", "cp_r", "install",
    >> ...] #
    >> def FileUtils.commands
    >> OPT_TABLE.keys
    >> end
    >>
    >> #
    >> # Returns an Array of option names.
    >> #
    >> # p FileUtils.options #=> ["noop", "force", "verbose",
    >> "preserve", "mode"] #
    >> def FileUtils.options
    >> OPT_TABLE.values.flatten.uniq
    >> end
    >>
    >> #
    >> # Returns true if the method +mid+ have an option +opt+.
    >> #
    >> # p FileUtils.have_option?:)cp, :noop) #=> true
    >> # p FileUtils.have_option?:)rm, :force) #=> true
    >> # p FileUtils.have_option?:)rm, :perserve) #=> false
    >> #
    >> def FileUtils.have_option?(mid, opt)
    >> li = OPT_TABLE[mid.to_s] or raise ArgumentError, "no such
    >> method: #{mid}" li.include?(opt.to_s)
    >> end
    >>
    >> #
    >> # Returns an Array of option names of the method +mid+.
    >> #
    >> # p FileUtils.options:)rm) #=> ["noop", "verbose", "force"]
    >> #
    >> def FileUtils.options_of(mid)
    >> OPT_TABLE[mid.to_s]
    >> end
    >>
    >> # [...]
    >>
    >> end
     
    Robert Klemme, Nov 2, 2005
    #5
  6. Hugh Sasse

    Hugh Sasse Guest

    On Thu, 3 Nov 2005, Robert Klemme wrote:

    > Hugh Sasse wrote:
    > > I see my changes to fileutils are now in the Ruby CVS.
    > > However, even with
    > > rescue Exception, SystemCallError => e
    > > or
    > > rescue Exception, Errno::EACCES, Errno::EBUSY => e
    > >
    > > I still cannot trap this error. From the call stack this part of
    > > the code is being used, so why won't the error cause ruby to go back
    > > up the callstack until it finds this rescue clause?

    >
    > Maybe there's another rescue clause that is closer to the place where the
    > exception is thrown...


    But unless I have completely misunderstood the point of rescue, even
    if that calls raise, the exception will still be caught by my
    enclosing rescue.

    neelix hgs 15 %> irb
    irb(main):001:0> begin
    irb(main):002:1* begin
    irb(main):003:2* raise StandardError
    irb(main):004:2> rescue
    irb(main):005:2> raise
    irb(main):006:2> end
    irb(main):007:1> rescue
    irb(main):008:1> puts "caught here"
    irb(main):009:1> end
    caught here
    => nil
    irb(main):010:0>

    So, if I'm doing
    rescue Exception => e
    how can Errno::EACCES or Errno::EBUSY get past that and crash out?
    >
    > robert
    >
    > >
    > > Hugh
    > >
    > > On Tue, 1 Nov 2005, Hugh Sasse wrote:
    > >
    > >> On Tue, 1 Nov 2005, Robert Klemme wrote:
    > >>
    > >>> Hugh Sasse <> wrote:
    > >>>> begin
    > >>>> #...
    > >>>> rescue => e
    > >>>> #...
    > >>>> end
    > >>>>
    > >>>> will trap e if it is a StandardError. SystemCallErrrors are
    > >>>> supposed to handle Errorcodes from the OS. All of these are
    > >>>> subclasses of Exception. So why do I get this failure under
    > >>>> Cygwin:
    > >>>>
    > >>>> $ ruby BACKUP.RB "C:\\" "D:\\buzz_c"
    > >>>> cp -rp C:\ D:\buzz_c
    > >>>> /usr/lib/ruby/1.8/new_fileutils.rb:1251:in `initialize': Device or
    > >>>> resource busy - C:\/WINDOWS/WIN386.SWP (Errno::EBUSY)
    > >>>> from /usr/lib/ruby/1.8/new_fileutils.rb:1251:in `copy_file'
    > >>>> from /usr/lib/ruby/1.8/new_fileutils.rb:1221:in `copy'
    > >>>> from /usr/lib/ruby/1.8/new_fileutils.rb:455:in `copy_entry'
    > >>>> from /usr/lib/ruby/1.8/new_fileutils.rb:1314:in `traverse'
    > >>>> from /usr/lib/ruby/1.8/new_fileutils.rb:453:in `copy_entry'
    > >>>> from /usr/lib/ruby/1.8/new_fileutils.rb:424:in `cp_r'
    > >>>> from /usr/lib/ruby/1.8/new_fileutils.rb:1385:in
    > >>>> `fu_each_src_dest' from
    > >>>> /usr/lib/ruby/1.8/new_fileutils.rb:1401:in
    > >>>> `fu_each_src_dest0' from
    > >>>> /usr/lib/ruby/1.8/new_fileutils.rb:1383:in
    > >>>> `fu_each_src_dest' from /usr/lib/ruby/1.8/new_fileutils.rb:422:in
    > >>>> `cp_r' from BACKUP.RB:27
    > >>>>
    > >>>> hgs@buzz ~/downloads
    > >>>>
    > >>>> when my modified FileUtils.cp_r has
    > >>>>
    > >>>> begin
    > >>>> copy_entry ...
    > >>>> rescue Exception => e
    > >>>> logger.error("backup"){"Error was #{e}")
    > >>>> end
    > >>>>
    > >>>> (essentially. Theres a bit more to it than that, but the details
    > >>>> shouldn't matter for my question.) So why can't I rescue it? (I'm
    > >>>> trying to log, and skip files I can't backup so at least I get most
    > >>>> of the files, and know which ones I have not.)
    > >>>
    > >>> Maybe it's in another thread. Or your code is actually not between
    > >>> "begin" and "rescue" but outside of that.
    > >>
    > >> there's no threading in there, and I'm pretty certain it is within
    > >> that, because it is in the call to copy_entry
    > >>
    > >>>
    > >>> Kind regards
    > >>>
    > >>> robert
    > >>>
    > >>
    > >> The modified fileutils is (heavily pruned) below
    > >> I've changed cp_r.
    > >>
    > >> Hugh
    > >>
    > >> #
    > >> # = fileutils.rb
    > >> #
    > >> # Copyright (c) 2000-2005 Minero Aoki <>
    > >> #
    > >> # This program is free software.
    > >> # You can distribute/modify this program under the same terms of
    > >> ruby. #
    > >> # == module FileUtils
    > >> #
    > >> # Namespace for several file utility methods for copying, moving,
    > >> removing, etc. #
    > >> # === Module Functions
    > >> #
    > >> # [...]
    > >> # cp_r(src, dest, options) {|s,d,e|...}
    > >> # cp_r(list, dir, options) {|s,d,e|...}
    > >> # [...]
    > >> #
    > >> # The <tt>options</tt> parameter is a hash of options, taken from
    > >> the list # <tt>:force</tt>, <tt>:noop</tt>, <tt>:preserve</tt>, and
    > >> <tt>:verbose</tt>. # <tt>:noop</tt> means that no changes are made.
    > >> The other two are obvious. # Each method documents the options that
    > >> it honours. #
    > >> # All methods that have the concept of a "source" file or directory
    > >> can take # either one file or a list of files in that argument. See
    > >> the method # documentation for examples.
    > >> #
    > >> # There are some `low level' methods, which do not accept any option:
    > >> #
    > >> # copy_entry(src, dest, preserve = false, dereference = false)
    > >> # copy_file(src, dest, preserve = false, dereference = true)
    > >> # [...]
    > >> #
    > >> # == module FileUtils::Verbose
    > >> #
    > >> # This module has all methods of FileUtils module, but it outputs
    > >> messages # before acting. This equates to passing the
    > >> <tt>:verbose</tt> flag to methods # in FileUtils.
    > >> #
    > >> # == module FileUtils::NoWrite
    > >> #
    > >> # This module has all methods of FileUtils module, but never changes
    > >> # files/directories. This equates to passing the <tt>:noop</tt>
    > >> flag to methods # in FileUtils.
    > >> #
    > >> # == module FileUtils::DryRun
    > >> #
    > >> # This module has all methods of FileUtils module, but never changes
    > >> # files/directories. This equates to passing the <tt>:noop</tt> and
    > >> # <tt>:verbose</tt> flags to methods in FileUtils.
    > >> #
    > >>
    > >> module FileUtils
    > >>
    > >> def self.private_module_function(name) #:nodoc:
    > >> module_function name
    > >> private_class_method name
    > >> end
    > >>
    > >> # This hash table holds command options.
    > >> OPT_TABLE = {} #:nodoc: internal use only
    > >>
    > >> # [...]
    > >>
    > >> def fu_mkdir(path, mode) #:nodoc:
    > >> path = path.sub(%r</\z>, '')
    > >> if mode
    > >> Dir.mkdir path, mode
    > >> File.chmod mode, path
    > >> else
    > >> Dir.mkdir path
    > >> end
    > >> end
    > >> private_module_function :fu_mkdir
    > >>
    > >> # [...]
    > >>
    > >> #
    > >> # Options: preserve noop verbose dereference_root
    > >> #
    > >> # Copies +src+ to +dest+. If +src+ is a directory, this method
    > >> copies # all its contents recursively. If +dest+ is a directory,
    > >> copies # +src+ to +dest/src+.
    > >> #
    > >> # +src+ can be a list of files.
    > >> #
    > >> # # Installing ruby library "mylib" under the site_ruby
    > >> # FileUtils.rm_r site_ruby + '/mylib', :force
    > >> # FileUtils.cp_r 'lib/', site_ruby + '/mylib'
    > >> #
    > >> # # Examples of copying several files to target directory.
    > >> # FileUtils.cp_r %w(mail.rb field.rb debug/), site_ruby +
    > >> '/tmail' # FileUtils.cp_r Dir.glob('*.rb'),
    > >> '/home/aamine/lib/ruby', :noop => true, :verbose => true #
    > >> # # If you want to copy all contents of a directory instead of
    > >> the # # directory itself, c.f. src/x -> dest/x, src/y -> dest/y,
    > >> # # use following code.
    > >> # FileUtils.cp_r 'src/.', 'dest' # cp_r('src', 'dest') makes
    > >> src/dest, # # but this
    > >> doesn't. #
    > >> def cp_r(src, dest, options = {})
    > >> fu_check_options options, :preserve, :noop, :verbose,
    > >> :dereference_root fu_output_message "cp -r#{options[:preserve] ?
    > >> 'p' : ''} #{[src,dest].flatten.join ' '}" if options[:verbose]
    > >> return if options[:noop] options[:dereference_root] = true
    > >> unless options.key?:)dereference_root) fu_each_src_dest(src,
    > >> dest) do |s, d| begin
    > >> copy_entry s, d, options[:preserve],
    > >> options[:dereference_root] rescue Exception => e
    > >> stop = true
    > >> if block_given?
    > >> stop = yield s,d,e
    > >> end
    > >> raise if stop
    > >> end
    > >> end
    > >> end
    > >> module_function :cp_r
    > >>
    > >> OPT_TABLE['cp_r'] = %w( noop verbose preserve dereference_root )
    > >>
    > >> #
    > >> # Copies a file system entry +src+ to +dest+.
    > >> # If +src+ is a directory, this method copies its contents
    > >> recursively. # This method preserves file types, c.f. symlink,
    > >> directory... # (FIFO, device files and etc. are not supported yet)
    > >> #
    > >> # Both of +src+ and +dest+ must be a path name.
    > >> # +src+ must exist, +dest+ must not exist.
    > >> #
    > >> # If +preserve+ is true, this method preserves owner, group,
    > >> permissions # and modified time.
    > >> #
    > >> # If +dereference_root+ is true, this method dereference tree root.
    > >> #
    > >> def copy_entry(src, dest, preserve = false, dereference_root =
    > >> false) Entry_.new(src, nil, dereference_root).traverse do |ent|
    > >> destent = Entry_.new(dest, ent.rel, false)
    > >> ent.copy destent.path
    > >> ent.copy_metadata destent.path if preserve
    > >> end
    > >> end
    > >> module_function :copy_entry
    > >>
    > >> #
    > >> # Copies file contents of +src+ to +dest+.
    > >> # Both of +src+ and +dest+ must be a path name.
    > >> #
    > >> def copy_file(src, dest, preserve = false, dereference = true)
    > >> ent = Entry_.new(src, nil, dereference)
    > >> ent.copy_file dest
    > >> ent.copy_metadata dest if preserve
    > >> end
    > >> module_function :copy_file
    > >>
    > >> # [...]
    > >>
    > >>
    > >> class Entry_ #:nodoc: internal use only
    > >> include StreamUtils_
    > >>
    > >> def initialize(a, b = nil, deref = false)
    > >> @prefix = @rel = @path = nil
    > >> if b
    > >> @prefix = a
    > >> @rel = b
    > >> else
    > >> @path = a
    > >> end
    > >> @deref = deref
    > >> @stat = nil
    > >> @lstat = nil
    > >> end
    > >>
    > >> def inspect
    > >> "\#<#{self.class} #{path()}>"
    > >> end
    > >>
    > >> def path
    > >> if @path
    > >> @path.to_str
    > >> else
    > >> join(@prefix, @rel)
    > >> end
    > >> end
    > >>
    > >> def prefix
    > >> @prefix || @path
    > >> end
    > >>
    > >> def rel
    > >> @rel
    > >> end
    > >>
    > >> def dereference?
    > >> @deref
    > >> end
    > >>
    > >> def exist?
    > >> lstat! ? true : false
    > >> end
    > >>
    > >> def file?
    > >> s = lstat!
    > >> s and s.file?
    > >> end
    > >>
    > >> def directory?
    > >> s = lstat!
    > >> s and s.directory?
    > >> end
    > >>
    > >> def symlink?
    > >> s = lstat!
    > >> s and s.symlink?
    > >> end
    > >>
    > >> def chardev?
    > >> s = lstat!
    > >> s and s.chardev?
    > >> end
    > >>
    > >> def blockdev?
    > >> s = lstat!
    > >> s and s.blockdev?
    > >> end
    > >>
    > >> def socket?
    > >> s = lstat!
    > >> s and s.socket?
    > >> end
    > >>
    > >> def pipe?
    > >> s = lstat!
    > >> s and s.pipe?
    > >> end
    > >>
    > >> S_IF_DOOR = 0xD000
    > >>
    > >> def door?
    > >> s = lstat!
    > >> s and (s.mode & 0xF000 == S_IF_DOOR)
    > >> end
    > >>
    > >> def entries
    > >> Dir.entries(path())\
    > >> .reject {|n| n == '.' or n == '..' }\
    > >> .map {|n| Entry_.new(prefix(), join(rel(), n.untaint)) }
    > >> end
    > >>
    > >> def stat
    > >> return @stat if @stat
    > >> if lstat() and lstat().symlink?
    > >> @stat = File.stat(path())
    > >> else
    > >> @stat = lstat()
    > >> end
    > >> @stat
    > >> end
    > >>
    > >> def stat!
    > >> return @stat if @stat
    > >> if lstat! and lstat!.symlink?
    > >> @stat = File.stat(path())
    > >> else
    > >> @stat = lstat!
    > >> end
    > >> @stat
    > >> rescue SystemCallError
    > >> nil
    > >> end
    > >>
    > >> def lstat
    > >> if dereference?
    > >> @lstat ||= File.stat(path())
    > >> else
    > >> @lstat ||= File.lstat(path())
    > >> end
    > >> end
    > >>
    > >> def lstat!
    > >> lstat()
    > >> rescue SystemCallError
    > >> nil
    > >> end
    > >>
    > >> def chmod(mode)
    > >> if symlink?
    > >> File.lchmod mode, path() if have_lchmod?
    > >> else
    > >> File.chmod mode, path()
    > >> end
    > >> end
    > >>
    > >> def chown(uid, gid)
    > >> if symlink?
    > >> File.lchown uid, gid, path() if have_lchown?
    > >> else
    > >> File.chown uid, gid, path()
    > >> end
    > >> end
    > >>
    > >> def copy(dest)
    > >> case
    > >> when file?
    > >> copy_file dest
    > >> when directory?
    > >> begin
    > >> Dir.mkdir dest
    > >> rescue
    > >> raise unless File.directory?(dest)
    > >> end
    > >> when symlink?
    > >> File.symlink File.readlink(path()), dest
    > >> when chardev?
    > >> raise "cannot handle device file" unless
    > >> File.respond_to?:)mknod) mknod dest, ?c, 0666, lstat().rdev
    > >> when blockdev?
    > >> raise "cannot handle device file" unless
    > >> File.respond_to?:)mknod) mknod dest, ?b, 0666, lstat().rdev
    > >> when socket?
    > >> raise "cannot handle socket" unless File.respond_to?:)mknod)
    > >> mknod dest, nil, lstat().mode, 0
    > >> when pipe?
    > >> raise "cannot handle FIFO" unless File.respond_to?:)mkfifo)
    > >> mkfifo dest, 0666
    > >> when door?
    > >> raise "cannot handle door: #{path()}"
    > >> else
    > >> raise "unknown file type: #{path()}"
    > >> end
    > >> end
    > >>
    > >> def copy_file(dest)
    > >> st = stat()
    > >> File.open(path(), 'rb') {|r|
    > >> File.open(dest, 'wb', st.mode) {|w|
    > >> fu_copy_stream0 r, w, (fu_blksize(st) ||
    > >> fu_default_blksize()) }
    > >> }
    > >> end
    > >>
    > >> def copy_metadata(path)
    > >> st = lstat()
    > >> File.utime st.atime, st.mtime, path
    > >> begin
    > >> File.chown st.uid, st.gid, path
    > >> rescue Errno::EPERM
    > >> # clear setuid/setgid
    > >> File.chmod st.mode & 01777, path
    > >> else
    > >> File.chmod st.mode, path
    > >> end
    > >> end
    > >>
    > >> # [...]
    > >>
    > >> def platform_support
    > >> return yield unless fu_windows?
    > >> first_time_p = true
    > >> begin
    > >> yield
    > >> rescue Errno::ENOENT
    > >> raise
    > >> rescue => err
    > >> if first_time_p
    > >> first_time_p = false
    > >> begin
    > >> File.chmod 0700, path() # Windows does not have symlink
    > >> retry
    > >> rescue SystemCallError
    > >> end
    > >> end
    > >> raise err
    > >> end
    > >> end
    > >>
    > >> def preorder_traverse
    > >> stack = [self]
    > >> while ent = stack.pop
    > >> yield ent
    > >> stack.concat ent.entries.reverse if ent.directory?
    > >> end
    > >> end
    > >>
    > >> alias traverse preorder_traverse
    > >>
    > >> def postorder_traverse
    > >> if directory?
    > >> entries().each do |ent|
    > >> ent.postorder_traverse do |e|
    > >> yield e
    > >> end
    > >> end
    > >> end
    > >> yield self
    > >> end
    > >>
    > >>
    > >> # [...]
    > >>
    > >> def join(dir, base)
    > >> return dir.to_str if not base or base == '.'
    > >> return base.to_str if not dir or dir == '.'
    > >> File.join(dir, base)
    > >> end
    > >> end # class Entry_
    > >>
    > >> def fu_list(arg) #:nodoc:
    > >> [arg].flatten.map {|path| path.to_str }
    > >> end
    > >> private_module_function :fu_list
    > >>
    > >> def fu_each_src_dest(src, dest) #:nodoc:
    > >> fu_each_src_dest0(src, dest) do |s, d|
    > >> raise ArgumentError, "same file: #{s} and #{d}" if fu_same?(s,
    > >> d) yield s, d
    > >> end
    > >> end
    > >> private_module_function :fu_each_src_dest
    > >>
    > >> def fu_each_src_dest0(src, dest) #:nodoc:
    > >> if src.is_a?(Array)
    > >> src.each do |s|
    > >> s = s.to_str
    > >> yield s, File.join(dest, File.basename(s))
    > >> end
    > >> else
    > >> src = src.to_str
    > >> if File.directory?(dest)
    > >> yield src, File.join(dest, File.basename(src))
    > >> else
    > >> yield src, dest.to_str
    > >> end
    > >> end
    > >> end
    > >> private_module_function :fu_each_src_dest0
    > >>
    > >> 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
    > >> private_module_function :fu_same?
    > >>
    > >> def fu_have_st_ino? #:nodoc:
    > >> not fu_windows?
    > >> end
    > >> private_module_function :fu_have_st_ino?
    > >>
    > >> def fu_check_options(options, *optdecl) #:nodoc:
    > >> h = options.dup
    > >> optdecl.each do |name|
    > >> h.delete name
    > >> end
    > >> raise ArgumentError, "no such option: #{h.keys.join(' ')}"
    > >> unless h.empty? end
    > >> private_module_function :fu_check_options
    > >>
    > >> def fu_update_option(args, new) #:nodoc:
    > >> if args.last.is_a?(Hash)
    > >> args[-1] = args.last.dup.update(new)
    > >> else
    > >> args.push new
    > >> end
    > >> args
    > >> end
    > >> private_module_function :fu_update_option
    > >>
    > >> @fileutils_output = $stderr
    > >> @fileutils_label = ''
    > >>
    > >> def fu_output_message(msg) #:nodoc:
    > >> @fileutils_output ||= $stderr
    > >> @fileutils_label ||= ''
    > >> @fileutils_output.puts @fileutils_label + msg
    > >> end
    > >> private_module_function :fu_output_message
    > >>
    > >> #
    > >> # Returns an Array of method names which have any options.
    > >> #
    > >> # p FileUtils.commands #=> ["chmod", "cp", "cp_r", "install",
    > >> ...] #
    > >> def FileUtils.commands
    > >> OPT_TABLE.keys
    > >> end
    > >>
    > >> #
    > >> # Returns an Array of option names.
    > >> #
    > >> # p FileUtils.options #=> ["noop", "force", "verbose",
    > >> "preserve", "mode"] #
    > >> def FileUtils.options
    > >> OPT_TABLE.values.flatten.uniq
    > >> end
    > >>
    > >> #
    > >> # Returns true if the method +mid+ have an option +opt+.
    > >> #
    > >> # p FileUtils.have_option?:)cp, :noop) #=> true
    > >> # p FileUtils.have_option?:)rm, :force) #=> true
    > >> # p FileUtils.have_option?:)rm, :perserve) #=> false
    > >> #
    > >> def FileUtils.have_option?(mid, opt)
    > >> li = OPT_TABLE[mid.to_s] or raise ArgumentError, "no such
    > >> method: #{mid}" li.include?(opt.to_s)
    > >> end
    > >>
    > >> #
    > >> # Returns an Array of option names of the method +mid+.
    > >> #
    > >> # p FileUtils.options:)rm) #=> ["noop", "verbose", "force"]
    > >> #
    > >> def FileUtils.options_of(mid)
    > >> OPT_TABLE[mid.to_s]
    > >> end
    > >>
    > >> # [...]
    > >>
    > >> end

    >
    >
    >
     
    Hugh Sasse, Nov 2, 2005
    #6
  7. Hugh Sasse wrote:
    > On Thu, 3 Nov 2005, Robert Klemme wrote:
    >
    >> Hugh Sasse wrote:
    >>> I see my changes to fileutils are now in the Ruby CVS.
    >>> However, even with
    >>> rescue Exception, SystemCallError => e
    >>> or
    >>> rescue Exception, Errno::EACCES, Errno::EBUSY => e
    >>>
    >>> I still cannot trap this error. From the call stack this part of
    >>> the code is being used, so why won't the error cause ruby to go back
    >>> up the callstack until it finds this rescue clause?

    >>
    >> Maybe there's another rescue clause that is closer to the place
    >> where the exception is thrown...

    >
    > But unless I have completely misunderstood the point of rescue, even
    > if that calls raise, the exception will still be caught by my
    > enclosing rescue.


    But who guarantees that the other rescue clause actually throws again? If
    it doesn't you can't catch it.

    ....
    rescue Exception => e
    puts "Catch me if you can >:-}"
    end

    ;-)

    Cheers

    robert
     
    Robert Klemme, Nov 2, 2005
    #7
  8. Hugh Sasse

    Hugh Sasse Guest

    On Thu, 3 Nov 2005, Robert Klemme wrote:

    > Hugh Sasse wrote:
    > > On Thu, 3 Nov 2005, Robert Klemme wrote:
    > >
    > >> Hugh Sasse wrote:
    > >>> I see my changes to fileutils are now in the Ruby CVS.
    > >>> However, even with
    > >>> rescue Exception, SystemCallError => e
    > >>> or
    > >>> rescue Exception, Errno::EACCES, Errno::EBUSY => e
    > >>>
    > >>> I still cannot trap this error. From the call stack this part of
    > >>> the code is being used, so why won't the error cause ruby to go back
    > >>> up the callstack until it finds this rescue clause?
    > >>
    > >> Maybe there's another rescue clause that is closer to the place
    > >> where the exception is thrown...

    > >
    > > But unless I have completely misunderstood the point of rescue, even
    > > if that calls raise, the exception will still be caught by my
    > > enclosing rescue.

    >
    > But who guarantees that the other rescue clause actually throws again? If
    > it doesn't you can't catch it.
    >
    > ....
    > rescue Exception => e
    > puts "Catch me if you can >:-}"
    > end
    >
    > ;-)
    >


    Then it's already caught, and I should never see the error.

    neelix hgs 58 %> irb
    irb(main):001:0> begin
    irb(main):002:1* begin
    irb(main):003:2* raise StandardError
    irb(main):004:2> rescue => e
    irb(main):005:2> puts "catch me if you can #{e}"
    irb(main):006:2> end
    irb(main):007:1> rescue
    irb(main):008:1> puts "caught something"
    irb(main):009:1> end
    catch me if you can StandardError
    => nil
    irb(main):010:0>

    i.e. that's a normal exit.

    So, I have an error that is not already caught, and I can't catch
    it.

    > Cheers
    >
    > robert
    >


    Hugh
     
    Hugh Sasse, Nov 2, 2005
    #8
  9. Hugh Sasse <> wrote:
    > On Thu, 3 Nov 2005, Robert Klemme wrote:
    >
    >> Hugh Sasse wrote:
    >>> On Thu, 3 Nov 2005, Robert Klemme wrote:
    >>>
    >>>> Hugh Sasse wrote:
    >>>>> I see my changes to fileutils are now in the Ruby CVS.
    >>>>> However, even with
    >>>>> rescue Exception, SystemCallError => e
    >>>>> or
    >>>>> rescue Exception, Errno::EACCES, Errno::EBUSY => e
    >>>>>
    >>>>> I still cannot trap this error. From the call stack this part of
    >>>>> the code is being used, so why won't the error cause ruby to go
    >>>>> back up the callstack until it finds this rescue clause?
    >>>>
    >>>> Maybe there's another rescue clause that is closer to the place
    >>>> where the exception is thrown...
    >>>
    >>> But unless I have completely misunderstood the point of rescue, even
    >>> if that calls raise, the exception will still be caught by my
    >>> enclosing rescue.

    >>
    >> But who guarantees that the other rescue clause actually throws
    >> again? If it doesn't you can't catch it.
    >>
    >> ....
    >> rescue Exception => e
    >> puts "Catch me if you can >:-}"
    >> end
    >>
    >> ;-)
    >>

    >
    > Then it's already caught, and I should never see the error.


    Why not? If it's printed in the other rescue clause you would see it. Or
    am I missing something here?

    robert

    >
    > neelix hgs 58 %> irb
    > irb(main):001:0> begin
    > irb(main):002:1* begin
    > irb(main):003:2* raise StandardError
    > irb(main):004:2> rescue => e
    > irb(main):005:2> puts "catch me if you can #{e}"
    > irb(main):006:2> end
    > irb(main):007:1> rescue
    > irb(main):008:1> puts "caught something"
    > irb(main):009:1> end
    > catch me if you can StandardError
    > => nil
    > irb(main):010:0>
    >
    > i.e. that's a normal exit.
    >
    > So, I have an error that is not already caught, and I can't catch
    > it.
    >
    >> Cheers
    >>
    >> robert
    >>

    >
    > Hugh
     
    Robert Klemme, Nov 2, 2005
    #9
  10. Hugh Sasse

    Hugh Sasse Guest

    On Thu, 3 Nov 2005, Robert Klemme wrote:

    > Hugh Sasse <> wrote:
    > > On Thu, 3 Nov 2005, Robert Klemme wrote:
    > >
    > > > Hugh Sasse wrote:
    > > > > On Thu, 3 Nov 2005, Robert Klemme wrote:
    > > > >
    > > > > > Hugh Sasse wrote:
    > > > > > > I see my changes to fileutils are now in the Ruby CVS.
    > > > > > > However, even with
    > > > > > > rescue Exception, SystemCallError => e
    > > > > > > or
    > > > > > > rescue Exception, Errno::EACCES, Errno::EBUSY => e
    > > > > > >
    > > > > > > I still cannot trap this error. From the call stack this part of
    > > > > > > the code is being used, so why won't the error cause ruby to go
    > > > > > > back up the callstack until it finds this rescue clause?
    > > > > >
    > > > > > Maybe there's another rescue clause that is closer to the place
    > > > > > where the exception is thrown...
    > > > >
    > > > > But unless I have completely misunderstood the point of rescue, even
    > > > > if that calls raise, the exception will still be caught by my
    > > > > enclosing rescue.
    > > >
    > > > But who guarantees that the other rescue clause actually throws
    > > > again? If it doesn't you can't catch it.
    > > >
    > > > ....
    > > > rescue Exception => e
    > > > puts "Catch me if you can >:-}"
    > > > end
    > > >
    > > > ;-)
    > > >

    > >
    > > Then it's already caught, and I should never see the error.

    >
    > Why not? If it's printed in the other rescue clause you would see it. Or am
    > I missing something here?


    I wouldn't see it as an error which kills my program. It would have
    been caught, and dealt with, or caught and re-raised, in which case
    the outer block would catch it.

    1 We have established that a begin...rescue...end block
    will rescue any errors raised inside it, provided the rescue
    clause matches that error type.

    2 We have established that if a begin ... rescue ... raise ... end
    block re-raises an error, it can be caught by a surrounding
    begin...rescue...end block

    3 My case is that I have a
    begin
    part1
    rescue Exception, SystemCallError, Errno::EACCES, Errno::EBUSY => e
    part2
    end

    block and it is not catching a Errno::EBUSY error from part1: The
    error crashes the program. So:
    If that error has been raised in part1, and not caught in part1
    then I should be able to catch it.
    If that error has been raised in part1, and caught in part1,
    part2 should never come into play, and the program should
    continue

    4 How can a subclass of Exception not be caught by Exception?
    5 Why doesn't SystemCallError catch it?
    6 Why doesn't the Errno::%s form catch it?

    i.e everything between "Exception" and " =>" should be unnecessary,
    but even with those it doesn't catch the error.

    >
    > robert
    >

    Hugh
     
    Hugh Sasse, Nov 2, 2005
    #10
  11. Hugh Sasse wrote:
    > On Thu, 3 Nov 2005, Robert Klemme wrote:
    >
    >> Hugh Sasse <> wrote:
    >>> On Thu, 3 Nov 2005, Robert Klemme wrote:
    >>>
    >>>> Hugh Sasse wrote:
    >>>>> On Thu, 3 Nov 2005, Robert Klemme wrote:
    >>>>>
    >>>>>> Hugh Sasse wrote:
    >>>>>>> I see my changes to fileutils are now in the Ruby CVS.
    >>>>>>> However, even with
    >>>>>>> rescue Exception, SystemCallError => e
    >>>>>>> or
    >>>>>>> rescue Exception, Errno::EACCES, Errno::EBUSY => e
    >>>>>>>
    >>>>>>> I still cannot trap this error. From the call stack this part
    >>>>>>> of the code is being used, so why won't the error cause ruby to
    >>>>>>> go back up the callstack until it finds this rescue clause?
    >>>>>>
    >>>>>> Maybe there's another rescue clause that is closer to the place
    >>>>>> where the exception is thrown...
    >>>>>
    >>>>> But unless I have completely misunderstood the point of rescue,
    >>>>> even if that calls raise, the exception will still be caught by my
    >>>>> enclosing rescue.
    >>>>
    >>>> But who guarantees that the other rescue clause actually throws
    >>>> again? If it doesn't you can't catch it.
    >>>>
    >>>> ....
    >>>> rescue Exception => e
    >>>> puts "Catch me if you can >:-}"
    >>>> end
    >>>>
    >>>> ;-)
    >>>>
    >>>
    >>> Then it's already caught, and I should never see the error.

    >>
    >> Why not? If it's printed in the other rescue clause you would see
    >> it. Or am I missing something here?

    >
    > I wouldn't see it as an error which kills my program. It would have
    > been caught, and dealt with, or caught and re-raised, in which case
    > the outer block would catch it.


    Well, there's at least the theoretical chance that this block just calls
    #exit... :)

    > 1 We have established that a begin...rescue...end block
    > will rescue any errors raised inside it, provided the rescue
    > clause matches that error type.
    >
    > 2 We have established that if a begin ... rescue ... raise ... end
    > block re-raises an error, it can be caught by a surrounding
    > begin...rescue...end block
    >
    > 3 My case is that I have a
    > begin
    > part1
    > rescue Exception, SystemCallError, Errno::EACCES, Errno::EBUSY => e
    > part2
    > end
    >
    > block and it is not catching a Errno::EBUSY error from part1: The
    > error crashes the program. So:
    > If that error has been raised in part1, and not caught in part1
    > then I should be able to catch it.
    > If that error has been raised in part1, and caught in part1,
    > part2 should never come into play, and the program should
    > continue
    >
    > 4 How can a subclass of Exception not be caught by Exception?
    > 5 Why doesn't SystemCallError catch it?
    > 6 Why doesn't the Errno::%s form catch it?
    >
    > i.e everything between "Exception" and " =>" should be unnecessary,
    > but even with those it doesn't catch the error.


    This sounds really strange. Here's what I'd do: use set_trace_func to
    write out all method invocations, returns and thread ids and try to see
    where it goes. HTH

    Kind regards

    robert
     
    Robert Klemme, Nov 3, 2005
    #11
  12. Hugh Sasse

    Hugh Sasse Guest

    On Thu, 3 Nov 2005, Robert Klemme wrote:

    > Hugh Sasse wrote:
    > > On Thu, 3 Nov 2005, Robert Klemme wrote:
    > >
    > >> Hugh Sasse <> wrote:

    [...]
    > >>> Then it's already caught, and I should never see the error.
    > >>
    > >> Why not? If it's printed in the other rescue clause you would see
    > >> it. Or am I missing something here?

    > >
    > > I wouldn't see it as an error which kills my program. It would have
    > > been caught, and dealt with, or caught and re-raised, in which case
    > > the outer block would catch it.

    >
    > Well, there's at least the theoretical chance that this block just calls
    > #exit... :)


    It died with a stack trace. exit doesn't do that.
    >
    > > 1 We have established that a begin...rescue...end block
    > > will rescue any errors raised inside it, provided the rescue
    > > clause matches that error type.
    > >
    > > 2 We have established that if a begin ... rescue ... raise ... end
    > > block re-raises an error, it can be caught by a surrounding
    > > begin...rescue...end block
    > >
    > > 3 My case is that I have a
    > > begin
    > > part1
    > > rescue Exception, SystemCallError, Errno::EACCES, Errno::EBUSY => e
    > > part2
    > > end
    > >
    > > block and it is not catching a Errno::EBUSY error from part1: The
    > > error crashes the program. So:
    > > If that error has been raised in part1, and not caught in part1
    > > then I should be able to catch it.
    > > If that error has been raised in part1, and caught in part1,
    > > part2 should never come into play, and the program should
    > > continue
    > >
    > > 4 How can a subclass of Exception not be caught by Exception?
    > > 5 Why doesn't SystemCallError catch it?
    > > 6 Why doesn't the Errno::%s form catch it?
    > >
    > > i.e everything between "Exception" and " =>" should be unnecessary,
    > > but even with those it doesn't catch the error.

    >
    > This sounds really strange. Here's what I'd do: use set_trace_func to
    > write out all method invocations, returns and thread ids and try to see
    > where it goes. HTH


    Good job I tried to add docs to profiler.rb in stdlib yesterday.
    I'll have a go at that. I've not played with set_trace_func before,
    so it should be interesting.
    >
    > Kind regards
    >
    > robert
    >

    Hugh
     
    Hugh Sasse, Nov 3, 2005
    #12
  13. Hugh Sasse wrote:
    > On Thu, 3 Nov 2005, Robert Klemme wrote:
    >
    >> Hugh Sasse wrote:
    >>> On Thu, 3 Nov 2005, Robert Klemme wrote:
    >>>
    >>>> Hugh Sasse <> wrote:

    > [...]
    >>>>> Then it's already caught, and I should never see the error.
    >>>>
    >>>> Why not? If it's printed in the other rescue clause you would see
    >>>> it. Or am I missing something here?
    >>>
    >>> I wouldn't see it as an error which kills my program. It would have
    >>> been caught, and dealt with, or caught and re-raised, in which case
    >>> the outer block would catch it.

    >>
    >> Well, there's at least the theoretical chance that this block just
    >> calls #exit... :)

    >
    > It died with a stack trace. exit doesn't do that.


    Yes, but it's not too difficult to print a stack trace like the one you
    see when the interpreter writs it.

    >>> 1 We have established that a begin...rescue...end block
    >>> will rescue any errors raised inside it, provided the rescue
    >>> clause matches that error type.
    >>>
    >>> 2 We have established that if a begin ... rescue ... raise ... end
    >>> block re-raises an error, it can be caught by a surrounding
    >>> begin...rescue...end block
    >>>
    >>> 3 My case is that I have a
    >>> begin
    >>> part1
    >>> rescue Exception, SystemCallError, Errno::EACCES, Errno::EBUSY
    >>> => e part2
    >>> end
    >>>
    >>> block and it is not catching a Errno::EBUSY error from part1: The
    >>> error crashes the program. So:
    >>> If that error has been raised in part1, and not caught in part1
    >>> then I should be able to catch it.
    >>> If that error has been raised in part1, and caught in part1,
    >>> part2 should never come into play, and the program should
    >>> continue
    >>>
    >>> 4 How can a subclass of Exception not be caught by Exception?
    >>> 5 Why doesn't SystemCallError catch it?
    >>> 6 Why doesn't the Errno::%s form catch it?
    >>>
    >>> i.e everything between "Exception" and " =>" should be unnecessary,
    >>> but even with those it doesn't catch the error.

    >>
    >> This sounds really strange. Here's what I'd do: use set_trace_func
    >> to write out all method invocations, returns and thread ids and try
    >> to see where it goes. HTH

    >
    > Good job I tried to add docs to profiler.rb in stdlib yesterday.
    > I'll have a go at that. I've not played with set_trace_func before,
    > so it should be interesting.


    This should get you started:

    set_trace_func lambda {|event, file, line, id, binding, classname|
    $stderr.printf "th %10d: %-10s %s: %d\n", Thread.current.object_id,
    event, file, line if
    /call|return/ =~ event
    }

    Good luck!

    robert
     
    Robert Klemme, Nov 3, 2005
    #13
  14. Hugh Sasse

    Hugh Sasse Guest

    On Thu, 3 Nov 2005, Robert Klemme wrote:

    > Hugh Sasse wrote:
    > > On Thu, 3 Nov 2005, Robert Klemme wrote:
    > >
    > >> This sounds really strange. Here's what I'd do: use set_trace_func
    > >> to write out all method invocations, returns and thread ids and try
    > >> to see where it goes. HTH

    > >
    > > Good job I tried to add docs to profiler.rb in stdlib yesterday.
    > > I'll have a go at that. I've not played with set_trace_func before,
    > > so it should be interesting.

    >
    > This should get you started:
    >
    > set_trace_func lambda {|event, file, line, id, binding, classname|
    > $stderr.printf "th %10d: %-10s %s: %d\n", Thread.current.object_id,
    > event, file, line if
    > /call|return/ =~ event
    > }
    >
    > Good luck!


    thanks. It did the trick. I was hoisted by my own petard.

    begin
    copy_entry s, d, options[:preserve], options[:dereference_root]
    rescue Exception, SystemCallError => e
    stop = true
    if block_given?
    stop = yield s,d,e
    end
    raise if stop
    end

    Yes, I forgot to return nil from the *flaming* block! So it re-raised
    because stop was true.

    I didn't realize set_trace_func could be so useful. I'd previously
    considered it obscure. Thank you for helping me out with this.

    >
    > robert
    >


    Hugh
     
    Hugh Sasse, Nov 3, 2005
    #14
  15. Hugh Sasse wrote:
    > On Thu, 3 Nov 2005, Robert Klemme wrote:
    >
    >> Hugh Sasse wrote:
    >>> On Thu, 3 Nov 2005, Robert Klemme wrote:
    >>>
    >>>> This sounds really strange. Here's what I'd do: use set_trace_func
    >>>> to write out all method invocations, returns and thread ids and try
    >>>> to see where it goes. HTH
    >>>
    >>> Good job I tried to add docs to profiler.rb in stdlib yesterday.
    >>> I'll have a go at that. I've not played with set_trace_func before,
    >>> so it should be interesting.

    >>
    >> This should get you started:
    >>
    >> set_trace_func lambda {|event, file, line, id, binding, classname|
    >> $stderr.printf "th %10d: %-10s %s: %d\n", Thread.current.object_id,
    >> event, file, line if
    >> /call|return/ =~ event
    >> }
    >>
    >> Good luck!

    >
    > thanks. It did the trick. I was hoisted by my own petard.


    Although the meaning is obvious I had to look up "petard". Did you know
    your proverb originates from Shaky?
    http://dictionary.reference.com/search?q=petard

    > begin
    > copy_entry s, d, options[:preserve],
    > options[:dereference_root] rescue Exception, SystemCallError =>
    > e stop = true
    > if block_given?
    > stop = yield s,d,e
    > end
    > raise if stop
    > end
    >
    > Yes, I forgot to return nil from the *flaming* block! So it re-raised
    > because stop was true.


    :)) Silly us - this happens to me once in a while, too.

    > I didn't realize set_trace_func could be so useful. I'd previously
    > considered it obscure. Thank you for helping me out with this.


    You're welcome! I'm glad you finally managed to kill the beast. :)

    Kind regards

    robert
     
    Robert Klemme, Nov 3, 2005
    #15
  16. Hugh Sasse

    Hugh Sasse Guest

    On Thu, 3 Nov 2005, Robert Klemme wrote:

    > Hugh Sasse wrote:
    > > On Thu, 3 Nov 2005, Robert Klemme wrote:
    > >
    > >> This should get you started:
    > >>
    > >> set_trace_func lambda {|event, file, line, id, binding, classname|
    > >> $stderr.printf "th %10d: %-10s %s: %d\n", Thread.current.object_id,
    > >> event, file, line if
    > >> /call|return/ =~ event
    > >> }
    > >>
    > >> Good luck!

    > >
    > > thanks. It did the trick. I was hoisted by my own petard.

    >
    > Although the meaning is obvious I had to look up "petard". Did you know
    > your proverb originates from Shaky?
    > http://dictionary.reference.com/search?q=petard


    I thought you meant "Shaking Stevens" for a minute! I know it was
    Shakespearian in origin, but didn't know about the French and Latin
    roots. Makes one wonder about "petition"...
    >
    > > begin
    > > copy_entry s, d, options[:preserve],
    > > options[:dereference_root] rescue Exception, SystemCallError =>
    > > e stop = true
    > > if block_given?
    > > stop = yield s,d,e
    > > end
    > > raise if stop
    > > end
    > >
    > > Yes, I forgot to return nil from the *flaming* block! So it re-raised
    > > because stop was true.

    >
    > :)) Silly us - this happens to me once in a while, too.


    It seems to take so long to figure out. Anyway, now I've a
    shortcut.
    >
    > > I didn't realize set_trace_func could be so useful. I'd previously
    > > considered it obscure. Thank you for helping me out with this.

    >
    > You're welcome! I'm glad you finally managed to kill the beast. :)
    >
    > Kind regards
    >
    > robert
    >

    Thank you,
    Hugh
    >
    >
     
    Hugh Sasse, Nov 3, 2005
    #16
  17. Selon Hugh Sasse <>:

    >
    > I thought you meant "Shaking Stevens" for a minute! I know it was
    > Shakespearian in origin, but didn't know about the French and Latin
    > roots. Makes one wonder about "petition"...
    > >


    It does come from Latin through French too, but luckily it doesn't have t=
    he same
    Latin root ;) . In this case, the root is the Latin verb petere: to ask, =
    to
    request. Yeah, I know it's disappointing ;) .

    See: http://dictionary.reference.com/search?q=3Dpetition
    --
    Christophe Grandsire.

    http://rainbow.conlang.free.fr

    It takes a straight mind to create a twisted conlang.
     
    Christophe Grandsire, Nov 3, 2005
    #17
  18. Hugh Sasse

    Hugh Sasse Guest

    On Thu, 3 Nov 2005, Christophe Grandsire wrote:

    > Selon Hugh Sasse <>:
    >
    > >
    > > I thought you meant "Shaking Stevens" for a minute! I know it was
    > > Shakespearian in origin, but didn't know about the French and Latin
    > > roots. Makes one wonder about "petition"...
    > > >

    >
    > It does come from Latin through French too, but luckily it doesn't have the same


    I should have put a smiley there :)

    > Latin root ;) . In this case, the root is the Latin verb petere: to ask, to


    :) "simon, I shall call you Peter, because you will be asked a
    question three times..." :) [Yes, I know it was Petrus]

    > request. Yeah, I know it's disappointing ;) .
    >
    > See: http://dictionary.reference.com/search?q=petition
    > --
    > Christophe Grandsire.
    >
    > http://rainbow.conlang.free.fr
    >
    > It takes a straight mind to create a twisted conlang.


    And I was thinking of the latin contribution to Esperanto, but then
    peteri would be to ask part of a question :) Well, possibly only
    to the extent that litero should be part of a bed!

    Hugh
    >
    >
     
    Hugh Sasse, Nov 3, 2005
    #18
  19. Selon Hugh Sasse <>:

    >
    > I should have put a smiley there :)
    >


    I did understand it without the smiley, which is why I added the "Yeah, I=
    know
    it's disappointing ;)" sentence. OK, my humour sucks sometimes... OK, oft=
    en...
    ;)

    > >
    > > It takes a straight mind to create a twisted conlang.

    >
    > And I was thinking of the latin contribution to Esperanto, but then
    > peteri would be to ask part of a question :) Well, possibly only
    > to the extent that litero should be part of a bed!
    >


    LOL!
    --
    Christophe Grandsire.

    http://rainbow.conlang.free.fr

    It takes a straight mind to create a twisted conlang.
     
    Christophe Grandsire, Nov 3, 2005
    #19
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. =?Utf-8?B?QmlsbA==?=

    Trapping 'compile' errors when aspx page is rendered.

    =?Utf-8?B?QmlsbA==?=, Mar 29, 2005, in forum: ASP .Net
    Replies:
    4
    Views:
    518
    =?Utf-8?B?QmlsbA==?=
    Mar 29, 2005
  2. Aaron Fude

    Trapping JNI errors

    Aaron Fude, Jun 1, 2004, in forum: Java
    Replies:
    4
    Views:
    1,500
    Gordon Beaton
    Jun 2, 2004
  3. Avi Kak
    Replies:
    6
    Views:
    318
    Duncan Booth
    Feb 13, 2006
  4. Eitan

    Trapping errors in ASP

    Eitan, Jan 12, 2005, in forum: ASP General
    Replies:
    6
    Views:
    132
    Bob Barrows [MVP]
    Jan 13, 2005
  5. Eitan
    Replies:
    3
    Views:
    131
    Bob Barrows [MVP]
    Jan 12, 2005
Loading...

Share This Page