nanoc-core 4.11.12 → 4.11.13
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/nanoc/core.rb +37 -0
- data/lib/nanoc/core/basic_item_rep_collection_view.rb +88 -0
- data/lib/nanoc/core/basic_item_rep_view.rb +83 -0
- data/lib/nanoc/core/basic_item_view.rb +54 -0
- data/lib/nanoc/core/checksummer.rb +2 -0
- data/lib/nanoc/core/compilation_item_rep_collection_view.rb +12 -0
- data/lib/nanoc/core/compilation_item_rep_view.rb +51 -0
- data/lib/nanoc/core/compilation_item_view.rb +47 -0
- data/lib/nanoc/core/compilation_phases/abstract.rb +48 -0
- data/lib/nanoc/core/compilation_phases/cache.rb +43 -0
- data/lib/nanoc/core/compilation_phases/mark_done.rb +23 -0
- data/lib/nanoc/core/compilation_phases/notify.rb +19 -0
- data/lib/nanoc/core/compilation_phases/recalculate.rb +49 -0
- data/lib/nanoc/core/compilation_phases/resume.rb +52 -0
- data/lib/nanoc/core/compilation_phases/write.rb +84 -0
- data/lib/nanoc/core/compilation_stages/build_reps.rb +36 -0
- data/lib/nanoc/core/compilation_stages/calculate_checksums.rb +42 -0
- data/lib/nanoc/core/compilation_stages/cleanup.rb +43 -0
- data/lib/nanoc/core/compilation_stages/compile_reps.rb +96 -0
- data/lib/nanoc/core/compilation_stages/determine_outdatedness.rb +49 -0
- data/lib/nanoc/core/compilation_stages/forget_outdated_dependencies.rb +20 -0
- data/lib/nanoc/core/compilation_stages/load_stores.rb +35 -0
- data/lib/nanoc/core/compilation_stages/postprocess.rb +21 -0
- data/lib/nanoc/core/compilation_stages/preprocess.rb +32 -0
- data/lib/nanoc/core/compilation_stages/prune.rb +30 -0
- data/lib/nanoc/core/compilation_stages/store_post_compilation_state.rb +20 -0
- data/lib/nanoc/core/compilation_stages/store_pre_compilation_state.rb +32 -0
- data/lib/nanoc/core/compiler.rb +214 -0
- data/lib/nanoc/core/compiler_loader.rb +48 -0
- data/lib/nanoc/core/config_loader.rb +95 -0
- data/lib/nanoc/core/config_view.rb +67 -0
- data/lib/nanoc/core/configuration.rb +2 -4
- data/lib/nanoc/core/document_view_mixin.rb +87 -0
- data/lib/nanoc/core/errors.rb +97 -0
- data/lib/nanoc/core/executor.rb +134 -0
- data/lib/nanoc/core/feature.rb +92 -0
- data/lib/nanoc/core/filter.rb +269 -0
- data/lib/nanoc/core/identifiable_collection_view.rb +111 -0
- data/lib/nanoc/core/item_collection_with_reps_view.rb +12 -0
- data/lib/nanoc/core/item_collection_without_reps_view.rb +12 -0
- data/lib/nanoc/core/item_rep_builder.rb +54 -0
- data/lib/nanoc/core/item_rep_selector.rb +67 -0
- data/lib/nanoc/core/item_rep_writer.rb +85 -0
- data/lib/nanoc/core/layout_collection_view.rb +12 -0
- data/lib/nanoc/core/layout_view.rb +9 -0
- data/lib/nanoc/core/mutable_config_view.rb +16 -0
- data/lib/nanoc/core/mutable_document_view_mixin.rb +60 -0
- data/lib/nanoc/core/mutable_identifiable_collection_view.rb +19 -0
- data/lib/nanoc/core/mutable_item_collection_view.rb +34 -0
- data/lib/nanoc/core/mutable_item_view.rb +9 -0
- data/lib/nanoc/core/mutable_layout_collection_view.rb +26 -0
- data/lib/nanoc/core/mutable_layout_view.rb +9 -0
- data/lib/nanoc/core/outdatedness_checker.rb +222 -0
- data/lib/nanoc/core/outdatedness_rules/attributes_modified.rb +41 -0
- data/lib/nanoc/core/outdatedness_rules/code_snippets_modified.rb +31 -0
- data/lib/nanoc/core/outdatedness_rules/content_modified.rb +21 -0
- data/lib/nanoc/core/outdatedness_rules/item_collection_extended.rb +20 -0
- data/lib/nanoc/core/outdatedness_rules/layout_collection_extended.rb +20 -0
- data/lib/nanoc/core/outdatedness_rules/not_written.rb +17 -0
- data/lib/nanoc/core/outdatedness_rules/rules_modified.rb +45 -0
- data/lib/nanoc/core/outdatedness_rules/uses_always_outdated_filter.rb +26 -0
- data/lib/nanoc/core/post_compile_item_collection_view.rb +12 -0
- data/lib/nanoc/core/post_compile_item_rep_collection_view.rb +12 -0
- data/lib/nanoc/core/post_compile_item_rep_view.rb +33 -0
- data/lib/nanoc/core/post_compile_item_view.rb +20 -0
- data/lib/nanoc/core/pruner.rb +119 -0
- data/lib/nanoc/core/site_loader.rb +102 -0
- data/lib/nanoc/core/trivial_error.rb +10 -0
- data/lib/nanoc/core/version.rb +1 -1
- data/lib/nanoc/core/view.rb +43 -0
- data/lib/nanoc/core/view_context_for_compilation.rb +6 -6
- metadata +95 -2
@@ -0,0 +1,48 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Nanoc
|
4
|
+
module Core
|
5
|
+
# @api private
|
6
|
+
class CompilerLoader
|
7
|
+
def load(site, action_provider: nil)
|
8
|
+
action_sequence_store = Nanoc::Core::ActionSequenceStore.new(config: site.config)
|
9
|
+
|
10
|
+
dependency_store =
|
11
|
+
Nanoc::Core::DependencyStore.new(site.items, site.layouts, site.config)
|
12
|
+
|
13
|
+
objects = site.items.to_a + site.layouts.to_a + site.code_snippets + [site.config]
|
14
|
+
|
15
|
+
checksum_store =
|
16
|
+
Nanoc::Core::ChecksumStore.new(config: site.config, objects: objects)
|
17
|
+
|
18
|
+
action_provider ||= Nanoc::Core::ActionProvider.named(site.config.action_provider).for(site)
|
19
|
+
|
20
|
+
outdatedness_store =
|
21
|
+
Nanoc::Core::OutdatednessStore.new(config: site.config)
|
22
|
+
|
23
|
+
compiled_content_cache =
|
24
|
+
compiled_content_cache_class.new(config: site.config)
|
25
|
+
|
26
|
+
params = {
|
27
|
+
compiled_content_cache: compiled_content_cache,
|
28
|
+
checksum_store: checksum_store,
|
29
|
+
action_sequence_store: action_sequence_store,
|
30
|
+
dependency_store: dependency_store,
|
31
|
+
action_provider: action_provider,
|
32
|
+
outdatedness_store: outdatedness_store,
|
33
|
+
}
|
34
|
+
|
35
|
+
Nanoc::Core::Compiler.new(site, params)
|
36
|
+
end
|
37
|
+
|
38
|
+
def compiled_content_cache_class
|
39
|
+
feature_name = Nanoc::Core::Feature::BINARY_COMPILED_CONTENT_CACHE
|
40
|
+
if Nanoc::Core::Feature.enabled?(feature_name)
|
41
|
+
Nanoc::Core::CompiledContentCache
|
42
|
+
else
|
43
|
+
Nanoc::Core::TextualCompiledContentCache
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,95 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Nanoc
|
4
|
+
module Core
|
5
|
+
# @api private
|
6
|
+
class ConfigLoader
|
7
|
+
class NoConfigFileFoundError < ::Nanoc::Core::Error
|
8
|
+
def initialize
|
9
|
+
super('No configuration file found')
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
class NoParentConfigFileFoundError < ::Nanoc::Core::Error
|
14
|
+
def initialize(filename)
|
15
|
+
super("There is no parent configuration file at #{filename}")
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
class CyclicalConfigFileError < ::Nanoc::Core::Error
|
20
|
+
def initialize(filename)
|
21
|
+
super("The parent configuration file at #{filename} includes one of its descendants")
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
# @return [Boolean]
|
26
|
+
def self.cwd_is_nanoc_site?
|
27
|
+
!config_filename_for_cwd.nil?
|
28
|
+
end
|
29
|
+
|
30
|
+
# @return [String]
|
31
|
+
def self.config_filename_for_cwd
|
32
|
+
filenames =
|
33
|
+
if Nanoc::Core::Feature.enabled?(Nanoc::Core::Feature::TOML)
|
34
|
+
%w[nanoc.yaml config.yaml nanoc.toml]
|
35
|
+
else
|
36
|
+
%w[nanoc.yaml config.yaml]
|
37
|
+
end
|
38
|
+
candidate = filenames.find { |f| File.file?(f) }
|
39
|
+
candidate && File.expand_path(candidate)
|
40
|
+
end
|
41
|
+
|
42
|
+
def new_from_cwd
|
43
|
+
# Determine path
|
44
|
+
filename = self.class.config_filename_for_cwd
|
45
|
+
raise NoConfigFileFoundError if filename.nil?
|
46
|
+
|
47
|
+
# Read
|
48
|
+
config =
|
49
|
+
apply_parent_config(
|
50
|
+
Nanoc::Core::Configuration.new(
|
51
|
+
hash: load_file(filename),
|
52
|
+
dir: File.dirname(filename),
|
53
|
+
),
|
54
|
+
[filename],
|
55
|
+
).with_defaults
|
56
|
+
|
57
|
+
# Load environment
|
58
|
+
config.with_environment
|
59
|
+
end
|
60
|
+
|
61
|
+
def load_file(filename)
|
62
|
+
case File.extname(filename)
|
63
|
+
when '.yaml'
|
64
|
+
YAML.load_file(filename)
|
65
|
+
when '.toml'
|
66
|
+
Tomlrb.load_file(filename)
|
67
|
+
else
|
68
|
+
raise Nanoc::Core::Errors::InternalInconsistency, 'Unhandled config file extension'
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
# @api private
|
73
|
+
def apply_parent_config(config, processed_paths = [])
|
74
|
+
parent_path = config[:parent_config_file]
|
75
|
+
return config if parent_path.nil?
|
76
|
+
|
77
|
+
# Get absolute path
|
78
|
+
parent_path = File.absolute_path(parent_path, File.dirname(processed_paths.last))
|
79
|
+
unless File.file?(parent_path)
|
80
|
+
raise NoParentConfigFileFoundError.new(parent_path)
|
81
|
+
end
|
82
|
+
|
83
|
+
# Check recursion
|
84
|
+
if processed_paths.include?(parent_path)
|
85
|
+
raise CyclicalConfigFileError.new(parent_path)
|
86
|
+
end
|
87
|
+
|
88
|
+
# Load
|
89
|
+
parent_config = Nanoc::Core::Configuration.new(hash: load_file(parent_path), dir: config.dir)
|
90
|
+
full_parent_config = apply_parent_config(parent_config, processed_paths + [parent_path])
|
91
|
+
full_parent_config.merge(config.without(:parent_config_file))
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Nanoc
|
4
|
+
module Core
|
5
|
+
class ConfigView < ::Nanoc::Core::View
|
6
|
+
# @api private
|
7
|
+
def initialize(config, context)
|
8
|
+
super(context)
|
9
|
+
@config = config
|
10
|
+
end
|
11
|
+
|
12
|
+
# @api private
|
13
|
+
def _unwrap
|
14
|
+
@config
|
15
|
+
end
|
16
|
+
|
17
|
+
# @api private
|
18
|
+
def output_dir
|
19
|
+
@config.output_dir
|
20
|
+
end
|
21
|
+
|
22
|
+
# @see Hash#fetch
|
23
|
+
def fetch(key, fallback = Nanoc::Core::UNDEFINED, &_block)
|
24
|
+
@context.dependency_tracker.bounce(_unwrap, attributes: [key])
|
25
|
+
@config.fetch(key) do
|
26
|
+
if !Nanoc::Core::UNDEFINED.equal?(fallback)
|
27
|
+
fallback
|
28
|
+
elsif block_given?
|
29
|
+
yield(key)
|
30
|
+
else
|
31
|
+
raise KeyError, "key not found: #{key.inspect}"
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
# @see Hash#key?
|
37
|
+
def key?(key)
|
38
|
+
@context.dependency_tracker.bounce(_unwrap, attributes: [key])
|
39
|
+
@config.key?(key)
|
40
|
+
end
|
41
|
+
|
42
|
+
# @see Hash#[]
|
43
|
+
def [](key)
|
44
|
+
@context.dependency_tracker.bounce(_unwrap, attributes: [key])
|
45
|
+
@config[key]
|
46
|
+
end
|
47
|
+
|
48
|
+
# @see Hash#each
|
49
|
+
def each(&block)
|
50
|
+
@context.dependency_tracker.bounce(_unwrap, attributes: true)
|
51
|
+
@config.each(&block)
|
52
|
+
end
|
53
|
+
|
54
|
+
# @see Configuration#env_name
|
55
|
+
def env_name
|
56
|
+
@context.dependency_tracker.bounce(_unwrap, attributes: true)
|
57
|
+
@config.env_name
|
58
|
+
end
|
59
|
+
|
60
|
+
# @see Hash#dig
|
61
|
+
def dig(*keys)
|
62
|
+
@context.dependency_tracker.bounce(_unwrap, attributes: keys.take(1))
|
63
|
+
@config.dig(*keys)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -6,8 +6,6 @@ module Nanoc
|
|
6
6
|
class Configuration
|
7
7
|
include Nanoc::Core::ContractsSupport
|
8
8
|
|
9
|
-
NONE = Object.new.freeze
|
10
|
-
|
11
9
|
# The default configuration for a data source. A data source's
|
12
10
|
# configuration overrides these options.
|
13
11
|
DEFAULT_DATA_SOURCE_CONFIG = {
|
@@ -104,9 +102,9 @@ module Nanoc
|
|
104
102
|
end
|
105
103
|
|
106
104
|
contract C::Any, C::Maybe[C::Any], C::Maybe[C::Func[C::None => C::Any]] => C::Any
|
107
|
-
def fetch(key, fallback =
|
105
|
+
def fetch(key, fallback = Nanoc::Core::UNDEFINED, &_block)
|
108
106
|
@wrapped.fetch(key) do
|
109
|
-
if !
|
107
|
+
if !Nanoc::Core::UNDEFINED.equal?(fallback)
|
110
108
|
fallback
|
111
109
|
elsif block_given?
|
112
110
|
yield(key)
|
@@ -0,0 +1,87 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Nanoc
|
4
|
+
module Core
|
5
|
+
module DocumentViewMixin
|
6
|
+
# @api private
|
7
|
+
def initialize(document, context)
|
8
|
+
super(context)
|
9
|
+
@document = document
|
10
|
+
end
|
11
|
+
|
12
|
+
# @api private
|
13
|
+
def _unwrap
|
14
|
+
@document
|
15
|
+
end
|
16
|
+
|
17
|
+
# @see Object#==
|
18
|
+
def ==(other)
|
19
|
+
other.respond_to?(:identifier) && identifier == other.identifier
|
20
|
+
end
|
21
|
+
|
22
|
+
# @see Object#eql?
|
23
|
+
def eql?(other)
|
24
|
+
other.is_a?(self.class) && identifier.eql?(other.identifier)
|
25
|
+
end
|
26
|
+
|
27
|
+
# @see Object#hash
|
28
|
+
def hash
|
29
|
+
self.class.hash ^ identifier.hash
|
30
|
+
end
|
31
|
+
|
32
|
+
# @return [Nanoc::Core::Identifier]
|
33
|
+
def identifier
|
34
|
+
_unwrap.identifier
|
35
|
+
end
|
36
|
+
|
37
|
+
# @see Hash#[]
|
38
|
+
def [](key)
|
39
|
+
@context.dependency_tracker.bounce(_unwrap, attributes: [key])
|
40
|
+
_unwrap.attributes[key]
|
41
|
+
end
|
42
|
+
|
43
|
+
# @return [Hash]
|
44
|
+
def attributes
|
45
|
+
# TODO: Refine dependencies
|
46
|
+
@context.dependency_tracker.bounce(_unwrap, attributes: true)
|
47
|
+
_unwrap.attributes
|
48
|
+
end
|
49
|
+
|
50
|
+
# @see Hash#fetch
|
51
|
+
def fetch(key, fallback = Nanoc::Core::UNDEFINED, &_block)
|
52
|
+
@context.dependency_tracker.bounce(_unwrap, attributes: [key])
|
53
|
+
|
54
|
+
if _unwrap.attributes.key?(key)
|
55
|
+
_unwrap.attributes[key]
|
56
|
+
elsif !Nanoc::Core::UNDEFINED.equal?(fallback)
|
57
|
+
fallback
|
58
|
+
elsif block_given?
|
59
|
+
yield(key)
|
60
|
+
else
|
61
|
+
raise KeyError, "key not found: #{key.inspect}"
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
# @see Hash#key?
|
66
|
+
def key?(key)
|
67
|
+
@context.dependency_tracker.bounce(_unwrap, attributes: [key])
|
68
|
+
_unwrap.attributes.key?(key)
|
69
|
+
end
|
70
|
+
|
71
|
+
# @api private
|
72
|
+
def reference
|
73
|
+
_unwrap.reference
|
74
|
+
end
|
75
|
+
|
76
|
+
# @api private
|
77
|
+
def raw_content
|
78
|
+
@context.dependency_tracker.bounce(_unwrap, raw_content: true)
|
79
|
+
_unwrap.content.string
|
80
|
+
end
|
81
|
+
|
82
|
+
def inspect
|
83
|
+
"<#{self.class} identifier=#{_unwrap.identifier}>"
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
data/lib/nanoc/core/errors.rb
CHANGED
@@ -24,6 +24,31 @@ module Nanoc
|
|
24
24
|
end
|
25
25
|
end
|
26
26
|
|
27
|
+
# Error that is raised when compilation of an item rep fails. The
|
28
|
+
# underlying error is available by calling `#unwrap`.
|
29
|
+
class CompilationError < ::Nanoc::Core::Error
|
30
|
+
attr_reader :item_rep
|
31
|
+
|
32
|
+
def initialize(wrapped, item_rep)
|
33
|
+
@wrapped = wrapped
|
34
|
+
@item_rep = item_rep
|
35
|
+
end
|
36
|
+
|
37
|
+
def unwrap
|
38
|
+
@wrapped
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
# Error that is raised when a site is loaded that uses a data source with
|
43
|
+
# an unknown identifier.
|
44
|
+
class UnknownDataSource < ::Nanoc::Core::Error
|
45
|
+
# @param [String] data_source_name The data source name for which no
|
46
|
+
# data source could be found
|
47
|
+
def initialize(data_source_name)
|
48
|
+
super("The data source specified in the site’s configuration file, “#{data_source_name}”, does not exist.")
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
27
52
|
# Error that is raised when an rep cannot be compiled because it depends
|
28
53
|
# on other representations.
|
29
54
|
class UnmetDependency < ::Nanoc::Core::Error
|
@@ -44,6 +69,25 @@ module Nanoc
|
|
44
69
|
end
|
45
70
|
end
|
46
71
|
|
72
|
+
# Error that is raised during site compilation when an item (directly or
|
73
|
+
# indirectly) includes its own item content, leading to endless recursion.
|
74
|
+
class DependencyCycle < ::Nanoc::Core::Error
|
75
|
+
def initialize(stack)
|
76
|
+
start_idx = stack.index(stack.last)
|
77
|
+
cycle = stack[start_idx..-2]
|
78
|
+
|
79
|
+
msg_bits = []
|
80
|
+
msg_bits << 'The site cannot be compiled because there is a dependency cycle:'
|
81
|
+
msg_bits << ''
|
82
|
+
cycle.each.with_index do |r, i|
|
83
|
+
msg_bits << " (#{i + 1}) item #{r.item.identifier}, rep #{r.name.inspect}, uses compiled content of"
|
84
|
+
end
|
85
|
+
msg_bits << msg_bits.pop + ' (1)'
|
86
|
+
|
87
|
+
super(msg_bits.map { |x| x + "\n" }.join(''))
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
47
91
|
# Error that is raised when the compiled content of a binary item is attempted to be accessed.
|
48
92
|
class CannotGetCompiledContentOfBinaryItem < ::Nanoc::Core::Error
|
49
93
|
# @param [Nanoc::Core::ItemRep] rep The binary item representation whose compiled content was attempted to be accessed
|
@@ -51,6 +95,59 @@ module Nanoc
|
|
51
95
|
super("You cannot access the compiled content of a binary item representation (but you can access the path). The offending item rep is #{rep}.")
|
52
96
|
end
|
53
97
|
end
|
98
|
+
|
99
|
+
# Error that is raised when attempting to call #parent or #children on an item with a legacy identifier.
|
100
|
+
class CannotGetParentOrChildrenOfNonLegacyItem < ::Nanoc::Core::Error
|
101
|
+
def initialize(identifier)
|
102
|
+
super("You cannot get the parent or children of an item that has a “full” identifier (#{identifier}). Getting the parent or children of an item is only possible for items that have a legacy identifier.")
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
# Error that is raised during site compilation when an item uses a layout
|
107
|
+
# that is not present in the site.
|
108
|
+
class UnknownLayout < ::Nanoc::Core::Error
|
109
|
+
# @param [String] layout_identifier The layout identifier for which no
|
110
|
+
# layout could be found
|
111
|
+
def initialize(layout_identifier)
|
112
|
+
super("The site does not have a layout with identifier “#{layout_identifier}”.")
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
# Error that is raised when a binary item is attempted to be laid out.
|
117
|
+
class CannotLayoutBinaryItem < ::Nanoc::Core::Error
|
118
|
+
# @param [Nanoc::Core::ItemRep] rep The item representation that was attempted
|
119
|
+
# to be laid out
|
120
|
+
def initialize(rep)
|
121
|
+
super("The “#{rep.item.identifier}” item (rep “#{rep.name}”) cannot be laid out because it is a binary item. If you are getting this error for an item that should be textual instead of binary, make sure that its extension is included in the text_extensions array in the site configuration.")
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
# Error that is raised when a textual filter is attempted to be applied to
|
126
|
+
# a binary item representation.
|
127
|
+
class CannotUseTextualFilter < ::Nanoc::Core::Error
|
128
|
+
# @param [Nanoc::Core::ItemRep] rep The item representation that was
|
129
|
+
# attempted to be filtered
|
130
|
+
#
|
131
|
+
# @param [Class] filter_class The filter class that was used
|
132
|
+
def initialize(rep, filter_class)
|
133
|
+
super("The “#{filter_class.inspect}” filter cannot be used to filter the “#{rep.item.identifier}” item (rep “#{rep.name}”), because textual filters cannot be used on binary items.")
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
# Error that is raised when a binary filter is attempted to be applied to
|
138
|
+
# a textual item representation.
|
139
|
+
class CannotUseBinaryFilter < ::Nanoc::Core::Error
|
140
|
+
# @param [Nanoc::Core::ItemRep] rep The item representation that was
|
141
|
+
# attempted to be filtered
|
142
|
+
#
|
143
|
+
# @param [Class] filter_class The filter class that was used
|
144
|
+
def initialize(rep, filter_class)
|
145
|
+
super("The “#{filter_class.inspect}” filter cannot be used to filter the “#{rep.item.identifier}” item (rep “#{rep.name}”), because binary filters cannot be used on textual items. If you are getting this error for an item that should be textual instead of binary, make sure that its extension is included in the text_extensions array in the site configuration.")
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
class InternalInconsistency < ::Nanoc::Core::Error
|
150
|
+
end
|
54
151
|
end
|
55
152
|
end
|
56
153
|
end
|
@@ -0,0 +1,134 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Nanoc
|
4
|
+
module Core
|
5
|
+
class Executor
|
6
|
+
def initialize(rep, compilation_context, dependency_tracker)
|
7
|
+
@rep = rep
|
8
|
+
@compilation_context = compilation_context
|
9
|
+
@dependency_tracker = dependency_tracker
|
10
|
+
end
|
11
|
+
|
12
|
+
def filter(filter_name, filter_args = {})
|
13
|
+
filter = filter_for_filtering(filter_name)
|
14
|
+
|
15
|
+
begin
|
16
|
+
Nanoc::Core::NotificationCenter.post(:filtering_started, @rep, filter_name)
|
17
|
+
|
18
|
+
# Run filter
|
19
|
+
last = @compilation_context.compiled_content_store.get_current(@rep)
|
20
|
+
source = last.binary? ? last.filename : last.string
|
21
|
+
filter_args.freeze
|
22
|
+
result = filter.setup_and_run(source, filter_args)
|
23
|
+
last =
|
24
|
+
if filter.class.to_binary?
|
25
|
+
Nanoc::Core::BinaryContent.new(filter.output_filename).tap(&:freeze)
|
26
|
+
else
|
27
|
+
Nanoc::Core::TextualContent.new(result).tap(&:freeze)
|
28
|
+
end
|
29
|
+
|
30
|
+
# Store
|
31
|
+
@compilation_context.compiled_content_store.set_current(@rep, last)
|
32
|
+
ensure
|
33
|
+
Nanoc::Core::NotificationCenter.post(:filtering_ended, @rep, filter_name)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def layout(layout_identifier, extra_filter_args = nil)
|
38
|
+
layout = find_layout(layout_identifier)
|
39
|
+
filter_name_and_args = @compilation_context.filter_name_and_args_for_layout(layout)
|
40
|
+
filter_name = filter_name_and_args.name
|
41
|
+
if filter_name.nil?
|
42
|
+
raise ::Nanoc::Core::Error, "Cannot find rule for layout matching #{layout_identifier}"
|
43
|
+
end
|
44
|
+
|
45
|
+
filter_args = filter_name_and_args.args
|
46
|
+
filter_args = filter_args.merge(extra_filter_args || {})
|
47
|
+
filter_args.freeze
|
48
|
+
|
49
|
+
# Check whether item can be laid out
|
50
|
+
last = @compilation_context.compiled_content_store.get_current(@rep)
|
51
|
+
raise Nanoc::Core::Errors::CannotLayoutBinaryItem.new(@rep) if last.binary?
|
52
|
+
|
53
|
+
# Create filter
|
54
|
+
klass = Nanoc::Core::Filter.named!(filter_name)
|
55
|
+
layout_view = Nanoc::Core::LayoutView.new(layout, view_context)
|
56
|
+
filter = klass.new(assigns.merge(layout: layout_view))
|
57
|
+
|
58
|
+
# Visit
|
59
|
+
@dependency_tracker.bounce(layout, raw_content: true)
|
60
|
+
|
61
|
+
begin
|
62
|
+
Nanoc::Core::NotificationCenter.post(:filtering_started, @rep, filter_name)
|
63
|
+
|
64
|
+
# Layout
|
65
|
+
content = layout.content
|
66
|
+
arg = content.binary? ? content.filename : content.string
|
67
|
+
res = filter.setup_and_run(arg, filter_args)
|
68
|
+
|
69
|
+
# Store
|
70
|
+
last = Nanoc::Core::TextualContent.new(res).tap(&:freeze)
|
71
|
+
@compilation_context.compiled_content_store.set_current(@rep, last)
|
72
|
+
ensure
|
73
|
+
Nanoc::Core::NotificationCenter.post(:filtering_ended, @rep, filter_name)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def snapshot(snapshot_name)
|
78
|
+
last = @compilation_context.compiled_content_store.get_current(@rep)
|
79
|
+
@compilation_context.compiled_content_store.set(@rep, snapshot_name, last)
|
80
|
+
Nanoc::Core::NotificationCenter.post(:snapshot_created, @rep, snapshot_name)
|
81
|
+
end
|
82
|
+
|
83
|
+
def assigns
|
84
|
+
view_context.assigns_for(@rep, site: @compilation_context.site)
|
85
|
+
end
|
86
|
+
|
87
|
+
def layouts
|
88
|
+
@compilation_context.site.layouts
|
89
|
+
end
|
90
|
+
|
91
|
+
def find_layout(arg)
|
92
|
+
req_id = arg.__nanoc_cleaned_identifier
|
93
|
+
layout = layouts[req_id]
|
94
|
+
return layout if layout
|
95
|
+
|
96
|
+
if use_globs?
|
97
|
+
pat = Nanoc::Core::Pattern.from(arg)
|
98
|
+
layout = layouts.find { |l| pat.match?(l.identifier) }
|
99
|
+
return layout if layout
|
100
|
+
end
|
101
|
+
|
102
|
+
raise Nanoc::Core::Errors::UnknownLayout.new(arg)
|
103
|
+
end
|
104
|
+
|
105
|
+
def filter_for_filtering(filter_name)
|
106
|
+
klass = Nanoc::Core::Filter.named!(filter_name)
|
107
|
+
|
108
|
+
last = @compilation_context.compiled_content_store.get_current(@rep)
|
109
|
+
if klass.from_binary? && !last.binary?
|
110
|
+
raise Nanoc::Core::Errors::CannotUseBinaryFilter.new(@rep, klass)
|
111
|
+
elsif !klass.from_binary? && last.binary?
|
112
|
+
raise Nanoc::Core::Errors::CannotUseTextualFilter.new(@rep, klass)
|
113
|
+
end
|
114
|
+
|
115
|
+
klass.new(assigns)
|
116
|
+
end
|
117
|
+
|
118
|
+
def use_globs?
|
119
|
+
@compilation_context.site.config[:string_pattern_type] == 'glob'
|
120
|
+
end
|
121
|
+
|
122
|
+
def view_context
|
123
|
+
@_view_context ||=
|
124
|
+
Nanoc::Core::ViewContextForCompilation.new(
|
125
|
+
reps: @compilation_context.reps,
|
126
|
+
items: @compilation_context.site.items,
|
127
|
+
dependency_tracker: @dependency_tracker,
|
128
|
+
compilation_context: @compilation_context,
|
129
|
+
compiled_content_store: @compilation_context.compiled_content_store,
|
130
|
+
)
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|