<commit_before>require 'rundock'
require 'singleton'
require 'specinfra/core'
require 'io/console'
require 'net/ssh'

Specinfra::Configuration.error_on_missing_backend_type = true

module Rundock
  module Backend
    CommandResultStatusError = Class.new(StandardError)

    class << self
      def create(type, options = {})
        self.const_get(type.capitalize).new(type, options)
      end
    end

    class Base
      attr_reader :options
      attr_reader :backend

      def initialize(type, options)
        @options = parse(options)
        @backend = create_specinfra_backend
      end

      def run_command(cmd , options = {})

        command = cmd.strip
        command = "cd #{Shellwords.escape(options[:cwd])} && #{command}" if options[:cwd]
        command = "sudo -H -u #{Shellwords.escape(user)} -- /bin/sh -c #{command}" if options[:user]

        Logger.debug(%Q{Start executing: "#{command}"})

        result = @backend.run_command(command)
        exit_status = result.exit_status

        Logger.formatter.indent do
          Logger.error("#{result.stderr}") unless result.stderr.blank?
          Logger.info("#{result.stdout.strip}") unless result.stdout.strip.blank?
          Logger.debug("exit status: #{exit_status}")
        end

        if options[:no_continue_if_error] && exit_status != 0
          raise CommandResultStatucError
        end

        result
      end

      private

      def parse(options)
        raise NotImplementedError
      end

      def create_specinfra_backend
        raise NotImplementedError
      end
    end

    class Local < Base
      private

      def parse(options)
        options
      end

      def create_specinfra_backend
        Specinfra::Backend::Exec.new()
      end
    end

    class Ssh < Base
      private

      def parse(options)

        if options['ssh_config'] && File.exists?(options['ssh_config'])
          ssh_opts = Net::SSH::Config.for(options['host'], files=[options['ssh_config']])
        else
          ssh_opts = Net::SSH::Config.for(options['host'])
          ssh_opts[:user] = options['user'] || Etc.getlogin
          ssh_opts[:keys] = Array(options['key']) if options['key']
          ssh_opts[:keys] = ssh_opts[:keys] || ["#{ENV['HOME']}/.ssh/id_rsa"]
          ssh_opts[:port] = options['port'] || 22
        end

        ssh_opts[:host_name] = options['host']

        if options['ask_password']
          print "password: "
          passwd = STDIN.noecho(&:gets).strip
          print "\n"
          ssh_opts[:password] = passwd
        end

        ssh_opts.merge!(filter_net_ssh_options(options))

        Logger.debug(%Q{Net::SSH Options: "#{ssh_opts}"})

        ssh_opts
      end

      def filter_net_ssh_options(options)

        opts = {}
        options.each do |k,v|<commit_msg>Update Net::SSH options defaults should depends to Net::SSH::Config<commit_after>require 'rundock'
require 'singleton'
require 'specinfra/core'
require 'io/console'
require 'net/ssh'

Specinfra::Configuration.error_on_missing_backend_type = true

module Rundock
  module Backend
    CommandResultStatusError = Class.new(StandardError)

    class << self
      def create(type, options = {})
        self.const_get(type.capitalize).new(type, options)
      end
    end

    class Base
      attr_reader :options
      attr_reader :backend

      def initialize(type, options)
        @options = parse(options)
        @backend = create_specinfra_backend
      end

      def run_command(cmd , options = {})

        command = cmd.strip
        command = "cd #{Shellwords.escape(options[:cwd])} && #{command}" if options[:cwd]
        command = "sudo -H -u #{Shellwords.escape(user)} -- /bin/sh -c #{command}" if options[:user]

        Logger.debug(%Q{Start executing: "#{command}"})

        result = @backend.run_command(command)
        exit_status = result.exit_status

        Logger.formatter.indent do
          Logger.error("#{result.stderr}") unless result.stderr.blank?
          Logger.info("#{result.stdout.strip}") unless result.stdout.strip.blank?
          Logger.debug("exit status: #{exit_status}")
        end

        if options[:no_continue_if_error] && exit_status != 0
          raise CommandResultStatucError
        end

        result
      end

      private

      def parse(options)
        raise NotImplementedError
      end

      def create_specinfra_backend
        raise NotImplementedError
      end
    end

    class Local < Base
      private

      def parse(options)
        options
      end

      def create_specinfra_backend
        Specinfra::Backend::Exec.new()
      end
    end

    class Ssh < Base
      private

      def parse(options)

        if options['ssh_config'] && File.exists?(options['ssh_config'])
          ssh_opts = Net::SSH::Config.for(options['host'], files=[options['ssh_config']])
        else
          ssh_opts = Net::SSH::Config.for(options['host'])
        end

        ssh_opts[:host_name] = options['host']
        ssh_opts[:user] = options['user']
        ssh_opts[:keys] = Array(options['key']) if options['key']
        ssh_opts[:port] = options['port']

        if options['ask_password']
          print "password: "
          passwd = STDIN.noecho(&:gets).strip
          print "\n"
          ssh_opts[:password] = <PASSWORD>
        end

        ssh_opts.merge!(filter_net_ssh_options(options))

        Logger.debug(%Q{Net::SSH Options: "#{ssh_opts}"})

        ssh_opts
      end

      def filter_net_ssh_options(options)

        opts = {}
        options.each do |k,v|
{'fraction_non_alphanumeric': 0.11910759265922993, 'fraction_numerical': 0.0007196833393306944, 'mean_word_length': 2.437847866419295, 'pattern_counts': {'":': 0, '<': 12, '<?xml version=': 0, '>': 4, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 1, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4189751', 'n_tokens_mistral': 1696, 'n_tokens_neox': 1600, 'n_words': 339}