class Fig::Protocol::SSH

File transfers using external ssh and scp programs

Public Instance Methods

download(uri, path, prompt_for_login) click to toggle source

Returns whether the file was not downloaded because the file already exists and is already up-to-date.

# File lib/fig/protocol/ssh.rb, line 61
def download(uri, path, prompt_for_login)
  unescaped_path = CGI.unescape uri.path

  exists = remote_path_exists(uri.host, unescaped_path) {
    |error_message|

    raise Fig::NetworkError.new(
      "Unable to determine whether #{uri} exists: #{error_message}",
    )
  }
  if not exists
    raise Fig::FileNotFoundError.new "#{uri} doesn't exist.", uri
  end

  scp("#{uri.host}:#{unescaped_path}", path) {
    |error_message|

    raise Fig::NetworkError.new(
      "Unable to copy remote file to #{path}: #{error_message}",
    )
  }

  return true
end
download_list(uri) click to toggle source
# File lib/fig/protocol/ssh.rb, line 16
def download_list(uri)
  packages = []
  unescaped_path = CGI.unescape uri.path

  ls = ssh(uri.host, 'find', unescaped_path, '-type', 'd') {
    |error_message|

    raise Fig::NetworkError.new error_message
  }

  strip_paths_for_list(ls, packages, unescaped_path)

  return packages
end
path_up_to_date?(uri, path, prompt_for_login) click to toggle source

Determine whether we need to update something. Returns nil to indicate “don't know”.

# File lib/fig/protocol/ssh.rb, line 33
def path_up_to_date?(uri, path, prompt_for_login)
  unescaped_path = CGI.unescape uri.path

  size_mtime = ssh(uri.host, 'stat', '--format="%s %Z"', unescaped_path) {
    |error_message|

    raise Fig::NetworkError.new(
      "Unable to get size and modification time for remote path #{path}: #{error_message}",
    )
  }

  remote_size, remote_mtime = size_mtime.split
  remote_size  = remote_size.to_i
  remote_mtime = remote_mtime.to_i

  if remote_size != ::File.size(path)
    return false
  end

  if remote_mtime <= ::File.mtime(path).to_i
    return true
  end

  return false
end
upload(local_file, uri) click to toggle source
# File lib/fig/protocol/ssh.rb, line 86
def upload(local_file, uri)
  unescaped_path = CGI.unescape uri.path

  ssh(uri.host, 'mkdir', '-p', ::File.dirname(unescaped_path)) {
    |error_message|

    raise Fig::NetworkError.new(
      "Unable to create directory on remote: #{error_message}",
    )
  }

  scp(local_file, "#{uri.host}:#{unescaped_path}") {
    |error_message|

    raise Fig::NetworkError.new(
      "Unable to copy #{local_file} to remote: #{error_message}",
    )
  }

  return
end

Private Instance Methods

remote_path_exists(host, path) { |%Q<Could not run "#{join ' '}": #{message}.>| ... } click to toggle source
# File lib/fig/protocol/ssh.rb, line 130
def remote_path_exists(host, path, &error_block)
  ssh_command = ['ssh', '-n', host, 'test', '-e', path]
  begin
    *, result = Fig::ExternalProgram.capture ssh_command
  rescue Errno::ENOENT => error
    yield %Q<Could not run "#{ssh_command.join ' '}": #{error.message}.>

    return
  end

  if result && ! result.success?
    return false
  end

  return true
end
scp(from, to) { |%Q<Could not run "#{join ' '}": #{message}.>| ... } click to toggle source

Use external scp program to copy a file.

# File lib/fig/protocol/ssh.rb, line 148
def scp(from, to, &error_block)
  command = ['scp', from, to]
  begin
    output, errors, result = Fig::ExternalProgram.capture command
  rescue Errno::ENOENT => error
    yield %Q<Could not run "#{command.join ' '}": #{error.message}.>

    return
  end

  if result && ! result.success?
    yield %Q<Could not run "#{command.join ' '}": #{result}: #{errors}>

    return
  end

  return output
end
ssh(host, *command) { |%Q<Could not run "#{join ' '}": #{message}.>| ... } click to toggle source

Execute command on remote host with external ssh program.

# File lib/fig/protocol/ssh.rb, line 111
def ssh(host, *command, &error_block)
  ssh_command = ['ssh', '-n', host, *command]
  begin
    output, errors, result = Fig::ExternalProgram.capture ssh_command
  rescue Errno::ENOENT => error
    yield %Q<Could not run "#{ssh_command.join ' '}": #{error.message}.>

    return
  end

  if result && ! result.success?
    yield %Q<Could not run "#{ssh_command.join ' '}": #{result}: #{errors}>

    return
  end

  return output
end