middleman-core-with-external-sources-watch-fix 4.1.0 → 4.1.10

Sign up to get free protection for your applications and to get access to all the features.
Files changed (130) hide show
  1. checksums.yaml +4 -4
  2. data/features/asset_hash.feature +47 -10
  3. data/features/builder.feature +8 -4
  4. data/features/collections.feature +27 -0
  5. data/features/custom_layouts.feature +17 -1
  6. data/features/dynamic_pages.feature +15 -12
  7. data/features/front-matter-neighbor.feature +6 -2
  8. data/features/helpers_link_to.feature +11 -1
  9. data/features/i18n_link_to.feature +34 -34
  10. data/features/markdown_redcarpet_in_slim.feature +41 -0
  11. data/features/page-id.feature +26 -0
  12. data/features/partials.feature +17 -5
  13. data/features/relative_assets.feature +1 -1
  14. data/features/relative_assets_helpers_only.feature +123 -0
  15. data/features/sass_in_slim.feature +40 -0
  16. data/features/template-key-collision.feature +26 -0
  17. data/fixtures/asset-hash-minified-app/source/images/100px.jpg +0 -0
  18. data/fixtures/asset-hash-minified-app/source/stylesheets/test.css +3 -0
  19. data/fixtures/asset-hash-prefix/config.rb +7 -0
  20. data/fixtures/asset-hash-prefix/lib/middleware.rb +16 -0
  21. data/fixtures/asset-hash-prefix/source/index.html.erb +6 -0
  22. data/fixtures/asset-hash-prefix/source/javascripts/application.js +2 -0
  23. data/fixtures/asset-hash-prefix/source/javascripts/application.js.map +1 -0
  24. data/fixtures/asset-hash-prefix/source/layout.erb +17 -0
  25. data/fixtures/asset-hash-source-map/config.rb +6 -0
  26. data/fixtures/asset-hash-source-map/lib/middleware.rb +16 -0
  27. data/fixtures/asset-hash-source-map/source/index.html.erb +6 -0
  28. data/fixtures/asset-hash-source-map/source/javascripts/application.js +2 -0
  29. data/fixtures/asset-hash-source-map/source/javascripts/application.js.map +1 -0
  30. data/fixtures/asset-hash-source-map/source/layout.erb +17 -0
  31. data/fixtures/asset-host-app/source/images/blank0.gif +0 -0
  32. data/fixtures/asset-host-app/source/images/blank1.gif +0 -0
  33. data/fixtures/asset-host-app/source/images/blank10.gif +0 -0
  34. data/fixtures/asset-host-app/source/images/blank100.gif +0 -0
  35. data/fixtures/asset-host-app/source/images/blank101.gif +0 -0
  36. data/fixtures/asset-host-app/source/images/blank1010.gif +0 -0
  37. data/fixtures/asset-host-app/source/images/blank102.gif +0 -0
  38. data/fixtures/asset-host-app/source/images/blank1020.gif +0 -0
  39. data/fixtures/asset-host-app/source/images/blank1021.gif +0 -0
  40. data/fixtures/asset-host-app/source/images/blank1022.gif +0 -0
  41. data/fixtures/asset-host-app/source/images/blank1023.gif +0 -0
  42. data/fixtures/asset-host-app/source/images/blank1024.gif +0 -0
  43. data/fixtures/asset-host-app/source/images/blank103.gif +0 -0
  44. data/fixtures/asset-host-app/source/images/blank1030.gif +0 -0
  45. data/fixtures/asset-host-app/source/images/blank1031.gif +0 -0
  46. data/fixtures/asset-host-app/source/images/blank1032.gif +0 -0
  47. data/fixtures/asset-host-app/source/images/blank1033.gif +0 -0
  48. data/fixtures/asset-host-app/source/images/blank1034.gif +0 -0
  49. data/fixtures/asset-host-app/source/images/blank104.gif +0 -0
  50. data/fixtures/asset-host-app/source/images/blank1043.gif +0 -0
  51. data/fixtures/asset-host-app/source/images/blank1054.gif +0 -0
  52. data/fixtures/asset-host-app/source/images/blank2.gif +0 -0
  53. data/fixtures/asset-host-app/source/images/blank20.gif +0 -0
  54. data/fixtures/asset-host-app/source/images/blank21.gif +0 -0
  55. data/fixtures/asset-host-app/source/images/blank22.gif +0 -0
  56. data/fixtures/asset-host-app/source/images/blank23.gif +0 -0
  57. data/fixtures/asset-host-app/source/images/blank24.gif +0 -0
  58. data/fixtures/asset-host-app/source/images/blank3.gif +0 -0
  59. data/fixtures/asset-host-app/source/images/blank30.gif +0 -0
  60. data/fixtures/asset-host-app/source/images/blank31.gif +0 -0
  61. data/fixtures/asset-host-app/source/images/blank32.gif +0 -0
  62. data/fixtures/asset-host-app/source/images/blank33.gif +0 -0
  63. data/fixtures/asset-host-app/source/images/blank34.gif +0 -0
  64. data/fixtures/asset-host-app/source/images/blank4.gif +0 -0
  65. data/fixtures/asset-host-app/source/images/blank43.gif +0 -0
  66. data/fixtures/asset-host-app/source/images/blank54.gif +0 -0
  67. data/fixtures/dynamic-pages-app/config.rb +4 -0
  68. data/fixtures/dynamic-pages-app/source/should_be_ignored9.html +1 -0
  69. data/fixtures/external-pipeline-error/config.rb +5 -0
  70. data/fixtures/external-pipeline-error/source/javascripts/file.js +0 -0
  71. data/fixtures/page-id-app/config.rb +5 -0
  72. data/fixtures/page-id-app/source/fm.html.erb +5 -0
  73. data/fixtures/page-id-app/source/index.html.erb +6 -0
  74. data/fixtures/page-id-app/source/overwrites/from-default.html.erb +1 -0
  75. data/fixtures/page-id-app/source/overwrites/from-frontmatter.html.erb +5 -0
  76. data/fixtures/partials-app/source/_block.erb +3 -0
  77. data/fixtures/partials-app/source/block.html.erb +3 -0
  78. data/fixtures/partials-app/source/index_missing.html.erb +3 -0
  79. data/fixtures/relative-assets-app/source/images/blank2.gif +0 -0
  80. data/fixtures/sass-in-slim-app/config.rb +0 -0
  81. data/lib/middleman-core/application.rb +30 -4
  82. data/lib/middleman-core/builder.rb +8 -2
  83. data/lib/middleman-core/config_context.rb +5 -1
  84. data/lib/middleman-core/configuration.rb +1 -1
  85. data/lib/middleman-core/core_extensions/collections.rb +28 -17
  86. data/lib/middleman-core/core_extensions/collections/step_context.rb +14 -7
  87. data/lib/middleman-core/core_extensions/data.rb +4 -2
  88. data/lib/middleman-core/core_extensions/default_helpers.rb +1 -0
  89. data/lib/middleman-core/core_extensions/front_matter.rb +8 -6
  90. data/lib/middleman-core/core_extensions/i18n.rb +3 -1
  91. data/lib/middleman-core/core_extensions/inline_url_rewriter.rb +20 -35
  92. data/lib/middleman-core/core_extensions/routing.rb +6 -3
  93. data/lib/middleman-core/extension.rb +41 -6
  94. data/lib/middleman-core/extensions.rb +2 -2
  95. data/lib/middleman-core/extensions/asset_hash.rb +10 -5
  96. data/lib/middleman-core/extensions/asset_host.rb +4 -3
  97. data/lib/middleman-core/extensions/cache_buster.rb +2 -2
  98. data/lib/middleman-core/extensions/directory_indexes.rb +8 -2
  99. data/lib/middleman-core/extensions/external_pipeline.rb +54 -8
  100. data/lib/middleman-core/extensions/minify_css.rb +9 -1
  101. data/lib/middleman-core/extensions/minify_javascript.rb +8 -0
  102. data/lib/middleman-core/extensions/relative_assets.rb +38 -13
  103. data/lib/middleman-core/file_renderer.rb +4 -4
  104. data/lib/middleman-core/load_paths.rb +3 -1
  105. data/lib/middleman-core/logger.rb +1 -1
  106. data/lib/middleman-core/meta_pages/templates/index.html.erb +3 -1
  107. data/lib/middleman-core/preview_server.rb +25 -18
  108. data/lib/middleman-core/rack.rb +2 -0
  109. data/lib/middleman-core/renderers/redcarpet.rb +2 -2
  110. data/lib/middleman-core/renderers/sass_functions.rb +4 -6
  111. data/lib/middleman-core/renderers/slim.rb +1 -5
  112. data/lib/middleman-core/sitemap/extensions/import.rb +2 -2
  113. data/lib/middleman-core/sitemap/extensions/proxies.rb +4 -1
  114. data/lib/middleman-core/sitemap/extensions/redirects.rb +1 -2
  115. data/lib/middleman-core/sitemap/resource.rb +15 -5
  116. data/lib/middleman-core/sitemap/store.rb +33 -2
  117. data/lib/middleman-core/sources.rb +2 -1
  118. data/lib/middleman-core/sources/source_watcher.rb +17 -6
  119. data/lib/middleman-core/template_context.rb +26 -21
  120. data/lib/middleman-core/template_renderer.rb +22 -9
  121. data/lib/middleman-core/util/binary.rb +4 -5
  122. data/lib/middleman-core/util/data.rb +33 -18
  123. data/lib/middleman-core/util/files.rb +27 -24
  124. data/lib/middleman-core/util/paths.rb +74 -14
  125. data/lib/middleman-core/util/rack.rb +16 -6
  126. data/lib/middleman-core/version.rb +1 -1
  127. data/middleman-core.gemspec +11 -8
  128. data/spec/middleman-core/core_extensions/data_spec.rb +107 -1
  129. data/spec/middleman-core/util_spec.rb +37 -0
  130. metadata +196 -18
@@ -102,7 +102,7 @@ class Middleman::CoreExtensions::Internationalization < ::Middleman::Extension
102
102
  locale_suffix = ::I18n.locale
103
103
 
104
104
  extname = File.extname(partial_name)
105
- maybe_static = extname.length > 0
105
+ maybe_static = !extname.empty?
106
106
  suffixed_partial_name = if maybe_static
107
107
  partial_name.sub(extname, ".#{locale_suffix}#{extname}")
108
108
  else
@@ -213,6 +213,8 @@ class Middleman::CoreExtensions::Internationalization < ::Middleman::Extension
213
213
  def on_file_changed(_updated_files, _removed_files)
214
214
  ::I18n.load_path |= app.files.by_type(:locales).files.map { |p| p[:full_path].to_s }
215
215
  ::I18n.reload!
216
+
217
+ @app.sitemap.rebuild_resource_list!(:touched_locale_file)
216
218
  end
217
219
 
218
220
  def configure_i18n
@@ -1,6 +1,6 @@
1
1
  require 'rack'
2
2
  require 'rack/response'
3
- require 'addressable/uri'
3
+ require 'memoist'
4
4
  require 'middleman-core/util'
5
5
  require 'middleman-core/contracts'
6
6
 
@@ -11,13 +11,12 @@ module Middleman
11
11
 
12
12
  expose_to_application rewrite_inline_urls: :add
13
13
 
14
- IGNORE_DESCRIPTOR = Or[Regexp, RespondTo[:call], String]
15
14
  REWRITER_DESCRIPTOR = {
16
15
  id: Symbol,
17
16
  proc: Or[Proc, Method],
18
17
  url_extensions: ArrayOf[String],
19
18
  source_extensions: ArrayOf[String],
20
- ignore: ArrayOf[IGNORE_DESCRIPTOR],
19
+ ignore: ArrayOf[::Middleman::Util::IGNORE_DESCRIPTOR],
21
20
  after: Maybe[Symbol]
22
21
  }.freeze
23
22
 
@@ -33,6 +32,8 @@ module Middleman
33
32
  end
34
33
 
35
34
  def after_configuration
35
+ return if @rewriters.empty?
36
+
36
37
  rewriters = @rewriters.values.sort do |a, b|
37
38
  if b[:after] && b[:after] == a[:id]
38
39
  1
@@ -45,6 +46,7 @@ module Middleman
45
46
  end
46
47
 
47
48
  class Rack
49
+ extend Memoist
48
50
  include Contracts
49
51
 
50
52
  Contract RespondTo[:call], {
@@ -55,6 +57,17 @@ module Middleman
55
57
  @rack_app = app
56
58
  @middleman_app = options.fetch(:middleman_app)
57
59
  @rewriters = options.fetch(:rewriters)
60
+
61
+ all_source_exts = @rewriters
62
+ .reduce([]) { |sum, rewriter| sum + rewriter[:source_extensions] }
63
+ .flatten
64
+ .uniq
65
+ @source_exts_regex_text = Regexp.union(all_source_exts).to_s
66
+
67
+ @all_asset_exts = @rewriters
68
+ .reduce([]) { |sum, rewriter| sum + rewriter[:url_extensions] }
69
+ .flatten
70
+ .uniq
58
71
  end
59
72
 
60
73
  def call(env)
@@ -63,27 +76,16 @@ module Middleman
63
76
  # Allow configuration or upstream request to skip all rewriting
64
77
  return [status, headers, response] if env['bypass_inline_url_rewriter'] == 'true'
65
78
 
66
- all_source_exts = @rewriters
67
- .reduce([]) { |sum, rewriter| sum + rewriter[:source_extensions] }
68
- .flatten
69
- .uniq
70
- source_exts_regex_text = Regexp.union(all_source_exts).to_s
71
-
72
- all_asset_exts = @rewriters
73
- .reduce([]) { |sum, rewriter| sum + rewriter[:url_extensions] }
74
- .flatten
75
- .uniq
76
-
77
79
  path = ::Middleman::Util.full_path(env['PATH_INFO'], @middleman_app)
78
80
 
79
- return [status, headers, response] unless path =~ /(^\/$)|(#{source_exts_regex_text}$)/
81
+ return [status, headers, response] unless path =~ /(^\/$)|(#{@source_exts_regex_text}$)/
80
82
  return [status, headers, response] unless body = ::Middleman::Util.extract_response_text(response)
81
83
 
82
84
  dirpath = ::Pathname.new(File.dirname(path))
83
85
 
84
86
  rewritten = ::Middleman::Util.instrument 'inline_url_rewriter', path: path do
85
- ::Middleman::Util.rewrite_paths(body, path, all_asset_exts) do |asset_path|
86
- uri = ::Addressable::URI.parse(asset_path)
87
+ ::Middleman::Util.rewrite_paths(body, path, @all_asset_exts, @middleman_app) do |asset_path|
88
+ uri = ::Middleman::Util.parse_uri(asset_path)
87
89
 
88
90
  relative_path = uri.host.nil?
89
91
 
@@ -106,7 +108,7 @@ module Middleman
106
108
  next unless source_exts.include?(::File.extname(path))
107
109
 
108
110
  ignore = rewriter.fetch(:ignore)
109
- next if ignore.any? { |r| should_ignore?(r, full_asset_path) }
111
+ next if ignore.any? { |r| ::Middleman::Util.should_ignore?(r, full_asset_path) }
110
112
 
111
113
  rewrite_ignore = Array(rewriter[:rewrite_ignore] || [])
112
114
  next if rewrite_ignore.any? { |i| ::Middleman::Util.path_match(i, path) }
@@ -127,23 +129,6 @@ module Middleman
127
129
  headers
128
130
  ).finish
129
131
  end
130
-
131
- Contract IGNORE_DESCRIPTOR, String => Bool
132
- def should_ignore?(validator, value)
133
- if validator.is_a? Regexp
134
- # Treat as Regexp
135
- !!(value =~ validator)
136
- elsif validator.respond_to? :call
137
- # Treat as proc
138
- validator.call(value)
139
- elsif validator.is_a? String
140
- # Treat as glob
141
- File.fnmatch(value, validator)
142
- else
143
- # If some unknown thing, don't ignore
144
- false
145
- end
146
- end
147
132
  end
148
133
  end
149
134
  end
@@ -4,7 +4,7 @@ module Middleman
4
4
  class Routing < ConfigExtension
5
5
  # This should always run late, but not as late as :directory_indexes,
6
6
  # so it can add metadata to any pages generated by other extensions
7
- self.resource_list_manipulator_priority = 10
7
+ self.resource_list_manipulator_priority = [10, 130]
8
8
 
9
9
  # Expose the `page` method to config.
10
10
  expose_to_config :page
@@ -25,7 +25,7 @@ module Middleman
25
25
 
26
26
  resources
27
27
  .select { |r| ::Middleman::Util.path_match(normalized_path, "/#{r.path}") }
28
- .each { |r| r.add_metadata(metadata) }
28
+ .each { |r| r.add_metadata(metadata, true) }
29
29
 
30
30
  resources
31
31
  end
@@ -52,10 +52,13 @@ module Middleman
52
52
  def page(path, opts={})
53
53
  options = opts.dup
54
54
 
55
+ page_data = options.delete(:data) || {}
56
+ page_data[:id] = options.delete(:id) if options.key?(:id)
57
+
55
58
  # Default layout
56
59
  metadata = {
57
60
  locals: options.delete(:locals) || {},
58
- page: options.delete(:data) || {},
61
+ page: page_data,
59
62
  options: options
60
63
  }
61
64
 
@@ -1,4 +1,5 @@
1
1
  require 'forwardable'
2
+ require 'memoist'
2
3
  require 'active_support/core_ext/class/attribute'
3
4
  require 'middleman-core/configuration'
4
5
  require 'middleman-core/contracts'
@@ -66,6 +67,8 @@ module Middleman
66
67
  # @see http://middlemanapp.com/advanced/custom/ Middleman Custom Extensions Documentation
67
68
  class Extension
68
69
  extend Forwardable
70
+ extend Memoist
71
+
69
72
  include Contracts
70
73
 
71
74
  def_delegator :@app, :logger
@@ -402,11 +405,11 @@ module Middleman
402
405
  ext.after_configuration if ext.respond_to?(:after_configuration)
403
406
 
404
407
  if ext.respond_to?(:manipulate_resource_list)
405
- ext.app.sitemap.register_resource_list_manipulator(ext.class.ext_name, ext, ext.class.resource_list_manipulator_priority)
408
+ ext.app.sitemap.register_resource_list_manipulators(ext.class.ext_name, ext, ext.class.resource_list_manipulator_priority)
406
409
  end
407
410
 
408
411
  if ext.class.resources_generators && !ext.class.resources_generators.empty?
409
- ext.app.sitemap.register_resource_list_manipulator(
412
+ ext.app.sitemap.register_resource_list_manipulators(
410
413
  :"#{ext.class.ext_name}_generator",
411
414
  ext,
412
415
  ext.class.resource_list_manipulator_priority,
@@ -490,15 +493,14 @@ module Middleman
490
493
  class ConfigExtension < Extension
491
494
  def initialize(app, config={}, &block)
492
495
  @descriptors = {}
493
- @wrapped = {}
496
+ @ready = false
494
497
 
495
498
  self.class.exposed_to_config.each do |k, v|
496
499
  @descriptors[k] = []
497
500
 
498
501
  define_singleton_method(:"__original_#{v}", &method(v))
499
502
  define_singleton_method(v) do |*args, &b|
500
- @descriptors[k] << method(:"__original_#{v}").call(*args, &b)
501
- @app.sitemap.rebuild_resource_list!(:"first_run_change_#{v}")
503
+ proxy_method_call(k, v, args, &b)
502
504
  end
503
505
  end
504
506
 
@@ -506,11 +508,24 @@ module Middleman
506
508
  end
507
509
 
508
510
  def after_configuration
511
+ context = self
512
+
509
513
  self.class.exposed_to_config.each do |k, v|
510
- ::Middleman::CoreExtensions::Collections::StepContext.add_to_context(k, &method(:"__original_#{v}"))
514
+ ::Middleman::CoreExtensions::Collections::StepContext.add_to_context(k) do |*args, &b|
515
+ r = context.method(:"__original_#{v}").call(*args, &b)
516
+ descriptors << r if r.respond_to?(:execute_descriptor)
517
+ end
511
518
  end
512
519
  end
513
520
 
521
+ def ready
522
+ @ready = true
523
+
524
+ # @descriptors.each do |k, v|
525
+ # @descriptors[k] = []
526
+ # end
527
+ end
528
+
514
529
  # Update the main sitemap resource list
515
530
  # @return Array<Middleman::Sitemap::Resource>
516
531
  Contract ResourceList => ResourceList
@@ -519,5 +534,25 @@ module Middleman
519
534
  c.execute_descriptor(app, sum)
520
535
  end
521
536
  end
537
+
538
+ Contract Symbol, Symbol, ArrayOf[Any], Maybe[Proc] => Any
539
+ def proxy_method_call(k, v, args, &b)
540
+ if @ready
541
+ ctx = ::Middleman::CoreExtensions::Collections::StepContext.current
542
+ r = method(:"__original_#{v}").call(*args, &b)
543
+
544
+ if r.respond_to?(:execute_descriptor)
545
+ if ctx
546
+ ctx.descriptors << r
547
+ else
548
+ @descriptors[k] << r
549
+ @app.sitemap.rebuild_resource_list!(:"first_run_change_#{v}")
550
+ end
551
+ end
552
+ else
553
+ @descriptors[k] << method(:"__original_#{v}").call(*args, &b)
554
+ @app.sitemap.rebuild_resource_list!(:"first_run_change_#{v}")
555
+ end
556
+ end
522
557
  end
523
558
  end
@@ -52,7 +52,7 @@ module Middleman
52
52
  def register(name, extension_class=nil, options={}, &block)
53
53
  raise 'Extension name must be a symbol' unless name.is_a?(Symbol)
54
54
  # If we've already got an extension registered under this name, bail out
55
- raise "There is already an extension registered with the name '#{name}'" if registered.key?(name)
55
+ # raise "There is a already an extension registered with the name '#{name}'" if registered.key?(name)
56
56
 
57
57
  # If the extension is defined with a block, grab options out of the "extension_class" parameter.
58
58
  if extension_class && block_given? && options.empty? && extension_class.is_a?(Hash)
@@ -106,7 +106,7 @@ module Middleman
106
106
  # A flattened list of all extensions which are automatically activated
107
107
  # @return [Array<Symbol>] A list of extension names which are automatically activated.
108
108
  def auto_activated
109
- @auto_activate.values.map(&:to_a).flat_map(&:name)
109
+ @auto_activate.values.map(&:to_a).flatten.map(&:name)
110
110
  end
111
111
 
112
112
  # @api private
@@ -3,9 +3,10 @@ require 'middleman-core/rack'
3
3
 
4
4
  class Middleman::Extensions::AssetHash < ::Middleman::Extension
5
5
  option :sources, %w(.css .htm .html .js .php .xhtml), 'List of extensions that are searched for hashable assets.'
6
- option :exts, %w(.jpg .jpeg .png .gif .webp .js .css .otf .woff .woff2 .eot .ttf .svg .svgz), 'List of extensions that get asset hashes appended to them.'
6
+ option :exts, nil, 'List of extensions that get asset hashes appended to them.'
7
7
  option :ignore, [], 'Regexes of filenames to skip adding asset hashes to'
8
8
  option :rewrite_ignore, [], 'Regexes of filenames to skip processing for path rewrites'
9
+ option :prefix, '', 'Prefix for hash'
9
10
 
10
11
  def initialize(app, options_hash={}, &block)
11
12
  super
@@ -17,8 +18,12 @@ class Middleman::Extensions::AssetHash < ::Middleman::Extension
17
18
  # Allow specifying regexes to ignore, plus always ignore apple touch icons
18
19
  @ignore = Array(options.ignore) + [/^apple-touch-icon/]
19
20
 
21
+ # Exclude .ico from the default list because browsers expect it
22
+ # to be named "favicon.ico"
23
+ @exts = options.exts || (app.config[:asset_extensions] - %w(.ico))
24
+
20
25
  app.rewrite_inline_urls id: :asset_hash,
21
- url_extensions: options.exts.sort.reverse,
26
+ url_extensions: @exts.sort.reverse,
22
27
  source_extensions: options.sources,
23
28
  ignore: @ignore,
24
29
  rewrite_ignore: options.rewrite_ignore,
@@ -28,7 +33,7 @@ class Middleman::Extensions::AssetHash < ::Middleman::Extension
28
33
 
29
34
  Contract String, Or[String, Pathname], Any => Maybe[String]
30
35
  def rewrite_url(asset_path, dirpath, _request_path)
31
- uri = ::Addressable::URI.parse(asset_path)
36
+ uri = ::Middleman::Util.parse_uri(asset_path)
32
37
  relative_path = !uri.path.start_with?('/')
33
38
 
34
39
  full_asset_path = if relative_path
@@ -70,7 +75,7 @@ class Middleman::Extensions::AssetHash < ::Middleman::Extension
70
75
 
71
76
  Contract IsA['Middleman::Sitemap::Resource'] => Maybe[IsA['Middleman::Sitemap::Resource']]
72
77
  def manipulate_single_resource(resource)
73
- return unless options.exts.include?(resource.ext)
78
+ return unless @exts.include?(resource.ext)
74
79
  return if ignored_resource?(resource)
75
80
  return if resource.ignored?
76
81
 
@@ -88,7 +93,7 @@ class Middleman::Extensions::AssetHash < ::Middleman::Extension
88
93
  ::Digest::SHA1.hexdigest(response.body)[0..7]
89
94
  end
90
95
 
91
- resource.destination_path = resource.destination_path.sub(/\.(\w+)$/) { |ext| "-#{digest}#{ext}" }
96
+ resource.destination_path = resource.destination_path.sub(/\.(\w+)$/) { |ext| "-#{options.prefix}#{digest}#{ext}" }
92
97
  resource
93
98
  end
94
99
 
@@ -2,7 +2,7 @@ require 'addressable/uri'
2
2
 
3
3
  class Middleman::Extensions::AssetHost < ::Middleman::Extension
4
4
  option :host, nil, 'The asset host to use or a Proc to determine asset host', required: true
5
- option :exts, %w(.css .png .jpg .jpeg .webp .svg .svgz .js .gif), 'List of extensions that get cache busters strings appended to them.'
5
+ option :exts, nil, 'List of extensions that get cache busters strings appended to them.'
6
6
  option :sources, %w(.css .htm .html .js .php .xhtml), 'List of extensions that are searched for bustable 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 host rewrites'
@@ -11,7 +11,7 @@ class Middleman::Extensions::AssetHost < ::Middleman::Extension
11
11
  super
12
12
 
13
13
  app.rewrite_inline_urls id: :asset_host,
14
- url_extensions: options.exts,
14
+ url_extensions: options.exts || app.config[:asset_extensions],
15
15
  source_extensions: options.sources,
16
16
  ignore: options.ignore,
17
17
  rewrite_ignore: options.rewrite_ignore,
@@ -20,7 +20,7 @@ class Middleman::Extensions::AssetHost < ::Middleman::Extension
20
20
 
21
21
  Contract String, Or[String, Pathname], Any => String
22
22
  def rewrite_url(asset_path, dirpath, _request_path)
23
- uri = ::Addressable::URI.parse(asset_path)
23
+ uri = ::Middleman::Util.parse_uri(asset_path)
24
24
  relative_path = uri.path[0..0] != '/'
25
25
 
26
26
  full_asset_path = if relative_path
@@ -37,4 +37,5 @@ class Middleman::Extensions::AssetHost < ::Middleman::Extension
37
37
 
38
38
  File.join(asset_prefix, full_asset_path)
39
39
  end
40
+ memoize :rewrite_url
40
41
  end
@@ -1,6 +1,6 @@
1
1
  # The Cache Buster extension
2
2
  class Middleman::Extensions::CacheBuster < ::Middleman::Extension
3
- option :exts, %w(.css .png .jpg .jpeg .webp .svg .svgz .js .gif), 'List of extensions that get cache busters strings appended to them.'
3
+ option :exts, nil, 'List of extensions that get cache busters strings appended to them.'
4
4
  option :sources, %w(.css .htm .html .js .php .xhtml), 'List of extensions that are searched for bustable assets.'
5
5
  option :ignore, [], 'Regexes of filenames to skip adding query strings to'
6
6
  option :rewrite_ignore, [], 'Regexes of filenames to skip processing for path rewrites'
@@ -9,7 +9,7 @@ class Middleman::Extensions::CacheBuster < ::Middleman::Extension
9
9
  super
10
10
 
11
11
  app.rewrite_inline_urls id: :cache_buster,
12
- url_extensions: options.exts,
12
+ url_extensions: options.exts || app.config[:asset_extensions],
13
13
  source_extensions: options.sources,
14
14
  ignore: options.ignore,
15
15
  rewrite_ignore: options.rewrite_ignore,
@@ -11,16 +11,22 @@ class Middleman::Extensions::DirectoryIndexes < ::Middleman::Extension
11
11
  index_file = app.config[:index_file]
12
12
  new_index_path = "/#{index_file}"
13
13
 
14
+ extensions = %w(.htm .html .php .xhtml)
15
+
14
16
  resources.each do |resource|
15
17
  # Check if it would be pointless to reroute
16
18
  next if resource.destination_path == index_file ||
17
19
  resource.destination_path.end_with?(new_index_path) ||
18
- File.extname(index_file) != resource.ext
20
+ !extensions.include?(resource.ext)
19
21
 
20
22
  # Check if file metadata (options set by "page" in config.rb or frontmatter) turns directory_index off
21
23
  next if resource.options[:directory_index] == false
22
24
 
23
- resource.destination_path = resource.destination_path.chomp(File.extname(index_file)) + new_index_path
25
+ extensions.each do |ext|
26
+ resource.destination_path = resource.destination_path.chomp(ext)
27
+ end
28
+
29
+ resource.destination_path += new_index_path
24
30
  end
25
31
  end
26
32
  end
@@ -10,33 +10,79 @@ class Middleman::Extensions::ExternalPipeline < ::Middleman::Extension
10
10
  def initialize(app, config={}, &block)
11
11
  super
12
12
 
13
+ return if app.mode?(:config)
14
+
15
+ require 'servolux'
13
16
  require 'thread'
17
+ require 'fileutils'
18
+
19
+ source_path = File.expand_path(options[:source], app.root)
20
+
21
+ # Make sure it exists, or `listen` will explode.
22
+ ::FileUtils.mkdir_p(source_path)
14
23
 
15
24
  @watcher = app.files.watch :source,
16
- path: File.expand_path(options[:source], app.root),
25
+ path: source_path,
17
26
  latency: options[:latency],
18
27
  frontmatter: false
19
28
 
29
+ @current_thread = nil
30
+ app.reload(&method(:reload!))
31
+
20
32
  logger.info "== Executing: `#{options[:command]}`"
21
33
 
22
34
  if app.build? || options[:disable_background_execution]
23
- watch_command!
35
+ watch_command!(false)
36
+
37
+ @watcher.poll_once!
24
38
  else
25
- ::Thread.new { watch_command! }
39
+ watch_command!(true)
40
+ end
41
+ end
42
+
43
+ def reload!
44
+ if @current_thread
45
+ logger.info "== Stopping: `#{options[:command]}`"
46
+
47
+ @current_thread.stop
48
+ @current_thread = nil
26
49
  end
27
50
  end
28
51
 
29
- def watch_command!
30
- ::IO.popen(options[:command], 'r') do |pipe|
31
- while buf = pipe.gets
52
+ def watch_command!(async)
53
+ @current_thread = ::Servolux::Child.new(
54
+ command: options[:command],
55
+ suspend: 2
56
+ )
57
+
58
+ @current_thread.start
59
+
60
+ watch_thread = Thread.new do
61
+ while buf = @current_thread.io.gets
32
62
  without_newline = buf.sub(/\n$/, '')
33
- logger.info "== External: #{without_newline}" if without_newline.length > 0
63
+ logger.info "== External: #{without_newline}" unless without_newline.empty?
64
+ end
65
+
66
+ @current_thread.wait
67
+
68
+ if !@current_thread.exitstatus.nil? && @current_thread.exitstatus != 0
69
+ logger.error '== External: Command failed with non-zero exit status'
70
+ exit(1)
34
71
  end
35
72
  end
36
73
 
37
- @watcher.poll_once!
74
+ watch_thread.join unless async
38
75
  rescue ::Errno::ENOENT => e
39
76
  logger.error "== External: Command failed with message: #{e.message}"
40
77
  exit(1)
41
78
  end
79
+
80
+ private
81
+
82
+ def print_command(stdout)
83
+ while buf = stdout.gets
84
+ without_newline = buf.sub(/\n$/, '')
85
+ logger.info "== External: #{without_newline}" unless without_newline.empty?
86
+ end
87
+ end
42
88
  end