nanoc 4.11.1 → 4.11.2

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 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