class Middleman::Cli::BuildAction

A Thor Action, modular code, which does the majority of the work.

Attributes

logger[R]
source[R]

Public Class Methods

new(base, config={}) click to toggle source

Setup the action

@param [Middleman::Cli::Build] base @param [Hash] config

Calls superclass method
# File lib/middleman-core/cli/build.rb, line 112
def initialize(base, config={})
  @app        = base.class.shared_instance
  @source_dir = Pathname(@app.source_dir)
  @build_dir  = Pathname(@app.build_dir)
  @to_clean   = Set.new

  @logger = @app.logger
  @rack = ::Rack::Test::Session.new(@app.class.to_rack_app)

  super(base, @build_dir, config)
end

Public Instance Methods

invoke!() click to toggle source

Execute the action @return [void]

# File lib/middleman-core/cli/build.rb, line 126
def invoke!
  queue_current_paths if should_clean?
  execute!
  clean! if should_clean?
end

Protected Instance Methods

binary_encode(string) click to toggle source
# File lib/middleman-core/cli/build.rb, line 281
def binary_encode(string)
  string.force_encoding('ascii-8bit') if string.respond_to?(:force_encoding)
  string
end
build_resource(resource) click to toggle source
# File lib/middleman-core/cli/build.rb, line 218
def build_resource(resource)
  return if @config[:glob] && !File.fnmatch(@config[:glob], resource.destination_path)

  output_path = render_to_file(resource)

  return unless should_clean? && output_path.exist?

  if RUBY_PLATFORM =~ /darwin/
    # handle UTF-8-MAC filename on MacOS

    @to_clean.delete(output_path.realpath.to_s.encode('UTF-8', 'UTF-8-MAC'))
  else
    @to_clean.delete(output_path.realpath)
  end
end
clean!() click to toggle source

Remove files which were not built in this cycle @return [void]

# File lib/middleman-core/cli/build.rb, line 136
def clean!
  @to_clean.each do |f|
    base.remove_file f, force: true
  end

  Dir[@build_dir.join('**', '*')].select { |d| File.directory?(d) }.each do |d|
    base.remove_file d, force: true if directory_empty? d
  end
end
directory_empty?(directory) click to toggle source

Whether the given directory is empty @param [String, Pathname] directory @return [Boolean]

# File lib/middleman-core/cli/build.rb, line 155
def directory_empty?(directory)
  Pathname(directory).children.empty?
end
execute!() click to toggle source

Actually build the app @return [void]

# File lib/middleman-core/cli/build.rb, line 179
def execute!
  # Sort order, images, fonts, js/css and finally everything else.
  sort_order = %w(.png .jpeg .jpg .gif .bmp .svg .svgz .ico .woff .otf .ttf .eot .js .css)

  # Pre-request CSS to give Compass a chance to build sprites
  logger.debug '== Prerendering CSS'

  @app.sitemap.resources.select do |resource|
    resource.ext == '.css'
  end.each(&method(:build_resource))

  logger.debug '== Checking for Compass sprites'

  # Double-check for compass sprites
  @app.files.find_new_files((@source_dir + @app.images_dir).relative_path_from(@app.root_path))
  @app.sitemap.ensure_resource_list_updated!

  # Sort paths to be built by the above order. This is primarily so Compass can
  # find files in the build folder when it needs to generate sprites for the
  # css files

  logger.debug '== Building files'

  resources = @app.sitemap.resources.sort_by do |r|
    sort_order.index(r.ext) || 100
  end

  if @build_dir.expand_path.relative_path_from(@source_dir).to_s =~ /\A[.\/]+\Z/
    raise ":build_dir (#{@build_dir}) cannot be a parent of :source_dir (#{@source_dir})"
  end

  # Loop over all the paths and build them.
  resources.reject do |resource|
    resource.ext == '.css'
  end.each(&method(:build_resource))

  ::Middleman::Profiling.report('build')
end
handle_error(file_name, response, e=Thor::Error.new(response)) click to toggle source
# File lib/middleman-core/cli/build.rb, line 270
def handle_error(file_name, response, e=Thor::Error.new(response))
  base.had_errors = true

  base.say_status :error, file_name, :red
  if base.debugging
    raise e
  elsif base.options['verbose']
    base.shell.say response, :red
  end
end
queue_current_paths() click to toggle source

Get a list of all the file paths in the destination folder and save them for comparison against the files we build in this cycle @return [void]

# File lib/middleman-core/cli/build.rb, line 162
def queue_current_paths
  return unless File.exist?(@build_dir)

  paths = ::Middleman::Util.all_files_under(@build_dir).map(&:realpath).select(&:file?)

  @to_clean += paths.select do |path|
    path.to_s !~ /\/\./ || path.to_s =~ /\.(htaccess|htpasswd)/
  end

  return unless RUBY_PLATFORM =~ /darwin/

  # handle UTF-8-MAC filename on MacOS
  @to_clean = @to_clean.map { |path| path.to_s.encode('UTF-8', 'UTF-8-MAC') }
end
render_to_file(resource) click to toggle source

Render a resource to a file.

@param [Middleman::Sitemap::Resource] resource @return [Pathname] The full path of the file that was written

# File lib/middleman-core/cli/build.rb, line 238
def render_to_file(resource)
  output_file = @build_dir + resource.destination_path.gsub('%20', ' ')

  if resource.binary?
    if !output_file.exist?
      base.say_status :create, output_file, :green
    elsif FileUtils.compare_file(resource.source_file, output_file)
      base.say_status :identical, output_file, :blue
      return output_file
    else
      base.say_status :update, output_file, :yellow
    end

    output_file.dirname.mkpath
    FileUtils.cp(resource.source_file, output_file)
  else
    begin
      response = @rack.get(URI.escape(resource.request_path))

      if response.status == 200
        base.create_file(output_file, binary_encode(response.body))
      else
        handle_error(output_file, response.body)
      end
    rescue => e
      handle_error(output_file, "#{e}\n#{e.backtrace.join("\n")}", e)
    end
  end

  output_file
end
should_clean?() click to toggle source

Whether we should clean the build @return [Boolean]

# File lib/middleman-core/cli/build.rb, line 148
def should_clean?
  @config[:clean]
end