class Heroku::Command::Db

manage the database for an app

Public Instance Methods

pull() click to toggle source

db:pull [DATABASE_URL]

pull heroku data down into your local database

DATABASE_URL should reference your local database. if not specified, it will be guessed from config/database.yml

-c, –chunksize SIZE # specify the number of rows to send in each batch -d, –debug # enable debugging output -e, –exclude TABLES # exclude the specified tables from the pull -f, –filter REGEX # only pull certain tables -r, –resume FILE # resume transfer described by a .dat file -t, –tables TABLES # only pull the specified tables

# File lib/heroku/command/db.rb, line 48
def pull
  load_taps
  opts = parse_taps_opts

  display("Warning: Data in the database '#{opts[:database_url]}' will be overwritten and will not be recoverable.")

  if confirm_command
    taps_client(:pull, opts)
  end
end
push() click to toggle source

db:push [DATABASE_URL]

push local data up to your app

DATABASE_URL should reference your local database. if not specified, it will be guessed from config/database.yml

-c, –chunksize SIZE # specify the number of rows to send in each batch -d, –debug # enable debugging output -e, –exclude TABLES # exclude the specified tables from the push -f, –filter REGEX # only push certain tables -r, –resume FILE # resume transfer described by a .dat file -t, –tables TABLES # only push the specified tables

# File lib/heroku/command/db.rb, line 23
def push
  load_taps
  opts = parse_taps_opts

  display("Warning: Data in the app '#{app}' will be overwritten and will not be recoverable.")

  if confirm_command
    taps_client(:push, opts)
  end
end

Protected Instance Methods

conf_to_uri_hash(conf) click to toggle source
# File lib/heroku/command/db.rb, line 86
def conf_to_uri_hash(conf)
  uri = {}
  uri['scheme'] = conf['adapter']
  uri['username'] = conf['user'] || conf['username']
  uri['password'] = conf['password']
  uri['host'] = conf['host'] || conf['hostname'] || '127.0.0.1'
  uri['port'] = conf['port']
  uri['path'] = conf['database']

  conf['encoding'] = 'utf8' if conf['encoding'] == 'unicode' or conf['encoding'].nil?
  uri['query'] = "encoding=#{conf['encoding']}"

  uri
end
enforce_taps_version(version) click to toggle source
# File lib/heroku/command/db.rb, line 196
def enforce_taps_version(version)
  unless Taps.version >= version
    error "Your taps gem is out of date (v#{version} or higher required)."
  end
end
load_taps() click to toggle source
# File lib/heroku/command/db.rb, line 202
def load_taps
  begin
    require "rubygems"
  rescue LoadError
  end
  require 'taps/operation'
  require 'taps/cli'
  enforce_taps_version "0.3.23"
  display "Loaded Taps v#{Taps.version}"
rescue LoadError
  message  = "Taps Load Error: #{$!.message}\n"
  message << "You may need to install or update the taps gem to use db commands.\n"
  message << "On most systems this will be:\n\nsudo gem install taps"
  error message
end
parse_database_yml() click to toggle source
# File lib/heroku/command/db.rb, line 61
def parse_database_yml
  return "" unless File.exists?(Dir.pwd + '/config/database.yml')
  require 'erb'
  require 'yaml'

  environment = ENV['RAILS_ENV'] || ENV['MERB_ENV'] || ENV['RACK_ENV']
  environment = 'development' if environment.nil? or environment.empty?

  conf = YAML.load(ERB.new(File.read(Dir.pwd + '/config/database.yml')).result)[environment]
  case conf['adapter']
    when 'sqlite3'
      return "sqlite://#{conf['database']}"
    when 'postgresql'
      uri_hash = conf_to_uri_hash(conf)
      uri_hash['scheme'] = 'postgres'
      return uri_hash_to_url(uri_hash)
    else
      return uri_hash_to_url(conf_to_uri_hash(conf))
  end
rescue Exception => ex
  puts "Error parsing database.yml: #{ex.message}"
  puts ex.backtrace
  ""
end
parse_taps_opts() click to toggle source
# File lib/heroku/command/db.rb, line 128
def parse_taps_opts
  opts = {}
  opts[:default_chunksize] = options[:chunksize] || 1000
  opts[:default_chunksize] = opts[:default_chunksize].to_i rescue 1000

  if filter = options[:filter]
    opts[:table_filter] = filter
  elsif tables = options[:tables]
    r_tables = tables.split(",").collect { |t| "^#{t.strip}$" }
    opts[:table_filter] = "(#{r_tables.join("|")})"
  end

  if options[:'disable-compression']
    opts[:disable_compression] = true
  end

  if excluded_tables = options[:exclude]
    opts[:exclude_tables] = excluded_tables
  end

  if resume_file = options[:resume]
    opts[:resume_filename] = resume_file
  end

  opts[:indexes_first] = !options[:'indexes-last']

  opts[:database_url] = args.detect { |a| URI.parse(a).scheme } rescue nil

  unless opts[:database_url]
    opts[:database_url] = parse_database_yml
    display "Auto-detected local database: #{opts[:database_url]}" if opts[:database_url] != ''
  end
  raise(CommandFailed, "Invalid database url") if opts[:database_url] == ''

  if options[:debug]
    require 'logger'
    Taps.log.level = Logger::DEBUG
  end

  # setting local timezone equal to Heroku timezone allowing TAPS to
  # correctly transfer datetime fields between databases
  ENV['TZ'] = 'America/Los_Angeles'
  opts
end
taps_client(op, opts) click to toggle source
# File lib/heroku/command/db.rb, line 173
def taps_client(op, opts)
  Taps::Config.verify_database_url(opts[:database_url])
  if opts[:resume_filename]
    Taps::Cli.new([]).clientresumexfer(op, opts)
  else
    info = heroku.database_session(app)

    replacement_host = case
      when ENV["TAPS_HOST"] then ENV["TAPS_HOST"]
      when RUBY_VERSION >= '1.9' then "taps19.heroku.com"
      else nil
    end

    if replacement_host
      info["url"].gsub!("taps3.heroku.com", replacement_host)
    end

    opts[:remote_url] = info['url']
    opts[:session_uri] = info['session']
    Taps::Cli.new([]).clientxfer(op, opts)
  end
end
uri_hash_to_url(uri) click to toggle source
# File lib/heroku/command/db.rb, line 112
def uri_hash_to_url(uri)
  host = uri['host']
  host ||= '127.0.0.1' unless uri['scheme'] == 'postgres'
  uri_parts = {
    :scheme   => uri['scheme'],
    :userinfo => userinfo_from_uri(uri),
    :password => uri['password'],
    :host     => host,
    :port     => uri['port'],
    :path     => "/%s" % uri['path'],
    :query    => uri['query'],
  }

  URI::Generic.build(uri_parts).to_s
end
userinfo_from_uri(uri) click to toggle source
# File lib/heroku/command/db.rb, line 101
def userinfo_from_uri(uri)
  username = uri['username'].to_s
  password = uri['password'].to_s
  return nil if username == ''

  userinfo  = ""
  userinfo << username
  userinfo << ":" << password if password.length > 0
  userinfo
end