2008-05-11 18:51:30 -04:00
|
|
|
require 'erb'
|
2008-05-07 16:50:46 -04:00
|
|
|
require 'yaml'
|
2008-05-04 06:53:50 -04:00
|
|
|
require 'optparse'
|
2010-04-25 03:26:36 -04:00
|
|
|
require 'rbconfig'
|
2008-05-07 16:50:46 -04:00
|
|
|
|
2009-11-24 14:53:14 -05:00
|
|
|
module Rails
|
|
|
|
class DBConsole
|
2012-11-18 20:58:17 -05:00
|
|
|
attr_reader :arguments
|
Fix rails db command with sqlite3 database
When using sqlite3 it was attempting to find the database file based on
Rails.root, the problem is that Rails.root is not always present because
we try to first manually load "config/database.yml" instead of loading
the entire app, to make "rails db" faster.
This means that when we're in the root path of the app, calling "rails db"
won't allow us to use Rails.root, making the command fail for sqlite3
with the error:
./rails/commands/dbconsole.rb:62:in `start':
undefined method `root' for Rails:Module (NoMethodError)
The fix is to simply not pass any dir string to File.expand_path, which
will make it use the current directory of the process as base, or the
root path of the app, which is what we want.
When we are in any other subdirectory, calling "rails db" should work
just fine, because "config/database.yml" won't be found, thus "rails db"
will fallback to loading the app, making Rails.root available.
Closes #8257.
2012-11-18 20:46:33 -05:00
|
|
|
|
2012-05-04 10:40:32 -04:00
|
|
|
def self.start
|
2012-05-11 17:19:58 -04:00
|
|
|
new.start
|
2009-11-24 16:03:24 -05:00
|
|
|
end
|
|
|
|
|
2012-05-11 17:19:58 -04:00
|
|
|
def initialize(arguments = ARGV)
|
|
|
|
@arguments = arguments
|
2009-11-24 14:53:14 -05:00
|
|
|
end
|
2009-08-10 02:12:26 -04:00
|
|
|
|
2009-11-24 14:53:14 -05:00
|
|
|
def start
|
2012-05-11 17:19:58 -04:00
|
|
|
options = parse_arguments(arguments)
|
|
|
|
ENV['RAILS_ENV'] = options[:environment] || environment
|
2009-11-24 14:53:14 -05:00
|
|
|
|
|
|
|
case config["adapter"]
|
2010-05-04 16:46:52 -04:00
|
|
|
when /^mysql/
|
2009-11-24 14:53:14 -05:00
|
|
|
args = {
|
|
|
|
'host' => '--host',
|
|
|
|
'port' => '--port',
|
|
|
|
'socket' => '--socket',
|
|
|
|
'username' => '--user',
|
2012-09-10 15:36:49 -04:00
|
|
|
'encoding' => '--default-character-set',
|
|
|
|
'sslca' => '--ssl-ca',
|
|
|
|
'sslcert' => '--ssl-cert',
|
|
|
|
'sslcapath' => '--ssl-capath',
|
|
|
|
'sslcipher' => '--ssh-cipher',
|
|
|
|
'sslkey' => '--ssl-key'
|
2009-11-24 14:53:14 -05:00
|
|
|
}.map { |opt, arg| "#{arg}=#{config[opt]}" if config[opt] }.compact
|
|
|
|
|
2012-05-11 17:19:58 -04:00
|
|
|
if config['password'] && options['include_password']
|
2009-11-24 14:53:14 -05:00
|
|
|
args << "--password=#{config['password']}"
|
|
|
|
elsif config['password'] && !config['password'].to_s.empty?
|
|
|
|
args << "-p"
|
|
|
|
end
|
|
|
|
|
|
|
|
args << config['database']
|
|
|
|
|
2012-04-27 03:28:53 -04:00
|
|
|
find_cmd_and_exec(['mysql', 'mysql5'], *args)
|
2009-11-24 14:53:14 -05:00
|
|
|
|
2010-12-16 08:03:01 -05:00
|
|
|
when "postgresql", "postgres"
|
2009-11-24 14:53:14 -05:00
|
|
|
ENV['PGUSER'] = config["username"] if config["username"]
|
|
|
|
ENV['PGHOST'] = config["host"] if config["host"]
|
|
|
|
ENV['PGPORT'] = config["port"].to_s if config["port"]
|
2012-05-11 17:19:58 -04:00
|
|
|
ENV['PGPASSWORD'] = config["password"].to_s if config["password"] && options['include_password']
|
2012-04-27 03:28:53 -04:00
|
|
|
find_cmd_and_exec('psql', config["database"])
|
2009-11-24 14:53:14 -05:00
|
|
|
|
|
|
|
when "sqlite"
|
2012-04-27 03:28:53 -04:00
|
|
|
find_cmd_and_exec('sqlite', config["database"])
|
2009-11-24 14:53:14 -05:00
|
|
|
|
|
|
|
when "sqlite3"
|
|
|
|
args = []
|
|
|
|
|
|
|
|
args << "-#{options['mode']}" if options['mode']
|
|
|
|
args << "-header" if options['header']
|
Fix rails db command with sqlite3 database
When using sqlite3 it was attempting to find the database file based on
Rails.root, the problem is that Rails.root is not always present because
we try to first manually load "config/database.yml" instead of loading
the entire app, to make "rails db" faster.
This means that when we're in the root path of the app, calling "rails db"
won't allow us to use Rails.root, making the command fail for sqlite3
with the error:
./rails/commands/dbconsole.rb:62:in `start':
undefined method `root' for Rails:Module (NoMethodError)
The fix is to simply not pass any dir string to File.expand_path, which
will make it use the current directory of the process as base, or the
root path of the app, which is what we want.
When we are in any other subdirectory, calling "rails db" should work
just fine, because "config/database.yml" won't be found, thus "rails db"
will fallback to loading the app, making Rails.root available.
Closes #8257.
2012-11-18 20:46:33 -05:00
|
|
|
args << File.expand_path(config['database'], Rails.respond_to?(:root) ? Rails.root : nil)
|
2009-11-24 14:53:14 -05:00
|
|
|
|
2012-04-27 03:28:53 -04:00
|
|
|
find_cmd_and_exec('sqlite3', *args)
|
2010-01-22 15:58:31 -05:00
|
|
|
|
|
|
|
when "oracle", "oracle_enhanced"
|
|
|
|
logon = ""
|
|
|
|
|
|
|
|
if config['username']
|
|
|
|
logon = config['username']
|
2012-05-11 17:19:58 -04:00
|
|
|
logon << "/#{config['password']}" if config['password'] && options['include_password']
|
2010-01-22 15:58:31 -05:00
|
|
|
logon << "@#{config['database']}" if config['database']
|
|
|
|
end
|
|
|
|
|
2012-04-27 03:28:53 -04:00
|
|
|
find_cmd_and_exec('sqlplus', logon)
|
2010-01-22 15:58:31 -05:00
|
|
|
|
2009-11-24 14:53:14 -05:00
|
|
|
else
|
|
|
|
abort "Unknown command-line client for #{config['database']}. Submit a Rails patch to add support!"
|
|
|
|
end
|
2008-05-04 06:53:50 -04:00
|
|
|
end
|
2012-04-27 03:28:53 -04:00
|
|
|
|
2012-05-11 17:19:58 -04:00
|
|
|
def config
|
|
|
|
@config ||= begin
|
|
|
|
cfg = begin
|
2012-11-18 20:58:17 -05:00
|
|
|
YAML.load(ERB.new(IO.read("config/database.yml")).result)
|
2012-05-11 17:19:58 -04:00
|
|
|
rescue SyntaxError, StandardError
|
|
|
|
require APP_PATH
|
|
|
|
Rails.application.config.database_configuration
|
|
|
|
end
|
|
|
|
|
2012-11-18 20:58:17 -05:00
|
|
|
cfg[environment] || abort("No database is configured for the environment '#{environment}'")
|
2012-05-11 17:19:58 -04:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def environment
|
|
|
|
if Rails.respond_to?(:env)
|
|
|
|
Rails.env
|
|
|
|
else
|
|
|
|
ENV["RAILS_ENV"] || ENV["RACK_ENV"] || "development"
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2012-04-27 03:28:53 -04:00
|
|
|
protected
|
|
|
|
|
2012-05-11 17:19:58 -04:00
|
|
|
def parse_arguments(arguments)
|
|
|
|
options = {}
|
Fix rails db command with sqlite3 database
When using sqlite3 it was attempting to find the database file based on
Rails.root, the problem is that Rails.root is not always present because
we try to first manually load "config/database.yml" instead of loading
the entire app, to make "rails db" faster.
This means that when we're in the root path of the app, calling "rails db"
won't allow us to use Rails.root, making the command fail for sqlite3
with the error:
./rails/commands/dbconsole.rb:62:in `start':
undefined method `root' for Rails:Module (NoMethodError)
The fix is to simply not pass any dir string to File.expand_path, which
will make it use the current directory of the process as base, or the
root path of the app, which is what we want.
When we are in any other subdirectory, calling "rails db" should work
just fine, because "config/database.yml" won't be found, thus "rails db"
will fallback to loading the app, making Rails.root available.
Closes #8257.
2012-11-18 20:46:33 -05:00
|
|
|
|
2012-05-11 17:19:58 -04:00
|
|
|
OptionParser.new do |opt|
|
|
|
|
opt.banner = "Usage: rails dbconsole [environment] [options]"
|
|
|
|
opt.on("-p", "--include-password", "Automatically provide the password from database.yml") do |v|
|
|
|
|
options['include_password'] = true
|
|
|
|
end
|
|
|
|
|
|
|
|
opt.on("--mode [MODE]", ['html', 'list', 'line', 'column'],
|
|
|
|
"Automatically put the sqlite3 database in the specified mode (html, list, line, column).") do |mode|
|
|
|
|
options['mode'] = mode
|
|
|
|
end
|
|
|
|
|
|
|
|
opt.on("--header") do |h|
|
|
|
|
options['header'] = h
|
|
|
|
end
|
Fix rails db command with sqlite3 database
When using sqlite3 it was attempting to find the database file based on
Rails.root, the problem is that Rails.root is not always present because
we try to first manually load "config/database.yml" instead of loading
the entire app, to make "rails db" faster.
This means that when we're in the root path of the app, calling "rails db"
won't allow us to use Rails.root, making the command fail for sqlite3
with the error:
./rails/commands/dbconsole.rb:62:in `start':
undefined method `root' for Rails:Module (NoMethodError)
The fix is to simply not pass any dir string to File.expand_path, which
will make it use the current directory of the process as base, or the
root path of the app, which is what we want.
When we are in any other subdirectory, calling "rails db" should work
just fine, because "config/database.yml" won't be found, thus "rails db"
will fallback to loading the app, making Rails.root available.
Closes #8257.
2012-11-18 20:46:33 -05:00
|
|
|
|
2012-05-11 17:19:58 -04:00
|
|
|
opt.on("-h", "--help", "Show this help message.") do
|
|
|
|
puts opt
|
|
|
|
exit
|
|
|
|
end
|
|
|
|
|
|
|
|
opt.on("-e", "--environment=name", String,
|
|
|
|
"Specifies the environment to run this console under (test/development/production).",
|
|
|
|
"Default: development"
|
|
|
|
) { |v| options[:environment] = v.strip }
|
|
|
|
|
|
|
|
opt.parse!(arguments)
|
|
|
|
abort opt.to_s unless (0..1).include?(arguments.size)
|
|
|
|
end
|
|
|
|
|
|
|
|
if arguments.first && arguments.first[0] != '-'
|
|
|
|
env = arguments.first
|
|
|
|
options[:environment] = %w(production development test).detect {|e| e =~ /^#{env}/} || env
|
|
|
|
end
|
Fix rails db command with sqlite3 database
When using sqlite3 it was attempting to find the database file based on
Rails.root, the problem is that Rails.root is not always present because
we try to first manually load "config/database.yml" instead of loading
the entire app, to make "rails db" faster.
This means that when we're in the root path of the app, calling "rails db"
won't allow us to use Rails.root, making the command fail for sqlite3
with the error:
./rails/commands/dbconsole.rb:62:in `start':
undefined method `root' for Rails:Module (NoMethodError)
The fix is to simply not pass any dir string to File.expand_path, which
will make it use the current directory of the process as base, or the
root path of the app, which is what we want.
When we are in any other subdirectory, calling "rails db" should work
just fine, because "config/database.yml" won't be found, thus "rails db"
will fallback to loading the app, making Rails.root available.
Closes #8257.
2012-11-18 20:46:33 -05:00
|
|
|
|
2012-05-11 17:19:58 -04:00
|
|
|
options
|
|
|
|
end
|
|
|
|
|
2012-04-27 03:28:53 -04:00
|
|
|
def find_cmd_and_exec(commands, *args)
|
|
|
|
commands = Array(commands)
|
|
|
|
|
|
|
|
dirs_on_path = ENV['PATH'].to_s.split(File::PATH_SEPARATOR)
|
|
|
|
commands += commands.map{|cmd| "#{cmd}.exe"} if RbConfig::CONFIG['host_os'] =~ /mswin|mingw/
|
|
|
|
|
|
|
|
full_path_command = nil
|
|
|
|
found = commands.detect do |cmd|
|
2012-11-10 07:04:39 -05:00
|
|
|
dirs_on_path.detect do |path|
|
2012-04-27 03:28:53 -04:00
|
|
|
full_path_command = File.join(path, cmd)
|
|
|
|
File.executable? full_path_command
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
if found
|
|
|
|
exec full_path_command, *args
|
|
|
|
else
|
|
|
|
abort("Couldn't find database client: #{commands.join(', ')}. Check your $PATH and try again.")
|
|
|
|
end
|
|
|
|
end
|
2009-08-10 02:12:26 -04:00
|
|
|
end
|
2010-01-11 17:01:28 -05:00
|
|
|
end
|