class Kontena::Cli::Spinner

Constants

CHARS
CHARS_LENGTH

Public Class Methods

spin(msg) { |spin_status| ... } click to toggle source
# File lib/kontena/cli/spinner.rb, line 79
def self.spin(msg, &block)
  return spin_no_tty(msg, &block) unless $stdout.tty?

  unless block_given?
    Kernel.puts "\r [" + Kontena.pastel.green("done") + "] #{msg}"
    return
  end

  Thread.main['spinners'] ||= []
  unless Thread.main['spinners'].empty?
    Thread.main['spinners'].each do |thread|
      thread['pause'] = true
    end
    Kernel.puts "\r [#{Kontena.pastel.yellow('....')}] #{Thread.main['spinners'].last['msg']}"
  end

  Thread.main['spinner_msgs'] = []
  spin_thread = Thread.new do
    Thread.current['msg'] = msg
    message = "    *   #{msg} .. "
    Kernel.print(message + CHARS.first)
    curr_index = 0
    loop do
      if Thread.current['pause']
        until !Thread.current['pause'] || Thread.current['abort']
          sleep 0.1
        end
        Kernel.print "\r#{message}#{CHARS[curr_index]}"
      end

      if Thread.current['update_msg']
        msg = Thread.current['update_msg']
        Thread.current['update_msg'] = nil
        Thread.current['msg'] = msg
        message = "    *   #{msg} .. "
        Kernel.print "\r#{message}#{CHARS[curr_index]}"
      end

      break if Thread.current['abort']

      if Thread.main['spinner_msgs']
        Kernel.print "\r#{' ' * (message.gsub(/\e.+?m/, '').length + 1)}\r"
        while Thread.main['spinner_msgs'].size > 0
          Kernel.puts "\r#{Thread.main['spinner_msgs'].shift}"
        end
        Kernel.print "\r#{message + CHARS[curr_index]}"
      end
      sleep 0.1
      Kernel.print "\b#{CHARS[curr_index]}"
      curr_index = curr_index == CHARS_LENGTH - 1 ? 0 : curr_index + 1
    end
  end

  Thread.main['spinners'] << spin_thread

  status = nil
  result = nil
  begin
    spin_status = SpinnerStatus.new(spin_thread)
    result = yield spin_status
    spin_thread.kill
    case spin_status.result
    when :warn
      Kernel.puts "\r [" + Kontena.pastel.yellow("warn") + "] #{msg}     "
    when :fail
      Kernel.puts "\r [" + Kontena.pastel.red("fail") + "] #{msg}     "
    else
      Kernel.puts "\r [" + Kontena.pastel.green("done") + "] #{msg}     "
    end
  rescue SystemExit => ex
    spin_thread.kill
    if ex.status == 0
      Kernel.puts "\r [" + Kontena.pastel.green("done")   + "] #{msg}     "
    else
      Kernel.puts "\r [" + Kontena.pastel.red("fail")   + "] #{msg}     "
    end
    status = ex.status
  rescue SpinAbort
    spin_thread.kill
    Kernel.puts "\r [" + Kontena.pastel.red("fail")   + "] #{msg}     "
    Kontena.logger.debug { "Spin aborted through fail!" }
  rescue Exception => ex
    spin_thread.kill
    Kernel.puts "\r [" + Kontena.pastel.red("fail")   + "] #{msg}     "
    Kontena.logger.error(ex)
    raise ex
  ensure
    unless Thread.main['spinner_msgs'].empty?
      while msg = Thread.main['spinner_msgs'].shift
        Kernel.puts msg
      end
    end
    Thread.main['spinners'].delete(spin_thread)
  end

  exit(status) if status
  Thread.main['spinners'].pop
  unless Thread.main['spinners'].empty?
    Thread.main['spinners'].last['pause'] = false
  end
  result
end
spin_no_tty(msg) { |spin_status| ... } click to toggle source
# File lib/kontena/cli/spinner.rb, line 48
def self.spin_no_tty(msg, &block)
  unless block_given?
    Kernel.puts "\r [" + Kontena.pastel.green("done") + "] #{msg}"
    return
  end

  Kernel.puts "* #{msg}.. "
  result = nil
  status = nil
  begin
    spin_status = SpinnerStatus.new(Thread.current)
    result = yield spin_status
    Kernel.puts "* #{msg}.. #{spin_status.result}"
  rescue SpinAbort
    Kernel.puts "* #{msg}.. fail"
  rescue SystemExit => ex
    status = ex.status
    if status == 0
      Kernel.puts "* #{msg}.. done"
    else
      Kernel.puts "* #{msg}.. fail"
    end
  rescue Exception => ex
    Kernel.puts "* #{msg}.. fail"
    Kontena.logger.error(ex)
    raise ex
  end
  exit(status) if status
  result
end