aboutsummaryrefslogblamecommitdiffstats
path: root/railties/lib/rails/generators/rails/app/app_generator.rb
blob: fbad3c9ef126e78258b8252d2d146c744a19bf05 (plain) (tree)
1
2
3
4
5
6
7
8
9
                    
                                      
                                                       
 
                        

                                                                         
                                                                                
 



                                                              
                           
                                                                      

                                 
                       
 
                                        
 
                                                                                      
                                                                                                           
 
                                                               

                                                                                                         





                                                                                                    

                                                                      
 
                                                                                            
                                                                       
 
                                                                                        
                                                               
 
                                                                                         
                                                                 
 
                                                                                   
                                                                 
 
                           





                                                                                 

                         
                                                                                



                                                                                                                        
                   
                                                                          
                      
 
                         
                            
                                    
       
 
                         
                        
                                                                   

                          
                                                      
       
 


                        
 

                              
 
                        


                                 
 



                                
       
 
                        
                               

       
                                 
                                           


                                                                                  


                       
 


                        
 

                           
                                              
       
 

                           
 


                                                               
                                                      
           

         
 
                           
                                                                                                     

       




                                       
                                                       


                              




                                                         

       
                           

                                     
         
                                             
       
 
                         
                                       

                      
 

                           
 

                                                     
                              
           

         
 
                           
                                                   
       
 
                            
                                            
                                                     
                                                                                      

       
                             

                                                                                   

       
             



                                                                  

                                









                                                         
                                                                           



                                  
                  
                                                     
         
 
                        
                                                                          

         
                   
                                                       


                          
                             
                                                                                                                    

                                                                                                                                       

                                                                                                                                                    
           

         


                                           
 



                                     














                                                                

         












                                                                                




                                                                        
     
   
require 'digest/md5'
require 'active_support/secure_random'
require 'rails/version' unless defined?(Rails::VERSION)

module Rails::Generators
  # We need to store the RAILS_DEV_PATH in a constant, otherwise the path
  # can change in Ruby 1.8.7 when we FileUtils.cd.
  RAILS_DEV_PATH = File.expand_path("../../../../../..", File.dirname(__FILE__))

  RESERVED_NAMES = %w[generate console server dbconsole
                      application destroy benchmarker profiler
                      plugin runner test]

  class AppGenerator < Base
    DATABASES = %w( mysql oracle postgresql sqlite3 frontbase ibm_db )

    attr_accessor :rails_template
    add_shebang_option!

    argument :app_path, :type => :string

    class_option :database, :type => :string, :aliases => "-d", :default => "sqlite3",
                            :desc => "Preconfigure for selected database (options: #{DATABASES.join('/')})"

    class_option :template, :type => :string, :aliases => "-m",
                            :desc => "Path to an application template (can be a filesystem path or URL)."

    class_option :dev, :type => :boolean, :default => false,
                       :desc => "Setup the application with Gemfile pointing to your Rails checkout"

    class_option :edge, :type => :boolean, :default => false,
                        :desc => "Setup the application with Gemfile pointing to Rails repository"

    class_option :skip_gemfile, :type => :boolean, :default => false,
                                     :desc => "Don't create a Gemfile"

    class_option :skip_activerecord, :type => :boolean, :aliases => "-O", :default => false,
                                     :desc => "Skip ActiveRecord files"

    class_option :skip_testunit, :type => :boolean, :aliases => "-T", :default => false,
                                 :desc => "Skip TestUnit files"

    class_option :skip_prototype, :type => :boolean, :aliases => "-J", :default => false,
                                  :desc => "Skip Prototype files"

    class_option :skip_git, :type => :boolean, :aliases => "-G", :default => false,
                            :desc => "Skip Git ignores and keeps"

    # Add bin/rails options
    class_option :version, :type => :boolean, :aliases => "-v", :group => :rails,
                           :desc => "Show Rails version number and quit"

    class_option :help, :type => :boolean, :aliases => "-h", :group => :rails,
                        :desc => "Show this help message and quit"

    def initialize(*args)
      super
      if !options[:skip_activerecord] && !DATABASES.include?(options[:database])
        raise Error, "Invalid value for --database option. Supported for preconfiguration are: #{DATABASES.join(", ")}."
      end
    end

    def create_root
      self.destination_root = File.expand_path(app_path, destination_root)
      valid_app_const?

      empty_directory '.'
      set_default_accessors!
      FileUtils.cd(destination_root)
    end

    def create_root_files
      copy_file "README"
      copy_file "gitignore", ".gitignore" unless options[:skip_git]
      template "Rakefile"
      template "config.ru"
      template "Gemfile" unless options[:skip_gemfile]
    end

    def create_app_files
      directory "app"
    end

    def create_config_files
      empty_directory "config"

      inside "config" do
        template "routes.rb"
        template "application.rb"
        template "environment.rb"

        directory "environments"
        directory "initializers"
        directory "locales"
      end
    end

    def create_boot_file
      template "config/boot.rb"
    end

    def create_activerecord_files
      return if options[:skip_activerecord]
      template "config/databases/#{options[:database]}.yml", "config/database.yml"
    end

    def create_db_files
      directory "db"
    end

    def create_doc_files
      directory "doc"
    end

    def create_lib_files
      empty_directory "lib"
      empty_directory_with_gitkeep "lib/tasks"
    end

    def create_log_files
      empty_directory "log"

      inside "log" do
        %w( server production development test ).each do |file|
          create_file "#{file}.log"
          chmod "#{file}.log", 0666, :verbose => false
        end
      end
    end

    def create_public_files
      directory "public", "public", :recursive => false # Do small steps, so anyone can overwrite it.
    end

    def create_public_image_files
      directory "public/images"
    end

    def create_public_stylesheets_files
      empty_directory_with_gitkeep "public/stylesheets"
    end

    def create_prototype_files
      unless options[:skip_prototype]
        directory "public/javascripts"
      else
        empty_directory_with_gitkeep "public/javascripts"
      end
    end

    def create_script_files
      directory "script" do |content|
        "#{shebang}\n" + content
      end
      chmod "script", 0755, :verbose => false
    end

    def create_test_files
      return if options[:skip_testunit]
      directory "test"
    end

    def create_tmp_files
      empty_directory "tmp"

      inside "tmp" do
        %w(sessions sockets cache pids).each do |dir|
          empty_directory(dir)
        end
      end
    end

    def create_vendor_files
      empty_directory_with_gitkeep "vendor/plugins"
    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 bundle_if_dev_or_edge
      bundle_command = File.basename(Thor::Util.ruby_command).sub(/ruby/, 'bundle')
      run "#{bundle_command} install" if dev_or_edge?
    end

    protected

      def self.banner
        "rails #{self.arguments.map(&:usage).join(' ')} [options]"
      end

      def set_default_accessors!
        self.rails_template = case options[:template]
          when /^http:\/\//
            options[:template]
          when String
            File.expand_path(options[:template], Dir.pwd)
          else
            options[:template]
        end
      end

      # Define file as an alias to create_file for backwards compatibility.
      def file(*args, &block)
        create_file(*args, &block)
      end

      def app_name
        @app_name ||= File.basename(destination_root)
      end

      def app_const_base
        @app_const_base ||= app_name.gsub(/\W/, '_').squeeze('_').camelize
      end

      def app_const
        @app_const ||= "#{app_const_base}::Application"
      end

      def valid_app_const?
        if app_const =~ /^\d/
          raise Error, "Invalid application name #{app_name}. Please give a name which does not start with numbers."
        elsif RESERVED_NAMES.include?(app_name)
          raise Error, "Invalid application name #{app_name}. Please give a name which does not match one of the reserved rails words."
        elsif Object.const_defined?(app_const_base)
          raise Error, "Invalid application name #{app_name}, constant #{app_const_base} is already in use. Please choose another application name."
        end
      end

      def app_secret
        ActiveSupport::SecureRandom.hex(64)
      end

      def dev_or_edge?
        options.dev? || options.edge?
      end

      def gem_for_database
        # %w( mysql oracle postgresql sqlite3 frontbase ibm_db )
        case options[:database]
        when "oracle"     then "ruby-oci8"
        when "postgresql" then "pg"
        when "sqlite3"    then "sqlite3-ruby"
        when "frontbase"  then "ruby-frontbase"
        else options[:database]
        end
      end

      def require_for_database
        case options[:database]
        when "sqlite3" then "sqlite3"
        end
      end

      def mysql_socket
        @mysql_socket ||= [
          "/tmp/mysql.sock",                        # default
          "/var/run/mysqld/mysqld.sock",            # debian/gentoo
          "/var/tmp/mysql.sock",                    # freebsd
          "/var/lib/mysql/mysql.sock",              # fedora
          "/opt/local/lib/mysql/mysql.sock",        # fedora
          "/opt/local/var/run/mysqld/mysqld.sock",  # mac + darwinports + mysql
          "/opt/local/var/run/mysql4/mysqld.sock",  # mac + darwinports + mysql4
          "/opt/local/var/run/mysql5/mysqld.sock",  # mac + darwinports + mysql5
          "/opt/lampp/var/mysql/mysql.sock"         # xampp for linux
        ].find { |f| File.exist?(f) } unless RUBY_PLATFORM =~ /(:?mswin|mingw)/
      end

      def empty_directory_with_gitkeep(destination, config = {})
        empty_directory(destination, config)
        create_file("#{destination}/.gitkeep") unless options[:skip_git]
      end
  end
end