1
0
Fork 0
mirror of https://github.com/rails/rails.git synced 2022-11-09 12:12:34 -05:00
rails--rails/railties/lib/rails/generators/app_base.rb

450 lines
16 KiB
Ruby
Raw Normal View History

require "fileutils"
require "digest/md5"
require "active_support/core_ext/string/strip"
require "rails/version" unless defined?(Rails::VERSION)
require "open-uri"
require "uri"
require "rails/generators"
require "active_support/core_ext/array/extract_options"
module Rails
module Generators
class AppBase < Base # :nodoc:
DATABASES = %w( mysql postgresql sqlite3 oracle frontbase ibm_db sqlserver )
2011-06-20 19:52:28 -04:00
JDBC_DATABASES = %w( jdbcmysql jdbcsqlite3 jdbcpostgresql jdbc )
2011-04-23 14:47:19 -04:00
DATABASES.concat(JDBC_DATABASES)
attr_accessor :rails_template
add_shebang_option!
argument :app_path, type: :string
def self.strict_args_position
false
end
def self.add_shared_options_for(name)
class_option :template, type: :string, aliases: "-m",
desc: "Path to some #{name} template (can be a filesystem path or URL)"
class_option :database, type: :string, aliases: "-d", default: "sqlite3",
desc: "Preconfigure for selected database (options: #{DATABASES.join('/')})"
class_option :javascript, type: :string, aliases: "-j",
desc: "Preconfigure for selected JavaScript library"
class_option :webpack, type: :string, default: nil,
desc: "Preconfigure for app-like JavaScript with Webpack"
class_option :skip_yarn, type: :boolean, default: false,
desc: "Don't use Yarn for managing JavaScript dependencies"
class_option :skip_gemfile, type: :boolean, default: false,
desc: "Don't create a Gemfile"
class_option :skip_git, type: :boolean, aliases: "-G", default: false,
desc: "Skip .gitignore file"
class_option :skip_keeps, type: :boolean, default: false,
desc: "Skip source control .keep files"
class_option :skip_action_mailer, type: :boolean, aliases: "-M",
default: false,
desc: "Skip Action Mailer files"
class_option :skip_active_record, type: :boolean, aliases: "-O", default: false,
desc: "Skip Active Record files"
class_option :skip_puma, type: :boolean, aliases: "-P", default: false,
desc: "Skip Puma related files"
Add Default Puma Config When the `puma` command is run without any configuration options it will detect presence of a `config/puma.rb` file and use that. Currently there is discrepancy between `puma` command and `rails server` but Evan said it would be reasonable to add in reading in config from the default location. I am working on that right now as a feature in puma/puma. Why do we need this? By default Puma uses 16 threads, and by default ActiveRecord only has 5 threads. Due to the architecture of AR it is guaranteed that if you're running with fewer DB connections than your server has threads you will hit `ActiveRecord::ConnectionTimeoutError ` eventually if your app gets modest amounts of traffic. Since we are providing a default webserver, we should provide reasonable configuration for that webserver. This PR does a few things, first it sets the default Puma thread count to 5 to mach ActiveRecord's default. It sets the default environment to `"development"` and the default port to 300 so that booting the server with `$ puma` will give you the same default port as `rails server`. It is worth mentioning that by reading in from `PORT` environment variable this config can work with containerized deployments, such as on Heroku. We are not using worker processes by default, that way JRuby and windows devs can use this configuration without modification. I went ahead and included a default `on_worker_boot`. It won't be used unless a worker count is specified, that means this config will not use it. Even though it's not being used now It will make someone who wants to try modifying their config to run extra workers easier. cc/ @pixeltrix
2016-01-14 14:05:41 -05:00
class_option :skip_action_cable, type: :boolean, aliases: "-C", default: false,
desc: "Skip Action Cable files"
class_option :skip_sprockets, type: :boolean, aliases: "-S", default: false,
desc: "Skip Sprockets files"
class_option :skip_spring, type: :boolean, default: false,
desc: "Don't install Spring application preloader"
class_option :skip_listen, type: :boolean, default: false,
desc: "Don't generate configuration that depends on the listen gem"
class_option :skip_coffee, type: :boolean, default: false,
desc: "Don't use CoffeeScript"
class_option :skip_javascript, type: :boolean, aliases: "-J", default: false,
desc: "Skip JavaScript files"
class_option :skip_turbolinks, type: :boolean, default: false,
desc: "Skip turbolinks gem"
class_option :skip_test, type: :boolean, aliases: "-T", default: false,
desc: "Skip test files"
class_option :skip_system_test, type: :boolean, default: false,
desc: "Skip system test files"
class_option :dev, type: :boolean, default: false,
desc: "Setup the #{name} with Gemfile pointing to your Rails checkout"
class_option :edge, type: :boolean, default: false,
desc: "Setup the #{name} with Gemfile pointing to Rails repository"
class_option :rc, type: :string, default: nil,
desc: "Path to file containing extra configuration options for rails command"
class_option :no_rc, type: :boolean, default: false,
desc: "Skip loading of extra configuration options from .railsrc file"
class_option :help, type: :boolean, aliases: "-h", group: :rails,
desc: "Show this help message and quit"
end
def initialize(*args)
@gem_filter = lambda { |gem| true }
@extra_entries = []
super
convert_database_option_for_jruby
end
private
def gemfile_entry(name, *args) # :doc:
options = args.extract_options!
version = args.first
github = options[:github]
path = options[:path]
if github
@extra_entries << GemfileEntry.github(name, github)
elsif path
@extra_entries << GemfileEntry.path(name, path)
else
@extra_entries << GemfileEntry.version(name, version)
end
self
end
def gemfile_entries # :doc:
2014-06-17 19:16:04 -04:00
[rails_gemfile_entry,
database_gemfile_entry,
Add Default Puma Config When the `puma` command is run without any configuration options it will detect presence of a `config/puma.rb` file and use that. Currently there is discrepancy between `puma` command and `rails server` but Evan said it would be reasonable to add in reading in config from the default location. I am working on that right now as a feature in puma/puma. Why do we need this? By default Puma uses 16 threads, and by default ActiveRecord only has 5 threads. Due to the architecture of AR it is guaranteed that if you're running with fewer DB connections than your server has threads you will hit `ActiveRecord::ConnectionTimeoutError ` eventually if your app gets modest amounts of traffic. Since we are providing a default webserver, we should provide reasonable configuration for that webserver. This PR does a few things, first it sets the default Puma thread count to 5 to mach ActiveRecord's default. It sets the default environment to `"development"` and the default port to 300 so that booting the server with `$ puma` will give you the same default port as `rails server`. It is worth mentioning that by reading in from `PORT` environment variable this config can work with containerized deployments, such as on Heroku. We are not using worker processes by default, that way JRuby and windows devs can use this configuration without modification. I went ahead and included a default `on_worker_boot`. It won't be used unless a worker count is specified, that means this config will not use it. Even though it's not being used now It will make someone who wants to try modifying their config to run extra workers easier. cc/ @pixeltrix
2016-01-14 14:05:41 -05:00
webserver_gemfile_entry,
2014-06-17 19:16:04 -04:00
assets_gemfile_entry,
webpacker_gemfile_entry,
2014-06-17 19:16:04 -04:00
javascript_gemfile_entry,
jbuilder_gemfile_entry,
psych_gemfile_entry,
cable_gemfile_entry,
2014-06-17 19:16:04 -04:00
@extra_entries].flatten.find_all(&@gem_filter)
2013-10-31 14:46:11 -04:00
end
def add_gem_entry_filter # :doc:
@gem_filter = lambda { |next_filter, entry|
2013-10-31 14:46:11 -04:00
yield(entry) && next_filter.call(entry)
}.curry[@gem_filter]
2013-10-28 20:10:00 -04:00
end
def builder # :doc:
@builder ||= begin
builder_class = get_builder_class
builder_class.include(ActionMethods)
builder_class.new(self)
end
end
def build(meth, *args) # :doc:
builder.send(meth, *args) if builder.respond_to?(meth)
end
def create_root # :doc:
valid_const?
empty_directory "."
FileUtils.cd(destination_root) unless options[:pretend]
end
def apply_rails_template # :doc:
remove railties changes. fixes #14054 Squashed commit of the following: commit 96991e8e919edfb20cc4120bca4e36ed51175d57 Author: Aaron Patterson <aaron.patterson@gmail.com> Date: Fri Feb 14 11:29:24 2014 -0800 Revert "gems can be added or skipped from the template" This reverts commit 8beb42cfbc41753ae4dbb91e16abcd1fb7d00356. Conflicts: railties/lib/rails/generators/rails/app/app_generator.rb railties/test/generators/app_generator_test.rb commit 35599c0e657245ef14ac0f28c9189ad16acf40e6 Author: Aaron Patterson <aaron.patterson@gmail.com> Date: Fri Feb 14 11:26:53 2014 -0800 Revert "oops, template replay needs to happen after bundle. :orz:" This reverts commit 9104702be61253f9448ca070a22fc86bb4299555. Conflicts: railties/lib/rails/generators/rails/app/app_generator.rb commit f519c3902c313db8e906a49251c91643b8e6499e Author: Aaron Patterson <aaron.patterson@gmail.com> Date: Fri Feb 14 11:25:51 2014 -0800 Revert "only ask for these ivars if the target responds to them" This reverts commit 656d412546cd97d5660c634c2a41c799d3f9e211. commit aa524a9428e3e4c45fe221f10a66a08efb827ab5 Author: Aaron Patterson <aaron.patterson@gmail.com> Date: Fri Feb 14 11:25:39 2014 -0800 Revert "refactor generator tests to use block form of Tempfile" This reverts commit 65251820ef0ab7f3cffb38130de3dd41af8d72be. commit 7d3740549fa4dfa62e3761f8d4bc6d6d441256e7 Author: Aaron Patterson <aaron.patterson@gmail.com> Date: Fri Feb 14 11:25:25 2014 -0800 Revert "add a more restricted codepath for templates fixes #13390" This reverts commit 2875b4a66e38e4333da887a4afbed33358999298. commit 525df0af1001918986cdfce59539fd2d52c4f32c Author: Aaron Patterson <aaron.patterson@gmail.com> Date: Fri Feb 14 11:25:11 2014 -0800 Revert "add a send so `apply` can be called. Fixes #13510" This reverts commit c5034d60dba0cd31a6a8c612ee35d63b8127793a.
2014-02-14 14:38:26 -05:00
apply rails_template if rails_template
rescue Thor::Error, LoadError, Errno::ENOENT => e
raise Error, "The template [#{rails_template}] could not be loaded. Error: #{e}"
end
def set_default_accessors! # :doc:
self.destination_root = File.expand_path(app_path, destination_root)
self.rails_template = \
case options[:template]
when /^https?:\/\//
options[:template]
when String
File.expand_path(options[:template], Dir.pwd)
remove railties changes. fixes #14054 Squashed commit of the following: commit 96991e8e919edfb20cc4120bca4e36ed51175d57 Author: Aaron Patterson <aaron.patterson@gmail.com> Date: Fri Feb 14 11:29:24 2014 -0800 Revert "gems can be added or skipped from the template" This reverts commit 8beb42cfbc41753ae4dbb91e16abcd1fb7d00356. Conflicts: railties/lib/rails/generators/rails/app/app_generator.rb railties/test/generators/app_generator_test.rb commit 35599c0e657245ef14ac0f28c9189ad16acf40e6 Author: Aaron Patterson <aaron.patterson@gmail.com> Date: Fri Feb 14 11:26:53 2014 -0800 Revert "oops, template replay needs to happen after bundle. :orz:" This reverts commit 9104702be61253f9448ca070a22fc86bb4299555. Conflicts: railties/lib/rails/generators/rails/app/app_generator.rb commit f519c3902c313db8e906a49251c91643b8e6499e Author: Aaron Patterson <aaron.patterson@gmail.com> Date: Fri Feb 14 11:25:51 2014 -0800 Revert "only ask for these ivars if the target responds to them" This reverts commit 656d412546cd97d5660c634c2a41c799d3f9e211. commit aa524a9428e3e4c45fe221f10a66a08efb827ab5 Author: Aaron Patterson <aaron.patterson@gmail.com> Date: Fri Feb 14 11:25:39 2014 -0800 Revert "refactor generator tests to use block form of Tempfile" This reverts commit 65251820ef0ab7f3cffb38130de3dd41af8d72be. commit 7d3740549fa4dfa62e3761f8d4bc6d6d441256e7 Author: Aaron Patterson <aaron.patterson@gmail.com> Date: Fri Feb 14 11:25:25 2014 -0800 Revert "add a more restricted codepath for templates fixes #13390" This reverts commit 2875b4a66e38e4333da887a4afbed33358999298. commit 525df0af1001918986cdfce59539fd2d52c4f32c Author: Aaron Patterson <aaron.patterson@gmail.com> Date: Fri Feb 14 11:25:11 2014 -0800 Revert "add a send so `apply` can be called. Fixes #13510" This reverts commit c5034d60dba0cd31a6a8c612ee35d63b8127793a.
2014-02-14 14:38:26 -05:00
else
options[:template]
end
end
def database_gemfile_entry # :doc:
2013-10-27 14:16:09 -04:00
return [] if options[:skip_active_record]
gem_name, gem_version = gem_for_database
GemfileEntry.version gem_name, gem_version,
2013-10-27 20:47:21 -04:00
"Use #{options[:database]} as the database for Active Record"
end
def webserver_gemfile_entry # :doc:
Add Default Puma Config When the `puma` command is run without any configuration options it will detect presence of a `config/puma.rb` file and use that. Currently there is discrepancy between `puma` command and `rails server` but Evan said it would be reasonable to add in reading in config from the default location. I am working on that right now as a feature in puma/puma. Why do we need this? By default Puma uses 16 threads, and by default ActiveRecord only has 5 threads. Due to the architecture of AR it is guaranteed that if you're running with fewer DB connections than your server has threads you will hit `ActiveRecord::ConnectionTimeoutError ` eventually if your app gets modest amounts of traffic. Since we are providing a default webserver, we should provide reasonable configuration for that webserver. This PR does a few things, first it sets the default Puma thread count to 5 to mach ActiveRecord's default. It sets the default environment to `"development"` and the default port to 300 so that booting the server with `$ puma` will give you the same default port as `rails server`. It is worth mentioning that by reading in from `PORT` environment variable this config can work with containerized deployments, such as on Heroku. We are not using worker processes by default, that way JRuby and windows devs can use this configuration without modification. I went ahead and included a default `on_worker_boot`. It won't be used unless a worker count is specified, that means this config will not use it. Even though it's not being used now It will make someone who wants to try modifying their config to run extra workers easier. cc/ @pixeltrix
2016-01-14 14:05:41 -05:00
return [] if options[:skip_puma]
comment = "Use Puma as the app server"
GemfileEntry.new("puma", "~> 3.7", comment)
Add Default Puma Config When the `puma` command is run without any configuration options it will detect presence of a `config/puma.rb` file and use that. Currently there is discrepancy between `puma` command and `rails server` but Evan said it would be reasonable to add in reading in config from the default location. I am working on that right now as a feature in puma/puma. Why do we need this? By default Puma uses 16 threads, and by default ActiveRecord only has 5 threads. Due to the architecture of AR it is guaranteed that if you're running with fewer DB connections than your server has threads you will hit `ActiveRecord::ConnectionTimeoutError ` eventually if your app gets modest amounts of traffic. Since we are providing a default webserver, we should provide reasonable configuration for that webserver. This PR does a few things, first it sets the default Puma thread count to 5 to mach ActiveRecord's default. It sets the default environment to `"development"` and the default port to 300 so that booting the server with `$ puma` will give you the same default port as `rails server`. It is worth mentioning that by reading in from `PORT` environment variable this config can work with containerized deployments, such as on Heroku. We are not using worker processes by default, that way JRuby and windows devs can use this configuration without modification. I went ahead and included a default `on_worker_boot`. It won't be used unless a worker count is specified, that means this config will not use it. Even though it's not being used now It will make someone who wants to try modifying their config to run extra workers easier. cc/ @pixeltrix
2016-01-14 14:05:41 -05:00
end
def include_all_railties? # :doc:
2015-12-14 20:44:52 -05:00
options.values_at(:skip_active_record, :skip_action_mailer, :skip_test, :skip_sprockets, :skip_action_cable).none?
2011-05-06 11:29:15 -04:00
end
def comment_if(value) # :doc:
options[value] ? "# " : ""
2011-05-06 11:29:15 -04:00
end
def keeps? # :doc:
!options[:skip_keeps]
end
def sqlite3? # :doc:
!options[:skip_active_record] && options[:database] == "sqlite3"
end
class GemfileEntry < Struct.new(:name, :version, :comment, :options, :commented_out)
2013-11-01 09:58:40 -04:00
def initialize(name, version, comment, options = {}, commented_out = false)
super
end
def self.github(name, github, branch = nil, comment = nil)
if branch
new(name, nil, comment, github: github, branch: branch)
else
new(name, nil, comment, github: github)
end
end
def self.version(name, version, comment = nil)
2013-11-01 09:58:40 -04:00
new(name, version, comment)
end
def self.path(name, path, comment = nil)
2013-11-01 09:58:40 -04:00
new(name, nil, comment, path: path)
end
def version
version = super
if version.is_a?(Array)
version.join("', '")
else
version
end
end
end
def rails_gemfile_entry
dev_edge_common = [
2015-12-18 01:53:38 -05:00
]
if options.dev?
[
GemfileEntry.path("rails", Rails::Generators::RAILS_DEV_PATH)
] + dev_edge_common
elsif options.edge?
2014-12-12 15:49:45 -05:00
[
GemfileEntry.github("rails", "rails/rails")
] + dev_edge_common
else
[GemfileEntry.version("rails",
rails_version_specifier,
"Bundle edge Rails instead: gem 'rails', github: 'rails/rails'")]
end
end
def rails_version_specifier(gem_version = Rails.gem_version)
if gem_version.segments.size == 3 || gem_version.release.segments.size == 3
# ~> 1.2.3
# ~> 1.2.3.pre4
"~> #{gem_version}"
else
# ~> 1.2.3, >= 1.2.3.4
# ~> 1.2.3, >= 1.2.3.4.pre5
patch = gem_version.segments[0, 3].join(".")
["~> #{patch}", ">= #{gem_version}"]
end
end
def gem_for_database
# %w( mysql postgresql sqlite3 oracle frontbase ibm_db sqlserver jdbcmysql jdbcsqlite3 jdbcpostgresql )
case options[:database]
when "mysql" then ["mysql2", [">= 0.3.18", "< 0.5"]]
when "postgresql" then ["pg", ["~> 0.18"]]
when "oracle" then ["activerecord-oracle_enhanced-adapter", nil]
when "frontbase" then ["ruby-frontbase", nil]
when "sqlserver" then ["activerecord-sqlserver-adapter", nil]
when "jdbcmysql" then ["activerecord-jdbcmysql-adapter", nil]
when "jdbcsqlite3" then ["activerecord-jdbcsqlite3-adapter", nil]
when "jdbcpostgresql" then ["activerecord-jdbcpostgresql-adapter", nil]
when "jdbc" then ["activerecord-jdbc-adapter", nil]
else [options[:database], nil]
end
end
2011-05-02 02:23:31 -04:00
def convert_database_option_for_jruby
if defined?(JRUBY_VERSION)
case options[:database]
when "postgresql" then options[:database].replace "jdbcpostgresql"
when "mysql" then options[:database].replace "jdbcmysql"
when "sqlite3" then options[:database].replace "jdbcsqlite3"
end
end
end
2011-07-01 14:21:08 -04:00
def assets_gemfile_entry
return [] if options[:skip_sprockets]
gems = []
gems << GemfileEntry.github("sass-rails", "rails/sass-rails", nil,
"Use SCSS for stylesheets")
if !options[:skip_javascript]
gems << GemfileEntry.version("uglifier",
">= 1.3.0",
"Use Uglifier as compressor for JavaScript assets")
end
2013-04-26 08:17:05 -04:00
gems
2011-07-01 14:21:08 -04:00
end
def webpacker_gemfile_entry
return [] unless options[:webpack]
comment = "Transpile app-like JavaScript. Read more: https://github.com/rails/webpacker"
GemfileEntry.new "webpacker", nil, comment
end
def jbuilder_gemfile_entry
comment = "Build JSON APIs with ease. Read more: https://github.com/rails/jbuilder"
GemfileEntry.new "jbuilder", "~> 2.5", comment, {}, options[:api]
end
def coffee_gemfile_entry
GemfileEntry.version "coffee-rails", "~> 4.2", "Use CoffeeScript for .coffee assets and views"
end
def javascript_gemfile_entry
if options[:skip_javascript] || options[:skip_sprockets]
[]
else
gems = [javascript_runtime_gemfile_entry]
gems << coffee_gemfile_entry unless options[:skip_coffee]
if options[:javascript]
gems << GemfileEntry.version("#{options[:javascript]}-rails", nil,
"Use #{options[:javascript]} as the JavaScript library")
end
unless options[:skip_turbolinks]
2016-06-30 13:18:52 -04:00
gems << GemfileEntry.version("turbolinks", "~> 5",
2016-02-23 18:55:49 -05:00
"Turbolinks makes navigating your web application faster. Read more: https://github.com/turbolinks/turbolinks")
end
gems
end
end
def javascript_runtime_gemfile_entry
comment = "See https://github.com/rails/execjs#readme for more supported runtimes"
if defined?(JRUBY_VERSION)
GemfileEntry.version "therubyrhino", nil, comment
else
GemfileEntry.new "therubyracer", nil, comment, { platforms: :ruby }, true
end
end
def psych_gemfile_entry
return [] unless defined?(Rubinius)
comment = "Use Psych as the YAML engine, instead of Syck, so serialized " \
"data can be read safely from different rubies (see http://git.io/uuLVag)"
GemfileEntry.new("psych", "~> 2.0", comment, platforms: :rbx)
end
def cable_gemfile_entry
return [] if options[:skip_action_cable]
comment = "Use Redis adapter to run Action Cable in production"
gems = []
gems << GemfileEntry.new("redis", "~> 3.0", comment, {}, true)
gems
end
def bundle_command(command)
say_status :run, "bundle #{command}"
2011-06-10 19:18:08 -04:00
# We are going to shell out rather than invoking Bundler::CLI.new(command)
# because `rails new` loads the Thor gem and on the other hand bundler uses
# its own vendored Thor, which could be a different version. Running both
# things in the same process is a recipe for a night with paracetamol.
#
# We unset temporary bundler variables to load proper bundler and Gemfile.
#
# Thanks to James Tucker for the Gem tricks involved in this call.
_bundle_command = Gem.bin_path("bundler", "bundle")
require "bundler"
Bundler.with_clean_env do
full_command = %Q["#{Gem.ruby}" "#{_bundle_command}" #{command}]
if options[:quiet]
system(full_command, out: File::NULL)
else
system(full_command)
end
end
end
def bundle_install?
!(options[:skip_gemfile] || options[:skip_bundle] || options[:pretend])
end
def spring_install?
!options[:skip_spring] && !options.dev? && Process.respond_to?(:fork) && !RUBY_PLATFORM.include?("cygwin")
end
def depend_on_listen?
!options[:skip_listen] && os_supports_listen_out_of_the_box?
end
def os_supports_listen_out_of_the_box?
RbConfig::CONFIG["host_os"] =~ /darwin|linux/
end
def run_bundle
bundle_command("install") if bundle_install?
end
def run_webpack
if !(webpack = options[:webpack]).nil?
rails_command "webpacker:install"
rails_command "webpacker:install:#{webpack}" unless webpack == "webpack"
end
end
def generate_spring_binstubs
if bundle_install? && spring_install?
bundle_command("exec spring binstub --all")
end
end
def empty_directory_with_keep_file(destination, config = {})
empty_directory(destination, config)
keep_file(destination)
end
2011-05-02 02:23:31 -04:00
def keep_file(destination)
create_file("#{destination}/.keep") if keeps?
end
end
end
2011-05-02 02:23:31 -04:00
end