<commit_before>module Fog
  module SSH

    def self.new(address, username, options = {})
      unless options[:key_data] || options[:keys] || options[:password] || ENV['SSH_AUTH_SOCK']
        raise ArgumentError.new(':key_data, :keys, :password or ENV[\'SSH_AUTH_SOCK\'] are required to initialize SSH')
      end
      if Fog.mocking?
        Fog::SSH::Mock.new(address, username, options)
      else
        Fog::SSH::Real.new(address, username, options)
      end
    end

    def self.reset_data(keys=Mock.data.keys)
      Mock.reset_data(keys)
    end

    class Mock

      def self.data
        @data ||= Hash.new do |hash, key|
          hash[key] = {}
        end
      end

      def initialize(address, username, options)
        @address  = address
        @username = username
        @options  = options
      end

      def run(commands)
        Fog::Mock.not_implemented
      end

    end

    class Real

      def initialize(address, username, options)
        require 'net/ssh'
        @address  = address
        @username = username
        @options  = { :paranoid => false }.merge(options)
      end

      def run(commands)
        commands = [*commands]
        results  = []
        begin
          Net::SSH.start(@address, @username, @options) do |ssh|
            commands.each do |command|
              escaped_command = command.sub(/'/, %{'"'"'})
              result = Result.new(escaped_command)
              ssh.open_channel do |ssh_channel|
                ssh_channel.request_pty
                ssh_channel.exec(%{bash -lc '#{escaped_command}'}) do |channel, success|
                  unless success
                    raise "Could not execute command: #{command.inspect}"
                  end

                  channel.on_data do |ch, data|
                    result.stdout << data
                  end

                  channel.on_extended_data do |ch, type, data|<commit_msg>Use Net::SSH's KeyManager to detect ssh-agent<commit_after>module Fog
  module SSH

    def self.new(address, username, options = {})
      if Fog.mocking?
        Fog::SSH::Mock.new(address, username, options)
      else
        Fog::SSH::Real.new(address, username, options)
      end
    end

    def self.reset_data(keys=Mock.data.keys)
      Mock.reset_data(keys)
    end

    class Mock

      def self.data
        @data ||= Hash.new do |hash, key|
          hash[key] = {}
        end
      end

      def initialize(address, username, options)
        @address  = address
        @username = username
        @options  = options
      end

      def run(commands)
        Fog::Mock.not_implemented
      end

    end

    class Real

      def initialize(address, username, options)
        require 'net/ssh'

        key_manager = Net::SSH::Authentication::KeyManager.new(nil, options)

        unless options[:key_data] || options[:keys] || options[:password] || key_manager.agent
          raise ArgumentError.new(':key_data, :keys, :password or a loaded ssh-agent is required to initialize SSH')
        end

        @address  = address
        @username = username
        @options  = { :paranoid => false }.merge(options)
      end

      def run(commands)
        commands = [*commands]
        results  = []
        begin
          Net::SSH.start(@address, @username, @options) do |ssh|
            commands.each do |command|
              escaped_command = command.sub(/'/, %{'"'"'})
              result = Result.new(escaped_command)
              ssh.open_channel do |ssh_channel|
                ssh_channel.request_pty
                ssh_channel.exec(%{bash -lc '#{escaped_command}'}) do |channel, success|
                  unless success
                    raise "Could not execute command: #{command.inspect}"
                  end

                  channel.on_data do |ch, data|
                    result.stdout << data
                  end

                  channel.on_extended_data do |ch, type, data|
{'fraction_non_alphanumeric': 0.10631313131313132, 'fraction_numerical': 0.0, 'mean_word_length': 1.8192170818505338, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 5, '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': '4583100', 'n_tokens_mistral': 1163, 'n_tokens_neox': 1089, 'n_words': 277}