GomaaK/sshez

View on GitHub
lib/sshez/exec.rb

Summary

Maintainability
A
1 hr
Test Coverage
require 'forwardable'
module Sshez
  #
  # handles all the ssh commands and updates to the .ssh/config file
  #
  class Exec
    extend Forwardable
    FILE_PATH = File.expand_path('~') + '/.ssh/config'
    PRINTER = PrintingManager.instance
    #
    # to create an instance pass any +Struct+(listener) that handles the following methods
    # *  :argument_error(+Command+)
    # *  :done_with_no_guarantee
    # *  :permission_error
    # *  :finished_successfully
    #
    attr_reader :listener

    def_delegators :@listener, :argument_error
    def_delegators :@listener, :done_with_no_guarantee

    #
    # Must have the methods mentioned above
    #
    def initialize(listener)
      @listener = listener
    end

    #
    # Starts the execution of the +Command+ parsed with its options
    #
    def start_exec(command, options)
      all_args = command.args
      all_args << options
      self.send(command.name, *all_args)
    end

    private
    #
    # connects to host using alias
    #
    def connect(alias_name, options)
      file = File.open(FILE_PATH, 'r')
      servers = all_hosts_in(file)
      if servers.include?alias_name
        PRINTER.verbose_print "Connecting to #{alias_name}"
        exec "ssh #{alias_name}"
      else
        PRINTER.print "Could not find host `#{alias_name}`"
      end
    end

    #
    # append an alias for the given user@host with the options passed
    #
    def add(alias_name, user, host, options)
      begin
        PRINTER.verbose_print "Adding\n"
        config_append = form(alias_name, user, host, options)
        PRINTER.verbose_print config_append
        unless options.test
          file = File.open(FILE_PATH, 'a+')
          file.write(config_append)
          file.close

          # causes a bug in fedore if permission was not updated to 0600
          File.chmod(0600, FILE_PATH)
          # system "chmod 600 #{FILE_PATH}"
        end
      rescue
        return permission_error
      end
      PRINTER.verbose_print "to #{FILE_PATH}"
      PRINTER.print "Successfully added `#{alias_name}` as an alias for `#{user}@#{host}`"
      PRINTER.print "Try sshez connect #{alias_name}"

      finish_exec
    end # add(alias_name, user, host, options)

    #
    # returns the text that will be added to the config file
    #
    def form(alias_name, user, host, options)
      retuned = "\n"
      retuned += "Host #{alias_name}\n"
      retuned += "  HostName #{host}\n"
      retuned += "  User #{user}\n"

      options.file_content.each_pair do |key, value|
        retuned += value
      end
      retuned

    end # form(alias_name, user, host, options)

    #
    # removes an alias from the config file (all its occurrences will be removed too)
    #
    def remove(alias_name, options)
      file = File.open(FILE_PATH, 'r')
      servers = all_hosts_in(file)
      if servers.include?alias_name
        new_file = File.open(FILE_PATH + 'temp', 'w')
        remove_alias_name(alias_name, file, new_file)

        File.delete(FILE_PATH)
        File.rename(FILE_PATH + 'temp', FILE_PATH)
        # Causes a bug in fedore if permission was not updated to 0600
        File.chmod(0600, FILE_PATH)
        PRINTER.print "`#{alias_name}` was successfully removed from your hosts"
      else
        PRINTER.print "Could not find host `#{alias_name}`"
      end
      finish_exec
    end # remove(alias_name, options)

    #
    # copies the content of the file to the new file without
    # the sections concerning the alias_name
    #
    def remove_alias_name(alias_name, file, new_file)
      started_removing = false
      file.each do |line|
        started_removing ||= line.include?("Host #{alias_name}")
        if started_removing
          # I will never stop till I find another host that is not the one I'm removing
          stop_removing = (started_removing && line.include?('Host ') && !(line =~ /\b#{alias_name}\b/))
          PRINTER.verbose_print line unless stop_removing
          if stop_removing && started_removing
            new_file.write(line)
          end
          started_removing = !stop_removing
        else
          # Everything else should be transfered safely to the other file
          new_file.write(line)
        end
      end
      file.close
      new_file.close
    end #remove_alias_name(alias_name, file, new_file)

    #
    # lists the aliases available in the config file
    #
    def list(options)
      file = File.open(FILE_PATH, 'a+')
      servers = all_hosts_in(file)
      file.close
      if servers.empty?
        PRINTER.print 'No aliases added'
      else
        PRINTER.print 'Listing aliases:'
        servers.each{|x| PRINTER.print "\t- #{x}"}
      end
      finish_exec
    end # list(options)

    def reset(options)
      resp = PRINTER.prompt 'Are you sure you want to remove all aliases? [Y/n]'
      if resp.match(/y/i)
        file = File.open(FILE_PATH, "w")
        file.close
        PRINTER.print 'You have successfully reset your ssh config file.'
      end
    end

    #
    # Returns all the alias names of in the file
    #
    def all_hosts_in(file)
      servers = []
      file.each do |line|
        if line.include?('Host ')
          servers << line.sub('Host ', '').strip
        end
      end
      servers
    end

    #
    # Raises a permission error to the listener
    #
    def permission_error
      listener.permission_error
    end

    #
    # finished editing the file successfully
    #
    def finish_exec
      listener.finished_successfully
    end
    # private
  end # class FileManager
end