Class: Fig::OperatingSystem

Inherits:
Object
  • Object
show all
Defined in:
lib/fig/operating_system.rb

Overview

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

Constant Summary collapse

WINDOWS_FILE_NAME_ILLEGAL_CHARACTERS =
%w[ \\ / : * ? " < > | ]
UNIX_FILE_NAME_ILLEGAL_CHARACTERS =
%w[ / ]

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(login) ⇒ OperatingSystem

Returns a new instance of OperatingSystem.



61
62
63
64
65
66
67
# File 'lib/fig/operating_system.rb', line 61

def initialize()
  @protocols = {}
  @protocols['file'] = Fig::Protocol::File.new
  @protocols['ftp']  = Fig::Protocol::FTP.new 
  @protocols['http'] = Fig::Protocol::HTTP.new
  @protocols['sftp'] = Fig::Protocol::SFTP.new
end

Class Method Details

.file_name_illegal_charactersObject



37
38
39
40
41
42
43
# File 'lib/fig/operating_system.rb', line 37

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) ⇒ Object



53
54
55
56
57
58
59
# File 'lib/fig/operating_system.rb', line 53

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

.unix?Boolean

Returns:

  • (Boolean)


33
34
35
# File 'lib/fig/operating_system.rb', line 33

def self.unix?
  ! Fig::OperatingSystem.windows?
end

.windows?Boolean

Returns:

  • (Boolean)


29
30
31
# File 'lib/fig/operating_system.rb', line 29

def self.windows?
  return !! (RbConfig::CONFIG['host_os'] =~ /mswin|mingw/)
end

.wrap_variable_name_with_shell_expansion(variable_name) ⇒ Object



45
46
47
48
49
50
51
# File 'lib/fig/operating_system.rb', line 45

def self.wrap_variable_name_with_shell_expansion(variable_name)
  if Fig::OperatingSystem.windows?
    return "%#{variable_name}%"
  else
    return "$#{variable_name}"
  end
end

Instance Method Details

#copy(source, target, msg = nil) ⇒ Object



161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
# 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)
      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) ⇒ Object

Expects paths_to_archive as an Array of paths.



184
185
186
187
188
189
190
191
192
193
# File 'lib/fig/operating_system.rb', line 184

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) ⇒ Object



156
157
158
159
# 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) ⇒ Object

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



106
107
108
109
110
111
112
# File 'lib/fig/operating_system.rb', line 106

def download(url, path, )
  protocol, uri = decode_protocol url

  FileUtils.mkdir_p(File.dirname path)

  return protocol.download uri, path, 
end

#download_and_unpack_archive(url, download_directory, unpack_directory) ⇒ Object



126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
# 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) ⇒ Object



81
82
83
84
85
86
87
88
89
90
91
92
93
# 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) ⇒ Object

Returns the basename and full path to the download.



115
116
117
118
119
120
121
122
123
124
# 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) ⇒ Object



69
70
71
# File 'lib/fig/operating_system.rb', line 69

def list(dir)
  Dir.entries(dir) - ['.', '..']
end

#move_file(directory, from, to) ⇒ Object



179
180
181
# File 'lib/fig/operating_system.rb', line 179

def move_file(directory, from, to)
  Dir.chdir(directory) { FileUtils.mv(from, to, :force => true) }
end

#mtime(path) ⇒ Object



73
74
75
# File 'lib/fig/operating_system.rb', line 73

def mtime(path)
  File.mtime(path)
end

#path_up_to_date?(url, path, prompt_for_login) ⇒ Boolean

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

Returns:

  • (Boolean)


97
98
99
100
101
102
# File 'lib/fig/operating_system.rb', line 97

def path_up_to_date?(url, path, )
  return false if ! File.exist? path

  protocol, uri = decode_protocol url
  return protocol.path_up_to_date? uri, path, 
end

#plain_exec(command) ⇒ Object



241
242
243
244
245
246
247
248
249
250
251
252
253
# File 'lib/fig/operating_system.rb', line 241

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) ⇒ Object

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.



257
258
259
260
261
262
263
# File 'lib/fig/operating_system.rb', line 257

def plain_or_shell_exec(command)
  if command.size > 1
    plain_exec(command)
  else
    shell_exec(command[0])
  end
end

#shell_exec(command) ⇒ Object



233
234
235
236
237
238
239
# File 'lib/fig/operating_system.rb', line 233

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) ⇒ Object

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



200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
# File 'lib/fig/operating_system.rb', line 200

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) ⇒ Object



146
147
148
149
150
151
152
153
154
# 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) ⇒ Object



77
78
79
# File 'lib/fig/operating_system.rb', line 77

def write(path, content)
  File.open(path, 'wb') { |f| f.binmode; f << content }
end