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?
问题:
回答1:
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.
回答2:
To add to Mike's answer (since I can't comment), I created this wrapper def
if you want to get the output as a string:
def fileutil_out
out = StringIO.new
FileUtils.fileutils_output = out
yield
return out.string
end
mylog.info fileutil_out { FileUtils.chmod_R(0664, 'file.txt', :verbose => isVerbose) }
I ended up not using it since I wanted to revert back to @fileutils_output ||= $stderr
afterwards.