middleman-core 4.1.0.rc.2 → 4.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/features/asset_hash.feature +30 -32
- data/features/asset_host.feature +2 -0
- data/features/gzip.feature +1 -1
- data/features/import_files.feature +0 -2
- data/features/nested_layouts.feature +20 -17
- data/fixtures/asset-host-app/source/javascripts/asset_host.js +2 -0
- data/fixtures/frontmatter-neighbor-app/config.rb +1 -1
- data/fixtures/frontmatter-settings-neighbor-app/config.rb +1 -1
- data/fixtures/nested-layout-app/source/layouts/inner.erb +5 -2
- data/fixtures/nested-layout-app/source/layouts/inner_haml.haml +6 -2
- data/fixtures/nested-layout-app/source/layouts/inner_slim.slim +6 -2
- data/fixtures/nested-layout-app/source/layouts/master.erb +7 -1
- data/fixtures/nested-layout-app/source/layouts/master_haml.haml +5 -1
- data/fixtures/nested-layout-app/source/layouts/master_slim.slim +5 -1
- data/fixtures/nested-layout-app/source/layouts/outer.erb +6 -2
- data/fixtures/nested-layout-app/source/layouts/outer_haml.haml +5 -1
- data/fixtures/nested-layout-app/source/layouts/outer_slim.slim +5 -1
- data/lib/middleman-core.rb +0 -3
- data/lib/middleman-core/application.rb +7 -9
- data/lib/middleman-core/builder.rb +88 -44
- data/lib/middleman-core/contracts.rb +102 -13
- data/lib/middleman-core/core_extensions/data.rb +15 -10
- data/lib/middleman-core/core_extensions/default_helpers.rb +15 -6
- data/lib/middleman-core/core_extensions/file_watcher.rb +2 -2
- data/lib/middleman-core/core_extensions/front_matter.rb +11 -3
- data/lib/middleman-core/core_extensions/i18n.rb +1 -1
- data/lib/middleman-core/core_extensions/inline_url_rewriter.rb +2 -2
- data/lib/middleman-core/extension.rb +1 -1
- data/lib/middleman-core/extensions.rb +1 -1
- data/lib/middleman-core/extensions/asset_hash.rb +1 -1
- data/lib/middleman-core/extensions/asset_host.rb +1 -1
- data/lib/middleman-core/extensions/automatic_image_sizes.rb +1 -1
- data/lib/middleman-core/extensions/cache_buster.rb +1 -1
- data/lib/middleman-core/extensions/external_pipeline.rb +2 -1
- data/lib/middleman-core/extensions/gzip.rb +2 -2
- data/lib/middleman-core/extensions/minify_css.rb +1 -1
- data/lib/middleman-core/extensions/minify_javascript.rb +1 -1
- data/lib/middleman-core/extensions/relative_assets.rb +1 -1
- data/lib/middleman-core/file_renderer.rb +12 -9
- data/lib/middleman-core/logger.rb +1 -0
- data/lib/middleman-core/preview_server.rb +14 -14
- data/lib/middleman-core/renderers/haml.rb +3 -1
- data/lib/middleman-core/renderers/less.rb +1 -1
- data/lib/middleman-core/renderers/liquid.rb +1 -1
- data/lib/middleman-core/renderers/sass.rb +7 -2
- data/lib/middleman-core/sitemap/extensions/ignores.rb +2 -2
- data/lib/middleman-core/sitemap/extensions/import.rb +3 -1
- data/lib/middleman-core/sitemap/resource.rb +7 -6
- data/lib/middleman-core/sources.rb +30 -13
- data/lib/middleman-core/sources/source_watcher.rb +50 -12
- data/lib/middleman-core/step_definitions/middleman_steps.rb +2 -2
- data/lib/middleman-core/template_context.rb +1 -1
- data/lib/middleman-core/template_renderer.rb +13 -4
- data/lib/middleman-core/util.rb +6 -606
- data/lib/middleman-core/util/binary.rb +79 -0
- data/lib/middleman-core/util/data.rb +37 -8
- data/lib/middleman-core/util/files.rb +134 -0
- data/lib/middleman-core/util/paths.rb +251 -0
- data/lib/middleman-core/util/rack.rb +52 -0
- data/lib/middleman-core/util/uri_templates.rb +97 -0
- data/lib/middleman-core/version.rb +1 -1
- data/middleman-core.gemspec +1 -0
- metadata +25 -4
@@ -112,7 +112,7 @@ class Middleman::Extensions::MinifyJavascript < ::Middleman::Extension
|
|
112
112
|
|
113
113
|
# Only compress script tags that contain JavaScript (as opposed to
|
114
114
|
# something like jQuery templates, identified with a "text/html" type).
|
115
|
-
if first.include?('
|
115
|
+
if !first.include?('type=') || first.include?('text/javascript')
|
116
116
|
first + minify(inline_content) + last
|
117
117
|
else
|
118
118
|
match
|
@@ -3,7 +3,7 @@ require 'addressable/uri'
|
|
3
3
|
# Relative Assets extension
|
4
4
|
class Middleman::Extensions::RelativeAssets < ::Middleman::Extension
|
5
5
|
option :exts, %w(.css .png .jpg .jpeg .webp .svg .svgz .js .gif .ttf .otf .woff .woff2 .eot), 'List of extensions that get cache busters strings appended to them.'
|
6
|
-
option :sources, %w(.htm .html .
|
6
|
+
option :sources, %w(.css .htm .html .xhtml), 'List of extensions that are searched for relative assets.'
|
7
7
|
option :ignore, [], 'Regexes of filenames to skip adding query strings to'
|
8
8
|
option :rewrite_ignore, [], 'Regexes of filenames to skip processing for path rewrites'
|
9
9
|
|
@@ -51,7 +51,7 @@ module Middleman
|
|
51
51
|
|
52
52
|
# Merge per-extension options from config
|
53
53
|
extension = File.extname(path)
|
54
|
-
options = opts.merge(options_for_ext(extension))
|
54
|
+
options = {}.merge!(opts).merge!(options_for_ext(extension))
|
55
55
|
options[:outvar] ||= '@_out_buf'
|
56
56
|
options[:context] = context
|
57
57
|
options.delete(:layout)
|
@@ -73,9 +73,10 @@ module Middleman
|
|
73
73
|
# end
|
74
74
|
|
75
75
|
# Render using Tilt
|
76
|
-
content = ::Middleman::Util.instrument 'render.tilt', path: path do
|
77
|
-
|
78
|
-
end
|
76
|
+
# content = ::Middleman::Util.instrument 'render.tilt', path: path do
|
77
|
+
# template.render(context, locs, &block)
|
78
|
+
# end
|
79
|
+
content = template.render(context, locs, &block)
|
79
80
|
|
80
81
|
# Allow hooks to manipulate the result after render
|
81
82
|
content = @app.callbacks_for(:after_render).reduce(content) do |sum, callback|
|
@@ -96,12 +97,14 @@ module Middleman
|
|
96
97
|
# @return [String]
|
97
98
|
Contract String
|
98
99
|
def template_data_for_file
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
100
|
+
file = @app.files.find(:source, @path)
|
101
|
+
|
102
|
+
if @app.extensions[:front_matter] || (file && !file[:types].include?(:no_frontmatter))
|
103
|
+
result = @app.extensions[:front_matter].template_data_for_file(@path)
|
104
|
+
return result unless result.nil?
|
104
105
|
end
|
106
|
+
|
107
|
+
file ? file.read : File.read(@path)
|
105
108
|
end
|
106
109
|
|
107
110
|
protected
|
@@ -40,6 +40,7 @@ module Middleman
|
|
40
40
|
return if @instrumenting.is_a?(String) && @instrumenting != 'instrument' && !message.include?(@instrumenting)
|
41
41
|
|
42
42
|
evt = ::ActiveSupport::Notifications::Event.new(message, *args)
|
43
|
+
return unless evt.duration > 30
|
43
44
|
info "== Instrument (#{evt.name.sub(/.middleman$/, '')}): #{evt.duration}ms\n#{args.last}"
|
44
45
|
end
|
45
46
|
end
|
@@ -151,19 +151,19 @@ module Middleman
|
|
151
151
|
config[:ssl_private_key] = opts[:ssl_private_key] if opts[:ssl_private_key]
|
152
152
|
|
153
153
|
ready do
|
154
|
-
match_against = [
|
155
|
-
%r{^config\.rb$},
|
156
|
-
%r{^environments/[^\.](.*)\.rb$},
|
157
|
-
%r{^lib/[^\.](.*)\.rb$},
|
158
|
-
%r{^#{config[:helpers_dir]}/[^\.](.*)\.rb$}
|
159
|
-
]
|
160
|
-
|
161
|
-
# config.rb
|
162
|
-
watcher = files.watch :reload,
|
163
|
-
path: root,
|
164
|
-
only: match_against
|
165
|
-
|
166
154
|
unless config[:watcher_disable]
|
155
|
+
match_against = [
|
156
|
+
%r{^config\.rb$},
|
157
|
+
%r{^environments/[^\.](.*)\.rb$},
|
158
|
+
%r{^lib/[^\.](.*)\.rb$},
|
159
|
+
%r{^#{config[:helpers_dir]}/[^\.](.*)\.rb$}
|
160
|
+
]
|
161
|
+
|
162
|
+
# config.rb
|
163
|
+
watcher = files.watch :reload,
|
164
|
+
path: root,
|
165
|
+
only: match_against
|
166
|
+
|
167
167
|
# Hack around node_modules in root.
|
168
168
|
watcher.listener.ignore(/^node_modules/)
|
169
169
|
|
@@ -235,8 +235,8 @@ module Middleman
|
|
235
235
|
|
236
236
|
if ssl_certificate || ssl_private_key
|
237
237
|
raise 'You must provide both :ssl_certificate and :ssl_private_key' unless ssl_private_key && ssl_certificate
|
238
|
-
http_opts[:SSLCertificate] = OpenSSL::X509::Certificate.new File.read ssl_certificate
|
239
|
-
http_opts[:SSLPrivateKey] = OpenSSL::PKey::RSA.new File.read ssl_private_key
|
238
|
+
http_opts[:SSLCertificate] = OpenSSL::X509::Certificate.new ::File.read ssl_certificate
|
239
|
+
http_opts[:SSLPrivateKey] = OpenSSL::PKey::RSA.new ::File.read ssl_private_key
|
240
240
|
else
|
241
241
|
# use a generated self-signed cert
|
242
242
|
http_opts[:SSLCertName] = [
|
@@ -30,7 +30,7 @@ module Middleman
|
|
30
30
|
end
|
31
31
|
|
32
32
|
def evaluate(scope, locals, &block)
|
33
|
-
options = @options.merge(filename: eval_file, line: line, context: @context || scope)
|
33
|
+
options = {}.merge!(@options).merge!(filename: eval_file, line: line, context: @context || scope)
|
34
34
|
@engine = ::Haml::Engine.new(data, options)
|
35
35
|
output = @engine.render(scope, locals, &block)
|
36
36
|
|
@@ -46,6 +46,7 @@ module Middleman
|
|
46
46
|
::Haml::Options.defaults[:context] = nil
|
47
47
|
::Haml::Options.send :attr_accessor, :context
|
48
48
|
|
49
|
+
# rubocop:disable NestedMethodDefinition
|
49
50
|
[::Haml::Filters::Sass, ::Haml::Filters::Scss, ::Haml::Filters::Markdown].each do |f|
|
50
51
|
f.class_exec do
|
51
52
|
def self.render_with_options(text, compiler_options)
|
@@ -57,6 +58,7 @@ module Middleman
|
|
57
58
|
end
|
58
59
|
end
|
59
60
|
end
|
61
|
+
# rubocop:enable NestedMethodDefinition
|
60
62
|
|
61
63
|
::Tilt.prefer(::Middleman::Renderers::HamlTemplate, :haml)
|
62
64
|
|
@@ -26,7 +26,7 @@ module Middleman
|
|
26
26
|
if ::Less.const_defined? :Engine
|
27
27
|
@engine = ::Less::Engine.new(data)
|
28
28
|
else
|
29
|
-
parser
|
29
|
+
parser = ::Less::Parser.new({}.merge!(options).merge!(filename: eval_file, line: line, paths: ['.', File.dirname(eval_file)]))
|
30
30
|
@engine = parser.parse(data)
|
31
31
|
end
|
32
32
|
end
|
@@ -14,7 +14,7 @@ module Middleman
|
|
14
14
|
def read_template_file(template_path, _)
|
15
15
|
file = app.files.find(:source, "_#{template_path}.liquid")
|
16
16
|
raise ::Liquid::FileSystemError, "No such template '#{template_path}'" unless file
|
17
|
-
|
17
|
+
file.read
|
18
18
|
end
|
19
19
|
|
20
20
|
# @return Array<Middleman::Sitemap::Resource>
|
@@ -1,5 +1,10 @@
|
|
1
1
|
require 'sass'
|
2
2
|
|
3
|
+
begin
|
4
|
+
require 'sassc'
|
5
|
+
rescue LoadError
|
6
|
+
end
|
7
|
+
|
3
8
|
module Middleman
|
4
9
|
module Renderers
|
5
10
|
# Sass renderer
|
@@ -76,7 +81,7 @@ module Middleman
|
|
76
81
|
filename: eval_file,
|
77
82
|
line: line,
|
78
83
|
syntax: syntax,
|
79
|
-
custom: (options[:custom] || {}).merge(
|
84
|
+
custom: {}.merge!(options[:custom] || {}).merge!(
|
80
85
|
middleman_context: ctx.app,
|
81
86
|
current_resource: ctx.current_resource
|
82
87
|
)
|
@@ -92,7 +97,7 @@ module Middleman
|
|
92
97
|
more_opts[:css_filename] = file.sub(/\.s[ac]ss$/, '')
|
93
98
|
end
|
94
99
|
|
95
|
-
options.merge(more_opts)
|
100
|
+
{}.merge!(options).merge!(more_opts)
|
96
101
|
end
|
97
102
|
end
|
98
103
|
|
@@ -11,7 +11,7 @@ module Middleman
|
|
11
11
|
# Ignore a path or add an ignore callback
|
12
12
|
# @param [String, Regexp] path Path glob expression, or path regex
|
13
13
|
# @return [IgnoreDescriptor]
|
14
|
-
Contract
|
14
|
+
Contract Or[String, Regexp, Proc] => RespondTo[:execute_descriptor]
|
15
15
|
def ignore(path=nil, &block)
|
16
16
|
@app.sitemap.invalidate_resources_not_ignored_cache!
|
17
17
|
IgnoreDescriptor.new(path, block)
|
@@ -49,7 +49,7 @@ module Middleman
|
|
49
49
|
else
|
50
50
|
match_path == path_clean
|
51
51
|
end
|
52
|
-
elsif
|
52
|
+
elsif block
|
53
53
|
block.call(match_path)
|
54
54
|
end
|
55
55
|
end
|
@@ -12,8 +12,10 @@ module Middleman
|
|
12
12
|
|
13
13
|
ImportFileDescriptor = Struct.new(:from, :to) do
|
14
14
|
def execute_descriptor(app, resources)
|
15
|
+
source = ::Middleman::SourceFile.new(Pathname(from).relative_path_from(app.source_dir), Pathname(from), app.source_dir, Set.new([:source, :binary]), 0)
|
16
|
+
|
15
17
|
resources + [
|
16
|
-
::Middleman::Sitemap::Resource.new(app.sitemap, to,
|
18
|
+
::Middleman::Sitemap::Resource.new(app.sitemap, to, source)
|
17
19
|
]
|
18
20
|
end
|
19
21
|
end
|
@@ -54,7 +54,7 @@ module Middleman
|
|
54
54
|
source = Pathname(source) if source && source.is_a?(String)
|
55
55
|
|
56
56
|
@file_descriptor = if source && source.is_a?(Pathname)
|
57
|
-
::Middleman::SourceFile.new(source.relative_path_from(@app.source_dir), source, @app.source_dir, Set.new([:source]))
|
57
|
+
::Middleman::SourceFile.new(source.relative_path_from(@app.source_dir), source, @app.source_dir, Set.new([:source]), 0)
|
58
58
|
else
|
59
59
|
source
|
60
60
|
end
|
@@ -66,6 +66,8 @@ module Middleman
|
|
66
66
|
# Page are data that is exposed through this resource's data member.
|
67
67
|
# Note: It is named 'page' for backwards compatibility with older MM.
|
68
68
|
@metadata = { options: {}, locals: {}, page: {} }
|
69
|
+
|
70
|
+
@page_data = nil
|
69
71
|
end
|
70
72
|
|
71
73
|
# Whether this resource has a template file
|
@@ -91,6 +93,7 @@ module Middleman
|
|
91
93
|
# Note: It is named 'page' for backwards compatibility with older MM.
|
92
94
|
Contract METADATA_HASH => METADATA_HASH
|
93
95
|
def add_metadata(meta={})
|
96
|
+
@page_data = nil
|
94
97
|
@metadata.deep_merge!(meta)
|
95
98
|
end
|
96
99
|
|
@@ -98,7 +101,7 @@ module Middleman
|
|
98
101
|
# @return [Hash]
|
99
102
|
Contract RespondTo[:indifferent_access?]
|
100
103
|
def data
|
101
|
-
::Middleman::Util.recursively_enhance(metadata[:page])
|
104
|
+
@page_data ||= ::Middleman::Util.recursively_enhance(metadata[:page])
|
102
105
|
end
|
103
106
|
|
104
107
|
# Options about how this resource is rendered, such as its :layout,
|
@@ -129,18 +132,16 @@ module Middleman
|
|
129
132
|
def render(opts={}, locs={})
|
130
133
|
return ::Middleman::FileRenderer.new(@app, file_descriptor[:full_path].to_s).template_data_for_file unless template?
|
131
134
|
|
132
|
-
# ::Middleman::Util.instrument 'render.resource', path: file_descriptor[:full_path].to_s, destination_path: destination_path do
|
133
135
|
md = metadata
|
134
136
|
opts = md[:options].deep_merge(opts)
|
135
137
|
locs = md[:locals].deep_merge(locs)
|
136
138
|
locs[:current_path] ||= destination_path
|
137
139
|
|
138
140
|
# Certain output file types don't use layouts
|
139
|
-
opts[:layout] = false if !opts.key?(:layout) && ext
|
141
|
+
opts[:layout] = false if !opts.key?(:layout) && !@app.config.extensions_with_layout.include?(ext)
|
140
142
|
|
141
143
|
renderer = ::Middleman::TemplateRenderer.new(@app, file_descriptor[:full_path].to_s)
|
142
144
|
renderer.render(locs, opts)
|
143
|
-
# end
|
144
145
|
end
|
145
146
|
|
146
147
|
# A path without the directory index - so foo/index.html becomes
|
@@ -161,7 +162,7 @@ module Middleman
|
|
161
162
|
# @return [Boolean]
|
162
163
|
Contract Bool
|
163
164
|
def binary?
|
164
|
-
!file_descriptor.nil? && ::Middleman::Util.binary?(file_descriptor[:full_path].to_s)
|
165
|
+
!file_descriptor.nil? && (file_descriptor[:types].include?(:binary) || ::Middleman::Util.binary?(file_descriptor[:full_path].to_s))
|
165
166
|
end
|
166
167
|
|
167
168
|
# Ignore a resource directly, without going through the whole
|
@@ -3,7 +3,12 @@ require 'middleman-core/contracts'
|
|
3
3
|
|
4
4
|
module Middleman
|
5
5
|
# The standard "record" that contains information about a file on disk.
|
6
|
-
SourceFile = Struct.new
|
6
|
+
SourceFile = Struct.new(:relative_path, :full_path, :directory, :types, :version) do
|
7
|
+
def read
|
8
|
+
::Middleman::Sources.file_cache[full_path] ||= {}
|
9
|
+
::Middleman::Sources.file_cache[full_path][version] ||= ::File.read(full_path)
|
10
|
+
end
|
11
|
+
end
|
7
12
|
|
8
13
|
# Sources handle multiple on-disk collections of files which make up
|
9
14
|
# a Middleman project. They are separated by `type` which can then be
|
@@ -36,6 +41,8 @@ module Middleman
|
|
36
41
|
# Reference to the global logger.
|
37
42
|
def_delegator :@app, :logger
|
38
43
|
|
44
|
+
cattr_accessor :file_cache
|
45
|
+
|
39
46
|
# Built-in types
|
40
47
|
# :source, :data, :locales, :reload
|
41
48
|
|
@@ -50,6 +57,8 @@ module Middleman
|
|
50
57
|
@watchers = watchers
|
51
58
|
@sorted_watchers = @watchers.dup.freeze
|
52
59
|
|
60
|
+
::Middleman::Sources.file_cache = {}
|
61
|
+
|
53
62
|
@options = options
|
54
63
|
|
55
64
|
# Set of procs wanting to be notified of changes
|
@@ -82,7 +91,7 @@ module Middleman
|
|
82
91
|
validator: (block_given? ? block : regex))
|
83
92
|
|
84
93
|
bump_count
|
85
|
-
|
94
|
+
poll_once! if @running
|
86
95
|
end
|
87
96
|
|
88
97
|
# Whether this path is ignored.
|
@@ -175,11 +184,13 @@ module Middleman
|
|
175
184
|
# @param [String] path The file path.
|
176
185
|
# @param [Boolean] glob If the path contains wildcard or glob characters.
|
177
186
|
# @return [Middleman::SourceFile, nil]
|
178
|
-
Contract Or[Symbol, ArrayOf[Symbol], SetOf[Symbol]], String, Maybe[Bool] => Maybe[SourceFile]
|
187
|
+
Contract Or[Symbol, ArrayOf[Symbol], SetOf[Symbol]], Or[Pathname, String], Maybe[Bool] => Maybe[SourceFile]
|
179
188
|
def find(types, path, glob=false)
|
189
|
+
array_of_types = Array(types)
|
190
|
+
|
180
191
|
watchers
|
181
192
|
.lazy
|
182
|
-
.select { |d|
|
193
|
+
.select { |d| array_of_types.include?(d.type) }
|
183
194
|
.map { |d| d.find(path, glob) }
|
184
195
|
.reject(&:nil?)
|
185
196
|
.first
|
@@ -192,10 +203,7 @@ module Middleman
|
|
192
203
|
# @return [Boolean]
|
193
204
|
Contract Or[Symbol, ArrayOf[Symbol], SetOf[Symbol]], String => Bool
|
194
205
|
def exists?(types, path)
|
195
|
-
watchers
|
196
|
-
.lazy
|
197
|
-
.select { |d| Array(types).include?(d.type) }
|
198
|
-
.any? { |d| d.exists?(path) }
|
206
|
+
watchers.any? { |d| Array(types).include?(d.type) && d.exists?(path) }
|
199
207
|
end
|
200
208
|
|
201
209
|
# Check if a file for a given type exists.
|
@@ -205,18 +213,27 @@ module Middleman
|
|
205
213
|
# @return [Boolean]
|
206
214
|
Contract Or[Symbol, ArrayOf[Symbol], SetOf[Symbol]], String => Maybe[HANDLER]
|
207
215
|
def watcher_for_path(types, path)
|
208
|
-
watchers
|
209
|
-
.select { |d| Array(types).include?(d.type) }
|
210
|
-
.find { |d| d.exists?(path) }
|
216
|
+
watchers.detect { |d| Array(types).include?(d.type) && d.exists?(path) }
|
211
217
|
end
|
212
218
|
|
213
|
-
# Manually
|
219
|
+
# Manually check for new files
|
214
220
|
#
|
215
221
|
# @return [void]
|
216
222
|
Contract ArrayOf[Pathname]
|
217
223
|
def find_new_files!
|
218
224
|
return [] unless @update_count != @last_update_count
|
219
225
|
|
226
|
+
@last_update_count = @update_count
|
227
|
+
watchers.reduce([]) { |sum, w| sum + w.find_new_files! }
|
228
|
+
end
|
229
|
+
|
230
|
+
# Manually poll all watchers for new content.
|
231
|
+
#
|
232
|
+
# @return [void]
|
233
|
+
Contract ArrayOf[Pathname]
|
234
|
+
def poll_once!
|
235
|
+
return [] unless @update_count != @last_update_count
|
236
|
+
|
220
237
|
@last_update_count = @update_count
|
221
238
|
watchers.reduce([]) { |sum, w| sum + w.poll_once! }
|
222
239
|
end
|
@@ -297,7 +314,7 @@ module Middleman
|
|
297
314
|
def matches?(validator, file)
|
298
315
|
path = file[:relative_path]
|
299
316
|
if validator.is_a? Regexp
|
300
|
-
!!
|
317
|
+
!!(path.to_s =~ validator)
|
301
318
|
else
|
302
319
|
!!validator.call(path, @app)
|
303
320
|
end
|
@@ -1,6 +1,7 @@
|
|
1
1
|
# Watcher Library
|
2
2
|
require 'listen'
|
3
3
|
require 'middleman-core/contracts'
|
4
|
+
require 'digest'
|
4
5
|
|
5
6
|
# Monkey patch Listen silencer so `only` works on directories too
|
6
7
|
module Listen
|
@@ -48,6 +49,8 @@ module Middleman
|
|
48
49
|
# Reference to lower level listener
|
49
50
|
attr_reader :listener
|
50
51
|
|
52
|
+
IGNORED_DIRECTORIES = %w(.git node_modules .sass-cache).freeze
|
53
|
+
|
51
54
|
# Construct a new SourceWatcher
|
52
55
|
#
|
53
56
|
# @param [Middleman::Sources] parent The parent collection.
|
@@ -65,6 +68,8 @@ module Middleman
|
|
65
68
|
@files = {}
|
66
69
|
@extensionless_files = {}
|
67
70
|
|
71
|
+
@frontmatter = options.fetch(:frontmatter, true)
|
72
|
+
@binary = options.fetch(:binary, false)
|
68
73
|
@validator = options.fetch(:validator, proc { true })
|
69
74
|
@ignored = options.fetch(:ignored, proc { false })
|
70
75
|
@only = Array(options.fetch(:only, []))
|
@@ -177,22 +182,30 @@ module Middleman
|
|
177
182
|
@listener = nil
|
178
183
|
end
|
179
184
|
|
185
|
+
Contract ArrayOf[Pathname]
|
186
|
+
def find_new_files!
|
187
|
+
new_files = ::Middleman::Util.all_files_under(@directory.to_s, &method(:should_not_recurse?))
|
188
|
+
.reject { |p| @files.key?(p) }
|
189
|
+
|
190
|
+
update(new_files, []).flatten.map { |s| s[:full_path] }
|
191
|
+
end
|
192
|
+
|
180
193
|
# Manually trigger update events.
|
181
194
|
#
|
182
195
|
# @return [void]
|
183
196
|
Contract ArrayOf[Pathname]
|
184
197
|
def poll_once!
|
185
|
-
updated = ::Middleman::Util.all_files_under(@directory.to_s)
|
198
|
+
updated = ::Middleman::Util.all_files_under(@directory.to_s, &method(:should_not_recurse?))
|
186
199
|
removed = @files.keys.reject { |p| updated.include?(p) }
|
187
200
|
|
188
|
-
update(updated, removed)
|
201
|
+
result = update(updated, removed)
|
189
202
|
|
190
203
|
if @waiting_for_existence && @directory.exist?
|
191
204
|
@waiting_for_existence = false
|
192
205
|
listen!
|
193
206
|
end
|
194
207
|
|
195
|
-
|
208
|
+
result.flatten.map { |s| s[:full_path] }
|
196
209
|
end
|
197
210
|
|
198
211
|
# Work around this bug: http://bugs.ruby-lang.org/issues/4521
|
@@ -206,6 +219,11 @@ module Middleman
|
|
206
219
|
|
207
220
|
protected
|
208
221
|
|
222
|
+
Contract Pathname => Bool
|
223
|
+
def should_not_recurse?(p)
|
224
|
+
IGNORED_DIRECTORIES.include?(p.basename.to_s)
|
225
|
+
end
|
226
|
+
|
209
227
|
# The `listen` gem callback.
|
210
228
|
#
|
211
229
|
# @param [Array] modified List of modified files.
|
@@ -225,14 +243,14 @@ module Middleman
|
|
225
243
|
#
|
226
244
|
# @param [String, Pathname] path The updated file path.
|
227
245
|
# @return [void]
|
228
|
-
Contract ArrayOf[Pathname], ArrayOf[Pathname] =>
|
246
|
+
Contract ArrayOf[Pathname], ArrayOf[Pathname] => ArrayOf[ArrayOf[IsA['Middleman::SourceFile']]]
|
229
247
|
def update(updated_paths, removed_paths)
|
230
248
|
valid_updates = updated_paths
|
231
|
-
.map { |p|
|
249
|
+
.map { |p| @files[p] || path_to_source_file(p, @directory, @type, @options[:destination_dir]) }
|
232
250
|
.select(&method(:valid?))
|
233
251
|
|
234
252
|
valid_updates.each do |f|
|
235
|
-
|
253
|
+
record_file_change(f)
|
236
254
|
logger.debug "== Change (#{f[:types].inspect}): #{f[:relative_path]}"
|
237
255
|
end
|
238
256
|
|
@@ -245,11 +263,9 @@ module Middleman
|
|
245
263
|
valid_updates |= related_updates
|
246
264
|
|
247
265
|
valid_removes = removed_paths
|
248
|
-
.lazy
|
249
266
|
.select(&@files.method(:key?))
|
250
267
|
.map(&@files.method(:[]))
|
251
268
|
.select(&method(:valid?))
|
252
|
-
.to_a
|
253
269
|
.each do |f|
|
254
270
|
remove_file_from_cache(f)
|
255
271
|
logger.debug "== Deletion (#{f[:types].inspect}): #{f[:relative_path]}"
|
@@ -260,12 +276,34 @@ module Middleman
|
|
260
276
|
valid_removes,
|
261
277
|
self
|
262
278
|
]) unless valid_updates.empty? && valid_removes.empty?
|
279
|
+
|
280
|
+
[valid_updates, valid_removes]
|
281
|
+
end
|
282
|
+
|
283
|
+
# Convert a path to a file resprentation.
|
284
|
+
#
|
285
|
+
# @param [Pathname] path The path.
|
286
|
+
# @return [Middleman::SourceFile]
|
287
|
+
Contract Pathname, Pathname, Symbol, Maybe[String] => ::Middleman::SourceFile
|
288
|
+
def path_to_source_file(path, directory, type, destination_dir)
|
289
|
+
types = Set.new([type])
|
290
|
+
types << :no_frontmatter unless @frontmatter
|
291
|
+
types << :binary if @binary
|
292
|
+
|
293
|
+
relative_path = path.relative_path_from(directory)
|
294
|
+
relative_path = File.join(destination_dir, relative_path) if destination_dir
|
295
|
+
|
296
|
+
::Middleman::SourceFile.new(Pathname(relative_path), path, directory, types, 0)
|
263
297
|
end
|
264
298
|
|
265
299
|
Contract IsA['Middleman::SourceFile'] => Any
|
266
|
-
def
|
267
|
-
@files[f[:full_path]]
|
268
|
-
|
300
|
+
def record_file_change(f)
|
301
|
+
if @files[f[:full_path]]
|
302
|
+
@files[f[:full_path]][:version] += 1
|
303
|
+
else
|
304
|
+
@files[f[:full_path]] = f
|
305
|
+
@extensionless_files[strip_extensions(f[:full_path])] = f
|
306
|
+
end
|
269
307
|
end
|
270
308
|
|
271
309
|
Contract IsA['Middleman::SourceFile'] => Any
|
@@ -291,7 +329,7 @@ module Middleman
|
|
291
329
|
if @only.empty?
|
292
330
|
!@ignored.call(file)
|
293
331
|
else
|
294
|
-
@only.any? { |reg|
|
332
|
+
@only.any? { |reg| file[:relative_path].to_s =~ reg }
|
295
333
|
end
|
296
334
|
end
|
297
335
|
end
|