tags:

views:

21

answers:

1

When you pass the :verbose flag to a FileUtils command, the command gets printed to stdout - is there a way to capture the command so it can be logged or used elsewhere?

+2  A: 

If you look at the source for FileUtils it uses the following method for doing its verbose output:

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

i.e. it is writing the messages to @fileutils_output and by default it is using $stderr. There doesn't seem to be a method to alter @fileutils_output but you could add one:

module FileUtils
  def FileUtils.fileutils_output=(new_out)
    @fileutils_output = new_out
  end
end

Then if you wanted to capture the commands into a file you could do:

my_fu_log = open('fu_log.log', 'w')
FileUtils.fileutils_output = my_fu_log
# FileUtils operations with :verbose => true here
my_fu_log.close
FileUtils.fileutils_output = $stderr # restore writing to stderr if you want

or if you wanted to get them in a string you could do:

log = StringIO.new
FileUtils.fileutils_output = log
# FileUtils operations with :verbose => true here
# commands are in log.string 

Also, there is a module FileUtils::Verbose which basically includes FileUtils (so has all the same methods) but defaults the options to :verbose => true so if you wanted to capture lots of commands you could use this instead of specifying the option each time. (you would need to add the fileutils_output= method to this module in the same way as above.)

Alternatives

As Joshua says in the comments below, an alternative is to reassign $stderr but as he says this does mean that everything written to stderr (not just by FileUtils) is redirected. If all the FileUtils operations are happening in one go without anything else in between then this might not be an issue. So something along the lines of:

orig_stderr = $stderr # keep reference to original stderr
$stderr = my_fu_log
# use FileUtils here
$stderr = orig_stderr # restore stderr

Finally, you could reopen FileUtils and override fu_output_message(msg) itself if you need more control.

mikej
That was a great answer. Another thing you could do is redirect $stderr to your own object, then you don't have to open up FileUtils class. Of course, you will catch the results of non FileUtils methods that print to $stderr.
Joshua Cheek
@Joshua Yep, you're right. I actually started off with that approach by looking at reassigning `$stdout` but when that didn't work (because it's writing to `$stderr` instead) I ended up digging into the `FileUtils` code and coming up with the above.
mikej
Excellent! Thanks very for the clear answer (and for this discussion here!) Just what I needed :)
Sam Johnson