lib/rye/box.rb in rye-0.7.4 vs lib/rye/box.rb in rye-0.7.5

- old
+ new

@@ -32,29 +32,38 @@ def host; @rye_host; end def opts; @rye_opts; end def safe; @rye_safe; end def user; (@rye_opts || {})[:user]; end + # A storage area +@rye_stash+ + def stash; @rye_stash; end + def nickname; @rye_nickname || host; end + def host=(val); @rye_host = val; end def opts=(val); @rye_opts = val; end + # Returns the storage area +@rye_stash+ + def stash=(val); @rye_stash = val; end + def nickname=(val); @rye_nickname = val; end + def enable_safe_mode; @rye_safe = true; end def disable_safe_mode; @rye_safe = false; end # The most recent value from Box.cd or Box.[] def current_working_directory; @rye_current_working_directory; end # The most recent valud for umask (or 0022) def current_umask; @rye_current_umask; end - - def ssh; @rye_ssh; end + def info; @rye_info; end def debug; @rye_debug; end def error; @rye_error; end def pre_command_hook=(val); @rye_pre_command_hook = val; end def post_command_hook=(val); @rye_post_command_hook = val; end + # A Hash. The keys are exception classes, the values are Procs to execute + def exception_hook=(val); @rye_exception_hook = val; end # * +host+ The hostname to connect to. The default is localhost. # * +opts+ a hash of optional arguments. # # The +opts+ hash excepts the following keys: @@ -70,10 +79,11 @@ # # NOTE: +opts+ can also contain any parameter supported by # Net::SSH.start that is not already mentioned above. # def initialize(host='localhost', opts={}) + @rye_exception_hook = {} @rye_host = host # These opts are use by Rye::Box and also passed to Net::SSH @rye_opts = { :user => Rye.sysinfo.user, @@ -220,11 +230,11 @@ if ret.is_a?(Rye::Rap) debug "ssh-add exit_code: #{ret.exit_code}" debug "ssh-add stdout: #{ret.stdout}" debug "ssh-add stderr: #{ret.stderr}" end - self #MUST RETURN itself + self # MUST RETURN self end alias :add_key :add_keys # Return the value of uname in lowercase # This is a temporary fix. We can use SysInfo for this, upload @@ -277,12 +287,12 @@ # Returns +user@rye_host+ def to_s; '%s@rye_%s' % [user, @rye_host]; end def inspect - %q{#<%s:%s cwd=%s umask=%s env=%s safe=%s opts=%s>} % - [self.class.to_s, self.host, + %q{#<%s:%s name=%s cwd=%s umask=%s env=%s safe=%s opts=%s>} % + [self.class.to_s, self.host, self.nickname, @rye_current_working_directory, @rye_current_umask, (@rye_current_environment_variables || '').inspect, self.safe, self.opts.inspect] end @@ -422,11 +432,13 @@ end # A handler for undefined commands. # Raises Rye::CommandNotFound exception. def method_missing(meth, *args, &block) - raise Rye::CommandNotFound, "#{meth.to_s}" + ex = Rye::CommandNotFound.new(meth.to_s) + raise ex unless @rye_exception_hook.has_key? ex.class + @rye_exception_hook[Rye::CommandNotFound].call ex end # Returns the command an arguments as a String. def preview_command(*args) prep_args(*args).join(' ') @@ -442,10 +454,31 @@ def pre_command_hook(&block) @rye_pre_command_hook = block if block @rye_pre_command_hook end + # Supply a block to be called whenever there's an Exception. It's called + # with 1 argument: the exception class. If the exception block returns + # :retry, the command will be executed again. + # + # e.g. + # rbox.exception_hook(CommandNotFound) do |ex| + # STDERR.puts "An error occurred: #{ex.class}" + # choice = Annoy.get_user_input('(S)kip (R)etry (A)bort: ') + # if choice == 'R' + # :retry + # elsif choice == 'S' + # # do nothing + # else + # exit # ! + # end + # end + def exception_hook(klass, &block) + @rye_exception_hook[klass] = block if block + @rye_exception_hook[klass] + end + # Execute a block in the context of an instance of Rye::Box. # # rbox = Rye::Box.new # # rbox.batch do @@ -620,16 +653,15 @@ if @rye_current_umask cwd = Rye.escape(@rye_safe, 'umask', @rye_current_umask) cmd_clean = [cwd, cmd_clean].join(' && ') end - info "COMMAND: #{cmd_clean}" debug "Executing: %s" % cmd_clean if @rye_pre_command_hook.is_a?(Proc) - @rye_pre_command_hook.call(cmd, args, user, host) + @rye_pre_command_hook.call(cmd, args, user, host, nickname) end ## NOTE: Do not raise a CommandNotFound exception in this method. # We want it to be possible to define methods to a single instance # of Rye::Box. i.e. def rbox.rm()... @@ -637,29 +669,34 @@ # return false. We could use self.respond_to? but it's possible # to get a name collision. I could write a work around but I think # this is good enough for now. ## raise Rye::CommandNotFound unless self.can?(cmd) - stdout, stderr, ecode, esignal = net_ssh_exec!(cmd_clean) - - rap = Rye::Rap.new(self) - rap.add_stdout(stdout || '') - rap.add_stderr(stderr || '') - rap.add_exit_code(ecode) - rap.exit_signal = esignal - rap.cmd = cmd - - if @rye_post_command_hook.is_a?(Proc) - @rye_post_command_hook.call(rap) - else + begin + stdout, stderr, ecode, esignal = net_ssh_exec!(cmd_clean) + + rap = Rye::Rap.new(self) + rap.add_stdout(stdout || '') + rap.add_stderr(stderr || '') + rap.add_exit_code(ecode) + rap.exit_signal = esignal + rap.cmd = cmd + # It seems a convention for various commands to return -1 # when something only mildly concerning happens. ls even # returns -1 for apparently no reason sometimes. In any # case, the real errors are the ones greater than zero raise Rye::CommandError.new(rap) if ecode > 0 + + rescue Exception => ex + raise ex unless @rye_exception_hook.has_key? ex.class + ret = @rye_exception_hook[ex.class].call(ex) + retry if ret == :retry end + @rye_post_command_hook.call(rap) if @rye_post_command_hook.is_a?(Proc) + rap end alias :cmd :run_command # Takes a list of arguments appropriate for run_command or @@ -720,10 +757,10 @@ channel = @rye_ssh.exec(command, &block) channel.wait # block until we get a response channel.request_pty do |ch, success| - raise "Could not obtain pty (i.e. an interactive ssh session)" if !success + raise Rye::NoPty if !success end channel[:exit_code] = 0 if channel[:exit_code] == nil channel[:exit_code] &&= channel[:exit_code].to_i