module Heroku::Helpers
Public Class Methods
error_with_failure()
click to toggle source
# File lib/heroku/helpers.rb, line 295 def self.error_with_failure @@error_with_failure ||= false end
error_with_failure=(new_error_with_failure)
click to toggle source
# File lib/heroku/helpers.rb, line 299 def self.error_with_failure=(new_error_with_failure) @@error_with_failure = new_error_with_failure end
extended(base)
click to toggle source
# File lib/heroku/helpers.rb, line 315 def self.extended(base) extended_into << base end
extended_into()
click to toggle source
# File lib/heroku/helpers.rb, line 307 def self.extended_into @@extended_into ||= [] end
included(base)
click to toggle source
# File lib/heroku/helpers.rb, line 311 def self.included(base) included_into << base end
included_into()
click to toggle source
# File lib/heroku/helpers.rb, line 303 def self.included_into @@included_into ||= [] end
Public Instance Methods
action(message, options={}) { || ... }
click to toggle source
DISPLAY HELPERS
# File lib/heroku/helpers.rb, line 254 def action(message, options={}) message = "#{message} in space #{options[:space]}" if options[:space] message = "#{message} in organization #{org}" if options[:org] display("#{message}... ", false) Heroku::Helpers.error_with_failure = true ret = yield Heroku::Helpers.error_with_failure = false display((options[:success] || "done"), false) if @status display(", #{@status}", false) @status = nil end display ret end
app_owner(email)
click to toggle source
# File lib/heroku/helpers.rb, line 564 def app_owner email org?(email) ? email.gsub(/^(.*)@#{org_host}$/,'\1') : email end
ask()
click to toggle source
# File lib/heroku/helpers.rb, line 88 def ask $stdin.gets.to_s.strip end
confirm(message="Are you sure you wish to continue? (y/n)")
click to toggle source
# File lib/heroku/helpers.rb, line 57 def confirm(message="Are you sure you wish to continue? (y/n)") display("#{message} ", false) ['y', 'yes'].include?(ask.downcase) end
confirm_command(app_to_confirm = app, message=nil)
click to toggle source
# File lib/heroku/helpers.rb, line 62 def confirm_command(app_to_confirm = app, message=nil) if confirmed_app = Heroku::Command.current_options[:confirm] unless confirmed_app == app_to_confirm raise(Heroku::Command::CommandFailed, "Confirmed app #{confirmed_app} did not match the selected app #{app_to_confirm}.") end return true else display message ||= "WARNING: Destructive Action\nThis command will affect the app: #{app_to_confirm}" message << "\nTo proceed, type \"#{app_to_confirm}\" or re-run this command with --confirm #{app_to_confirm}" output_with_bang(message) display display "> ", false if ask.downcase != app_to_confirm error("Confirmation did not match #{app_to_confirm}. Aborted.") else true end end end
create_git_remote(remote, url)
click to toggle source
# File lib/heroku/helpers.rb, line 179 def create_git_remote(remote, url) return if has_git_remote? remote git "remote add #{remote} #{url}" display "Git remote #{remote} added" if $?.success? end
debug(*args)
click to toggle source
# File lib/heroku/helpers.rb, line 41 def debug(*args) $stderr.puts(*args) if debugging? end
debugging?()
click to toggle source
# File lib/heroku/helpers.rb, line 53 def debugging? ENV['HEROKU_DEBUG'] end
deep_clone(obj)
click to toggle source
cheap deep clone
# File lib/heroku/helpers.rb, line 577 def deep_clone(obj) json_decode(json_encode(obj)) end
default_org_host()
click to toggle source
# File lib/heroku/helpers.rb, line 556 def default_org_host "herokumanager.com" end
deprecate(message)
click to toggle source
# File lib/heroku/helpers.rb, line 37 def deprecate(message) display "WARNING: #{message}" end
display(msg="", new_line=true)
click to toggle source
# File lib/heroku/helpers.rb, line 24 def display(msg="", new_line=true) if new_line puts(msg) else print(msg) end $stdout.flush end
display_header(message="", new_line=true)
click to toggle source
# File lib/heroku/helpers.rb, line 319 def display_header(message="", new_line=true) return if message.to_s.strip == "" display("=== " + message.to_s.split("\n").join("\n=== "), new_line) end
display_object(object)
click to toggle source
# File lib/heroku/helpers.rb, line 324 def display_object(object) case object when Array # list of objects object.each do |item| display_object(item) end when Hash # if all values are arrays, it is a list with headers # otherwise it is a single header with pairs of data if object.values.all? {|value| value.is_a?(Array)} object.keys.sort_by {|key| key.to_s}.each do |key| display_header(key) display_object(object[key]) hputs end end else hputs(object.to_s) end end
display_row(row, lengths)
click to toggle source
# File lib/heroku/helpers.rb, line 204 def display_row(row, lengths) row_data = [] row.zip(lengths).each do |column, length| format = column.is_a?(Fixnum) ? "%#{length}s" : "%-#{length}s" row_data << format % column end display(row_data.join(" ")) end
display_table(objects, columns, headers)
click to toggle source
# File lib/heroku/helpers.rb, line 189 def display_table(objects, columns, headers) lengths = [] columns.each_with_index do |column, index| header = headers[index] lengths << longest([header].concat(objects.map { |o| o[column].to_s })) end lines = lengths.map {|length| "-" * length} lengths[-1] = 0 # remove padding from last column display_row headers, lengths display_row lines, lengths objects.each do |row| display_row columns.map { |column| row[column] }, lengths end end
error(message, report=false)
click to toggle source
# File lib/heroku/helpers.rb, line 284 def error(message, report=false) if Heroku::Helpers.error_with_failure display("failed") Heroku::Helpers.error_with_failure = false end $stderr.puts(format_with_bang(message)) rollbar_id = Rollbar.error(message) if report $stderr.puts("Error ID: #{rollbar_id}") if rollbar_id exit(1) end
error_log(*obj)
click to toggle source
# File lib/heroku/helpers.rb, line 455 def error_log(*obj) FileUtils.mkdir_p(File.dirname(error_log_path)) File.open(error_log_path, 'a') do |file| file.write(obj.join("\n") + "\n") end end
error_log_path()
click to toggle source
# File lib/heroku/helpers.rb, line 462 def error_log_path File.join(home_directory, '.heroku', 'error.log') end
fail(message)
click to toggle source
# File lib/heroku/helpers.rb, line 248 def fail(message) raise Heroku::Command::CommandFailed, message end
format_bytes(amount)
click to toggle source
# File lib/heroku/helpers.rb, line 162 def format_bytes(amount) amount = amount.to_i return '(empty)' if amount == 0 return amount if amount < @@kb return "#{(amount / @@kb).round}k" if amount < @@mb return "#{(amount / @@mb).round}M" if amount < @@gb return "#{(amount / @@gb).round}G" end
format_date(date)
click to toggle source
# File lib/heroku/helpers.rb, line 83 def format_date(date) date = Time.parse(date).utc if date.is_a?(String) date.strftime("%Y-%m-%d %H:%M %Z").gsub('GMT', 'UTC') end
format_error(error, message='Heroku client internal error.', rollbar_id=nil)
click to toggle source
# File lib/heroku/helpers.rb, line 399 def format_error(error, message='Heroku client internal error.', rollbar_id=nil) formatted_error = [] formatted_error << " ! #{message}" formatted_error << ' ! Search for help at: https://help.heroku.com' formatted_error << ' ! Or report a bug at: https://github.com/heroku/heroku/issues/new' formatted_error << '' formatted_error << " Error: #{error.message} (#{error.class})" command = ARGV.map do |arg| if arg.include?(' ') arg = %Q{"#{arg}"} else arg end end.join(' ') formatted_error << " Command: heroku #{command}" require 'heroku/auth' unless Heroku::Auth.host == Heroku::Auth.default_host formatted_error << " Host: #{Heroku::Auth.host}" end if http_proxy = ENV['http_proxy'] || ENV['HTTP_PROXY'] formatted_error << " HTTP Proxy: #{http_proxy}" end if https_proxy = ENV['https_proxy'] || ENV['HTTPS_PROXY'] formatted_error << " HTTPS Proxy: #{https_proxy}" end plugins = Heroku::Plugin.list.sort unless plugins.empty? formatted_error << " Plugins: #{plugins.first}" plugins[1..-1].each do |plugin| formatted_error << " #{plugin}" end if plugins.length > 1 formatted_error << '' $stderr.puts end end formatted_error << " Version: #{Heroku.user_agent}" formatted_error << " Error ID: #{rollbar_id}" if rollbar_id formatted_error << "\n" formatted_error << " More information in #{error_log_path}" formatted_error << "\n" formatted_error.join("\n") end
format_with_bang(message)
click to toggle source
# File lib/heroku/helpers.rb, line 274 def format_with_bang(message) return '' if message.to_s.strip == "" " ! " + message.split("\n").join("\n ! ") end
get_terminal_environment()
click to toggle source
# File lib/heroku/helpers.rb, line 242 def get_terminal_environment { "TERM" => ENV["TERM"], "COLUMNS" => %x`tput cols`.strip, "LINES" => %x`tput lines`.strip } rescue { "TERM" => ENV["TERM"] } end
git(args)
click to toggle source
# File lib/heroku/helpers.rb, line 117 def git(args) return "" unless has_git? flattened_args = [args].flatten.compact.join(" ") %x{ git #{flattened_args} 2>&1 }.strip end
has_git?()
click to toggle source
# File lib/heroku/helpers.rb, line 112 def has_git? %x{ git --version } $?.success? end
has_git_remote?(remote)
click to toggle source
# File lib/heroku/helpers.rb, line 175 def has_git_remote?(remote) git('remote').split("\n").include?(remote) && $?.success? end
has_http_git_entry_in_netrc()
click to toggle source
# File lib/heroku/helpers.rb, line 568 def has_http_git_entry_in_netrc Auth.netrc && Auth.netrc[Auth.http_git_host] end
home_directory()
click to toggle source
# File lib/heroku/helpers.rb, line 7 def home_directory if running_on_windows? && RUBY_VERSION == '1.9.3' # https://bugs.ruby-lang.org/issues/10126 Dir.home.force_encoding('cp775') else Dir.home end end
hprint(string='')
click to toggle source
# File lib/heroku/helpers.rb, line 350 def hprint(string='') Kernel.print(string) $stdout.flush end
hputs(string='')
click to toggle source
# File lib/heroku/helpers.rb, line 346 def hputs(string='') Kernel.puts(string) end
json_decode(json)
click to toggle source
# File lib/heroku/helpers.rb, line 217 def json_decode(json) JSON.parse(json) rescue JSON::ParserError nil end
json_encode(object)
click to toggle source
# File lib/heroku/helpers.rb, line 213 def json_encode(object) JSON.generate(object) end
launchy(message, url)
click to toggle source
# File lib/heroku/helpers.rb, line 359 def launchy(message, url) action(message) do require("launchy") launchy = Launchy.open(url) if launchy.respond_to?(:join) launchy.join end end end
line_formatter(array)
click to toggle source
produces a printf formatter line for an array of items if an individual line item is an array, it will create columns that are lined-up
#line_formatter([“foo”, “barbaz”]) # => “%-6s” #line_formatter([“foo”, “barbaz”], [“bar”, “qux”]) # => “%-3s %-6s”
# File lib/heroku/helpers.rb, line 376 def line_formatter(array) if array.any? {|item| item.is_a?(Array)} cols = [] array.each do |item| if item.is_a?(Array) item.each_with_index { |val,idx| cols[idx] = [cols[idx]||0, (val || '').length].max } end end cols.map { |col| "%-#{col}s" }.join(" ") else "%s" end end
longest(items)
click to toggle source
# File lib/heroku/helpers.rb, line 185 def longest(items) items.map { |i| i.to_s.length }.sort.last end
org?(email)
click to toggle source
# File lib/heroku/helpers.rb, line 560 def org? email email =~ /^.*@#{org_host}$/ end
org_host()
click to toggle source
# File lib/heroku/helpers.rb, line 552 def org_host ENV["HEROKU_ORG_HOST"] || default_org_host end
output_with_bang(message="", new_line=true)
click to toggle source
# File lib/heroku/helpers.rb, line 279 def output_with_bang(message="", new_line=true) return if message.to_s.strip == "" display(format_with_bang(message), new_line) end
quantify(string, num)
click to toggle source
# File lib/heroku/helpers.rb, line 171 def quantify(string, num) "%d %s" % [ num, num.to_i == 1 ? string : "#{string}s" ] end
redisplay(line, line_break = false)
click to toggle source
# File lib/heroku/helpers.rb, line 33 def redisplay(line, line_break = false) display("\r\e[0K#{line}", line_break) end
retry_on_exception(*exceptions) { || ... }
click to toggle source
# File lib/heroku/helpers.rb, line 100 def retry_on_exception(*exceptions) retry_count = 0 begin yield rescue *exceptions => ex raise ex if retry_count >= 3 sleep 3 retry_count += 1 retry end end
run_command(command, args=[])
click to toggle source
# File lib/heroku/helpers.rb, line 96 def run_command(command, args=[]) Heroku::Command.run(command, args) end
running_on_a_mac?()
click to toggle source
# File lib/heroku/helpers.rb, line 20 def running_on_a_mac? RUBY_PLATFORM =~ /-darwin\d/ end
running_on_windows?()
click to toggle source
# File lib/heroku/helpers.rb, line 16 def running_on_windows? RUBY_PLATFORM =~ /mswin32|mingw32/ end
set_buffer(enable)
click to toggle source
# File lib/heroku/helpers.rb, line 223 def set_buffer(enable) with_tty do if enable %x`stty icanon echo` else %x`stty -icanon -echo` end end end
shell(cmd)
click to toggle source
# File lib/heroku/helpers.rb, line 92 def shell(cmd) FileUtils.cd(Dir.pwd) {|d| return %x`#{cmd}`} end
spinner(ticks)
click to toggle source
# File lib/heroku/helpers.rb, line 355 def spinner(ticks) %w(/ - \\ |)[ticks % 4] end
status(message)
click to toggle source
# File lib/heroku/helpers.rb, line 270 def status(message) @status = message end
stderr_print(*args)
click to toggle source
# File lib/heroku/helpers.rb, line 49 def stderr_print(*args) $stderr.print(*args) end
stderr_puts(*args)
click to toggle source
# File lib/heroku/helpers.rb, line 45 def stderr_puts(*args) $stderr.puts(*args) end
string_distance(first, last)
click to toggle source
# File lib/heroku/helpers.rb, line 498 def string_distance(first, last) distances = [] # 0x0s 0.upto(first.length) do |index| distances << [index] + [0] * last.length end distances[0] = 0.upto(last.length).to_a 1.upto(last.length) do |last_index| 1.upto(first.length) do |first_index| first_char = first[first_index - 1, 1] last_char = last[last_index - 1, 1] if first_char == last_char distances[first_index][last_index] = distances[first_index - 1][last_index - 1] # noop else distances[first_index][last_index] = [ distances[first_index - 1][last_index], # deletion distances[first_index][last_index - 1], # insertion distances[first_index - 1][last_index - 1] # substitution ].min + 1 # cost if first_index > 1 && last_index > 1 first_previous_char = first[first_index - 2, 1] last_previous_char = last[last_index - 2, 1] if first_char == last_previous_char && first_previous_char == last_char distances[first_index][last_index] = [ distances[first_index][last_index], distances[first_index - 2][last_index - 2] + 1 # transposition ].min end end end end end distances[first.length][last.length] end
styled_array(array, options={})
click to toggle source
# File lib/heroku/helpers.rb, line 390 def styled_array(array, options={}) fmt = line_formatter(array) array = array.sort unless options[:sort] == false array.each do |element| display((fmt % element).rstrip) end display end
styled_error(error, message='Heroku client internal error.')
click to toggle source
# File lib/heroku/helpers.rb, line 443 def styled_error(error, message='Heroku client internal error.') if Heroku::Helpers.error_with_failure display("failed") Heroku::Helpers.error_with_failure = false end rollbar_id = Rollbar.error(error) $stderr.puts(format_error(error, message, rollbar_id)) error_log(message, error.message, error.backtrace.join("\n")) rescue => e $stderr.puts e, e.backtrace, error, error.backtrace end
styled_hash(hash, keys=nil)
click to toggle source
# File lib/heroku/helpers.rb, line 470 def styled_hash(hash, keys=nil) max_key_length = hash.keys.map {|key| key.to_s.length}.max + 2 keys ||= hash.keys.sort {|x,y| x.to_s <=> y.to_s} keys.each do |key| case value = hash[key] when Array if value.empty? next else elements = value.sort {|x,y| x.to_s <=> y.to_s} display("#{key}: ".ljust(max_key_length), false) display(elements[0]) elements[1..-1].each do |element| display("#{' ' * max_key_length}#{element}") end if elements.length > 1 display end end when nil next else display("#{key}: ".ljust(max_key_length), false) display(value) end end end
styled_header(header)
click to toggle source
# File lib/heroku/helpers.rb, line 466 def styled_header(header) display("=== #{header}") end
suggestion(actual, possibilities)
click to toggle source
# File lib/heroku/helpers.rb, line 532 def suggestion(actual, possibilities) distances = Hash.new {|hash,key| hash[key] = []} possibilities.each do |suggestion| distances[string_distance(actual, suggestion)] << suggestion end minimum_distance = distances.keys.min if minimum_distance < 4 suggestions = distances[minimum_distance].sort if suggestions.length == 1 "Perhaps you meant `#{suggestions.first}`." else "Perhaps you meant #{suggestions[0...-1].map {|suggestion| "`#{suggestion}`"}.join(', ')} or `#{suggestions.last}`." end else nil end end
time_ago(since)
click to toggle source
# File lib/heroku/helpers.rb, line 123 def time_ago(since) if since.is_a?(String) since = Time.parse(since) end elapsed = Time.now - since message = since.strftime("%Y/%m/%d %H:%M:%S") if elapsed <= 60 message << " (~ #{elapsed.floor}s ago)" elsif elapsed <= (60 * 60) message << " (~ #{(elapsed / 60).floor}m ago)" elsif elapsed <= (60 * 60 * 25) message << " (~ #{(elapsed / 60 / 60).floor}h ago)" end message end
time_remaining(from, to)
click to toggle source
# File lib/heroku/helpers.rb, line 141 def time_remaining(from, to) secs = (to - from).to_i mins = secs / 60 hours = mins / 60 return "#{hours}h #{mins % 60}m" if hours > 0 return "#{mins}m #{secs % 60}s" if mins > 0 return "#{secs}s" if secs >= 0 end
truncate(text, length)
click to toggle source
# File lib/heroku/helpers.rb, line 150 def truncate(text, length) return "" if text.nil? if text.size > length text[0, length - 2] + '..' else text end end
warn_if_using_jruby()
click to toggle source
# File lib/heroku/helpers.rb, line 572 def warn_if_using_jruby stderr_puts "WARNING: jruby is known to cause issues when used with the toolbelt." if RUBY_PLATFORM == "java" end
with_tty() { || ... }
click to toggle source
# File lib/heroku/helpers.rb, line 233 def with_tty(&block) return unless $stdin.isatty begin yield rescue # fails on windows end end