Module: LeapCli::Util

Extended by:
Util
Included in:
Commands, Util
Defined in:
lib/leap_cli/util.rb

Constant Summary collapse

@@exit_status =
nil

Instance Method Summary collapse

Instance Method Details

#assert!(boolean, message = nil, &block) ⇒ Object

bails out with message if assertion is false.



64
65
66
67
68
# File 'lib/leap_cli/util.rb', line 64

def assert!(boolean, message=nil, &block)
  if !boolean
    bail!(message, &block)
  end
end

#assert_bin!(cmd_name, msg = nil) ⇒ Object

assert that the command is available



73
74
75
76
77
78
79
80
81
# File 'lib/leap_cli/util.rb', line 73

def assert_bin!(cmd_name, msg=nil)
  assert! `which #{cmd_name}`.strip.any? do
    log :missing, "command '%s'" % cmd_name do
      if msg
        log msg
      end
    end
  end
end

#assert_config!(conf_path) ⇒ Object



103
104
105
106
107
108
109
110
111
112
113
114
# File 'lib/leap_cli/util.rb', line 103

def assert_config!(conf_path)
  value = nil
  begin
    value = manager.instance_eval(conf_path)
  #rescue NoMethodError
  #rescue NameError
  ensure
    assert! !value.nil? && value != "REQUIRED" do
      log :missing, "required configuration value for #{conf_path}"
    end
  end
end

#assert_files_exist!(*files) ⇒ Object



140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
# File 'lib/leap_cli/util.rb', line 140

def assert_files_exist!(*files)
  options = files.last.is_a?(Hash) ? files.pop : {}
  file_list = files.collect { |file_path|
    file_path = Path.named_path(file_path)
    !File.exist?(file_path) ? Path.relative_path(file_path) : nil
  }.compact
  if file_list.length > 1
    bail! do
      log :missing, "these files: #{file_list.join(', ')}"
      log options[:msg] if options[:msg]
    end
  elsif file_list.length == 1
    bail! do
      log :missing, "file #{file_list.first}"
      log options[:msg] if options[:msg]
    end
  end
end

#assert_files_missing!(*files) ⇒ Object

FILES AND DIRECTORIES



120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
# File 'lib/leap_cli/util.rb', line 120

def assert_files_missing!(*files)
  options = files.last.is_a?(Hash) ? files.pop : {}
  base = options[:base] || Path.provider
  file_list = files.collect { |file_path|
    file_path = Path.named_path(file_path, base)
    File.exist?(file_path) ? Path.relative_path(file_path, base) : nil
  }.compact
  if file_list.length > 1
    bail! do
      log :error, "Sorry, we can't continue because these files already exist: #{file_list.join(', ')}."
      log options[:msg] if options[:msg]
    end
  elsif file_list.length == 1
    bail! do
      log :error, "Sorry, we can't continue because this file already exists: #{file_list.first}."
      log options[:msg] if options[:msg]
    end
  end
end

#assert_run!(cmd, message = nil) ⇒ Object

assert that the command is run without an error. if successful, return output.



87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
# File 'lib/leap_cli/util.rb', line 87

def assert_run!(cmd, message=nil)
  cmd = cmd + " 2>&1"
  output = `#{cmd}`.strip
  unless $?.success?
    exit_status($?.exitstatus)
    bail! do
      log :run, cmd
      log :failed, "(exit #{$?.exitstatus}) #{output}", :indent => 1
      log message, :indent => 1 if message
    end
  else
    log 2, :ran, cmd
  end
  return output
end

#bail!(*message, &block) ⇒ Object

exit with error code and with a message that we are bailing out.

Raises:

  • (SystemExit)


43
44
45
46
47
48
49
50
51
# File 'lib/leap_cli/util.rb', line 43

def bail!(*message, &block)
  LeapCli.logger.log_level = 3 if LeapCli.logger.log_level < 3
  if message.any?
    log(0, *message, &block)
  else
    log(0, :bailing, "out", :color => :red, :style => :bold, &block)
  end
  raise SystemExit.new(exit_status || 1)
end

#cmd_exists?(cmd) ⇒ Boolean

Returns:



338
339
340
# File 'lib/leap_cli/util.rb', line 338

def cmd_exists?(cmd)
  `which #{cmd}`.strip.chars.any?
end

#current_git_branch(dir) ⇒ Object



438
439
440
441
442
443
444
445
446
447
# File 'lib/leap_cli/util.rb', line 438

def current_git_branch(dir)
  Dir.chdir(dir) do
    branch = `git symbolic-ref HEAD 2>/dev/null`.strip
    if branch.chars.any?
      branch.sub(/^refs\/heads\//, '')
    else
      nil
    end
  end
end

#current_git_commit(dir) ⇒ Object



449
450
451
452
453
# File 'lib/leap_cli/util.rb', line 449

def current_git_commit(dir)
  Dir.chdir(dir) do
    `git rev-parse HEAD 2>/dev/null`.strip
  end
end

#dir_exists?(*dirs) ⇒ Boolean

takes a list of symbolic paths. returns true if all are directories.

Returns:



171
172
173
174
175
176
177
178
179
# File 'lib/leap_cli/util.rb', line 171

def dir_exists?(*dirs)
  dirs.each do |dir_path|
    dir_path = Path.named_path(dir_path)
    if !Dir.exists?(dir_path)
      return false
    end
  end
  return true
end

#ensure_dir(dir) ⇒ Object

creates a directory if it doesn’t already exist



184
185
186
187
188
189
190
191
192
193
194
# File 'lib/leap_cli/util.rb', line 184

def ensure_dir(dir)
  dir = Path.named_path(dir)
  unless File.directory?(dir)
    assert_files_missing!(dir, :msg => "Cannot create directory #{dir}")
    FileUtils.mkdir_p(dir, :mode => 0700)
    unless dir =~ /\/$/
      dir = dir + '/'
    end
    log :created, dir
  end
end

#erb_eval(string, binding = nil) ⇒ Object

ERB



416
417
418
# File 'lib/leap_cli/util.rb', line 416

def erb_eval(string, binding=nil)
  ERB.new(string, nil, '%<>-').result(binding)
end

#exit_status(code = nil) ⇒ Object

QUITTING



21
22
23
24
25
26
27
28
29
30
# File 'lib/leap_cli/util.rb', line 21

def exit_status(code=nil)
  if !code.nil?
    if code == 0 && @@exit_status.nil?
      @@exit_status = 0
    else
      @@exit_status = code
    end
  end
  @@exit_status
end

#file_content_equals?(filepath, contents) ⇒ Boolean

compares md5 fingerprints to see if the contents of a file match the string we have in memory

Returns:



364
365
366
367
# File 'lib/leap_cli/util.rb', line 364

def file_content_equals?(filepath, contents)
  filepath = Path.named_path(filepath)
  Digest::MD5.file(filepath).hexdigest == Digest::MD5.hexdigest(contents)
end

#file_exists?(*files) ⇒ Boolean

takes a list of symbolic paths. returns true if all files exist or are directories.

Returns:



160
161
162
163
164
165
166
167
168
# File 'lib/leap_cli/util.rb', line 160

def file_exists?(*files)
  files.each do |file_path|
    file_path = Path.named_path(file_path)
    if !File.exist?(file_path)
      return false
    end
  end
  return true
end

#help!(message = nil) ⇒ Object

quit and print help



35
36
37
38
# File 'lib/leap_cli/util.rb', line 35

def help!(message=nil)
  ENV['GLI_DEBUG'] = "false"
  help_now!(message)
end

#is_git_directory?(dir) ⇒ Boolean

GIT

Returns:



424
425
426
427
428
429
# File 'lib/leap_cli/util.rb', line 424

def is_git_directory?(dir)
  Dir.chdir(dir) do
    `which git && git rev-parse 2>/dev/null`
    return $? == 0
  end
end

#is_git_subrepo?(dir) ⇒ Boolean

Returns:



431
432
433
434
435
436
# File 'lib/leap_cli/util.rb', line 431

def is_git_subrepo?(dir)
  Dir.chdir(dir) do
    `ls .gitrepo 2>/dev/null`
    return $? == 0
  end
end

#log(*args, &block) ⇒ Object



13
14
15
# File 'lib/leap_cli/util.rb', line 13

def log(*args, &block)
  LeapCli.log(*args, &block)
end

#long_running(&block) ⇒ Object

run a long running block of code in a separate process and display marching ants as time goes by. if the user hits ctrl-c, the program exits.



377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
# File 'lib/leap_cli/util.rb', line 377

def long_running(&block)
  pid = fork
  if pid == nil
    yield
    exit!
  end
  Signal.trap("SIGINT") do
    Process.kill("KILL", pid)
    Process.wait(pid)
    bail!
  end
  while true
    sleep 0.2
    STDOUT.print '.'
    STDOUT.flush
    break if Process.wait(pid, Process::WNOHANG)
  end
  STDOUT.puts
end

#pty_run(cmd) ⇒ Object

runs a command in a pseudo terminal



400
401
402
403
404
405
406
407
408
409
410
# File 'lib/leap_cli/util.rb', line 400

def pty_run(cmd)
  PTY.spawn(cmd) do |output, input, pid|
    begin
      while line = output.gets do
        puts line
      end
    rescue Errno::EIO
    end
  end
rescue PTY::ChildExited
end

#quit!(message = '') ⇒ Object

quit with message, but no additional error or warning about bailing.

Raises:

  • (SystemExit)


56
57
58
59
# File 'lib/leap_cli/util.rb', line 56

def quit!(message='')
  puts(message)
  raise SystemExit.new(exit_status || 0)
end

#read_file(filepath) ⇒ Object



222
223
224
225
226
227
# File 'lib/leap_cli/util.rb', line 222

def read_file(filepath)
  filepath = Path.named_path(filepath)
  if file_exists?(filepath)
    File.read(filepath, :encoding => 'UTF-8')
  end
end

#read_file!(filepath) ⇒ Object

All file read and write methods support using named paths in the place of an actual file path.

To call using a named path, use a symbol in the place of filepath, like so:

read_file(:known_hosts)

In some cases, the named path will take an argument. In this case, set the filepath to be an array:

write_file!([:user_ssh, 'bob'], ssh_key_str)

To resolve a named path, use the shortcut helper ‘path()’

path([:user_ssh, 'bob'])  ==>   files/users/bob/bob_ssh_pub.key


216
217
218
219
220
# File 'lib/leap_cli/util.rb', line 216

def read_file!(filepath)
  filepath = Path.named_path(filepath)
  assert_files_exist!(filepath)
  File.read(filepath, :encoding => 'UTF-8')
end

creates a relative symlink from absolute paths, removing prior symlink if necessary

symlink ‘new’ is created, pointing to ‘old’



347
348
349
350
351
352
353
354
355
356
357
358
# File 'lib/leap_cli/util.rb', line 347

def relative_symlink(old, new)
  relative_path  = Pathname.new(old).relative_path_from(Pathname.new(new))
  if File.symlink?(new)
    if File.readlink(new) != relative_path.to_s
      File.unlink(new)
      log :updated, 'symlink %s' % Path.relative_path(new)
    end
  else
    log :created, 'symlink %s' % Path.relative_path(new)
  end
  FileUtils.ln_s(relative_path, new)
end

#remove_directory!(filepath) ⇒ Object



281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
# File 'lib/leap_cli/util.rb', line 281

def remove_directory!(filepath)
  filepath = Path.named_path(filepath)
  if filepath !~ /^#{Regexp.escape(Path.provider)}/ || filepath =~ /\.\./
    bail! "sanity check on rm -r did not pass for #{filepath}"
  end
  if File.directory?(filepath)
    begin
      FileUtils.rm_r(filepath)
      log :removed, filepath
    rescue Exception => exc
      bail! do
        log :failed, "to remove directory #{filepath}"
        log "error message: " + exc.to_s
      end
    end
  else
    log :failed, "to remove '#{filepath}', it is not a directory"
  end
end

#remove_file!(filepath) ⇒ Object



262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
# File 'lib/leap_cli/util.rb', line 262

def remove_file!(filepath)
  filepath = Path.named_path(filepath)
  if File.exist?(filepath)
    if File.directory?(filepath)
      remove_directory!(filepath)
    else
      begin
        File.unlink(filepath)
        log :removed, filepath
      rescue Exception => exc
        bail! do
          log :failed, "to remove file #{filepath}"
          log "error message: " + exc.to_s
        end
      end
    end
  end
end

#rename_file!(oldpath, newpath) ⇒ Object



323
324
325
326
327
328
329
330
331
332
333
334
335
336
# File 'lib/leap_cli/util.rb', line 323

def rename_file!(oldpath, newpath)
  oldpath = Path.named_path(oldpath)
  newpath = Path.named_path(newpath)
  if File.exist? newpath
    log :skipping, "#{Path.relative_path(newpath)}, file already exists"
    return
  end
  if !File.exist? oldpath
    log :skipping, "#{Path.relative_path(oldpath)}, file is missing"
    return
  end
  FileUtils.mv oldpath, newpath
  log :moved, "#{Path.relative_path(oldpath)} to #{Path.relative_path(newpath)}"
end

#replace_file!(filepath, &block) ⇒ Object

replace contents of a file, with an exclusive lock.

  1. locks file

  2. reads contents

  3. yields contents

  4. replaces file with return value of the block



237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
# File 'lib/leap_cli/util.rb', line 237

def replace_file!(filepath, &block)
  filepath = Path.named_path(filepath)
  if !File.exist?(filepath)
    content = yield(nil)
    unless content.nil?
      write_file!(filepath, content)
    end
  else
    File.open(filepath, File::RDWR|File::CREAT, 0600, :encoding => 'UTF-8') do |f|
      f.flock(File::LOCK_EX)
      old_content = f.read
      new_content = yield(old_content)
      if old_content == new_content
        log :nochange, filepath, 2
      else
        f.rewind
        f.write(new_content)
        f.flush
        f.truncate(f.pos)
        log :updated, filepath
      end
    end
  end
end

#write_file!(filepath, contents) ⇒ Object



301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
# File 'lib/leap_cli/util.rb', line 301

def write_file!(filepath, contents)
  filepath = Path.named_path(filepath)
  ensure_dir File.dirname(filepath)
  existed = File.exist?(filepath)
  if existed
    if file_content_equals?(filepath, contents)
      log :nochange, filepath, 2
      return
    end
  end

  File.open(filepath, 'w', 0600, :encoding => 'UTF-8') do |f|
    f.write contents
  end

  if existed
    log :updated, filepath
  else
    log :created, filepath
  end
end