class Fig::OperatingSystem

Does things requiring real O/S interaction, primarilly taking care of file transfers and running external commands.

Constants

UNIX_FILE_NAME_ILLEGAL_CHARACTERS
WINDOWS_FILE_NAME_ILLEGAL_CHARACTERS

Public Class Methods

file_name_illegal_characters() click to toggle source
# File lib/fig/operating_system.rb, line 40
def self.file_name_illegal_characters()
  if Fig::OperatingSystem.windows?
    return WINDOWS_FILE_NAME_ILLEGAL_CHARACTERS
  end

  return UNIX_FILE_NAME_ILLEGAL_CHARACTERS
end
get_environment_variables(initial_values = nil) click to toggle source
# File lib/fig/operating_system.rb, line 56
def self.get_environment_variables(initial_values = nil)
  if Fig::OperatingSystem.windows?
    return Fig::EnvironmentVariables::CaseInsensitive.new(initial_values)
  end

  return Fig::EnvironmentVariables::CaseSensitive.new(initial_values)
end
new(login) click to toggle source
# File lib/fig/operating_system.rb, line 64
def initialize(login)
  @protocols = {}
  @protocols['file'] = Fig::Protocol::File.new
  @protocols['ftp']  = Fig::Protocol::FTP.new login
  @protocols['http'] = Fig::Protocol::HTTP.new
  @protocols['sftp'] = Fig::Protocol::SFTP.new
  @protocols['ssh']  = Fig::Protocol::SSH.new
end
unix?() click to toggle source
# File lib/fig/operating_system.rb, line 36
def self.unix?
  ! Fig::OperatingSystem.windows?
end
windows?() click to toggle source
# File lib/fig/operating_system.rb, line 32
def self.windows?
  return !! (RbConfig::CONFIG['host_os'] =~ /mswin|mingw/)
end
wrap_variable_name_with_shell_expansion(variable_name) click to toggle source
# File lib/fig/operating_system.rb, line 48
def self.wrap_variable_name_with_shell_expansion(variable_name)
  if Fig::OperatingSystem.windows?
    return "%#{variable_name}%"
  else
    return "$#{variable_name}"
  end
end

Public Instance Methods

copy(source, target, msg = nil) click to toggle source
# File lib/fig/operating_system.rb, line 161
def copy(source, target, msg = nil)
  if File.directory?(source)
    FileUtils.mkdir_p(target)
    Dir.foreach(source) do |child|
      if child != '.' and child != '..'
        copy(File.join(source, child), File.join(target, child), msg)
      end
    end
  else
    if (
          ! File.exist?(target)                     \
      ||  File.mtime(source) != File.mtime(target)  \
      ||  File.size(source) != File.size(target)
    )
      Fig::Logging.info "#{msg} #{target}" if msg
      FileUtils.mkdir_p(File.dirname(target))
      FileUtils.cp(source, target)
      File.utime(File.atime(source), File.mtime(source), target)
    end
  end
end
create_archive(archive_name, paths_to_archive) click to toggle source

Expects paths_to_archive as an Array of paths.

# File lib/fig/operating_system.rb, line 188
def create_archive(archive_name, paths_to_archive)
  # TODO: Need to verify files_to_archive exists.
  ::Archive.write_open_filename(
    archive_name, ::Archive::COMPRESSION_GZIP, ::Archive::FORMAT_TAR
  ) do |writer|
    paths_to_archive.each do |path|
      add_path_to_archive(path, writer)
    end
  end
end
delete_and_recreate_directory(dir) click to toggle source
# File lib/fig/operating_system.rb, line 156
def delete_and_recreate_directory(dir)
  FileUtils.rm_rf(dir)
  FileUtils.mkdir_p(dir)
end
download(url, 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/operating_system.rb, line 106
def download(url, path, prompt_for_login)
  protocol, uri = decode_protocol url

  FileUtils.mkdir_p(File.dirname path)

  return protocol.download uri, path, prompt_for_login
end
download_and_unpack_archive(url, download_directory, unpack_directory) click to toggle source
# File lib/fig/operating_system.rb, line 126
def download_and_unpack_archive(url, download_directory, unpack_directory)
  basename, path = download_resource(url, download_directory)

  case path
  when /\.tar\.gz$/
    unpack_archive(unpack_directory, path)
  when /\.tgz$/
    unpack_archive(unpack_directory, path)
  when /\.tar\.bz2$/
    unpack_archive(unpack_directory, path)
  when /\.zip$/
    unpack_archive(unpack_directory, path)
  else
    Fig::Logging.fatal "Unknown archive type: #{basename}"
    raise Fig::NetworkError.new("Unknown archive type: #{basename}")
  end

  return
end
download_list(url) click to toggle source
# File lib/fig/operating_system.rb, line 81
def download_list(url)
  begin
    protocol, uri = decode_protocol url

    return protocol.download_list uri
  rescue SocketError => error
    Fig::Logging.debug error.message
    raise Fig::NetworkError.new "#{url}: #{error.message}"
  rescue Errno::ETIMEDOUT => error
    Fig::Logging.debug error.message
    raise Fig::NetworkError.new "#{url}: #{error.message}"
  end
end
download_resource(url, download_directory) click to toggle source

Returns the basename and full path to the download.

# File lib/fig/operating_system.rb, line 115
def download_resource(url, download_directory)
  FileUtils.mkdir_p(download_directory)

  basename = CGI.unescape Fig::URL.parse(url).path.split('/').last
  path     = File.join(download_directory, basename)

  download(url, path, false)

  return basename, path
end
list(dir) click to toggle source
# File lib/fig/operating_system.rb, line 73
def list(dir)
  Dir.entries(dir) - ['.', '..']
end
move_file(directory, from, to) click to toggle source
# File lib/fig/operating_system.rb, line 183
def move_file(directory, from, to)
  Dir.chdir(directory) { FileUtils.mv(from, to, :force => true) }
end
path_up_to_date?(url, 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/operating_system.rb, line 97
def path_up_to_date?(url, path, prompt_for_login)
  return false if ! File.exist? path

  protocol, uri = decode_protocol url
  return protocol.path_up_to_date? uri, path, prompt_for_login
end
plain_exec(command) click to toggle source
# File lib/fig/operating_system.rb, line 245
def plain_exec(command)
  # Kernel#exec won't run Kernel#at_exit handlers.
  Fig::AtExit.execute()
  if ENV['FIG_COVERAGE']
    SimpleCov.at_exit.call
  end

  begin
    Kernel.exec(*command)
  rescue SystemCallError => exception
    raise Fig::UserInputError.new exception
  end
end
plain_or_shell_exec(command) click to toggle source

sigh Apparently Ruby < v1.9.3 does some wacko thing with single argument exec that causes it to not invoke the shell, so we've got this mess.

# File lib/fig/operating_system.rb, line 261
def plain_or_shell_exec(command)
  if command.size > 1
    plain_exec(command)
  else
    shell_exec(command[0])
  end
end
shell_exec(command) click to toggle source
# File lib/fig/operating_system.rb, line 237
def shell_exec(command)
  if Fig::OperatingSystem.windows?
    plain_exec [ ENV['ComSpec'],            '/c', command ]
  else
    plain_exec [ ENV['SHELL'] || '/bin/sh', '-c', command ]
  end
end
unpack_archive(directory, archive_path) click to toggle source

This method can handle the following archive types: .tar.bz2 .tar.gz .tgz .zip

# File lib/fig/operating_system.rb, line 204
def unpack_archive(directory, archive_path)
  FileUtils.mkdir_p directory
  Dir.chdir(directory) do
    if ! File.exists? archive_path
      raise Fig::RepositoryError.new "#{archive_path} does not exist."
    end

    running_on_windows = Fig::OperatingSystem.windows?
    ::Archive.read_open_filename(archive_path) do |reader|
      while entry = reader.next_header
        if running_on_windows
          check_archive_entry_for_windows entry, archive_path
        end

        begin
          reader.extract(entry)
        rescue Archive::Error => exception
          # Nice how the error message doesn't include any information about
          # what was having the problem.
          message = exception.message.sub(/^Extract archive failed: /, '')
          new_exception =
            Fig::RepositoryError.new(
              "Could not extract #{entry.pathname} from #{archive_path}: #{message}"
            )

          new_exception.set_backtrace exception.backtrace
          raise new_exception
        end
      end
    end
  end
end
upload(local_file, remote_file) click to toggle source
# File lib/fig/operating_system.rb, line 146
def upload(local_file, remote_file)
  Fig::Logging.debug "Uploading #{local_file} to #{remote_file}."


  protocol, uri = decode_protocol remote_file
  protocol.upload local_file, uri

  return
end
write(path, content) click to toggle source
# File lib/fig/operating_system.rb, line 77
def write(path, content)
  File.open(path, 'wb') { |f| f.binmode; f << content }
end

Private Instance Methods

add_path_to_archive(path, archive_writer) click to toggle source
# File lib/fig/operating_system.rb, line 279
def add_path_to_archive(path, archive_writer)
  children = []
  archive_writer.new_entry do |entry|
    entry.copy_lstat(path.chomp '/') # chomp required on Windows
    entry.pathname = path
    if entry.symbolic_link?
      linked = File.readlink(path)
      entry.symlink = linked
    end
    archive_writer.write_header(entry)

    if entry.regular?
      archive_writer.write_data(open(path) {|f| f.binmode; f.read })
    elsif entry.directory?
      children = Dir.entries(path) - ['.', '..']
    end
  end

  children.each do
    |child|
    add_path_to_archive(File.join(path, child), archive_writer)
  end

  return
end
check_archive_entry_for_windows(entry, archive_path) click to toggle source
# File lib/fig/operating_system.rb, line 305
def check_archive_entry_for_windows(entry, archive_path)
  bad_type = nil
  if entry.symbolic_link?
    bad_type = 'symbolic link'
  elsif entry.block_special?
    bad_type = 'block device'
  elsif entry.character_special?
    bad_type = 'character device'
  elsif entry.fifo?
    bad_type = 'pipe'
  elsif entry.socket?
    bad_type = 'socket'
  end

  if bad_type
    raise Fig::RepositoryError.new(
      "Could not extract #{entry.pathname} from #{archive_path} because it is a #{bad_type}."
    )
  end

  return
end
decode_protocol(url) click to toggle source
# File lib/fig/operating_system.rb, line 271
def decode_protocol(url)
  uri = Fig::URL.parse(url)
  protocol = @protocols[uri.scheme]
  raise_unknown_protocol(url) if protocol.nil?

  return protocol, uri
end
raise_unknown_protocol(url) click to toggle source
# File lib/fig/operating_system.rb, line 328
def raise_unknown_protocol(url)
  Fig::Logging.fatal %Q<Don't know how to handle the protocol in "#{url}".>
  raise Fig::NetworkError.new(
    %Q<Don't know how to handle the protocol in "#{url}".>
  )

  return
end