nanoc 4.4.4 → 4.4.5
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/Gemfile +1 -0
- data/Gemfile.lock +9 -8
- data/NEWS.md +10 -0
- data/lib/nanoc/base.rb +0 -3
- data/lib/nanoc/base/contracts_support.rb +55 -2
- data/lib/nanoc/base/core_ext/array.rb +0 -2
- data/lib/nanoc/base/core_ext/hash.rb +0 -2
- data/lib/nanoc/base/entities.rb +1 -0
- data/lib/nanoc/base/entities/context.rb +1 -4
- data/lib/nanoc/base/entities/directed_graph.rb +0 -10
- data/lib/nanoc/base/entities/identifiable_collection.rb +1 -2
- data/lib/nanoc/base/entities/identifier.rb +6 -8
- data/lib/nanoc/base/entities/item_rep.rb +12 -18
- data/lib/nanoc/base/{compilation → entities}/outdatedness_reasons.rb +0 -0
- data/lib/nanoc/base/entities/site.rb +3 -19
- data/lib/nanoc/base/errors.rb +9 -0
- data/lib/nanoc/base/memoization.rb +0 -2
- data/lib/nanoc/base/repos/checksum_store.rb +21 -14
- data/lib/nanoc/base/repos/compiled_content_cache.rb +11 -15
- data/lib/nanoc/base/repos/dependency_store.rb +8 -27
- data/lib/nanoc/base/services.rb +3 -0
- data/lib/nanoc/base/services/compiler.rb +379 -0
- data/lib/nanoc/base/services/compiler_loader.rb +3 -1
- data/lib/nanoc/base/services/executor.rb +27 -41
- data/lib/nanoc/base/services/item_rep_builder.rb +4 -0
- data/lib/nanoc/base/services/item_rep_writer.rb +5 -2
- data/lib/nanoc/base/{compilation → services}/outdatedness_checker.rb +1 -1
- data/lib/nanoc/base/views/post_compile_item_rep_view.rb +1 -1
- data/lib/nanoc/base/views/view_context.rb +3 -3
- data/lib/nanoc/checking/check.rb +1 -1
- data/lib/nanoc/checking/checks/external_links.rb +1 -1
- data/lib/nanoc/cli.rb +0 -4
- data/lib/nanoc/cli/commands/compile.rb +2 -2
- data/lib/nanoc/cli/commands/shell.rb +1 -1
- data/lib/nanoc/data_sources/filesystem.rb +10 -20
- data/lib/nanoc/data_sources/filesystem/errors.rb +55 -0
- data/lib/nanoc/filters/asciidoc.rb +0 -2
- data/lib/nanoc/filters/coffeescript.rb +0 -2
- data/lib/nanoc/filters/colorize_syntax.rb +0 -2
- data/lib/nanoc/filters/handlebars.rb +0 -2
- data/lib/nanoc/filters/mustache.rb +0 -2
- data/lib/nanoc/filters/redcarpet.rb +0 -4
- data/lib/nanoc/filters/slim.rb +0 -2
- data/lib/nanoc/filters/typogruby.rb +0 -2
- data/lib/nanoc/filters/xsl.rb +0 -2
- data/lib/nanoc/filters/yui_compressor.rb +0 -2
- data/lib/nanoc/helpers/capturing.rb +22 -19
- data/lib/nanoc/helpers/link_to.rb +3 -7
- data/lib/nanoc/helpers/rendering.rb +1 -1
- data/lib/nanoc/rule_dsl/action_provider.rb +2 -2
- data/lib/nanoc/rule_dsl/compiler_dsl.rb +0 -2
- data/lib/nanoc/rule_dsl/recording_executor.rb +6 -6
- data/lib/nanoc/rule_dsl/rule.rb +0 -2
- data/lib/nanoc/rule_dsl/rule_context.rb +3 -3
- data/lib/nanoc/rule_dsl/rule_memory_calculator.rb +5 -5
- data/lib/nanoc/spec.rb +1 -1
- data/lib/nanoc/version.rb +1 -1
- data/test/base/test_compiler.rb +3 -1
- data/test/base/test_dependency_tracker.rb +0 -19
- data/test/base/test_item_rep.rb +3 -0
- data/test/cli/commands/test_create_site.rb +1 -1
- data/test/data_sources/test_filesystem.rb +5 -5
- data/test/filters/test_coffeescript.rb +2 -0
- data/test/filters/test_handlebars.rb +4 -0
- data/test/filters/test_uglify_js.rb +4 -0
- data/test/filters/test_xsl.rb +1 -1
- data/test/helper.rb +6 -0
- data/test/helpers/test_capturing.rb +6 -1
- data/test/helpers/test_xml_sitemap.rb +1 -1
- metadata +6 -6
- data/lib/nanoc/base/compilation/compiler.rb +0 -295
- data/test/base/test_checksum_store.rb +0 -28
data/lib/nanoc/base/errors.rb
CHANGED
@@ -207,5 +207,14 @@ module Nanoc::Int
|
|
207
207
|
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.")
|
208
208
|
end
|
209
209
|
end
|
210
|
+
|
211
|
+
class UndefinedFilterForLayout < Generic
|
212
|
+
def initialize(layout)
|
213
|
+
super("There is no filter defined for the layout #{layout.identifier}")
|
214
|
+
end
|
215
|
+
end
|
216
|
+
|
217
|
+
class InternalInconsistency < Generic
|
218
|
+
end
|
210
219
|
end
|
211
220
|
end
|
@@ -6,27 +6,25 @@ module Nanoc::Int
|
|
6
6
|
class ChecksumStore < ::Nanoc::Int::Store
|
7
7
|
include Nanoc::Int::ContractsSupport
|
8
8
|
|
9
|
-
|
10
|
-
|
9
|
+
attr_accessor :objects
|
10
|
+
|
11
|
+
c_obj = C::Or[Nanoc::Int::Item, Nanoc::Int::Layout, Nanoc::Int::Configuration, Nanoc::Int::CodeSnippet]
|
12
|
+
|
13
|
+
contract C::KeywordArgs[site: C::Maybe[Nanoc::Int::Site], objects: C::IterOf[c_obj]] => C::Any
|
14
|
+
def initialize(site: nil, objects:)
|
11
15
|
super(Nanoc::Int::Store.tmp_path_for(env_name: (site.config.env_name if site), store_name: 'checksums'), 1)
|
12
16
|
|
13
|
-
@
|
17
|
+
@objects = objects
|
14
18
|
|
15
19
|
@checksums = {}
|
16
20
|
end
|
17
21
|
|
18
|
-
contract
|
19
|
-
# Returns the old checksum for the given object. This makes sense for
|
20
|
-
# items, layouts and code snippets.
|
21
|
-
#
|
22
|
-
# @param [#reference] obj The object for which to fetch the checksum
|
23
|
-
#
|
24
|
-
# @return [String] The checksum for the given object
|
22
|
+
contract c_obj => C::Maybe[String]
|
25
23
|
def [](obj)
|
26
24
|
@checksums[obj.reference]
|
27
25
|
end
|
28
26
|
|
29
|
-
|
27
|
+
contract c_obj => self
|
30
28
|
def add(obj)
|
31
29
|
if obj.is_a?(Nanoc::Int::Document)
|
32
30
|
@checksums[[obj.reference, :content]] = Nanoc::Int::Checksummer.calc_for_content_of(obj)
|
@@ -34,14 +32,16 @@ module Nanoc::Int
|
|
34
32
|
end
|
35
33
|
|
36
34
|
@checksums[obj.reference] = Nanoc::Int::Checksummer.calc(obj)
|
35
|
+
|
36
|
+
self
|
37
37
|
end
|
38
38
|
|
39
|
-
contract
|
39
|
+
contract c_obj => C::Maybe[String]
|
40
40
|
def content_checksum_for(obj)
|
41
41
|
@checksums[[obj.reference, :content]]
|
42
42
|
end
|
43
43
|
|
44
|
-
contract
|
44
|
+
contract c_obj => C::Maybe[String]
|
45
45
|
def attributes_checksum_for(obj)
|
46
46
|
@checksums[[obj.reference, :attributes]]
|
47
47
|
end
|
@@ -53,7 +53,14 @@ module Nanoc::Int
|
|
53
53
|
end
|
54
54
|
|
55
55
|
def data=(new_data)
|
56
|
-
|
56
|
+
references = Set.new(@objects.map(&:reference))
|
57
|
+
|
58
|
+
@checksums = {}
|
59
|
+
new_data.each_pair do |key, checksum|
|
60
|
+
if references.include?(key) || references.include?(key.first)
|
61
|
+
@checksums[key] = checksum
|
62
|
+
end
|
63
|
+
end
|
57
64
|
end
|
58
65
|
end
|
59
66
|
end
|
@@ -4,6 +4,9 @@ module Nanoc::Int
|
|
4
4
|
#
|
5
5
|
# @api private
|
6
6
|
class CompiledContentCache < ::Nanoc::Int::Store
|
7
|
+
include Nanoc::Int::ContractsSupport
|
8
|
+
|
9
|
+
contract C::KeywordArgs[env_name: C::Maybe[String], items: C::IterOf[Nanoc::Int::Item]] => C::Any
|
7
10
|
def initialize(env_name: nil, items:)
|
8
11
|
super(Nanoc::Int::Store.tmp_path_for(env_name: env_name, store_name: 'compiled_content'), 2)
|
9
12
|
|
@@ -11,32 +14,25 @@ module Nanoc::Int
|
|
11
14
|
@cache = {}
|
12
15
|
end
|
13
16
|
|
14
|
-
|
15
|
-
#
|
16
|
-
# are the snapshot names and the values the compiled content at the
|
17
|
-
# given snapshot.
|
18
|
-
#
|
19
|
-
# @param [Nanoc::Int::ItemRep] rep The item rep to fetch the content for
|
17
|
+
contract Nanoc::Int::ItemRep => C::Maybe[C::HashOf[Symbol => Nanoc::Int::Content]]
|
18
|
+
# Returns the cached compiled content for the given item representation.
|
20
19
|
#
|
21
|
-
#
|
22
|
-
#
|
20
|
+
# This cached compiled content is a hash where the keys are the snapshot
|
21
|
+
# names. and the values the compiled content at the given snapshot.
|
23
22
|
def [](rep)
|
24
23
|
item_cache = @cache[rep.item.identifier] || {}
|
25
24
|
item_cache[rep.name]
|
26
25
|
end
|
27
26
|
|
27
|
+
contract Nanoc::Int::ItemRep, C::HashOf[Symbol => Nanoc::Int::Content] => self
|
28
28
|
# Sets the compiled content for the given representation.
|
29
29
|
#
|
30
|
-
#
|
31
|
-
#
|
32
|
-
#
|
33
|
-
# @param [Hash<Symbol,String>] content A hash containing the compiled
|
34
|
-
# content of the given representation
|
35
|
-
#
|
36
|
-
# @return [void]
|
30
|
+
# This cached compiled content is a hash where the keys are the snapshot
|
31
|
+
# names. and the values the compiled content at the given snapshot.
|
37
32
|
def []=(rep, content)
|
38
33
|
@cache[rep.item.identifier] ||= {}
|
39
34
|
@cache[rep.item.identifier][rep.name] = content
|
35
|
+
self
|
40
36
|
end
|
41
37
|
|
42
38
|
protected
|
@@ -11,7 +11,8 @@ module Nanoc::Int
|
|
11
11
|
super(Nanoc::Int::Store.tmp_path_for(env_name: env_name, store_name: 'dependencies'), 4)
|
12
12
|
|
13
13
|
@objects = objects
|
14
|
-
@
|
14
|
+
@new_objects = []
|
15
|
+
@graph = Nanoc::Int::DirectedGraph.new([nil] + @objects)
|
15
16
|
end
|
16
17
|
|
17
18
|
contract C::Or[Nanoc::Int::Item, Nanoc::Int::ItemRep, Nanoc::Int::Layout] => C::ArrayOf[Nanoc::Int::Dependency]
|
@@ -50,24 +51,11 @@ module Nanoc::Int
|
|
50
51
|
# predecessors of
|
51
52
|
# the given object
|
52
53
|
def objects_causing_outdatedness_of(object)
|
53
|
-
@
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
# The direct inverse dependencies of the given object include the objects
|
59
|
-
# that will be marked as outdated when the given object is outdated.
|
60
|
-
# Indirect dependencies will not be returned (e.g. if A depends on B which
|
61
|
-
# depends on C, then the direct inverse dependencies of C do not include
|
62
|
-
# A).
|
63
|
-
#
|
64
|
-
# @param [Nanoc::Int::Item, Nanoc::Int::Layout] object The object for which to
|
65
|
-
# fetch the direct successors
|
66
|
-
#
|
67
|
-
# @return [Array<Nanoc::Int::Item, Nanoc::Int::Layout>] The direct successors of
|
68
|
-
# the given object
|
69
|
-
def objects_outdated_due_to(object)
|
70
|
-
@graph.direct_successors_of(object).compact
|
54
|
+
if @new_objects.any?
|
55
|
+
[@new_objects.first]
|
56
|
+
else
|
57
|
+
@graph.direct_predecessors_of(object)
|
58
|
+
end
|
71
59
|
end
|
72
60
|
|
73
61
|
contract C::Maybe[C::Or[Nanoc::Int::Item, Nanoc::Int::Layout]], C::Maybe[C::Or[Nanoc::Int::Item, Nanoc::Int::Layout]], C::KeywordArgs[raw_content: C::Optional[C::Bool], attributes: C::Optional[C::Bool], compiled_content: C::Optional[C::Bool], path: C::Optional[C::Bool]] => C::Any
|
@@ -141,14 +129,7 @@ module Nanoc::Int
|
|
141
129
|
end
|
142
130
|
|
143
131
|
# Record dependency from all items on new items
|
144
|
-
new_objects =
|
145
|
-
new_props = { raw_content: true, attributes: true, compiled_content: true, path: true }
|
146
|
-
new_objects.each do |new_obj|
|
147
|
-
@objects.each do |obj|
|
148
|
-
next unless obj.is_a?(Nanoc::Int::Item)
|
149
|
-
@graph.add_edge(new_obj, obj, props: new_props)
|
150
|
-
end
|
151
|
-
end
|
132
|
+
@new_objects = @objects - previous_objects
|
152
133
|
end
|
153
134
|
end
|
154
135
|
end
|
data/lib/nanoc/base/services.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
require_relative 'services/action_provider'
|
2
2
|
require_relative 'services/checksummer'
|
3
|
+
require_relative 'services/compiler'
|
3
4
|
require_relative 'services/compiler_loader'
|
4
5
|
require_relative 'services/dependency_tracker'
|
5
6
|
require_relative 'services/executor'
|
@@ -13,3 +14,5 @@ require_relative 'services/pruner'
|
|
13
14
|
require_relative 'services/temp_filename_factory'
|
14
15
|
require_relative 'services/outdatedness_rule'
|
15
16
|
require_relative 'services/outdatedness_rules'
|
17
|
+
|
18
|
+
require_relative 'services/outdatedness_checker'
|
@@ -0,0 +1,379 @@
|
|
1
|
+
module Nanoc::Int
|
2
|
+
# Responsible for compiling a site’s item representations.
|
3
|
+
#
|
4
|
+
# The compilation process makes use of notifications (see
|
5
|
+
# {Nanoc::Int::NotificationCenter}) to track dependencies between items,
|
6
|
+
# layouts, etc. The following notifications are used:
|
7
|
+
#
|
8
|
+
# * `compilation_started` — indicates that the compiler has started
|
9
|
+
# compiling this item representation. Has one argument: the item
|
10
|
+
# representation itself. Only one item can be compiled at a given moment;
|
11
|
+
# therefore, it is not possible to get two consecutive
|
12
|
+
# `compilation_started` notifications without also getting a
|
13
|
+
# `compilation_ended` notification in between them.
|
14
|
+
#
|
15
|
+
# * `compilation_ended` — indicates that the compiler has finished compiling
|
16
|
+
# this item representation (either successfully or with failure). Has one
|
17
|
+
# argument: the item representation itself.
|
18
|
+
#
|
19
|
+
# @api private
|
20
|
+
class Compiler
|
21
|
+
# Provides common functionality for accesing “context” of an item that is being compiled.
|
22
|
+
class CompilationContext
|
23
|
+
def initialize(action_provider:, reps:, site:, compiled_content_cache:)
|
24
|
+
@action_provider = action_provider
|
25
|
+
@reps = reps
|
26
|
+
@site = site
|
27
|
+
@compiled_content_cache = compiled_content_cache
|
28
|
+
end
|
29
|
+
|
30
|
+
def filter_name_and_args_for_layout(layout)
|
31
|
+
mem = @action_provider.memory_for(layout)
|
32
|
+
if mem.nil? || mem.size != 1 || !mem[0].is_a?(Nanoc::Int::ProcessingActions::Filter)
|
33
|
+
raise Nanoc::Int::Errors::UndefinedFilterForLayout.new(layout)
|
34
|
+
end
|
35
|
+
[mem[0].filter_name, mem[0].params]
|
36
|
+
end
|
37
|
+
|
38
|
+
def create_view_context(dependency_tracker)
|
39
|
+
Nanoc::ViewContext.new(
|
40
|
+
reps: @reps,
|
41
|
+
items: @site.items,
|
42
|
+
dependency_tracker: dependency_tracker,
|
43
|
+
compilation_context: self,
|
44
|
+
)
|
45
|
+
end
|
46
|
+
|
47
|
+
def assigns_for(rep, dependency_tracker)
|
48
|
+
content_or_filename_assigns =
|
49
|
+
if rep.binary?
|
50
|
+
{ filename: rep.snapshot_contents[:last].filename }
|
51
|
+
else
|
52
|
+
{ content: rep.snapshot_contents[:last].string }
|
53
|
+
end
|
54
|
+
|
55
|
+
view_context = create_view_context(dependency_tracker)
|
56
|
+
|
57
|
+
content_or_filename_assigns.merge(
|
58
|
+
item: Nanoc::ItemWithRepsView.new(rep.item, view_context),
|
59
|
+
rep: Nanoc::ItemRepView.new(rep, view_context),
|
60
|
+
item_rep: Nanoc::ItemRepView.new(rep, view_context),
|
61
|
+
items: Nanoc::ItemCollectionWithRepsView.new(@site.items, view_context),
|
62
|
+
layouts: Nanoc::LayoutCollectionView.new(@site.layouts, view_context),
|
63
|
+
config: Nanoc::ConfigView.new(@site.config, view_context),
|
64
|
+
)
|
65
|
+
end
|
66
|
+
|
67
|
+
def site
|
68
|
+
@site
|
69
|
+
end
|
70
|
+
|
71
|
+
def compiled_content_cache
|
72
|
+
@compiled_content_cache
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
# Provides functionality for (re)calculating the content of an item rep, without caching or
|
77
|
+
# outdatedness checking.
|
78
|
+
class RecalculatingItemRepCompiler
|
79
|
+
include Nanoc::Int::ContractsSupport
|
80
|
+
|
81
|
+
def initialize(action_provider:, dependency_store:, compilation_context:)
|
82
|
+
@action_provider = action_provider
|
83
|
+
@dependency_store = dependency_store
|
84
|
+
@compilation_context = compilation_context
|
85
|
+
end
|
86
|
+
|
87
|
+
contract Nanoc::Int::ItemRep, C::KeywordArgs[is_outdated: C::Bool] => C::Any
|
88
|
+
def run(rep, is_outdated:) # rubocop:disable Lint/UnusedMethodArgument
|
89
|
+
dependency_tracker = Nanoc::Int::DependencyTracker.new(@dependency_store)
|
90
|
+
dependency_tracker.enter(rep.item)
|
91
|
+
|
92
|
+
executor = Nanoc::Int::Executor.new(rep, @compilation_context, dependency_tracker)
|
93
|
+
|
94
|
+
@action_provider.memory_for(rep).each do |action|
|
95
|
+
case action
|
96
|
+
when Nanoc::Int::ProcessingActions::Filter
|
97
|
+
executor.filter(action.filter_name, action.params)
|
98
|
+
when Nanoc::Int::ProcessingActions::Layout
|
99
|
+
executor.layout(action.layout_identifier, action.params)
|
100
|
+
when Nanoc::Int::ProcessingActions::Snapshot
|
101
|
+
executor.snapshot(action.snapshot_name, final: action.final?, path: action.path)
|
102
|
+
else
|
103
|
+
raise Nanoc::Int::Errors::InternalInconsistency, "unknown action #{action.inspect}"
|
104
|
+
end
|
105
|
+
end
|
106
|
+
ensure
|
107
|
+
dependency_tracker.exit
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
# Provides functionality for (re)calculating the content of an item rep, with caching or
|
112
|
+
# outdatedness checking. Delegates to RecalculatingItemRepCompiler if outdated or no cache available.
|
113
|
+
class CachingItemRepCompiler
|
114
|
+
include Nanoc::Int::ContractsSupport
|
115
|
+
|
116
|
+
def initialize(compiled_content_cache:, wrapped:)
|
117
|
+
@compiled_content_cache = compiled_content_cache
|
118
|
+
@wrapped = wrapped
|
119
|
+
end
|
120
|
+
|
121
|
+
contract Nanoc::Int::ItemRep, C::KeywordArgs[is_outdated: C::Bool] => C::Any
|
122
|
+
def run(rep, is_outdated:)
|
123
|
+
if can_reuse_content_for_rep?(rep, is_outdated: is_outdated)
|
124
|
+
Nanoc::Int::NotificationCenter.post(:cached_content_used, rep)
|
125
|
+
rep.snapshot_contents = @compiled_content_cache[rep]
|
126
|
+
else
|
127
|
+
@wrapped.run(rep, is_outdated: is_outdated)
|
128
|
+
end
|
129
|
+
|
130
|
+
rep.compiled = true
|
131
|
+
@compiled_content_cache[rep] = rep.snapshot_contents
|
132
|
+
end
|
133
|
+
|
134
|
+
contract Nanoc::Int::ItemRep, C::KeywordArgs[is_outdated: C::Bool] => C::Bool
|
135
|
+
def can_reuse_content_for_rep?(rep, is_outdated:)
|
136
|
+
!is_outdated && !@compiled_content_cache[rep].nil?
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
# Provides functionality for suspending and resuming item rep compilation (using fibers).
|
141
|
+
class ResumableItemRepCompiler
|
142
|
+
include Nanoc::Int::ContractsSupport
|
143
|
+
|
144
|
+
def initialize(wrapped:)
|
145
|
+
@wrapped = wrapped
|
146
|
+
end
|
147
|
+
|
148
|
+
contract Nanoc::Int::ItemRep, C::KeywordArgs[is_outdated: C::Bool] => C::Any
|
149
|
+
def run(rep, is_outdated:)
|
150
|
+
fiber = fiber_for(rep, is_outdated: is_outdated)
|
151
|
+
while fiber.alive?
|
152
|
+
Nanoc::Int::NotificationCenter.post(:compilation_started, rep)
|
153
|
+
res = fiber.resume
|
154
|
+
|
155
|
+
case res
|
156
|
+
when Nanoc::Int::Errors::UnmetDependency
|
157
|
+
Nanoc::Int::NotificationCenter.post(:compilation_suspended, rep, res)
|
158
|
+
raise(res)
|
159
|
+
when Proc
|
160
|
+
fiber.resume(res.call)
|
161
|
+
else
|
162
|
+
# TODO: raise
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
Nanoc::Int::NotificationCenter.post(:compilation_ended, rep)
|
167
|
+
end
|
168
|
+
|
169
|
+
private
|
170
|
+
|
171
|
+
contract Nanoc::Int::ItemRep, C::KeywordArgs[is_outdated: C::Bool] => Fiber
|
172
|
+
def fiber_for(rep, is_outdated:)
|
173
|
+
@fibers ||= {}
|
174
|
+
|
175
|
+
@fibers[rep] ||=
|
176
|
+
Fiber.new do
|
177
|
+
@wrapped.run(rep, is_outdated: is_outdated)
|
178
|
+
@fibers.delete(rep)
|
179
|
+
end
|
180
|
+
|
181
|
+
@fibers[rep]
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
class WritingItemRepCompiler
|
186
|
+
include Nanoc::Int::ContractsSupport
|
187
|
+
|
188
|
+
def initialize(wrapped:)
|
189
|
+
@wrapped = wrapped
|
190
|
+
end
|
191
|
+
|
192
|
+
contract Nanoc::Int::ItemRep, C::KeywordArgs[is_outdated: C::Bool] => C::Any
|
193
|
+
def run(rep, is_outdated:)
|
194
|
+
@wrapped.run(rep, is_outdated: is_outdated)
|
195
|
+
|
196
|
+
rep.snapshot_defs.each do |sdef|
|
197
|
+
if sdef.final?
|
198
|
+
ItemRepWriter.new.write(rep, sdef.name)
|
199
|
+
end
|
200
|
+
end
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
204
|
+
include Nanoc::Int::ContractsSupport
|
205
|
+
|
206
|
+
# @api private
|
207
|
+
attr_reader :site
|
208
|
+
|
209
|
+
# @api private
|
210
|
+
attr_reader :compiled_content_cache
|
211
|
+
|
212
|
+
# @api private
|
213
|
+
attr_reader :checksum_store
|
214
|
+
|
215
|
+
# @api private
|
216
|
+
attr_reader :rule_memory_store
|
217
|
+
|
218
|
+
# @api private
|
219
|
+
attr_reader :action_provider
|
220
|
+
|
221
|
+
# @api private
|
222
|
+
attr_reader :dependency_store
|
223
|
+
|
224
|
+
# @api private
|
225
|
+
attr_reader :outdatedness_checker
|
226
|
+
|
227
|
+
# @api private
|
228
|
+
attr_reader :reps
|
229
|
+
|
230
|
+
def initialize(site, compiled_content_cache:, checksum_store:, rule_memory_store:, action_provider:, dependency_store:, outdatedness_checker:, reps:)
|
231
|
+
@site = site
|
232
|
+
|
233
|
+
@compiled_content_cache = compiled_content_cache
|
234
|
+
@checksum_store = checksum_store
|
235
|
+
@rule_memory_store = rule_memory_store
|
236
|
+
@dependency_store = dependency_store
|
237
|
+
@outdatedness_checker = outdatedness_checker
|
238
|
+
@reps = reps
|
239
|
+
@action_provider = action_provider
|
240
|
+
end
|
241
|
+
|
242
|
+
def run_all
|
243
|
+
@action_provider.preprocess(@site)
|
244
|
+
build_reps
|
245
|
+
prune
|
246
|
+
run
|
247
|
+
@action_provider.postprocess(@site, @reps)
|
248
|
+
end
|
249
|
+
|
250
|
+
def run
|
251
|
+
load_stores
|
252
|
+
@site.freeze
|
253
|
+
|
254
|
+
compile_reps
|
255
|
+
store
|
256
|
+
ensure
|
257
|
+
Nanoc::Int::TempFilenameFactory.instance.cleanup(
|
258
|
+
Nanoc::Filter::TMP_BINARY_ITEMS_DIR,
|
259
|
+
)
|
260
|
+
Nanoc::Int::TempFilenameFactory.instance.cleanup(
|
261
|
+
Nanoc::Int::ItemRepWriter::TMP_TEXT_ITEMS_DIR,
|
262
|
+
)
|
263
|
+
end
|
264
|
+
|
265
|
+
def load_stores
|
266
|
+
# FIXME: icky hack to update the dependency/checksum store’s list of objects
|
267
|
+
# (does not include preprocessed objects otherwise)
|
268
|
+
dependency_store.objects = site.items.to_a + site.layouts.to_a
|
269
|
+
checksum_store.objects = site.items.to_a + site.layouts.to_a + site.code_snippets + [site.config]
|
270
|
+
|
271
|
+
stores.each(&:load)
|
272
|
+
end
|
273
|
+
|
274
|
+
# Store the modified helper data used for compiling the site.
|
275
|
+
#
|
276
|
+
# @return [void]
|
277
|
+
def store
|
278
|
+
# Calculate rule memory
|
279
|
+
(@reps.to_a + @site.layouts.to_a).each do |obj|
|
280
|
+
rule_memory_store[obj] = action_provider.memory_for(obj).serialize
|
281
|
+
end
|
282
|
+
|
283
|
+
# Calculate checksums
|
284
|
+
objects_to_checksum =
|
285
|
+
site.items.to_a + site.layouts.to_a + site.code_snippets + [site.config]
|
286
|
+
objects_to_checksum.each { |obj| checksum_store.add(obj) }
|
287
|
+
|
288
|
+
# Store
|
289
|
+
stores.each(&:store)
|
290
|
+
end
|
291
|
+
|
292
|
+
def build_reps
|
293
|
+
builder = Nanoc::Int::ItemRepBuilder.new(
|
294
|
+
site, action_provider, @reps
|
295
|
+
)
|
296
|
+
builder.run
|
297
|
+
end
|
298
|
+
|
299
|
+
def compilation_context
|
300
|
+
@_compilation_context ||= CompilationContext.new(
|
301
|
+
action_provider: action_provider,
|
302
|
+
reps: @reps,
|
303
|
+
site: @site,
|
304
|
+
compiled_content_cache: compiled_content_cache,
|
305
|
+
)
|
306
|
+
end
|
307
|
+
|
308
|
+
private
|
309
|
+
|
310
|
+
def prune
|
311
|
+
if site.config[:prune][:auto_prune]
|
312
|
+
Nanoc::Pruner.new(site.config, reps, exclude: prune_config_exclude).run
|
313
|
+
end
|
314
|
+
end
|
315
|
+
|
316
|
+
def prune_config
|
317
|
+
site.config[:prune] || {}
|
318
|
+
end
|
319
|
+
|
320
|
+
def prune_config_exclude
|
321
|
+
prune_config[:exclude] || {}
|
322
|
+
end
|
323
|
+
|
324
|
+
def compile_reps
|
325
|
+
outdated_items = @reps.select { |r| outdatedness_checker.outdated?(r) }.map(&:item).uniq
|
326
|
+
outdated_items.each { |i| @dependency_store.forget_dependencies_for(i) }
|
327
|
+
|
328
|
+
reps_to_recompile = Set.new(outdated_items.flat_map { |i| @reps[i] })
|
329
|
+
selector = Nanoc::Int::ItemRepSelector.new(reps_to_recompile)
|
330
|
+
selector.each do |rep|
|
331
|
+
handle_errors_while(rep) { compile_rep(rep, is_outdated: reps_to_recompile.include?(rep)) }
|
332
|
+
end
|
333
|
+
end
|
334
|
+
|
335
|
+
def handle_errors_while(item_rep)
|
336
|
+
yield
|
337
|
+
rescue => e
|
338
|
+
raise Nanoc::Int::Errors::CompilationError.new(e, item_rep)
|
339
|
+
end
|
340
|
+
|
341
|
+
def compile_rep(rep, is_outdated:)
|
342
|
+
item_rep_compiler.run(rep, is_outdated: is_outdated)
|
343
|
+
end
|
344
|
+
|
345
|
+
def item_rep_compiler
|
346
|
+
@_item_rep_compiler ||= begin
|
347
|
+
recalculating_item_rep_compiler = RecalculatingItemRepCompiler.new(
|
348
|
+
action_provider: action_provider,
|
349
|
+
dependency_store: @dependency_store,
|
350
|
+
compilation_context: compilation_context,
|
351
|
+
)
|
352
|
+
|
353
|
+
caching_item_rep_compiler = CachingItemRepCompiler.new(
|
354
|
+
compiled_content_cache: compiled_content_cache,
|
355
|
+
wrapped: recalculating_item_rep_compiler,
|
356
|
+
)
|
357
|
+
|
358
|
+
resumable_item_rep_compiler = ResumableItemRepCompiler.new(
|
359
|
+
wrapped: caching_item_rep_compiler,
|
360
|
+
)
|
361
|
+
|
362
|
+
WritingItemRepCompiler.new(
|
363
|
+
wrapped: resumable_item_rep_compiler,
|
364
|
+
)
|
365
|
+
end
|
366
|
+
end
|
367
|
+
|
368
|
+
# Returns all stores that can load/store data that can be used for
|
369
|
+
# compilation.
|
370
|
+
def stores
|
371
|
+
[
|
372
|
+
checksum_store,
|
373
|
+
compiled_content_cache,
|
374
|
+
@dependency_store,
|
375
|
+
rule_memory_store,
|
376
|
+
]
|
377
|
+
end
|
378
|
+
end
|
379
|
+
end
|