diff options
author | Genadi Samokovarov <gsamokovarov@gmail.com> | 2018-02-19 20:31:56 +0200 |
---|---|---|
committer | Genadi Samokovarov <gsamokovarov@gmail.com> | 2018-03-04 17:50:29 +0200 |
commit | 5af643d8d6f8af19a85a34475f40ac18db7c71e9 (patch) | |
tree | e32e0f33589c49b06d523ce514e1263097fb0adb /railties | |
parent | 22a67927f1c3e0fbc6a77b9b1c8892166a171c78 (diff) | |
download | rails-5af643d8d6f8af19a85a34475f40ac18db7c71e9.tar.gz rails-5af643d8d6f8af19a85a34475f40ac18db7c71e9.tar.bz2 rails-5af643d8d6f8af19a85a34475f40ac18db7c71e9.zip |
Introduce explicit rails server handler option
I mistype `rails server production` instead of `rails server -e
production` expecting to lunch a server in the production environment
all the time. However, the signature of `rails server --help` is:
```
Usage:
rails server [puma, thin etc] [options]
```
This means that the `production` argument is being interpreted as a Rack
server handler like Puma, Thin or Unicorn.
Should we argue for the `rails server production`? I'm not sure of the
reasons, but the `rails console production` behavior was deprecated in:
https://github.com/rails/rails/pull/29358, so parity with the existing
`rails console production` usage may not hold anymore.
In any case, this PR introduces an explicit option for the Rack servers
configuration. The option is called `--using` (or `-u` for short) to
avoid the `rails server --server` tantrum.
The new interface of `rails server` is:
```
Usage:
rails server [using] [options]
Options:
-p, [--port=port] # Runs Rails on the specified port - defaults to 3000.
-b, [--binding=IP] # Binds Rails to the specified IP - defaults to 'localhost' in development and '0.0.0.0' in other environments'.
-c, [--config=file] # Uses a custom rackup configuration.
# Default: config.ru
-d, [--daemon], [--no-daemon] # Runs server as a Daemon.
-e, [--environment=name] # Specifies the environment to run this server under (development/test/production).
-u, [--using=name] # Specifies the Rack server used to run the application (thin/puma/webrick).
-P, [--pid=PID] # Specifies the PID file.
# Default: tmp/pids/server.pid
-C, [--dev-caching], [--no-dev-caching] # Specifies whether to perform caching in development.
[--early-hints], [--no-early-hints] # Enables HTTP/2 early hints.
```
As a bonus, if you mistype the server to use, you'll get an
auto-correction message:
```
$ rails s tin
Could not find handler "tin". Maybe you meant "thin" or "cgi"?
Run `rails server --help` for more options.
```
Diffstat (limited to 'railties')
-rw-r--r-- | railties/CHANGELOG.md | 18 | ||||
-rw-r--r-- | railties/lib/rails/commands/server/server_command.rb | 88 | ||||
-rw-r--r-- | railties/test/commands/server_test.rb | 33 |
3 files changed, 119 insertions, 20 deletions
diff --git a/railties/CHANGELOG.md b/railties/CHANGELOG.md index a38888afe5..335eb6c4e3 100644 --- a/railties/CHANGELOG.md +++ b/railties/CHANGELOG.md @@ -1,5 +1,23 @@ ## Rails 6.0.0.alpha (Unreleased) ## +* Deprecate passing Rack server name as a regular argument to `rails server`. + + Previously: + + $ bin/rails server thin + + There wasn't an explicit option for the Rack server to use, now we have the + `--using` option with the `-u` short switch. + + Now: + + $ bin/rails server -u thin + + This change also improves the error message if a missing or mistyped rack + server is given. + + *Genadi Samokovarov* + * Add "rails routes --expanded" option to output routes in expanded mode like "psql --expanded". Result looks like: diff --git a/railties/lib/rails/commands/server/server_command.rb b/railties/lib/rails/commands/server/server_command.rb index e546fe3e4b..44b26d3846 100644 --- a/railties/lib/rails/commands/server/server_command.rb +++ b/railties/lib/rails/commands/server/server_command.rb @@ -44,7 +44,6 @@ module Rails end def start - print_boot_information trap(:INT) { exit } create_tmp_directories setup_dev_caching @@ -52,9 +51,14 @@ module Rails super ensure - # The '-h' option calls exit before @options is set. - # If we call 'options' with it unset, we get double help banners. - puts "Exiting" unless @options && options[:daemonize] + yield + end + + def serveable? # :nodoc: + server + true + rescue LoadError, NameError + false end def middleware @@ -65,6 +69,10 @@ module Rails super.merge(@default_options) end + def served_url + "#{options[:SSLEnable] ? 'https' : 'http'}://#{host}:#{port}" unless use_puma? + end + private def setup_dev_caching if options[:environment] == "development" @@ -72,13 +80,6 @@ module Rails end end - def print_boot_information - url = "on #{options[:SSLEnable] ? 'https' : 'http'}://#{options[:Host]}:#{options[:Port]}" unless use_puma? - puts "=> Booting #{ActiveSupport::Inflector.demodulize(server)}" - puts "=> Rails #{Rails.version} application starting in #{Rails.env} #{url}" - puts "=> Run `rails server -h` for more startup options" - end - def create_tmp_directories %w(cache pids sockets).each do |dir_to_make| FileUtils.mkdir_p(File.join(Rails.root, "tmp", dir_to_make)) @@ -108,9 +109,15 @@ module Rails module Command class ServerCommand < Base # :nodoc: + # Hard-coding a bunch of handlers here as we don't have a public way of + # querying them from the Rack::Handler registry. + RACK_SERVERS = %w(cgi fastcgi webrick lsws scgi thin puma unicorn) + DEFAULT_PORT = 3000 DEFAULT_PID_PATH = "tmp/pids/server.pid".freeze + argument :using, optional: true + class_option :port, aliases: "-p", type: :numeric, desc: "Runs Rails on the specified port - defaults to 3000.", banner: :port class_option :binding, aliases: "-b", type: :string, @@ -122,6 +129,8 @@ module Rails desc: "Runs server as a Daemon." class_option :environment, aliases: "-e", type: :string, desc: "Specifies the environment to run this server under (development/test/production).", banner: :name + class_option :using, aliases: "-u", type: :string, + desc: "Specifies the Rack server used to run the application (thin/puma/webrick).", banner: :name class_option :pid, aliases: "-P", type: :string, default: DEFAULT_PID_PATH, desc: "Specifies the PID file." class_option "dev-caching", aliases: "-C", type: :boolean, default: nil, @@ -132,19 +141,28 @@ module Rails def initialize(args = [], local_options = {}, config = {}) @original_options = local_options super - @server = self.args.shift + @using = deprecated_positional_rack_server(using) || options[:using] @log_stdout = options[:daemon].blank? && (options[:environment] || Rails.env) == "development" end def perform set_application_directory! prepare_restart + Rails::Server.new(server_options).tap do |server| # Require application after server sets environment to propagate # the --environment option. require APP_PATH Dir.chdir(Rails.application.root) - server.start + + if server.serveable? + print_boot_information(server.server, server.served_url) + server.start do + say "Exiting" unless options[:daemon] + end + else + say rack_server_suggestion(using) + end end end @@ -152,7 +170,7 @@ module Rails def server_options { user_supplied_options: user_supplied_options, - server: @server, + server: using, log_stdout: @log_stdout, Port: port, Host: host, @@ -226,7 +244,7 @@ module Rails end def restart_command - "bin/rails server #{@server} #{@original_options.join(" ")} --restart" + "bin/rails server #{using} #{@original_options.join(" ")} --restart" end def early_hints @@ -238,12 +256,50 @@ module Rails end def self.banner(*) - "rails server [puma, thin etc] [options]" + "rails server [thin/puma/webrick] [options]" end def prepare_restart FileUtils.rm_f(options[:pid]) if options[:restart] end + + def deprecated_positional_rack_server(value) + if value + ActiveSupport::Deprecation.warn(<<-MSG.squish) + Passing the Rack server name as a regular argument is deprecated + and will be removed in the next Rails version. Please, use the -u + option instead. + MSG + value + end + end + + def rack_server_suggestion(server) + if server.in?(RACK_SERVERS) + <<~MSG + Could not load server "#{server}". Maybe you need to the add it to the Gemfile? + + gem "#{server}" + + Run `rails server --help` for more options. + MSG + else + suggestions = Rails::Command::Spellchecker.suggest(server, from: RACK_SERVERS).map(&:inspect) + + <<~MSG + Could not find server "#{server}". Maybe you meant #{suggestions.first} or #{suggestions.second}? + Run `rails server --help` for more options. + MSG + end + end + + def print_boot_information(server, url) + say <<~MSG + => Booting #{ActiveSupport::Inflector.demodulize(server)} + => Rails #{Rails.version} application starting in #{Rails.env} #{url} + => Run `rails server --help` for more startup options + MSG + end end end end diff --git a/railties/test/commands/server_test.rb b/railties/test/commands/server_test.rb index 33715ea75f..c84be439e4 100644 --- a/railties/test/commands/server_test.rb +++ b/railties/test/commands/server_test.rb @@ -1,15 +1,15 @@ # frozen_string_literal: true -require "abstract_unit" +require "isolation/abstract_unit" require "env_helpers" require "rails/command" require "rails/commands/server/server_command" -class Rails::ServerTest < ActiveSupport::TestCase +class Rails::Command::ServerCommandTest < ActiveSupport::TestCase include EnvHelpers def test_environment_with_server_option - args = ["thin", "-e", "production"] + args = ["-u", "thin", "-e", "production"] options = parse_arguments(args) assert_equal "production", options[:environment] assert_equal "thin", options[:server] @@ -22,6 +22,24 @@ class Rails::ServerTest < ActiveSupport::TestCase assert_nil options[:server] end + def test_explicit_using_option + args = ["-u", "thin"] + options = parse_arguments(args) + assert_equal "thin", options[:server] + end + + def test_using_server_mistype + assert_match(/Could not find server "tin". Maybe you meant "thin" or "cgi"/, run_command("--using", "tin")) + end + + def test_using_positional_argument_deprecation + assert_match(/DEPRECATION WARNING/, run_command("tin")) + end + + def test_using_known_server_that_isnt_in_the_gemfile + assert_match(/Could not load server "unicorn". Maybe you need to the add it to the Gemfile/, run_command("-u", "unicorn")) + end + def test_daemon_with_option args = ["-d"] options = parse_arguments(args) @@ -35,7 +53,7 @@ class Rails::ServerTest < ActiveSupport::TestCase end def test_server_option_without_environment - args = ["thin"] + args = ["-u", "thin"] with_rack_env nil do with_rails_env nil do options = parse_arguments(args) @@ -222,6 +240,13 @@ class Rails::ServerTest < ActiveSupport::TestCase end private + def run_command(*args) + build_app + rails "server", *args + ensure + teardown_app + end + def parse_arguments(args = []) Rails::Command::ServerCommand.new([], args).server_options end |