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
Max Holder 2a5bb9d56e Print bundle install output in rails new as soon as it's available
Previously, running `rails new` would not print any of the output from
`bundle install` until all the gems had finished installing. This made
it look like the generator was hanging at the `bundle install` step.

This commit switches to using `system` so that the bundle command can
output as it needs to.

This has the added benefit of including output bundler produces on
standard error, which the previous code ignored since backticks only
capture standard out. This is not a big deal right now since bundler
does not currently print errors to standard error, but that may change
in the future (see: bundler/bundler/issues/3353).
2015-03-28 09:16:13 -04:00

362 lines
13 KiB
Ruby

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 oracle postgresql sqlite3 frontbase ibm_db sqlserver )
JDBC_DATABASES = %w( jdbcmysql jdbcsqlite3 jdbcpostgresql jdbc )
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 :skip_gemfile, type: :boolean, default: false,
desc: "Don't create a Gemfile"
class_option :skip_bundle, type: :boolean, aliases: '-B', default: false,
desc: "Don't run bundle install"
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_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 :database, type: :string, aliases: '-d', default: 'sqlite3',
desc: "Preconfigure for selected database (options: #{DATABASES.join('/')})"
class_option :javascript, type: :string, aliases: '-j', default: 'jquery',
desc: 'Preconfigure for selected JavaScript library'
class_option :skip_javascript, type: :boolean, aliases: '-J', default: false,
desc: 'Skip JavaScript 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 :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 :rc, type: :string, default: false,
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
protected
def gemfile_entry(name, *args)
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
[rails_gemfile_entry,
database_gemfile_entry,
assets_gemfile_entry,
javascript_gemfile_entry,
jbuilder_gemfile_entry,
psych_gemfile_entry,
@extra_entries].flatten.find_all(&@gem_filter)
end
def add_gem_entry_filter
@gem_filter = lambda { |next_filter, entry|
yield(entry) && next_filter.call(entry)
}.curry[@gem_filter]
end
def builder
@builder ||= begin
builder_class = get_builder_class
builder_class.include(ActionMethods)
builder_class.new(self)
end
end
def build(meth, *args)
builder.send(meth, *args) if builder.respond_to?(meth)
end
def create_root
valid_const?
empty_directory '.'
FileUtils.cd(destination_root) unless options[:pretend]
end
def apply_rails_template
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!
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)
else
options[:template]
end
end
def database_gemfile_entry
return [] if options[:skip_active_record]
GemfileEntry.version gem_for_database, nil,
"Use #{options[:database]} as the database for Active Record"
end
def include_all_railties?
options.values_at(:skip_active_record, :skip_action_mailer, :skip_test, :skip_sprockets).none?
end
def comment_if(value)
options[value] ? '# ' : ''
end
def sqlite3?
!options[:skip_active_record] && options[:database] == 'sqlite3'
end
class GemfileEntry < Struct.new(:name, :version, :comment, :options, :commented_out)
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)
new(name, version, comment)
end
def self.path(name, path, comment = nil)
new(name, nil, comment, path: path)
end
end
def rails_gemfile_entry
if options.dev?
[
GemfileEntry.path('rails', Rails::Generators::RAILS_DEV_PATH),
GemfileEntry.github('arel', 'rails/arel')
]
elsif options.edge?
[
GemfileEntry.github('rails', 'rails/rails'),
GemfileEntry.github('arel', 'rails/arel')
]
else
[GemfileEntry.version('rails',
Rails::VERSION::STRING,
"Bundle edge Rails instead: gem 'rails', github: 'rails/rails'")]
end
end
def gem_for_database
# %w( mysql oracle postgresql sqlite3 frontbase ibm_db sqlserver jdbcmysql jdbcsqlite3 jdbcpostgresql )
case options[:database]
when "oracle" then "ruby-oci8"
when "postgresql" then "pg"
when "frontbase" then "ruby-frontbase"
when "mysql" then "mysql2"
when "sqlserver" then "activerecord-sqlserver-adapter"
when "jdbcmysql" then "activerecord-jdbcmysql-adapter"
when "jdbcsqlite3" then "activerecord-jdbcsqlite3-adapter"
when "jdbcpostgresql" then "activerecord-jdbcpostgresql-adapter"
when "jdbc" then "activerecord-jdbc-adapter"
else options[:database]
end
end
def convert_database_option_for_jruby
if defined?(JRUBY_VERSION)
case options[:database]
when "oracle" then options[:database].replace "jdbc"
when "postgresql" then options[:database].replace "jdbcpostgresql"
when "mysql" then options[:database].replace "jdbcmysql"
when "sqlite3" then options[:database].replace "jdbcsqlite3"
end
end
end
def assets_gemfile_entry
return [] if options[:skip_sprockets]
gems = []
gems << GemfileEntry.version('sass-rails', '~> 5.0',
'Use SCSS for stylesheets')
gems << GemfileEntry.version('uglifier',
'>= 1.3.0',
'Use Uglifier as compressor for JavaScript assets')
gems
end
def jbuilder_gemfile_entry
comment = 'Build JSON APIs with ease. Read more: https://github.com/rails/jbuilder'
GemfileEntry.version('jbuilder', '~> 2.0', comment)
end
def coffee_gemfile_entry
comment = 'Use CoffeeScript for .coffee assets and views'
if options.dev? || options.edge?
GemfileEntry.github 'coffee-rails', 'rails/coffee-rails', nil, comment
else
GemfileEntry.version 'coffee-rails', '~> 4.1.0', comment
end
end
def javascript_gemfile_entry
if options[:skip_javascript]
[]
else
gems = [coffee_gemfile_entry, javascript_runtime_gemfile_entry]
gems << GemfileEntry.version("#{options[:javascript]}-rails", nil,
"Use #{options[:javascript]} as the JavaScript library")
unless options[:skip_turbolinks]
gems << GemfileEntry.version("turbolinks", nil,
"Turbolinks makes following links in your web application faster. Read more: https://github.com/rails/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 bundle_command(command)
say_status :run, "bundle #{command}"
# 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] && Process.respond_to?(:fork) && !RUBY_PLATFORM.include?("cygwin")
end
def run_bundle
bundle_command('install') if bundle_install?
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
def keep_file(destination)
create_file("#{destination}/.keep") unless options[:skip_keeps]
end
end
end
end