Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Rails commands for existing rake tasks #21254

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions railties/lib/rails/commands/cache_digests.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
require 'rails/commands/command'

module Rails
module Commands
class CacheDigests < Command
rake_delegate 'cache_digests:dependencies',
'cache_digests:nested_dependencies'

set_banner :cache_digests_dependencies,
'Lookup first-level dependencies for TEMPLATE (like messages/show or comments/_comment.html)'
set_banner :cache_digests_nested_dependencies,
'Lookup nested dependencies for TEMPLATE (like messages/show or comments/_comment.html)'
end
end
end
83 changes: 83 additions & 0 deletions railties/lib/rails/commands/command.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
module Rails
module Commands
class Command
attr_reader :argv

def initialize(argv)
@argv = argv

@option_parser = build_option_parser
@options = {}
end

def run(task_name)
command_name = Command.name_for(task_name)

parse_options_for(command_name)
@option_parser.parse! @argv

if command_instance = command_instance_for(command_name)
command_instance.public_send(command_name)
else
puts @option_parser
end
end

def tasks
public_instance_methods.map { |method| method.gsub('_', ':') }
end

def self.options_for(command_name, &options_to_parse)
@@command_options[command_name] = options_to_parse
end

def self.rake_delegate(*task_names)
task_names.each do |task_name|
define_method(name_for(task_name)) do
system "rake #{task_name}"
end
end
end

def self.name_for(task_name)
task_name.gsub(':', '_')
end

def self.set_banner(command_name, banner)
options_for(command_name) { |opts, _| opts.banner banner }
end

private
@@commands = []
@@command_options = {}

def parse_options_for(command_name)
@@command_options.fetch(command_name.to_sym, -> {}).call(@option_parser, @options)
rescue ArgumentError
false
end

def build_option_parser
OptionParser.new do |opts|
opts.on('-h', '--help', 'Show this help.') do
puts opts
exit
end
end
end

def self.inherited(command)
@@commands << command
end

def command_instance_for(command_name)
klass = @@commands.find do |command|
command_instance_methods = command.public_instance_methods
command_instance_methods.include?(command_name.to_sym)
end

klass.new(@argv)
end
end
end
end
183 changes: 15 additions & 168 deletions railties/lib/rails/commands/commands_tasks.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,14 @@
require 'rails/commands/cache_digests'
require 'rails/commands/command'
require 'rails/commands/core'
require 'rails/commands/db'
require 'rails/commands/docs'
require 'rails/commands/dev_cache'
require 'rails/commands/help'
require 'rails/commands/notes'
require 'rails/commands/test'
require 'rails/commands/tmp'

module Rails
# This is a class which takes in a rails command and initiates the appropriate
# initiation sequence.
Expand All @@ -7,179 +18,15 @@ module Rails
class CommandsTasks # :nodoc:
attr_reader :argv

HELP_MESSAGE = <<-EOT
Usage: rails COMMAND [ARGS]

The most common rails commands are:
generate Generate new code (short-cut alias: "g")
console Start the Rails console (short-cut alias: "c")
server Start the Rails server (short-cut alias: "s")
test Run tests (short-cut alias: "t")
dbconsole Start a console for the database specified in config/database.yml
(short-cut alias: "db")
new Create a new Rails application. "rails new my_app" creates a
new application called MyApp in "./my_app"

In addition to those, there are:
destroy Undo code generated with "generate" (short-cut alias: "d")
plugin new Generates skeleton for developing a Rails plugin
runner Run a piece of code in the application environment (short-cut alias: "r")

All commands can be run with -h (or --help) for more information.
EOT

COMMAND_WHITELIST = %w(plugin generate destroy console server dbconsole runner new version help test)

def initialize(argv)
@argv = argv
@command = Rails::Commands::Command.new(argv)
end

def run_command!(command)
command = parse_command(command)
if COMMAND_WHITELIST.include?(command)
send(command)
else
write_error_message(command)
end
end

def plugin
require_command!("plugin")
end

def generate
generate_or_destroy(:generate)
end

def destroy
generate_or_destroy(:destroy)
end

def console
require_command!("console")
options = Rails::Console.parse_arguments(argv)

# RAILS_ENV needs to be set before config/application is required
ENV['RAILS_ENV'] = options[:environment] if options[:environment]

# shift ARGV so IRB doesn't freak
shift_argv!

require_application_and_environment!
Rails::Console.start(Rails.application, options)
end

def server
set_application_directory!
require_command!("server")

Rails::Server.new.tap do |server|
# We need to require application after the server sets environment,
# otherwise the --environment option given to the server won't propagate.
require APP_PATH
Dir.chdir(Rails.application.root)
server.start
end
end

def test
require_command!("test")
end

def dbconsole
require_command!("dbconsole")
Rails::DBConsole.start
end

def runner
require_command!("runner")
end

def new
if %w(-h --help).include?(argv.first)
require_command!("application")
else
exit_with_initialization_warning!
end
end

def version
argv.unshift '--version'
require_command!("application")
end

def help
write_help_message
@command.run(command)
rescue
@command.run('help')
end

private

def exit_with_initialization_warning!
puts "Can't initialize a new Rails application within the directory of another, please change to a non-Rails directory first.\n"
puts "Type 'rails' for help."
exit(1)
end

def shift_argv!
argv.shift if argv.first && argv.first[0] != '-'
end

def require_command!(command)
require "rails/commands/#{command}"
end

def generate_or_destroy(command)
require 'rails/generators'
require_application_and_environment!
Rails.application.load_generators
require_command!(command)
end

# Change to the application's path if there is no config.ru file in current directory.
# This allows us to run `rails server` from other directories, but still get
# the main config.ru and properly set the tmp directory.
def set_application_directory!
Dir.chdir(File.expand_path('../../', APP_PATH)) unless File.exist?(File.expand_path("config.ru"))
end

def require_application_and_environment!
require APP_PATH
Rails.application.require_environment!
end

def write_help_message
puts HELP_MESSAGE
end

# Output an error message stating that the attempted command is not a valid rails command.
# Run the attempted command as a rake command with the --dry-run flag. If successful, suggest
# to the user that they possibly meant to run the given rails command as a rake command.
# Append the help message.
#
# Example:
# $ rails db:migrate
# Error: Command 'db:migrate' not recognized
# Did you mean: `$ rake db:migrate` ?
# (Help message output)
#
def write_error_message(command)
puts "Error: Command '#{command}' not recognized"
if %x{rake #{command} --dry-run 2>&1 } && $?.success?
puts "Did you mean: `$ rake #{command}` ?\n\n"
end
write_help_message
exit(1)
end

def parse_command(command)
case command
when '--version', '-v'
'version'
when '--help', '-h'
'help'
else
command
end
end
end
end
Loading