1
0
Fork 0
mirror of https://github.com/middleman/middleman.git synced 2022-11-09 12:20:27 -05:00

Centralize file reading and avoid parsing non-template files for front matter (#2229)

* Centralize file reading

Be able to tell the difference between static files and templates

Check other places for static_file?

Allow pipelines to still operate on js/css

chmod after moving

* Fix check on frontmatter parsing

* Reuse var

* Fix mime check

* Handle non-file resources with  static  check

* Fix .php files and minification
This commit is contained in:
Thomas Reynolds 2018-12-27 16:01:52 -08:00 committed by GitHub
parent 2880e9860f
commit 4c2b89bf41
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
22 changed files with 128 additions and 44 deletions

View file

@ -1,6 +1,7 @@
master
===
* Add `--dry-run` to run a build, but skip outputting to disk.
* Incremental builds: `--track-dependencies` and `--only-changed` flags (#2220)
* Remove Rack support in favor of `resource.filters << proc { |oldbody| newbody }`
* `manipulate_resource_list_container!` as a faster, less functional approach.

View file

@ -36,6 +36,10 @@ module Middleman::Cli
type: :boolean,
default: false,
desc: 'Generate profiling report for the build'
class_option :dry_run,
type: :boolean,
default: false,
desc: 'Skip writing output files'
class_option :track_dependencies,
type: :boolean,
default: false,
@ -86,6 +90,7 @@ module Middleman::Cli
builder = Middleman::Builder.new(@app,
glob: options['glob'],
dry_run: options['dry_run'],
clean: options['clean'],
parallel: options['parallel'],
only_changed: options['only_changed'],

View file

@ -55,7 +55,7 @@ Feature: Builder
Scenario: Builded text file(ex: html, css, xml, txt)'s permission is 0644
Given a successfully built app at "large-build-app"
When I cd to "build"
Then the mode of filesystem object "index.html" should match "0644"
And the mode of filesystem object "stylesheets/static.css" should match "0644"
And the mode of filesystem object "feed.xml" should match "0644"
And the mode of filesystem object ".htaccess" should match "0644"
Then the file named "index.html" should have permissions "0644"
And the file named "stylesheets/static.css" should have permissions "0644"
And the file named "feed.xml" should have permissions "0644"
And the file named ".htaccess" should have permissions "0644"

View file

@ -322,13 +322,13 @@ module Middleman
config_rb = File.join(root, 'config.rb')
if File.exist? config_rb
logger.debug '== Reading: Local config: config.rb'
config_context.instance_eval File.read(config_rb), config_rb, 1
config_context.instance_eval ::Middleman::Util.read_file(config_rb), config_rb, 1
else
# Check for and evaluate local configuration in `middleman.rb`
middleman_rb = File.join(root, 'middleman.rb')
if File.exist? middleman_rb
logger.debug '== Reading: Local middleman: middleman.rb'
config_context.instance_eval File.read(middleman_rb), middleman_rb, 1
config_context.instance_eval ::Middleman::Util.read_file(middleman_rb), middleman_rb, 1
end
end
@ -336,7 +336,7 @@ module Middleman
return unless File.exist? env_config
logger.debug "== Reading: #{config[:environment]} config"
config_context.instance_eval File.read(env_config), env_config, 1
config_context.instance_eval ::Middleman::Util.read_file(env_config), env_config, 1
end
# Clean up missing Tilt exts

View file

@ -23,7 +23,7 @@ module Middleman
def_delegator :@app, :logger
# Sort order, images, fonts, js/css and finally everything else.
SORT_ORDER = %w[.png .jpeg .jpg .gif .bmp .svg .svgz .webp .ico .woff .woff2 .otf .ttf .eot .js .css].freeze
SORT_ORDER = %w[.png .jpeg .jpg .gif .bmp .svg .svgz .webp .ico .woff .woff2 .otf .ttf .eot .js .mjs .css].freeze
# Create a new Builder instance.
# @param [Middleman::Application] app The app to build.
@ -40,7 +40,8 @@ module Middleman
@only_changed = options_hash.fetch(:only_changed, false)
@missing_and_changed = options_hash.fetch(:missing_and_changed, false)
@track_dependencies = options_hash.fetch(:track_dependencies, false)
@cleaning = options_hash.fetch(:clean)
@dry_run = options_hash.fetch(:dry_run)
@cleaning = !@dry_run && options_hash.fetch(:clean)
@callbacks = ::Middleman::CallbackManager.new
@callbacks.install_methods!(self, [:on_build_event])
@ -253,7 +254,6 @@ module Middleman
])
file.binmode
file.write(contents)
File.chmod(0o644, file)
file.close
file
end
@ -264,6 +264,8 @@ module Middleman
# @return [void]
Contract Pathname, Or[String, Pathname], Maybe[Bool] => Any
def export_file!(output_file, source, binary = false)
return if @dry_run
::Middleman::Util.instrument 'write_file', output_file: output_file do
source = write_tempfile(output_file, source.to_s) if source.is_a? String
@ -278,6 +280,7 @@ module Middleman
if %i[created updated].include?(mode)
::FileUtils.mkdir_p(output_file.dirname)
method.call(source_path, output_file.to_s)
::File.chmod(0o644, output_file.to_s)
end
source.unlink if source.is_a? Tempfile
@ -318,7 +321,7 @@ module Middleman
vertices = nil
if resource.binary?
if resource.binary? || resource.static_file?
export_file!(output_file, resource.file_descriptor[:full_path], true)
else
content = resource.render({}, {})

View file

@ -46,7 +46,7 @@ module Middleman
return unless File.exist? other_config
instance_eval File.read(other_config), other_config, 1
instance_eval ::Middleman::Util.read_file(other_config), other_config, 1
end
def set(key, default = nil, &block)

View file

@ -86,10 +86,14 @@ module Middleman::CoreExtensions
file_path = file[:full_path].to_s
@cache[file_path] ||= begin
::Middleman::Util::Data.parse(
file,
app.config[:frontmatter_delims]
)
if ::Middleman::Util.contains_frontmatter?(file_path, app.config[:frontmatter_delims])
::Middleman::Util::Data.parse(
file,
app.config[:frontmatter_delims]
)
else
[{}, nil]
end
end
end

View file

@ -1,7 +1,6 @@
require 'hamster'
require 'set'
require 'pathname'
require 'digest/sha1'
require 'yaml'
require 'middleman-core/contracts'
require 'middleman-core/dependencies/graph'
@ -30,7 +29,7 @@ module Middleman
ruby_files = Dir.glob(RUBY_FILES).reduce([]) do |sum, file|
sum << {
file: Pathname(File.expand_path(file)).relative_path_from(app.root_path).to_s,
hash: ::Digest::SHA1.file(file).hexdigest
hash: ::Middleman::Util.hash_file(file)
}
end
@ -62,7 +61,7 @@ module Middleman
Contract ArrayOf[String]
def invalidated_ruby_files(known_files)
known_files.reject do |file|
file[:hash] == ::Digest::SHA1.file(file[:file]).hexdigest
file[:hash] == ::Middleman::Util.hash_file(file[:file])
end
end

View file

@ -1,5 +1,4 @@
require 'hamster'
require 'digest/sha1'
require 'middleman-core/contracts'
require 'middleman-core/dependencies/vertices/vertex'
require 'middleman-core/core_extensions/data/controller'
@ -47,7 +46,7 @@ module Middleman
def current_hash
@current_hash ||= begin
data = lookup_path(key_to_path)
::Digest::SHA1.hexdigest(data.to_s)
::Middleman::Util.hash_string(data.to_s)
end
end

View file

@ -1,5 +1,4 @@
require 'hamster'
require 'digest/sha1'
require 'middleman-core/contracts'
require 'middleman-core/dependencies/vertices/vertex'
@ -56,7 +55,7 @@ module Middleman
def current_hash
return nil if @data.nil?
@current_hash ||= ::Digest::SHA1.hexdigest(@data.to_s)
@current_hash ||= ::Middleman::Util.hash_string(@data.to_s)
end
Contract Maybe[String]

View file

@ -1,5 +1,4 @@
require 'pathname'
require 'digest/sha1'
require 'middleman-core/contracts'
require 'middleman-core/dependencies/vertices/vertex'
@ -59,7 +58,7 @@ module Middleman
Contract String
def hash_file
::Digest::SHA1.file(@full_path).hexdigest
::Middleman::Util.hash_file(@full_path)
end
end
end

View file

@ -1,7 +1,7 @@
require 'middleman-core/util'
class Middleman::Extensions::AssetHash < ::Middleman::Extension
option :sources, %w[.css .htm .html .js .json .php .xhtml], 'List of extensions that are searched for hashable assets.'
option :sources, %w[.css .htm .html .js .mjs .json .php .xhtml], 'List of extensions that are searched for hashable assets.'
option :exts, nil, 'List of extensions that get asset hashes appended to them.'
option :ignore, [], 'Regexes of filenames to skip adding asset hashes to'
option :rewrite_ignore, [], 'Regexes of filenames to skip processing for path rewrites'
@ -10,8 +10,6 @@ class Middleman::Extensions::AssetHash < ::Middleman::Extension
def initialize(app, options_hash = ::Middleman::EMPTY_HASH, &block)
super
require 'digest/sha1'
# Allow specifying regexes to ignore, plus always ignore apple touch icons
@ignore = Array(options.ignore) + [/^apple-touch-icon/]
@ -66,7 +64,7 @@ class Middleman::Extensions::AssetHash < ::Middleman::Extension
sorted_resources = resource_list.by_extensions(@set_of_exts).sort_by do |a|
if %w[.svg .svgz].include? a.ext
0
elsif %w[.js .css].include? a.ext
elsif %w[.js .mjs .css].include? a.ext
1
else
-1
@ -83,12 +81,12 @@ class Middleman::Extensions::AssetHash < ::Middleman::Extension
return if ignored_resource?(resource)
return if resource.ignored?
digest = if resource.binary?
::Digest::SHA1.file(resource.source_file).hexdigest[0..7]
digest = if resource.binary? || resource.static_file?
::Middleman::Util.hash_file(resource.source_file)[0..7]
else
# Render without asset hash
body = resource.render({}, {}) { |f| !f.respond_to?(:filter_name) || f.filter_name != :asset_hash }
::Digest::SHA1.hexdigest(body)[0..7]
::Middleman::Util.hash_string(body)[0..7]
end
resource_list.update!(resource, :destination_path) do

View file

@ -1,7 +1,7 @@
class Middleman::Extensions::AssetHost < ::Middleman::Extension
option :host, nil, 'The asset host to use or a Proc to determine asset host', required: true
option :exts, nil, 'List of extensions that get cache busters strings appended to them.'
option :sources, %w[.css .htm .html .js .php .xhtml], 'List of extensions that are searched for bustable assets.'
option :sources, %w[.css .htm .html .js .mjs .php .xhtml], 'List of extensions that are searched for bustable assets.'
option :ignore, [], 'Regexes of filenames to skip adding query strings to'
option :rewrite_ignore, [], 'Regexes of filenames to skip processing for host rewrites'

View file

@ -1,7 +1,7 @@
# The Cache Buster extension
class Middleman::Extensions::CacheBuster < ::Middleman::Extension
option :exts, nil, 'List of extensions that get cache busters strings appended to them.'
option :sources, %w[.css .htm .html .js .php .xhtml], 'List of extensions that are searched for bustable assets.'
option :sources, %w[.css .htm .html .js .mjs .php .xhtml], 'List of extensions that are searched for bustable assets.'
option :ignore, [], 'Regexes of filenames to skip adding query strings to'
option :rewrite_ignore, [], 'Regexes of filenames to skip processing for path rewrites'

View file

@ -7,10 +7,10 @@
# to serve your Gzipped files whenever the normal (non-.gz) filename is requested.
#
# Pass the :exts options to customize which file extensions get zipped (defaults
# to .css, .htm, .html, .js, and .xhtml
# to .css, .htm, .html, .js, .mjs, and .xhtml
#
class Middleman::Extensions::Gzip < ::Middleman::Extension
option :exts, %w[.css .htm .html .js .svg .xhtml], 'File extensions to Gzip when building.'
option :exts, %w[.css .htm .html .js .mjs .svg .xhtml], 'File extensions to Gzip when building.'
option :ignore, [], 'Patterns to avoid gzipping'
option :overwrite, false, 'Overwrite original files instead of adding .gz extension.'

View file

@ -102,7 +102,7 @@ module Middleman
return result unless result.nil?
end
file ? file.read : ::File.read(@path)
file ? file.read : ::Middleman::Util.read_file(@path)
end
protected

View file

@ -98,7 +98,7 @@ module Middleman
return not_found(res, full_request_path) unless resource && !resource.ignored?
# If this path is a binary file, send it immediately
return send_file(resource, env) if resource.binary?
return send_file(resource, env) if resource.binary? || resource.static_file?
res['Content-Type'] = resource.content_type || 'text/plain'
@ -141,7 +141,10 @@ module Middleman
response[1]['Content-Encoding'] = 'gzip' if %w[.svgz .gz].include?(resource.ext)
# Do not set Content-Type if status is 1xx, 204, 205 or 304, otherwise
# Rack will throw an error (500)
response[1]['Content-Type'] = resource.content_type || 'application/octet-stream' if !(100..199).cover?(status) && ![204, 205, 304].include?(status)
if !(100..199).cover?(status) && ![204, 205, 304].include?(status)
response[1]['Content-Type'] = resource.content_type || (resource.binary? ? 'application/octet-stream' : 'text/plain')
end
halt response
end
end

View file

@ -91,6 +91,13 @@ module Middleman
!::Middleman::Util.tilt_class(file_descriptor[:full_path].to_s).nil?
end
Contract Bool
def static_file?
return false if file_descriptor.nil?
::Middleman::Util.static_file?(file_descriptor[:full_path].to_s, app.config[:frontmatter_delims])
end
# Backwards compatible method for turning descriptor into a string.
# @return [String]
Contract Maybe[String]

View file

@ -7,7 +7,7 @@ module Middleman
SourceFile = Struct.new(:relative_path, :full_path, :directory, :types, :version) do
def read
::Middleman::Sources.file_cache[full_path] ||= {}
::Middleman::Sources.file_cache[full_path][version] ||= ::File.read(full_path)
::Middleman::Sources.file_cache[full_path][version] ||= ::Middleman::Util.read_file(full_path.to_s)
end
def normalized_relative_path

View file

@ -5,6 +5,15 @@ require 'set'
require 'middleman-core/contracts'
KNOWN_NON_STATIC_FILE_EXTENSIONS = Set.new %w[
css
js
mjs
html
htm
php
]
KNOWN_BINARY_FILE_EXTENSIONS = Set.new %w[
3dm
3ds
@ -330,5 +339,44 @@ module Middleman
false
end
Contract String, Maybe[HashOf[Symbol, Any]] => Bool
def static_file?(path, frontmatter_delims)
path = Pathname(path)
ext = path.extname
without_dot = ext.sub('.', '')
if KNOWN_NON_STATIC_FILE_EXTENSIONS.include?(without_dot) || contains_frontmatter?(path, frontmatter_delims)
false
else
!::Tilt.registered?(without_dot)
end
end
Contract String, Maybe[HashOf[Symbol, Any]] => Bool
def contains_frontmatter?(path, frontmatter_delims)
file = ::File.open(path)
first_line = file.gets
first_line = file.gets if first_line =~ /\A(?:[^\r\n]*coding:[^\r\n]*\r?\n)/
file.close
possible_openers = possible_delim_openers(frontmatter_delims)
!first_line.nil? && !first_line.match(possible_openers).nil?
rescue EOFError, IOError, ::Errno::ENOENT
false
end
Contract Maybe[HashOf[Symbol, Any]] => Regexp
def possible_delim_openers(frontmatter_delims)
all_possible = frontmatter_delims
.values
.flatten(1)
.map(&:first)
.uniq
/\A#{::Regexp.union(all_possible)}/
end
end
end

View file

@ -45,13 +45,14 @@ module Middleman
# @param [String] path
# @return [Array<Hash, String>]
Contract IsA['Middleman::SourceFile'], Maybe[Symbol] => [Hash, Maybe[String]]
def parse(file, frontmatter_delims, known_type = nil)
full_path = file[:full_path]
return [{}, nil] if ::Middleman::Util.binary?(full_path) || file[:types].include?(:binary)
def parse(source_file, frontmatter_delims, known_type = nil)
full_path = source_file[:full_path]
return [{}, nil] if ::Middleman::Util.binary?(full_path) || source_file[:types].include?(:binary)
# Avoid weird race condition when a file is renamed
begin
content = file.read
content = source_file.read
rescue EOFError, IOError, ::Errno::ENOENT
return [{}, nil]
end

View file

@ -1,3 +1,4 @@
require 'digest/sha1'
require 'set'
module Middleman
@ -130,5 +131,22 @@ module Middleman
end
end.map(&:file_descriptor)
end
Contract String, Maybe[Num] => String
def read_file(path, bytes = nil)
# puts "Read: #{path}"
File.read(path, bytes)
end
Contract String => String
def hash_file(path)
# puts "Read (hash): #{path}"
::Digest::SHA1.file(path).hexdigest
end
Contract String => String
def hash_string(data)
::Digest::SHA1.hexdigest(data)
end
end
end