nanoc 4.11.1 → 4.11.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 81da98fdd728f76e389fc4618fc54a22e98827d40e20320e0102ab7dc4b2b89f
4
- data.tar.gz: c642b86779f1564d1d09a499e4b3e6bbe0d60ebdb5d3c828c05dee3101bf4c08
3
+ metadata.gz: c038b8ba7dfde390ca7151a64421060d91173371c080b1de0e8cf2b44cea073f
4
+ data.tar.gz: aef94fe2c56a0c01506d933fe68497b9e930b8b3b81933f5140dc15b9307b024
5
5
  SHA512:
6
- metadata.gz: '078c89114ddab916b9bf54fcf7f32359d51472351fd9bde7abe1d03e575797b13fa02782e228bb87677d1e74950d187b2afcfd6612b80b37fe9438f37fe65dc5'
7
- data.tar.gz: 8ab157e67fc2172adf8aa910f52937cf92505a42441bc9b54ec2b5d0beae5c880cd0f62472bc0633a0445a7916fdc3cadc208f96a012dffaddbddcb87bbf93b0
6
+ metadata.gz: a9687e4103a49256b1065f92107f0659f204e5b65b975af71f0240f9eb2857086b096081282a3038a25e1595a7af5c18077b44fbe4c6ce0ed388eca142369eae
7
+ data.tar.gz: ed741694c5373b8d8770211695dd7e6a53e2fe393ed1dfd96a6464e2ffd030e754a6c4e7eeb0cc04e0fe26bc09e4395849071967c8d0e0539a91affe01302fa3
data/NEWS.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # Nanoc news
2
2
 
3
+ ## 4.11.2 (2019-02-16)
4
+
5
+ Fixes:
6
+
7
+ * Fixed issue which prevented Sass (not SCSS) files from being imported (#1397, #1407) [Alexander Groß]
8
+
3
9
  ## 4.11.1 (2019-02-09)
4
10
 
5
11
  Fixes:
@@ -98,3 +98,7 @@ Nanoc::Feature.define('live_cmd', version: '4.11')
98
98
  # Tracking issue:
99
99
  # https://github.com/nanoc/features/issues/40
100
100
  Nanoc::Feature.define('toml', version: '4.11')
101
+
102
+ # Tracking issue:
103
+ # https://github.com/nanoc/features/issues/20
104
+ Nanoc::Feature.define('binary_compiled_content_cache', version: '4.11')
@@ -6,6 +6,8 @@ Nanoc::DataSource = Nanoc::Core::DataSource
6
6
  require_relative 'repos/store'
7
7
 
8
8
  require_relative 'repos/checksum_store'
9
+ require_relative 'repos/binary_compiled_content_cache'
10
+ require_relative 'repos/textual_compiled_content_cache'
9
11
  require_relative 'repos/compiled_content_cache'
10
12
  require_relative 'repos/config_loader'
11
13
  require_relative 'repos/dependency_store'
@@ -0,0 +1,128 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Nanoc
4
+ module Int
5
+ # Represents a cache than can be used to store already compiled content,
6
+ # to prevent it from being needlessly recompiled.
7
+ #
8
+ # @api private
9
+ class BinaryCompiledContentCache < ::Nanoc::Int::Store
10
+ include Nanoc::Core::ContractsSupport
11
+
12
+ contract C::KeywordArgs[config: Nanoc::Core::Configuration] => C::Any
13
+ def initialize(config:)
14
+ super(Nanoc::Int::Store.tmp_path_for(config: config, store_name: 'binary_content'), 1)
15
+
16
+ @cache = {}
17
+ end
18
+
19
+ contract Nanoc::Core::ItemRep => C::Maybe[C::HashOf[Symbol => Nanoc::Core::Content]]
20
+ # Returns the cached compiled content for the given item representation.
21
+ #
22
+ # This cached compiled content is a hash where the keys are the snapshot
23
+ # names, and the values the compiled content at the given snapshot.
24
+ def [](rep)
25
+ item_cache = @cache[rep.item.identifier] || {}
26
+
27
+ rep_cache = item_cache[rep.name]
28
+ return nil if rep_cache.nil?
29
+
30
+ rep_cache.transform_values do |filename|
31
+ Nanoc::Core::Content.create(filename, binary: true)
32
+ end
33
+ end
34
+
35
+ contract Nanoc::Core::ItemRep => C::Bool
36
+ def include?(rep)
37
+ item_cache = @cache[rep.item.identifier] || {}
38
+ item_cache.key?(rep.name)
39
+ end
40
+
41
+ contract Nanoc::Core::ItemRep, C::HashOf[Symbol => Nanoc::Core::BinaryContent] => C::HashOf[Symbol => Nanoc::Core::Content]
42
+ # Sets the compiled content for the given representation.
43
+ #
44
+ # This cached compiled content is a hash where the keys are the snapshot
45
+ # names, and the values the compiled content at the given snapshot.
46
+ def []=(rep, content)
47
+ @cache[rep.item.identifier] ||= {}
48
+ @cache[rep.item.identifier][rep.name] ||= {}
49
+ rep_cache = @cache[rep.item.identifier][rep.name]
50
+
51
+ content.each do |snapshot, binary_content|
52
+ filename = build_filename(rep, snapshot)
53
+ rep_cache[snapshot] = filename
54
+
55
+ # Avoid reassigning the same content if this binary cached content was
56
+ # already used, because it was available and the item wasn’t oudated.
57
+ next if binary_content.filename == filename
58
+
59
+ # Copy
60
+ #
61
+ # NOTE: hardlinking is not an option in this case, because hardlinking
62
+ # would make it possible for the content to be (inadvertently)
63
+ # changed outside of Nanoc.
64
+ FileUtils.mkdir_p(File.dirname(filename))
65
+ FileUtils.cp(binary_content.filename, filename)
66
+ end
67
+ end
68
+
69
+ def prune(items:)
70
+ item_identifiers = Set.new(items.map(&:identifier))
71
+
72
+ @cache.each_key do |key|
73
+ # TODO: remove unused item reps
74
+ next if item_identifiers.include?(key)
75
+
76
+ @cache.delete(key)
77
+ path = dirname_for_item_identifier(key)
78
+ FileUtils.rm_rf(path)
79
+ end
80
+ end
81
+
82
+ def data
83
+ @cache
84
+ end
85
+
86
+ def data=(new_data)
87
+ @cache = {}
88
+
89
+ new_data.each_pair do |item_identifier, content_per_rep|
90
+ @cache[item_identifier] ||= content_per_rep
91
+ end
92
+ end
93
+
94
+ private
95
+
96
+ def dirname
97
+ filename + '_data'
98
+ end
99
+
100
+ def string_to_path_component(string)
101
+ string.gsub(/[^a-zA-Z0-9]+/, '_') +
102
+ '-' +
103
+ Digest::SHA1.hexdigest(string)[0..9]
104
+ end
105
+
106
+ def dirname_for_item_identifier(item_identifier)
107
+ File.join(
108
+ dirname,
109
+ string_to_path_component(item_identifier.to_s),
110
+ )
111
+ end
112
+
113
+ def dirname_for_item_rep(rep)
114
+ File.join(
115
+ dirname_for_item_identifier(rep.item.identifier),
116
+ string_to_path_component(rep.name.to_s),
117
+ )
118
+ end
119
+
120
+ def build_filename(rep, snapshot_name)
121
+ File.join(
122
+ dirname_for_item_rep(rep),
123
+ string_to_path_component(snapshot_name.to_s),
124
+ )
125
+ end
126
+ end
127
+ end
128
+ end
@@ -11,9 +11,10 @@ module Nanoc
11
11
 
12
12
  contract C::KeywordArgs[config: Nanoc::Core::Configuration] => C::Any
13
13
  def initialize(config:)
14
- super(Nanoc::Int::Store.tmp_path_for(config: config, store_name: 'compiled_content'), 2)
14
+ @textual_cache = Nanoc::Int::TextualCompiledContentCache.new(config: config)
15
+ @binary_cache = Nanoc::Int::BinaryCompiledContentCache.new(config: config)
15
16
 
16
- @cache = {}
17
+ @wrapped_caches = [@textual_cache, @binary_cache]
17
18
  end
18
19
 
19
20
  contract Nanoc::Core::ItemRep => C::Maybe[C::HashOf[Symbol => Nanoc::Core::Content]]
@@ -22,40 +23,45 @@ module Nanoc
22
23
  # This cached compiled content is a hash where the keys are the snapshot
23
24
  # names. and the values the compiled content at the given snapshot.
24
25
  def [](rep)
25
- item_cache = @cache[rep.item.identifier] || {}
26
- item_cache[rep.name]
26
+ textual_content_map = @textual_cache[rep]
27
+ binary_content_map = @binary_cache[rep]
28
+
29
+ # If either the textual or the binary content cache is nil, assume the
30
+ # cache is entirely absent.
31
+ #
32
+ # This is necessary to support the case where only textual content is
33
+ # cached (which was the case in older versions of Nanoc).
34
+ return nil if [textual_content_map, binary_content_map].any?(&:nil?)
35
+
36
+ textual_content_map.merge(binary_content_map)
27
37
  end
28
38
 
29
- contract Nanoc::Core::ItemRep, C::HashOf[Symbol => Nanoc::Core::Content] => C::HashOf[Symbol => Nanoc::Core::Content]
39
+ contract Nanoc::Core::ItemRep, C::HashOf[Symbol => Nanoc::Core::Content] => C::Any
30
40
  # Sets the compiled content for the given representation.
31
41
  #
32
42
  # This cached compiled content is a hash where the keys are the snapshot
33
- # names. and the values the compiled content at the given snapshot.
43
+ # names and the values the compiled content at the given snapshot.
34
44
  def []=(rep, content)
35
- @cache[rep.item.identifier] ||= {}
36
- @cache[rep.item.identifier][rep.name] = content
45
+ @textual_cache[rep] = content.select { |_key, c| c.textual? }
46
+ @binary_cache[rep] = content.select { |_key, c| c.binary? }
37
47
  end
38
48
 
39
- def prune(items:)
40
- item_identifiers = Set.new(items.map(&:identifier))
41
-
42
- @cache.keys.each do |key|
43
- @cache.delete(key) unless item_identifiers.include?(key)
44
- end
49
+ def prune(*args)
50
+ @wrapped_caches.each { |w| w.prune(*args) }
45
51
  end
46
52
 
47
- protected
48
-
49
- def data
50
- @cache
53
+ # True if there is cached compiled content available for this item, and
54
+ # all entries are present (either textual or binary).
55
+ def full_cache_available?(rep)
56
+ @textual_cache.include?(rep) && @binary_cache.include?(rep)
51
57
  end
52
58
 
53
- def data=(new_data)
54
- @cache = {}
59
+ def load(*args)
60
+ @wrapped_caches.each { |w| w.load(*args) }
61
+ end
55
62
 
56
- new_data.each_pair do |item_identifier, content_per_rep|
57
- @cache[item_identifier] ||= content_per_rep
58
- end
63
+ def store(*args)
64
+ @wrapped_caches.each { |w| w.store(*args) }
59
65
  end
60
66
  end
61
67
  end
@@ -0,0 +1,82 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Nanoc
4
+ module Int
5
+ # Represents a cache than can be used to store already compiled content,
6
+ # to prevent it from being needlessly recompiled.
7
+ #
8
+ # @api private
9
+ class TextualCompiledContentCache < ::Nanoc::Int::Store
10
+ include Nanoc::Core::ContractsSupport
11
+
12
+ contract C::KeywordArgs[config: Nanoc::Core::Configuration] => C::Any
13
+ def initialize(config:)
14
+ super(Nanoc::Int::Store.tmp_path_for(config: config, store_name: 'compiled_content'), 2)
15
+
16
+ @cache = {}
17
+ end
18
+
19
+ contract Nanoc::Core::ItemRep => C::Maybe[C::HashOf[Symbol => Nanoc::Core::Content]]
20
+ # Returns the cached compiled content for the given item representation.
21
+ #
22
+ # This cached compiled content is a hash where the keys are the snapshot
23
+ # names, and the values the compiled content at the given snapshot.
24
+ def [](rep)
25
+ item_cache = @cache[rep.item.identifier] || {}
26
+ item_cache[rep.name]
27
+ end
28
+
29
+ contract Nanoc::Core::ItemRep => C::Bool
30
+ def include?(rep)
31
+ item_cache = @cache[rep.item.identifier] || {}
32
+ item_cache.key?(rep.name)
33
+ end
34
+
35
+ contract Nanoc::Core::ItemRep, C::HashOf[Symbol => Nanoc::Core::Content] => C::Any
36
+ # Sets the compiled content for the given representation.
37
+ #
38
+ # This cached compiled content is a hash where the keys are the snapshot
39
+ # names, and the values the compiled content at the given snapshot.
40
+ def []=(rep, content)
41
+ # FIXME: once the binary content cache is properly enabled (no longer
42
+ # behind a feature flag), change contract to be TextualContent, rather
43
+ # than Content.
44
+
45
+ @cache[rep.item.identifier] ||= {}
46
+ @cache[rep.item.identifier][rep.name] = content
47
+ end
48
+
49
+ def prune(items:)
50
+ item_identifiers = Set.new(items.map(&:identifier))
51
+
52
+ @cache.each_key do |key|
53
+ # TODO: remove unused item reps
54
+ next if item_identifiers.include?(key)
55
+
56
+ @cache.delete(key)
57
+ end
58
+ end
59
+
60
+ # True if there is cached compiled content available for this item, and
61
+ # all entries are textual.
62
+ def full_cache_available?(rep)
63
+ cache = self[rep]
64
+ cache ? cache.none? { |_snapshot_name, content| content.binary? } : false
65
+ end
66
+
67
+ protected
68
+
69
+ def data
70
+ @cache
71
+ end
72
+
73
+ def data=(new_data)
74
+ @cache = {}
75
+
76
+ new_data.each_pair do |item_identifier, content_per_rep|
77
+ @cache[item_identifier] ||= content_per_rep
78
+ end
79
+ end
80
+ end
81
+ end
82
+ end
@@ -35,8 +35,7 @@ module Nanoc
35
35
  if is_outdated
36
36
  false
37
37
  else
38
- cache = @compiled_content_cache[rep]
39
- cache ? cache.none? { |_snapshot_name, content| content.binary? } : false
38
+ @compiled_content_cache.full_cache_available?(rep)
40
39
  end
41
40
  end
42
41
  end
@@ -21,7 +21,7 @@ module Nanoc
21
21
  Nanoc::Int::OutdatednessStore.new(config: site.config)
22
22
 
23
23
  compiled_content_cache =
24
- Nanoc::Int::CompiledContentCache.new(config: site.config)
24
+ compiled_content_cache_class.new(config: site.config)
25
25
 
26
26
  params = {
27
27
  compiled_content_cache: compiled_content_cache,
@@ -34,6 +34,15 @@ module Nanoc
34
34
 
35
35
  Nanoc::Int::Compiler.new(site, params)
36
36
  end
37
+
38
+ def compiled_content_cache_class
39
+ feature_name = Nanoc::Feature::BINARY_COMPILED_CONTENT_CACHE
40
+ if Nanoc::Feature.enabled?(feature_name)
41
+ Nanoc::Int::CompiledContentCache
42
+ else
43
+ Nanoc::Int::TextualCompiledContentCache
44
+ end
45
+ end
37
46
  end
38
47
  end
39
48
  end
@@ -8,7 +8,7 @@ module Nanoc
8
8
 
9
9
  def compiled_content(snapshot: nil)
10
10
  compilation_context = @context.compilation_context
11
- snapshot_contents = compilation_context.compiled_content_cache[_unwrap]
11
+ snapshot_contents = compilation_context.compiled_content_cache[_unwrap] || {}
12
12
 
13
13
  snapshot_name = snapshot || (snapshot_contents[:pre] ? :pre : :last)
14
14
 
@@ -36,13 +36,9 @@ module Nanoc::Filters::SassCommon
36
36
  items = filter.items.find_all(identifier)
37
37
  return if items.empty?
38
38
 
39
- content = if items.size == 1
40
- items.first.compiled_content
41
- else
42
- items.map { |item| %(@import "#{item.identifier}";) }.join("\n")
43
- end
39
+ content, syntax = import(items)
44
40
 
45
- options[:syntax] = :scss
41
+ options[:syntax] = syntax
46
42
  options[:filename] = identifier.to_s
47
43
  options[:importer] = self
48
44
  ::Sass::Engine.new(content, options)
@@ -85,5 +81,37 @@ module Nanoc::Filters::SassCommon
85
81
  map = self.class.raw_filename_to_item_map_for_config(filter.config, filter.items)
86
82
  map[realpath]
87
83
  end
84
+
85
+ private
86
+
87
+ def import(items)
88
+ if items.size == 1
89
+ import_single(items.first)
90
+ else
91
+ import_all(items)
92
+ end
93
+ end
94
+
95
+ def import_single(item)
96
+ syntax = if (ext = item.identifier.ext).nil?
97
+ nil
98
+ else
99
+ ext.downcase.to_sym
100
+ end
101
+
102
+ [
103
+ item.compiled_content,
104
+ syntax,
105
+ ]
106
+ end
107
+
108
+ def import_all(items)
109
+ import_all = items.map { |i| %(@import "#{i.identifier}";) }.join("\n")
110
+
111
+ [
112
+ import_all,
113
+ :scss,
114
+ ]
115
+ end
88
116
  end
89
117
  end
@@ -2,5 +2,5 @@
2
2
 
3
3
  module Nanoc
4
4
  # The current Nanoc version.
5
- VERSION = '4.11.1'
5
+ VERSION = '4.11.2'
6
6
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: nanoc
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.11.1
4
+ version: 4.11.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Denis Defreyne
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-02-09 00:00:00.000000000 Z
11
+ date: 2019-02-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: addressable
@@ -44,14 +44,14 @@ dependencies:
44
44
  requirements:
45
45
  - - '='
46
46
  - !ruby/object:Gem::Version
47
- version: 4.11.1
47
+ version: 4.11.2
48
48
  type: :runtime
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
52
  - - '='
53
53
  - !ruby/object:Gem::Version
54
- version: 4.11.1
54
+ version: 4.11.2
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: parallel
57
57
  requirement: !ruby/object:Gem::Requirement
@@ -126,6 +126,7 @@ files:
126
126
  - lib/nanoc/base/repos.rb
127
127
  - lib/nanoc/base/repos/action_sequence_store.rb
128
128
  - lib/nanoc/base/repos/aggregate_data_source.rb
129
+ - lib/nanoc/base/repos/binary_compiled_content_cache.rb
129
130
  - lib/nanoc/base/repos/checksum_store.rb
130
131
  - lib/nanoc/base/repos/compiled_content_cache.rb
131
132
  - lib/nanoc/base/repos/compiled_content_store.rb
@@ -137,6 +138,7 @@ files:
137
138
  - lib/nanoc/base/repos/prefixed_data_source.rb
138
139
  - lib/nanoc/base/repos/site_loader.rb
139
140
  - lib/nanoc/base/repos/store.rb
141
+ - lib/nanoc/base/repos/textual_compiled_content_cache.rb
140
142
  - lib/nanoc/base/services.rb
141
143
  - lib/nanoc/base/services/action_provider.rb
142
144
  - lib/nanoc/base/services/action_sequence_builder.rb