require 'pty' require 'benchmark' module Deis module Helpers def run_util(name, *args) status = false time = Benchmark.realtime do status = get_runner(name).new(*args).run end STDOUT.puts "#{$0} #{name} #{args.join ' '}` took #{seconds_to_human time}".light_blue if debug? status end def debug? ENV['DEBUG'].in? TRUTHY_STRINGS end def get_runner(name) Deis::Commands.const_get(name.gsub('-', '_').camelize) rescue NameError STDERR.puts "command `#{name}` does not exist!".red exit 1 end def app_exists?(app) !!deis_command('info', app: app) rescue NonZeroExitError false end def status(msg) msg = "| #{msg} |" sep = ''.ljust(msg.size, '-') puts "\n\e[0;92;49m#{[sep, msg, sep].join "\n"}\e[0m" end def info(app) cmd_result = deis_command(:info, app: app) data = JSON.load cmd_result.match(/Application\r\n(?\{.*\})/m)[:json] controller_host = data['url'].split('.').tap { |p| p[p.index app] = 'deis' }.join('.') data['git_url'] = "ssh://git@#{controller_host}:2222/#{app}.git" data['domains'] = cmd_result.match(/Domains\r\n(?.*)/m)[:domains].lines.map(&:strip).reject(&:empty?) data.sort.to_h end def shell(*commands) result = '' Bundler.with_clean_env do flags = commands.last.is_a?(Hash) ? commands.pop : {} command = commands.join ' ' flags.each_with_object(command) do |(k, v), c| c << case v when TrueClass, FalseClass v ? " --#{k}" : '' when String, Fixnum " --#{k} #{v}" else raise ArgumentError end end result = nil time = Benchmark.realtime do result = capture_syscall command end STDOUT.puts "`#{command}` took #{seconds_to_human time}".light_black if debug? end result end def deis_command(*cmds) @retry_count ||= 0 shell :deis, *cmds rescue Errno::ENOENT deis_local_command *cmds rescue Deis::NonZeroExitError => e deis_command :login, username: ENV['DEIS_USERNAME'], password: ENV['DEIS_PASSWORD'] (@retry_count += 1) > 3 ? raise(e) : retry end def deis_local_command(*cmds) @retry_count ||= 0 shell('./deis', *cmds).tap { @retry_count = nil } rescue Errno::ENOENT => e shell 'curl -sSL http://deis.io/deis-cli/install.sh | sh -s 1.6.1' singleton_class.send :alias_method, :deis_command, :deis_local_command (@retry_count += 1) > 3 ? raise(e) : retry rescue Deis::NonZeroExitError => e deis_command :login, username: ENV['DEIS_USERNAME'], password: ENV['DEIS_PASSWORD'] (@retry_count += 1) > 3 ? raise(e) : retry end def git_clone(url, flags = {}) shell "git clone #{url}", flags end def deploy(url, options = {}) ref = options.delete(:ref) || 'master' shell "git push #{url} #{ref}:master", options end def capture_syscall(command) puts "\n#{command}".light_yellow if debug? String.new.tap do |output| threads = [] PTY.spawn(command) do |p_out, p_in, pid| threads << Thread.new { p_in.close } threads << Thread.new { output << capture_output(p_out) } Process.wait pid threads.each(&:join) end raise NonZeroExitError, output unless $?.exitstatus == 0 end end def capture_output(io) output = '' io.each do |line| output << line STDOUT.puts "#{line.strip}".light_black unless line.nil? || line.strip.empty? if debug? end ensure return output end def scale(app, opts={}) process_string = opts.map { |k, v| "#{k}=#{v}" }.join ' ' deis_command "scale #{process_string}", app: app end def get_units! unit_string = deis_command('ps', app: app) shell('foreman check').strip.sub(/.*\((.*)\)/, "\\1").split(', ').each do |unit| units[unit] ||= unit_string.lines.select { |l| l.include? "#{unit}." }.count end end def units @units ||= {} end module_function def seconds_to_human(secs) secs = secs.round output = '' seconds = secs % 60 minutes = (secs - seconds) / 60 output << "#{minutes}m" if minutes > 0 output << "#{seconds}s" end end end