diff --git a/middleman-cli/lib/middleman-cli/build.rb b/middleman-cli/lib/middleman-cli/build.rb index e3d098e7..df68c9e4 100644 --- a/middleman-cli/lib/middleman-cli/build.rb +++ b/middleman-cli/lib/middleman-cli/build.rb @@ -52,7 +52,7 @@ module Middleman::Cli ::Middleman::Logger.singleton(verbose, instrument) - ::Middleman::Util.instrument 'builder_setup' do + ::Middleman::Util.instrument 'builder.setup' do @app = ::Middleman::Application.new do config[:mode] = :build config[:environment] = env @@ -67,7 +67,7 @@ module Middleman::Cli builder.on_build_event(&method(:on_event)) end - ::Middleman::Util.instrument 'builder_run' do + ::Middleman::Util.instrument 'builder.run' do if builder.run! clean_directories! if options['clean'] shell.say 'Project built successfully.' diff --git a/middleman-core/lib/middleman-core/builder.rb b/middleman-core/lib/middleman-core/builder.rb index ef289d42..4562dc6c 100644 --- a/middleman-core/lib/middleman-core/builder.rb +++ b/middleman-core/lib/middleman-core/builder.rb @@ -51,18 +51,31 @@ module Middleman @has_error = false @events = {} - @app.execute_callbacks(:before_build, [self]) + ::Middleman::Util.instrument 'builder.before' do + @app.execute_callbacks(:before_build, [self]) + end - queue_current_paths if @cleaning + ::Middleman::Util.instrument 'builder.queue' do + queue_current_paths if @cleaning + end - prerender_css - output_files + ::Middleman::Util.instrument 'builder.prerender' do + prerender_css + end - clean! if @cleaning + ::Middleman::Util.instrument 'builder.output' do + output_files + end + + ::Middleman::Util.instrument 'builder.clean' do + clean! if @cleaning + end ::Middleman::Profiling.report('build') - @app.execute_callbacks(:after_build, [self]) + ::Middleman::Util.instrument 'builder.after' do + @app.execute_callbacks(:after_build, [self]) + end !@has_error end @@ -73,14 +86,18 @@ module Middleman def prerender_css logger.debug '== Prerendering CSS' - css_files = @app.sitemap.resources - .select { |resource| resource.ext == '.css' } - .each(&method(:output_resource)) + css_files = ::Middleman::Util.instrument 'builder.prerender.output' do + @app.sitemap.resources + .select { |resource| resource.ext == '.css' } + .each(&method(:output_resource)) + end - # Double-check for compass sprites - if @app.files.find_new_files!.length > 0 - logger.debug '== Checking for Compass sprites' - @app.sitemap.ensure_resource_list_updated! + ::Middleman::Util.instrument 'builder.prerender.check-files' do + # Double-check for compass sprites + if @app.files.find_new_files!.length > 0 + logger.debug '== Checking for Compass sprites' + @app.sitemap.ensure_resource_list_updated! + end end css_files @@ -92,11 +109,15 @@ module Middleman def output_files logger.debug '== Building files' - @app.sitemap.resources - .sort_by { |resource| SORT_ORDER.index(resource.ext) || 100 } + resources = @app.sitemap.resources .reject { |resource| resource.ext == '.css' } - .select { |resource| !@glob || File.fnmatch(@glob, resource.destination_path) } - .each(&method(:output_resource)) + .sort_by { |resource| SORT_ORDER.index(resource.ext) || 100 } + + if @glob + resources = resources.select { |resource| File.fnmatch(@glob, resource.destination_path) } + end + + resources.each(&method(:output_resource)) end # Figure out the correct event mode. @@ -162,25 +183,29 @@ module Middleman # @return [void] Contract IsA['Middleman::Sitemap::Resource'] => Any def output_resource(resource) - output_file = @build_dir + resource.destination_path.gsub('%20', ' ') + output_file = nil - begin - if resource.binary? - export_file!(output_file, resource.file_descriptor[:full_path]) - else - response = @rack.get(::URI.escape(resource.request_path)) + ::Middleman::Util.instrument "builder.output.resource", path: File.basename(resource.destination_path) do + output_file = @build_dir + resource.destination_path.gsub('%20', ' ') - # If we get a response, save it to a tempfile. - if response.status == 200 - export_file!(output_file, binary_encode(response.body)) + begin + if resource.binary? + export_file!(output_file, resource.file_descriptor[:full_path]) else - @has_error = true - trigger(:error, output_file, response.body) + response = @rack.get(::URI.escape(resource.request_path)) + + # If we get a response, save it to a tempfile. + if response.status == 200 + export_file!(output_file, binary_encode(response.body)) + else + @has_error = true + trigger(:error, output_file, response.body) + end end + rescue => e + @has_error = true + trigger(:error, output_file, "#{e}\n#{e.backtrace.join("\n")}") end - rescue => e - @has_error = true - trigger(:error, output_file, "#{e}\n#{e.backtrace.join("\n")}") end return unless @cleaning diff --git a/middleman-core/lib/middleman-core/core_extensions/data.rb b/middleman-core/lib/middleman-core/core_extensions/data.rb index 5f2a789f..cce997c6 100644 --- a/middleman-core/lib/middleman-core/core_extensions/data.rb +++ b/middleman-core/lib/middleman-core/core_extensions/data.rb @@ -57,6 +57,7 @@ module Middleman @app = app @data_file_matcher = data_file_matcher @local_data = {} + @local_data_enhanced = nil @local_sources = {} @callback_sources = {} end @@ -117,6 +118,8 @@ module Middleman end data_branch[basename] = data + + @local_data_enhanced = nil end # Remove a given file from the internal cache @@ -137,6 +140,8 @@ module Middleman end data_branch.delete(basename) if data_branch.key?(basename) + + @local_data_enhanced = nil end # Get a hash from either internal static data or a callback @@ -151,8 +156,7 @@ module Middleman callbacks[path.to_s].call end - response = ::Middleman::Util.recursively_enhance(response) - response + ::Middleman::Util.recursively_enhance(response) end # "Magically" find namespaces of data if they exist @@ -162,7 +166,8 @@ module Middleman def method_missing(path) if @local_data.key?(path.to_s) # Any way to cache this? - return ::Middleman::Util.recursively_enhance(@local_data[path.to_s]) + @local_data_enhanced ||= ::Middleman::Util.recursively_enhance(@local_data) + return @local_data_enhanced[path.to_s] else result = data_for_path(path) return result if result diff --git a/middleman-core/lib/middleman-core/file_renderer.rb b/middleman-core/lib/middleman-core/file_renderer.rb index 67f9411f..64519be0 100644 --- a/middleman-core/lib/middleman-core/file_renderer.rb +++ b/middleman-core/lib/middleman-core/file_renderer.rb @@ -73,9 +73,10 @@ module Middleman # end # Render using Tilt - content = ::Middleman::Util.instrument 'render.tilt', path: path do - template.render(context, locs, &block) - end + # content = ::Middleman::Util.instrument 'render.tilt', path: path do + # template.render(context, locs, &block) + # end + content = template.render(context, locs, &block) # Allow hooks to manipulate the result after render content = @app.callbacks_for(:after_render).reduce(content) do |sum, callback| diff --git a/middleman-core/lib/middleman-core/logger.rb b/middleman-core/lib/middleman-core/logger.rb index d1a1c402..30e28307 100644 --- a/middleman-core/lib/middleman-core/logger.rb +++ b/middleman-core/lib/middleman-core/logger.rb @@ -40,6 +40,7 @@ module Middleman return if @instrumenting.is_a?(String) && @instrumenting != 'instrument' && !message.include?(@instrumenting) evt = ::ActiveSupport::Notifications::Event.new(message, *args) + return unless evt.duration > 30 info "== Instrument (#{evt.name.sub(/.middleman$/, '')}): #{evt.duration}ms\n#{args.last}" end end diff --git a/middleman-core/lib/middleman-core/sitemap/resource.rb b/middleman-core/lib/middleman-core/sitemap/resource.rb index b1f614e4..5d7b9969 100644 --- a/middleman-core/lib/middleman-core/sitemap/resource.rb +++ b/middleman-core/lib/middleman-core/sitemap/resource.rb @@ -66,6 +66,8 @@ module Middleman # Page are data that is exposed through this resource's data member. # Note: It is named 'page' for backwards compatibility with older MM. @metadata = { options: {}, locals: {}, page: {} } + + @page_data = nil end # Whether this resource has a template file @@ -91,6 +93,7 @@ module Middleman # Note: It is named 'page' for backwards compatibility with older MM. Contract METADATA_HASH => METADATA_HASH def add_metadata(meta={}) + @page_data = nil @metadata.deep_merge!(meta) end @@ -98,7 +101,7 @@ module Middleman # @return [Hash] Contract RespondTo[:indifferent_access?] def data - ::Middleman::Util.recursively_enhance(metadata[:page]) + @page_data ||= ::Middleman::Util.recursively_enhance(metadata[:page]) end # Options about how this resource is rendered, such as its :layout, @@ -129,7 +132,6 @@ module Middleman def render(opts={}, locs={}) return ::Middleman::FileRenderer.new(@app, file_descriptor[:full_path].to_s).template_data_for_file unless template? - # ::Middleman::Util.instrument 'render.resource', path: file_descriptor[:full_path].to_s, destination_path: destination_path do md = metadata opts = md[:options].deep_merge(opts) locs = md[:locals].deep_merge(locs) @@ -140,7 +142,6 @@ module Middleman renderer = ::Middleman::TemplateRenderer.new(@app, file_descriptor[:full_path].to_s) renderer.render(locs, opts) - # end end # A path without the directory index - so foo/index.html becomes diff --git a/middleman-core/lib/middleman-core/sources/source_watcher.rb b/middleman-core/lib/middleman-core/sources/source_watcher.rb index 0c7356c2..e6ad077c 100644 --- a/middleman-core/lib/middleman-core/sources/source_watcher.rb +++ b/middleman-core/lib/middleman-core/sources/source_watcher.rb @@ -185,9 +185,7 @@ module Middleman new_files = ::Middleman::Util.all_files_under(@directory.to_s) .reject { |p| @files.key?(p) } - update(new_files, []) - - new_files + update(new_files, []).flatten.map { |s| s[:full_path] } end # Manually trigger update events. @@ -198,14 +196,14 @@ module Middleman updated = ::Middleman::Util.all_files_under(@directory.to_s) removed = @files.keys.reject { |p| updated.include?(p) } - update(updated, removed) + result = update(updated, removed) if @waiting_for_existence && @directory.exist? @waiting_for_existence = false listen! end - updated + removed + result.flatten.map { |s| s[:full_path] } end # Work around this bug: http://bugs.ruby-lang.org/issues/4521 @@ -238,7 +236,7 @@ module Middleman # # @param [String, Pathname] path The updated file path. # @return [void] - Contract ArrayOf[Pathname], ArrayOf[Pathname] => Any + Contract ArrayOf[Pathname], ArrayOf[Pathname] => ArrayOf[ArrayOf[IsA['Middleman::SourceFile']]] def update(updated_paths, removed_paths) valid_updates = updated_paths .map { |p| @files[p] || path_to_source_file(p, @directory, @type, @options[:destination_dir]) } @@ -271,6 +269,8 @@ module Middleman valid_removes, self ]) unless valid_updates.empty? && valid_removes.empty? + + [valid_updates, valid_removes] end # Convert a path to a file resprentation. diff --git a/middleman-core/lib/middleman-core/template_renderer.rb b/middleman-core/lib/middleman-core/template_renderer.rb index 4af4ce14..1930d434 100644 --- a/middleman-core/lib/middleman-core/template_renderer.rb +++ b/middleman-core/lib/middleman-core/template_renderer.rb @@ -133,12 +133,21 @@ module Middleman # Add extension helpers to context. @app.extensions.add_exposed_to_context(context) - content = _render_with_all_renderers(path, locs, context, opts, &block) + content = ::Middleman::Util.instrument 'builder.output.resource.render-template', path: File.basename(path) do + _render_with_all_renderers(path, locs, context, opts, &block) + end # If we need a layout and have a layout, use it - if layout_file = fetch_layout(engine, options) - layout_renderer = ::Middleman::FileRenderer.new(@app, layout_file[:relative_path].to_s) - content = layout_renderer.render(locals, options, context) { content } + layout_file = fetch_layout(engine, options) + if layout_file + content = ::Middleman::Util.instrument 'builder.output.resource.render-layout', path: File.basename(layout_file[:relative_path].to_s) do + if layout_file = fetch_layout(engine, options) + layout_renderer = ::Middleman::FileRenderer.new(@app, layout_file[:relative_path].to_s) + layout_renderer.render(locals, options, context) { content } + else + content + end + end end # Return result diff --git a/middleman-core/lib/middleman-core/util.rb b/middleman-core/lib/middleman-core/util.rb index ae15e3ec..a2cd1eef 100644 --- a/middleman-core/lib/middleman-core/util.rb +++ b/middleman-core/lib/middleman-core/util.rb @@ -98,7 +98,7 @@ module Middleman # @private # @param [Hash] data Normal hash # @return [Hash] - Contract Maybe[Hash] => Maybe[Or[Array, EnhancedHash]] + Contract Any => Maybe[Or[Array, EnhancedHash]] def recursively_enhance(obj) if obj.is_a? ::Array obj.map { |e| recursively_enhance(e) } @@ -480,6 +480,8 @@ module Middleman # @return [String] Contract String => ArrayOf[String] def collect_extensions(path) + return [] if File.basename(path).start_with?('.') + result = [] step_through_extensions(path) { |e| result << e } @@ -495,6 +497,8 @@ module Middleman # @return [Middleman::SourceFile] All related file paths, not including the source file paths. Contract ::Middleman::Application, ArrayOf[Pathname] => ArrayOf[::Middleman::SourceFile] def find_related_files(app, files) + return [] if files.empty? + all_extensions = files.flat_map { |f| collect_extensions(f.to_s) } sass_type_aliasing = ['.scss', '.sass']