diff options
Diffstat (limited to 'railties/lib/rails/commands')
9 files changed, 199 insertions, 49 deletions
diff --git a/railties/lib/rails/commands/credentials/USAGE b/railties/lib/rails/commands/credentials/USAGE index 85877c71b7..ea429f58d8 100644 --- a/railties/lib/rails/commands/credentials/USAGE +++ b/railties/lib/rails/commands/credentials/USAGE @@ -14,7 +14,7 @@ that just contains the secret_key_base used by MessageVerifiers/MessageEncryptor signing and encrypting cookies. For applications created prior to Rails 5.2, we'll automatically generate a new -credentials file in `config/credentials.yml.enc` the first time you run `bin/rails credentials:edit`. +credentials file in `config/credentials.yml.enc` the first time you run `rails credentials:edit`. If you didn't have a master key saved in `config/master.key`, that'll be created too. Don't lose this master key! Put it in a password manager your team can access. diff --git a/railties/lib/rails/commands/credentials/credentials_command.rb b/railties/lib/rails/commands/credentials/credentials_command.rb index 385d3976da..65c5218fc8 100644 --- a/railties/lib/rails/commands/credentials/credentials_command.rb +++ b/railties/lib/rails/commands/credentials/credentials_command.rb @@ -20,7 +20,7 @@ module Rails require_application_and_environment! ensure_editor_available(command: "bin/rails credentials:edit") || (return) - ensure_master_key_has_been_added + ensure_master_key_has_been_added if Rails.application.credentials.key.nil? ensure_credentials_have_been_added catch_editing_exceptions do @@ -69,9 +69,9 @@ module Rails def missing_credentials_message if Rails.application.credentials.key.nil? - "Missing master key to decrypt credentials. See bin/rails credentials:help" + "Missing master key to decrypt credentials. See `rails credentials:help`" else - "No credentials have been added yet. Use bin/rails credentials:edit to change that." + "No credentials have been added yet. Use `rails credentials:edit` to change that." end end end diff --git a/railties/lib/rails/commands/dbconsole/dbconsole_command.rb b/railties/lib/rails/commands/dbconsole/dbconsole_command.rb index 8df548b5de..806b7de6d6 100644 --- a/railties/lib/rails/commands/dbconsole/dbconsole_command.rb +++ b/railties/lib/rails/commands/dbconsole/dbconsole_command.rb @@ -97,7 +97,7 @@ module Rails elsif configurations[environment].blank? && configurations[connection].blank? raise ActiveRecord::AdapterNotSpecified, "'#{environment}' database is not configured. Available configuration: #{configurations.inspect}" else - configurations[environment].presence || configurations[connection] + configurations[connection] || configurations[environment].presence end end end diff --git a/railties/lib/rails/commands/encrypted/encrypted_command.rb b/railties/lib/rails/commands/encrypted/encrypted_command.rb index 912c453f09..8d5947652a 100644 --- a/railties/lib/rails/commands/encrypted/encrypted_command.rb +++ b/railties/lib/rails/commands/encrypted/encrypted_command.rb @@ -21,9 +21,10 @@ module Rails def edit(file_path) require_application_and_environment! + encrypted = Rails.application.encrypted(file_path, key_path: options[:key]) ensure_editor_available(command: "bin/rails encrypted:edit") || (return) - ensure_encryption_key_has_been_added(options[:key]) + ensure_encryption_key_has_been_added(options[:key]) if encrypted.key.nil? ensure_encrypted_file_has_been_added(file_path, options[:key]) catch_editing_exceptions do @@ -75,9 +76,9 @@ module Rails def missing_encrypted_message(key:, key_path:, file_path:) if key.nil? - "Missing '#{key_path}' to decrypt data. See bin/rails encrypted:help" + "Missing '#{key_path}' to decrypt data. See `rails encrypted:help`" else - "File '#{file_path}' does not exist. Use bin/rails encrypted:edit #{file_path} to change that." + "File '#{file_path}' does not exist. Use `rails encrypted:edit #{file_path}` to change that." end end end diff --git a/railties/lib/rails/commands/notes/notes_command.rb b/railties/lib/rails/commands/notes/notes_command.rb new file mode 100644 index 0000000000..64b339b3cd --- /dev/null +++ b/railties/lib/rails/commands/notes/notes_command.rb @@ -0,0 +1,39 @@ +# frozen_string_literal: true + +require "rails/source_annotation_extractor" + +module Rails + module Command + class NotesCommand < Base # :nodoc: + class_option :annotations, aliases: "-a", desc: "Filter by specific annotations, e.g. Foobar TODO", type: :array, default: %w(OPTIMIZE FIXME TODO) + + def perform(*) + require_application_and_environment! + + deprecation_warning + display_annotations + end + + private + def display_annotations + annotations = options[:annotations] + tag = (annotations.length > 1) + + Rails::SourceAnnotationExtractor.enumerate annotations.join("|"), tag: tag, dirs: directories + end + + def directories + Rails::SourceAnnotationExtractor::Annotation.directories + source_annotation_directories + end + + def deprecation_warning + return if source_annotation_directories.empty? + ActiveSupport::Deprecation.warn("`SOURCE_ANNOTATION_DIRECTORIES` is deprecated and will be removed in Rails 6.1. You can add default directories by using config.annotations.register_directories instead.") + end + + def source_annotation_directories + ENV["SOURCE_ANNOTATION_DIRECTORIES"].to_s.split(",") + end + end + end +end diff --git a/railties/lib/rails/commands/routes/routes_command.rb b/railties/lib/rails/commands/routes/routes_command.rb new file mode 100644 index 0000000000..b592a5212f --- /dev/null +++ b/railties/lib/rails/commands/routes/routes_command.rb @@ -0,0 +1,37 @@ +# frozen_string_literal: true + +require "rails/command" + +module Rails + module Command + class RoutesCommand < Base # :nodoc: + class_option :controller, aliases: "-c", desc: "Filter by a specific controller, e.g. PostsController or Admin::PostsController." + class_option :grep, aliases: "-g", desc: "Grep routes by a specific pattern." + class_option :expanded, type: :boolean, aliases: "-E", desc: "Print routes expanded vertically with parts explained." + + def perform(*) + require_application_and_environment! + require "action_dispatch/routing/inspector" + + say inspector.format(formatter, routes_filter) + end + + private + def inspector + ActionDispatch::Routing::RoutesInspector.new(Rails.application.routes.routes) + end + + def formatter + if options.key?("expanded") + ActionDispatch::Routing::ConsoleFormatter::Expanded.new + else + ActionDispatch::Routing::ConsoleFormatter::Sheet.new + end + end + + def routes_filter + options.symbolize_keys.slice(:controller, :grep) + end + end + end +end diff --git a/railties/lib/rails/commands/secrets/USAGE b/railties/lib/rails/commands/secrets/USAGE index 96e322fe91..e205cdc001 100644 --- a/railties/lib/rails/commands/secrets/USAGE +++ b/railties/lib/rails/commands/secrets/USAGE @@ -7,7 +7,7 @@ with the code. === Setup -Run `bin/rails secrets:setup` to opt in and generate the `config/secrets.yml.key` +Run `rails secrets:setup` to opt in and generate the `config/secrets.yml.key` and `config/secrets.yml.enc` files. The latter contains all the keys to be encrypted while the former holds the @@ -45,12 +45,12 @@ the key. Add this: config.read_encrypted_secrets = true -to the environment you'd like to read encrypted secrets. `bin/rails secrets:setup` +to the environment you'd like to read encrypted secrets. `rails secrets:setup` inserts this into the production environment by default. === Editing Secrets -After `bin/rails secrets:setup`, run `bin/rails secrets:edit`. +After `rails secrets:setup`, run `rails secrets:edit`. That command opens a temporary file in `$EDITOR` with the decrypted contents of `config/secrets.yml.enc` to edit the encrypted secrets. diff --git a/railties/lib/rails/commands/secrets/secrets_command.rb b/railties/lib/rails/commands/secrets/secrets_command.rb index a36ccf314c..2eebc0f35f 100644 --- a/railties/lib/rails/commands/secrets/secrets_command.rb +++ b/railties/lib/rails/commands/secrets/secrets_command.rb @@ -22,7 +22,7 @@ module Rails if ENV["EDITOR"].to_s.empty? say "No $EDITOR to open decrypted secrets in. Assign one like this:" say "" - say %(EDITOR="mate --wait" bin/rails secrets:edit) + say %(EDITOR="mate --wait" rails secrets:edit) say "" say "For editors that fork and exit immediately, it's important to pass a wait flag," say "otherwise the secrets will be saved immediately with no chance to edit." @@ -42,7 +42,7 @@ module Rails rescue Rails::Secrets::MissingKeyError => error say error.message rescue Errno::ENOENT => error - if error.message =~ /secrets\.yml\.enc/ + if /secrets\.yml\.enc/.match?(error.message) deprecate_in_favor_of_credentials_and_exit else raise @@ -56,7 +56,7 @@ module Rails private def deprecate_in_favor_of_credentials_and_exit say "Encrypted secrets is deprecated in favor of credentials. Run:" - say "bin/rails credentials:help" + say "rails credentials:help" exit 1 end diff --git a/railties/lib/rails/commands/server/server_command.rb b/railties/lib/rails/commands/server/server_command.rb index 703ec59087..9d517f3239 100644 --- a/railties/lib/rails/commands/server/server_command.rb +++ b/railties/lib/rails/commands/server/server_command.rb @@ -1,7 +1,6 @@ # frozen_string_literal: true require "fileutils" -require "optparse" require "action_dispatch" require "rails" require "active_support/deprecation" @@ -27,7 +26,7 @@ module Rails app = super if app.is_a?(Class) ActiveSupport::Deprecation.warn(<<-MSG.squish) - Use `Rails::Application` subclass to start the server is deprecated and will be removed in Rails 6.0. + Using `Rails::Application` subclass to start the server is deprecated and will be removed in Rails 6.0. Please change `run #{app}` to `run Rails.application` in config.ru. MSG end @@ -43,18 +42,22 @@ module Rails ENV["RAILS_ENV"] ||= options[:environment] end - def start - print_boot_information + def start(after_stop_callback = nil) trap(:INT) { exit } create_tmp_directories setup_dev_caching log_to_stdout if options[:log_stdout] - super + 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] + after_stop_callback.call if after_stop_callback + end + + def serveable? # :nodoc: + server + true + rescue LoadError, NameError + false end def middleware @@ -65,6 +68,10 @@ module Rails super.merge(@default_options) end + def served_url + "#{options[:SSLEnable] ? 'https' : 'http'}://#{options[:Host]}:#{options[:Port]}" unless use_puma? + end + private def setup_dev_caching if options[:environment] == "development" @@ -72,13 +79,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)) @@ -97,10 +97,6 @@ module Rails end end - def restart_command - "bin/rails server #{ARGV.join(' ')}" - end - def use_puma? server.to_s == "Rack::Handler::Puma" end @@ -108,9 +104,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,29 +124,41 @@ 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, + class_option :dev_caching, aliases: "-C", type: :boolean, default: nil, desc: "Specifies whether to perform caching in development." - class_option "restart", type: :boolean, default: nil, hide: true - class_option "early_hints", type: :boolean, default: nil, desc: "Enables HTTP/2 early hints." + class_option :restart, type: :boolean, default: nil, hide: true + class_option :early_hints, type: :boolean, default: nil, desc: "Enables HTTP/2 early hints." + class_option :log_to_stdout, type: :boolean, default: nil, optional: true, + desc: "Whether to log to stdout. Enabled by default in development when not daemonized." - def initialize(args = [], local_options = {}, config = {}) - @original_options = local_options + def initialize(args, local_options, *) super - @server = self.args.shift - @log_stdout = options[:daemon].blank? && (options[:environment] || Rails.env) == "development" + + @original_options = local_options - %w( --restart ) + deprecate_positional_rack_server_and_rewrite_to_option(@original_options) 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) + after_stop_callback = -> { say "Exiting" unless options[:daemon] } + server.start(after_stop_callback) + else + say rack_server_suggestion(using) + end end end @@ -152,8 +166,8 @@ module Rails def server_options { user_supplied_options: user_supplied_options, - server: @server, - log_stdout: @log_stdout, + server: using, + log_stdout: log_to_stdout?, Port: port, Host: host, DoNotReverseLookup: true, @@ -161,7 +175,7 @@ module Rails environment: environment, daemonize: options[:daemon], pid: pid, - caching: options["dev-caching"], + caching: options[:dev_caching], restart_cmd: restart_command, early_hints: early_hints } @@ -194,7 +208,7 @@ module Rails name = :Port when :binding name = :Host - when :"dev-caching" + when :dev_caching name = :caching when :daemonize name = :daemon @@ -202,7 +216,7 @@ module Rails user_supplied_options << name end end - user_supplied_options << :Host if ENV["HOST"] + user_supplied_options << :Host if ENV["HOST"] || ENV["BINDING"] user_supplied_options << :Port if ENV["PORT"] user_supplied_options.uniq end @@ -217,7 +231,17 @@ module Rails options[:binding] else default_host = environment == "development" ? "localhost" : "0.0.0.0" - ENV.fetch("HOST", default_host) + + if ENV["HOST"] && !ENV["BINDING"] + ActiveSupport::Deprecation.warn(<<-MSG.squish) + Using the `HOST` environment to specify the IP is deprecated and will be removed in Rails 6.1. + Please use `BINDING` environment instead. + MSG + + return ENV["HOST"] + end + + ENV.fetch("BINDING", default_host) end end @@ -226,24 +250,73 @@ module Rails end def restart_command - "bin/rails server #{@server} #{@original_options.join(" ")} --restart" + "bin/rails server #{@original_options.join(" ")} --restart" end def early_hints options[:early_hints] end + def log_to_stdout? + options.fetch(:log_to_stdout) do + options[:daemon].blank? && environment == "development" + end + end + def pid File.expand_path(options[:pid]) 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 deprecate_positional_rack_server_and_rewrite_to_option(original_options) + if using + ActiveSupport::Deprecation.warn(<<~MSG) + 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 + + original_options.concat [ "-u", using ] + else + # Use positional internally to get around Thor's immutable options. + # TODO: Replace `using` occurrences with `options[:using]` after deprecation removal. + @using = options[:using] + 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 + suggestion = Rails::Command::Spellchecker.suggest(server, from: RACK_SERVERS) + + <<~MSG + Could not find server "#{server}". Maybe you meant #{suggestion.inspect}? + 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 |