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.


64
65
66
67
68
69
70
71
# File 'lib/fig/operating_system.rb', line 64

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
  @protocols['ssh']  = Fig::Protocol::SSH.new
end

Class Method Details

.file_name_illegal_charactersObject


40
41
42
43
44
45
46
# 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) ⇒ Object


56
57
58
59
60
61
62
# 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

.unix?Boolean

Returns:

  • (Boolean)

36
37
38
# File 'lib/fig/operating_system.rb', line 36

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

.windows?Boolean

Returns:

  • (Boolean)

32
33
34
# 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) ⇒ Object


48
49
50
51
52
53
54
# 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

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
178
179
180
181
# 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) ⇒ Object

Expects paths_to_archive as an Array of paths.


188
189
190
191
192
193
194
195
196
197
# 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) ⇒ 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


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

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

#move_file(directory, from, to) ⇒ Object


183
184
185
# 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) ⇒ 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


245
246
247
248
249
250
251
252
253
254
255
256
257
# 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) ⇒ 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.


261
262
263
264
265
266
267
# 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) ⇒ Object


237
238
239
240
241
242
243
# 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) ⇒ Object

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


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
232
233
234
235
# 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) ⇒ 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