Module: LeapCli::Util

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

Defined Under Namespace

Modules: RemoteCommand Classes: Secret

Instance Method Summary collapse

Instance Method Details

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

bails out with message if assertion is false.



53
54
55
56
57
# File 'lib/leap_cli/util.rb', line 53

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



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

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



112
113
114
115
116
117
118
119
120
121
122
123
# File 'lib/leap_cli/util.rb', line 112

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



125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
# File 'lib/leap_cli/util.rb', line 125

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.exists?(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



92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
# File 'lib/leap_cli/util.rb', line 92

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.exists?(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.



76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
# File 'lib/leap_cli/util.rb', line 76

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

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

Raises:

  • (SystemExit)


31
32
33
34
35
36
37
38
39
40
# File 'lib/leap_cli/util.rb', line 31

def bail!(*message)
  if block_given?
    LeapCli.log_level = 3
    yield
  elsif message
    log 0, *message
  end
  log 0, :bail, ""
  raise SystemExit.new(@exit_status || 1)
end

#cmd_exists?(cmd) ⇒ Boolean

Returns:



315
316
317
# File 'lib/leap_cli/util.rb', line 315

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

#current_git_branch(dir) ⇒ Object



412
413
414
415
416
417
418
419
420
421
# File 'lib/leap_cli/util.rb', line 412

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



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

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

#ensure_dir(dir) ⇒ Object

creates a directory if it doesn’t already exist



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

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



397
398
399
# File 'lib/leap_cli/util.rb', line 397

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

#exit_status(code = nil) ⇒ Object

QUITTING



15
16
17
18
# File 'lib/leap_cli/util.rb', line 15

def exit_status(code=nil)
  @exit_status = code if code
  @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:



340
341
342
343
344
345
346
347
348
# File 'lib/leap_cli/util.rb', line 340

def file_content_equals?(filepath, contents)
  filepath = Path.named_path(filepath)
  output = `md5sum '#{filepath}'`.strip
  if $?.to_i == 0
    return output.split(" ").first == Digest::MD5.hexdigest(contents).to_s
  else
    return false
  end
end

#file_exists?(*files) ⇒ Boolean

Returns:



144
145
146
147
148
149
150
151
152
# File 'lib/leap_cli/util.rb', line 144

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

#help!(message = nil) ⇒ Object

quit and print help



23
24
25
26
# File 'lib/leap_cli/util.rb', line 23

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

#is_git_directory?(dir) ⇒ Boolean

GIT

Returns:



405
406
407
408
409
410
# File 'lib/leap_cli/util.rb', line 405

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



358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
# File 'lib/leap_cli/util.rb', line 358

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



381
382
383
384
385
386
387
388
389
390
391
# File 'lib/leap_cli/util.rb', line 381

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)


45
46
47
48
# File 'lib/leap_cli/util.rb', line 45

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

#read_file(filepath) ⇒ Object



199
200
201
202
203
204
# File 'lib/leap_cli/util.rb', line 199

def read_file(filepath)
  filepath = Path.named_path(filepath)
  if file_exists?(filepath)
    File.read(filepath)
  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


193
194
195
196
197
# File 'lib/leap_cli/util.rb', line 193

def read_file!(filepath)
  filepath = Path.named_path(filepath)
  assert_files_exist!(filepath)
  File.read(filepath)
end

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

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



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

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



258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
# File 'lib/leap_cli/util.rb', line 258

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



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

def remove_file!(filepath)
  filepath = Path.named_path(filepath)
  if File.exists?(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



300
301
302
303
304
305
306
307
308
309
310
311
312
313
# File 'lib/leap_cli/util.rb', line 300

def rename_file!(oldpath, newpath)
  oldpath = Path.named_path(oldpath)
  newpath = Path.named_path(newpath)
  if File.exists? newpath
    log :skipping, "#{Path.relative_path(newpath)}, file already exists"
    return
  end
  if !File.exists? 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



214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
# File 'lib/leap_cli/util.rb', line 214

def replace_file!(filepath, &block)
  filepath = Path.named_path(filepath)
  if !File.exists?(filepath)
    content = yield(nil)
    unless content.nil?
      write_file!(filepath, content)
    end
  else
    File.open(filepath, File::RDWR|File::CREAT, 0600) 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



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

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

  File.open(filepath, 'w', 0600) do |f|
    f.write contents
  end

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