nanoc 4.4.4 → 4.4.5
Sign up to get free protection for your applications and to get access to all the features.
- 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
|