From a21dca025ef7748ba36dcfe140f386b36abe5273 Mon Sep 17 00:00:00 2001 From: Thomas Reynolds Date: Fri, 6 Jun 2014 15:32:00 -0700 Subject: [PATCH] Separate Environments from Modes --- CHANGELOG.md | 1 + middleman-cli/lib/middleman-cli/build.rb | 36 ++++++++++--------- middleman-core/features/mount_rack.feature | 4 +-- middleman-core/fixtures/env-app/config.rb | 0 .../env-app/environments/development.rb | 1 + .../env-app/environments/production.rb | 2 ++ .../fixtures/env-app/source/index.html.erb | 3 ++ .../env-app/source/stylesheets/site.css.scss | 3 ++ .../fixtures/generator-test/config.rb | 4 +-- .../lib/middleman-core/application.rb | 34 +++++++++--------- .../lib/middleman-core/config_context.rb | 10 +++++- .../lib/middleman-core/core_extensions.rb | 6 ++++ .../core_extensions/extensions.rb | 34 ++++++++---------- .../middleman-core/core_extensions/i18n.rb | 4 +-- .../core_extensions/show_exceptions.rb | 23 +++++------- .../lib/middleman-core/extensions.rb | 27 +++++++++----- .../middleman-core/renderers/coffee_script.rb | 2 +- .../step_definitions/server_steps.rb | 14 +++----- .../lib/middleman-core/template_context.rb | 2 +- 19 files changed, 113 insertions(+), 97 deletions(-) create mode 100644 middleman-core/fixtures/env-app/config.rb create mode 100644 middleman-core/fixtures/env-app/environments/development.rb create mode 100644 middleman-core/fixtures/env-app/environments/production.rb create mode 100644 middleman-core/fixtures/env-app/source/index.html.erb create mode 100644 middleman-core/fixtures/env-app/source/stylesheets/site.css.scss diff --git a/CHANGELOG.md b/CHANGELOG.md index 9f4e8962..df41d316 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ master === +* Add support for `environments` with the `-e` CLI flag. Loads additional config from `environments/envname.rb`. Removed `development?` helper in favor of `environment?(:development)`. Added `server?` helper to differentiate between build and server mode. * Removed `with_layout`. Use loops of `page` instead. * Removed Queryable Sitemap API * Removed `css_compressor` setting, use `activate :minify_css, :compressor =>` instead. diff --git a/middleman-cli/lib/middleman-cli/build.rb b/middleman-cli/lib/middleman-cli/build.rb index 7b105629..60538431 100644 --- a/middleman-cli/lib/middleman-cli/build.rb +++ b/middleman-cli/lib/middleman-cli/build.rb @@ -18,6 +18,10 @@ module Middleman::Cli namespace :build desc 'build [options]', 'Builds the static site for deployment' + method_option :environment, + aliases: '-e', + default: ENV['MM_ENV'] || ENV['RACK_ENV'] || 'development', + desc: 'The environment Middleman will run under' method_option :clean, type: :boolean, default: true, @@ -58,18 +62,26 @@ module Middleman::Cli @debugging = Middleman::Cli::Base.respond_to?(:debugging) && Middleman::Cli::Base.debugging self.had_errors = false - self.class.shared_instance(options['verbose'], options['instrument']) + env = options['environment'].to_sym + verbose = options['verbose'] ? 0 : 1 + instrument = options['instrument'] + + app = ::Middleman::Application.server.inst do + config[:mode] = :build + config[:environment] = env + ::Middleman::Logger.singleton(verbose, instrument) + end opts = {} opts[:glob] = options['glob'] if options.key?('glob') opts[:clean] = options['clean'] - self.class.shared_instance.run_hook :before_build, self + app.run_hook :before_build, self - action BuildAction.new(self, opts) + action BuildAction.new(self, app, opts) - self.class.shared_instance.run_hook :after_build, self - self.class.shared_instance.config_context.execute_after_build_callbacks(self) + app.run_hook :after_build, self + app.config_context.execute_after_build_callbacks(self) if had_errors && !debugging msg = 'There were errors during this build' @@ -87,16 +99,6 @@ module Middleman::Cli def exit_on_failure? true end - - # Middleman::Application singleton - # - # @return [Middleman::Application] - def shared_instance(verbose=false, instrument=false) - @_shared_instance ||= ::Middleman::Application.server.inst do - config[:environment] = :build - ::Middleman::Logger.singleton(verbose ? 0 : 1, instrument) - end - end end end @@ -109,8 +111,8 @@ module Middleman::Cli # # @param [Middleman::Cli::Build] base # @param [Hash] config - def initialize(base, config={}) - @app = base.class.shared_instance + def initialize(base, app, config={}) + @app = app @source_dir = Pathname(@app.source_dir) @build_dir = Pathname(@app.config[:build_dir]) @to_clean = Set.new diff --git a/middleman-core/features/mount_rack.feature b/middleman-core/features/mount_rack.feature index ab105021..dcb83146 100644 --- a/middleman-core/features/mount_rack.feature +++ b/middleman-core/features/mount_rack.feature @@ -47,9 +47,7 @@ Feature: Support Rack apps mounted using map run MySinatra end - configure :build do - endpoint "sinatra/index2.html", path: "/sinatra/" - end + endpoint "sinatra/index2.html", path: "/sinatra/" endpoint "dedoo.html", path: "/sinatra/derp.html" diff --git a/middleman-core/fixtures/env-app/config.rb b/middleman-core/fixtures/env-app/config.rb new file mode 100644 index 00000000..e69de29b diff --git a/middleman-core/fixtures/env-app/environments/development.rb b/middleman-core/fixtures/env-app/environments/development.rb new file mode 100644 index 00000000..bce85faf --- /dev/null +++ b/middleman-core/fixtures/env-app/environments/development.rb @@ -0,0 +1 @@ +set :api_key, "dev1" diff --git a/middleman-core/fixtures/env-app/environments/production.rb b/middleman-core/fixtures/env-app/environments/production.rb new file mode 100644 index 00000000..1f217266 --- /dev/null +++ b/middleman-core/fixtures/env-app/environments/production.rb @@ -0,0 +1,2 @@ +set :api_key, "prod2" +activate :minify_css diff --git a/middleman-core/fixtures/env-app/source/index.html.erb b/middleman-core/fixtures/env-app/source/index.html.erb new file mode 100644 index 00000000..4b6d6950 --- /dev/null +++ b/middleman-core/fixtures/env-app/source/index.html.erb @@ -0,0 +1,3 @@ + diff --git a/middleman-core/fixtures/env-app/source/stylesheets/site.css.scss b/middleman-core/fixtures/env-app/source/stylesheets/site.css.scss new file mode 100644 index 00000000..bcb115c5 --- /dev/null +++ b/middleman-core/fixtures/env-app/source/stylesheets/site.css.scss @@ -0,0 +1,3 @@ +body { + backgroud: red; +} diff --git a/middleman-core/fixtures/generator-test/config.rb b/middleman-core/fixtures/generator-test/config.rb index 9fc9561c..f3b6a505 100644 --- a/middleman-core/fixtures/generator-test/config.rb +++ b/middleman-core/fixtures/generator-test/config.rb @@ -51,8 +51,8 @@ # Change the images directory # set :images_dir, "alternative_image_directory" -# Build-specific configuration -configure :build do +# Production build configuration +configure :production do # For example, change the Compass output style for deployment # activate :minify_css diff --git a/middleman-core/lib/middleman-core/application.rb b/middleman-core/lib/middleman-core/application.rb index 64ce952e..e264ea09 100644 --- a/middleman-core/lib/middleman-core/application.rb +++ b/middleman-core/lib/middleman-core/application.rb @@ -31,9 +31,6 @@ require 'middleman-core/core_extensions/request' # Custom Extension API and config.rb handling require 'middleman-core/core_extensions/extensions' -# Catch and show exceptions at the Rack level -require 'middleman-core/core_extensions/show_exceptions' - # Core Middleman Class module Middleman class Application @@ -73,9 +70,13 @@ module Middleman # @return [String] config.define_setting :source, 'source', 'Name of the source directory' - # Middleman environment. Defaults to :development, set to :build by the build process + # Middleman mode. Defaults to :server, set to :build by the build process # @return [String] - config.define_setting :environment, ((ENV['MM_ENV'] && ENV['MM_ENV'].to_sym) || :development), 'Middleman environment. Defaults to :development, set to :build by the build process' + config.define_setting :mode, ((ENV['MM_ENV'] && ENV['MM_ENV'].to_sym) || :server), 'Middleman mode. Defaults to :server' + + # Middleman environment. Defaults to :development + # @return [String] + config.define_setting :environment, :development, 'Middleman environment. Defaults to :development' # Which file should be used for directory indexes # @return [String] @@ -139,9 +140,6 @@ module Middleman # Basic Rack Request Handling include Middleman::CoreExtensions::Request - # Handle exceptions - include Middleman::CoreExtensions::ShowExceptions - # Setup custom rendering include Middleman::CoreExtensions::Rendering @@ -179,9 +177,7 @@ module Middleman # Setup the default values from calls to set before initialization self.class.config.load_settings(self.class.superclass.config.all_settings) - ::Middleman::Extensions.auto_activate[:before_sitemap].each do |ext_name| - activate ext_name - end + ::Middleman::Extensions.auto_activate(:before_sitemap, self) # Initialize the Sitemap @sitemap = ::Middleman::Sitemap::Store.new(self) @@ -204,16 +200,22 @@ module Middleman @config_context.define_singleton_method(name, &func) end - # Whether we're in development mode + # Whether we're in server mode # @return [Boolean] If we're in dev mode - def development? - config[:environment] == :development + def server? + config[:mode] == :server end # Whether we're in build mode - # @return [Boolean] If we're in build mode + # @return [Boolean] If we're in dev mode def build? - config[:environment] == :build + config[:mode] == :build + end + + # Whether we're in a specific environment + # @return [Boolean] + def environment?(key) + config[:environment] == key end # The full path to the source directory diff --git a/middleman-core/lib/middleman-core/config_context.rb b/middleman-core/lib/middleman-core/config_context.rb index ff5ffa76..96f30d1d 100644 --- a/middleman-core/lib/middleman-core/config_context.rb +++ b/middleman-core/lib/middleman-core/config_context.rb @@ -8,7 +8,7 @@ module Middleman attr_reader :app # Whitelist methods that can reach out. - delegate :config, :logger, :activate, :use, :map, :mime_type, :data, :root, to: :app + delegate :config, :logger, :activate, :use, :map, :mime_type, :data, :files, :root, to: :app def initialize(app, template_context_class) @app = app @@ -34,6 +34,14 @@ module Middleman end end + def include_environment(name) + path = File.dirname(__FILE__) + other_config = File.join(path, name.to_s) + if File.exist? other_config + instance_eval File.read(other_config), other_config, 1 + end + end + def ready(&block) @ready_callbacks << block end diff --git a/middleman-core/lib/middleman-core/core_extensions.rb b/middleman-core/lib/middleman-core/core_extensions.rb index 9fd5f985..e85afac3 100644 --- a/middleman-core/lib/middleman-core/core_extensions.rb +++ b/middleman-core/lib/middleman-core/core_extensions.rb @@ -11,6 +11,12 @@ Middleman::Extensions.register :data, auto_activate: :before_sitemap do Middleman::CoreExtensions::Data end +# Catch and show exceptions at the Rack level +Middleman::Extensions.register :show_exceptions, auto_activate: :before_configuration, modes: [:server] do + require 'middleman-core/core_extensions/show_exceptions' + Middleman::CoreExtensions::ShowExceptions +end + # File Change Notifier Middleman::Extensions.register :file_watcher, auto_activate: :before_sitemap do require 'middleman-core/core_extensions/file_watcher' diff --git a/middleman-core/lib/middleman-core/core_extensions/extensions.rb b/middleman-core/lib/middleman-core/core_extensions/extensions.rb index 475024a1..7a76776c 100644 --- a/middleman-core/lib/middleman-core/core_extensions/extensions.rb +++ b/middleman-core/lib/middleman-core/core_extensions/extensions.rb @@ -11,8 +11,6 @@ module Middleman app.define_hook :instance_available app.define_hook :after_configuration app.define_hook :before_configuration - app.define_hook :build_config - app.define_hook :development_config app.config.define_setting :autoload_sprockets, true, 'Automatically load sprockets at startup?' app.config[:autoload_sprockets] = (ENV['AUTOLOAD_SPROCKETS'] == 'true') if ENV['AUTOLOAD_SPROCKETS'] @@ -26,11 +24,11 @@ module Middleman # # @example # # Only minify when building - # configure :build do + # configure :production do # activate :minify_javascript # end # - # @param [String, Symbol] env The environment to run in (:build, :development) + # @param [String, Symbol] env The environment to run in # @return [void] def configure(env, &block) send("#{env}_config", &block) @@ -80,18 +78,19 @@ module Middleman # Override application initialization to load `config.rb` and to call lifecycle hooks. def initialize(&block) - super - self.class.inst = self # Search the root of the project for required files $LOAD_PATH.unshift(root) unless $LOAD_PATH.include?(root) + # Evaluate a passed block if given + config_context.instance_exec(&block) if block_given? + + super + ::Middleman::Extension.clear_after_extension_callbacks - ::Middleman::Extensions.auto_activate[:before_configuration].each do |ext_name| - activate ext_name - end + ::Middleman::Extensions.auto_activate(:before_configuration, self) if config[:autoload_sprockets] begin @@ -102,9 +101,6 @@ module Middleman end end - # Evaluate a passed block if given - config_context.instance_exec(&block) if block_given? - run_hook :initialized run_hook :before_configuration @@ -112,19 +108,17 @@ module Middleman # Check for and evaluate local configuration in `config.rb` local_config = File.join(root, 'config.rb') if File.exist? local_config - logger.debug '== Reading: Local config' + logger.debug '== Reading: Local config' config_context.instance_eval File.read(local_config), local_config, 1 end - if build? - run_hook :build_config - config_context.execute_configure_callbacks(:build) + env_config = File.join(root, 'environments', "#{config[:environment]}.rb") + if File.exist? env_config + logger.debug "== Reading: #{config[:environment]} config" + config_context.instance_eval File.read(env_config), env_config, 1 end - if development? - run_hook :development_config - config_context.execute_configure_callbacks(:development) - end + config_context.execute_configure_callbacks(config[:environment]) run_hook :instance_available diff --git a/middleman-core/lib/middleman-core/core_extensions/i18n.rb b/middleman-core/lib/middleman-core/core_extensions/i18n.rb index e83f7cfc..41e2ba0f 100644 --- a/middleman-core/lib/middleman-core/core_extensions/i18n.rb +++ b/middleman-core/lib/middleman-core/core_extensions/i18n.rb @@ -37,9 +37,7 @@ class Middleman::CoreExtensions::Internationalization < ::Middleman::Extension configure_i18n - unless app.build? - logger.info "== Locales: #{langs.join(', ')} (Default #{@mount_at_root})" - end + logger.info "== Locales: #{langs.join(', ')} (Default #{@mount_at_root})" # Don't output localizable files app.ignore File.join(options[:templates_dir], '**') diff --git a/middleman-core/lib/middleman-core/core_extensions/show_exceptions.rb b/middleman-core/lib/middleman-core/core_extensions/show_exceptions.rb index 67fad3c3..3f039ca6 100644 --- a/middleman-core/lib/middleman-core/core_extensions/show_exceptions.rb +++ b/middleman-core/lib/middleman-core/core_extensions/show_exceptions.rb @@ -1,21 +1,14 @@ # Support rack/showexceptions during development -module Middleman - module CoreExtensions - module ShowExceptions - def self.included(app) - # Require lib - require 'rack/showexceptions' +module Middleman::CoreExtensions + class ShowExceptions < ::Middleman::Extension + def initialize(app, options_hash={}, &block) + super - # Whether to catch and display exceptions - # @return [Boolean] - app.config.define_setting :show_exceptions, true, 'Whether to catch and display exceptions' + require 'rack/showexceptions' + end - # When in dev - app.configure :development do - # Include middlemare - use ::Rack::ShowExceptions if config[:show_exceptions] - end - end + def after_configuration + app.use ::Rack::ShowExceptions end end end diff --git a/middleman-core/lib/middleman-core/extensions.rb b/middleman-core/lib/middleman-core/extensions.rb index 519493be..a33bf203 100644 --- a/middleman-core/lib/middleman-core/extensions.rb +++ b/middleman-core/lib/middleman-core/extensions.rb @@ -14,6 +14,8 @@ module Middleman before_configuration: [] } + AutoActivation = Struct.new(:name, :modes) + class << self # @api private # A hash of all registered extensions. Registered extensions are not necessarily active - this @@ -21,12 +23,6 @@ module Middleman # @return [Hash{Symbol => Class, Proc}] A directory of known extensions indexed by the name they were registered under. The value may be a Proc, which can be lazily called to return an extension class. attr_reader :registered - # @api private - # A list of extensions that should be automatically loaded at different points in the application startup lifecycle. - # Only internal, built-in Middleman extensions should be listed here. - # @return [Hash{Symbol => Symbol}] A hash from event name to extension name. - attr_reader :auto_activate - # Register a new extension. Choose a name which will be # used to activate the extension in `config.rb`, like this: # @@ -71,7 +67,10 @@ module Middleman raise 'You must provide a Middleman::Extension or a block that returns a Middleman::Extension' end - @auto_activate[options[:auto_activate]] << name if options[:auto_activate] + if options[:auto_activate] + descriptor = AutoActivation.new(name, options[:modes] || :all) + @auto_activate[options[:auto_activate]] << descriptor + end end # @api private @@ -106,7 +105,19 @@ module Middleman # A flattened list of all extensions which are automatically activated # @return [Array] A list of extension names which are automatically activated. def auto_activated - @auto_activate.values.flatten + @auto_activate.values.map(&:name).flatten + end + + # @api private + # Load autoactivatable extensions for the given env. + # @param [Symbol] group The name of the auto_activation group. + # @param [Middleman::Application] app An instance of the app. + def auto_activate(group, app) + @auto_activate[group].each do |descriptor| + if descriptor[:modes] == :all || descriptor[:modes].include?(app.config[:mode]) + app.activate descriptor[:name] + end + end end end end diff --git a/middleman-core/lib/middleman-core/renderers/coffee_script.rb b/middleman-core/lib/middleman-core/renderers/coffee_script.rb index e6f57cb4..b8519845 100644 --- a/middleman-core/lib/middleman-core/renderers/coffee_script.rb +++ b/middleman-core/lib/middleman-core/renderers/coffee_script.rb @@ -30,7 +30,7 @@ module Middleman # @param [Hash] locals # @return [String] def evaluate(context, locals, &block) - return super if middleman_app.build? + return super unless middleman_app.server? begin super diff --git a/middleman-core/lib/middleman-core/step_definitions/server_steps.rb b/middleman-core/lib/middleman-core/step_definitions/server_steps.rb index 0009e67a..eee447ca 100644 --- a/middleman-core/lib/middleman-core/step_definitions/server_steps.rb +++ b/middleman-core/lib/middleman-core/step_definitions/server_steps.rb @@ -29,10 +29,6 @@ Given /^"([^\"]*)" is set to "([^\"]*)"$/ do |variable, value| } end -Given /^current environment is "([^\"]*)"$/ do |env| - @current_env = env.to_sym -end - Given /^the Server is running$/ do root_dir = File.expand_path(current_dir) @@ -45,14 +41,12 @@ Given /^the Server is running$/ do ENV['MM_ROOT'] = root_dir initialize_commands = @initialize_commands || [] - initialize_commands.unshift lambda { - config[:environment] = @current_env || :development - config[:show_exceptions] = false - } @server_inst = Middleman::Application.server.inst do - initialize_commands.each do |p| - instance_exec(&p) + app.initialized do + initialize_commands.each do |p| + config_context.instance_exec(&p) + end end end diff --git a/middleman-core/lib/middleman-core/template_context.rb b/middleman-core/lib/middleman-core/template_context.rb index 48ccad41..a81db78b 100644 --- a/middleman-core/lib/middleman-core/template_context.rb +++ b/middleman-core/lib/middleman-core/template_context.rb @@ -19,7 +19,7 @@ module Middleman attr_accessor :current_engine # Shorthand references to global values on the app instance. - delegate :config, :logger, :sitemap, :build?, :development?, :data, :extensions, :source_dir, :root, to: :app + delegate :config, :logger, :sitemap, :server?, :build?, :environment?, :data, :extensions, :source_dir, :root, to: :app # Initialize a context with the current app and predefined locals and options hashes. #