nanoc 4.6.0 → 4.6.1
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.lock +7 -7
- data/NEWS.md +13 -3
- data/README.md +1 -1
- data/lib/nanoc/base/entities/context.rb +14 -2
- data/lib/nanoc/base/services/compiler/phases/cache.rb +32 -0
- data/lib/nanoc/base/services/compiler/phases/mark_done.rb +16 -0
- data/lib/nanoc/base/services/compiler/phases/recalculate.rb +38 -0
- data/lib/nanoc/base/services/compiler/phases/resume.rb +46 -0
- data/lib/nanoc/base/services/compiler/phases/write.rb +19 -0
- data/lib/nanoc/base/services/compiler/phases.rb +8 -0
- data/lib/nanoc/base/services/compiler/stages/cleanup.rb +37 -0
- data/lib/nanoc/base/services/compiler/stages/compile_reps.rb +65 -0
- data/lib/nanoc/base/services/compiler/stages/determine_outdatedness.rb +22 -0
- data/lib/nanoc/base/services/compiler/stages/preprocess.rb +19 -0
- data/lib/nanoc/base/services/compiler/stages/prune.rb +24 -0
- data/lib/nanoc/base/services/compiler/stages.rb +8 -0
- data/lib/nanoc/base/services/compiler.rb +1 -308
- data/lib/nanoc/base/services/item_rep_selector.rb +38 -6
- data/lib/nanoc/base/services.rb +3 -0
- data/lib/nanoc/cli/commands/compile.rb +32 -29
- data/lib/nanoc/data_sources/filesystem.rb +12 -4
- data/lib/nanoc/version.rb +1 -1
- data/spec/nanoc/base/compiler_spec.rb +0 -77
- data/spec/nanoc/base/services/compiler/stages/cleanup_spec.rb +65 -1
- data/spec/nanoc/base/services/compiler/stages/compile_reps_spec.rb +141 -0
- data/spec/nanoc/base/services/item_rep_selector_spec.rb +16 -1
- data/spec/nanoc/cli/commands/compile/timing_recorder_spec.rb +3 -3
- data/spec/nanoc/data_sources/filesystem_spec.rb +23 -11
- metadata +16 -3
@@ -72,309 +72,6 @@ module Nanoc::Int
|
|
72
72
|
end
|
73
73
|
end
|
74
74
|
|
75
|
-
# All phases for the compilation of a single item rep. Phases will be repeated for every rep.
|
76
|
-
module Phases
|
77
|
-
# Provides functionality for (re)calculating the content of an item rep, without caching or
|
78
|
-
# outdatedness checking.
|
79
|
-
class Recalculate
|
80
|
-
include Nanoc::Int::ContractsSupport
|
81
|
-
|
82
|
-
def initialize(action_provider:, dependency_store:, compilation_context:)
|
83
|
-
@action_provider = action_provider
|
84
|
-
@dependency_store = dependency_store
|
85
|
-
@compilation_context = compilation_context
|
86
|
-
end
|
87
|
-
|
88
|
-
contract Nanoc::Int::ItemRep, C::KeywordArgs[is_outdated: C::Bool] => C::Any
|
89
|
-
def run(rep, is_outdated:) # rubocop:disable Lint/UnusedMethodArgument
|
90
|
-
dependency_tracker = Nanoc::Int::DependencyTracker.new(@dependency_store)
|
91
|
-
dependency_tracker.enter(rep.item)
|
92
|
-
|
93
|
-
executor = Nanoc::Int::Executor.new(rep, @compilation_context, dependency_tracker)
|
94
|
-
|
95
|
-
@compilation_context.snapshot_repo.set(rep, :last, rep.item.content)
|
96
|
-
|
97
|
-
@action_provider.memory_for(rep).each do |action|
|
98
|
-
case action
|
99
|
-
when Nanoc::Int::ProcessingActions::Filter
|
100
|
-
executor.filter(action.filter_name, action.params)
|
101
|
-
when Nanoc::Int::ProcessingActions::Layout
|
102
|
-
executor.layout(action.layout_identifier, action.params)
|
103
|
-
when Nanoc::Int::ProcessingActions::Snapshot
|
104
|
-
executor.snapshot(action.snapshot_name)
|
105
|
-
else
|
106
|
-
raise Nanoc::Int::Errors::InternalInconsistency, "unknown action #{action.inspect}"
|
107
|
-
end
|
108
|
-
end
|
109
|
-
ensure
|
110
|
-
dependency_tracker.exit
|
111
|
-
end
|
112
|
-
end
|
113
|
-
|
114
|
-
# Provides functionality for (re)calculating the content of an item rep, with caching or
|
115
|
-
# outdatedness checking. Delegates to s::Recalculate if outdated or no cache available.
|
116
|
-
class Cache
|
117
|
-
include Nanoc::Int::ContractsSupport
|
118
|
-
|
119
|
-
def initialize(compiled_content_cache:, snapshot_repo:, wrapped:)
|
120
|
-
@compiled_content_cache = compiled_content_cache
|
121
|
-
@snapshot_repo = snapshot_repo
|
122
|
-
@wrapped = wrapped
|
123
|
-
end
|
124
|
-
|
125
|
-
contract Nanoc::Int::ItemRep, C::KeywordArgs[is_outdated: C::Bool] => C::Any
|
126
|
-
def run(rep, is_outdated:)
|
127
|
-
if can_reuse_content_for_rep?(rep, is_outdated: is_outdated)
|
128
|
-
Nanoc::Int::NotificationCenter.post(:cached_content_used, rep)
|
129
|
-
|
130
|
-
@snapshot_repo.set_all(rep, @compiled_content_cache[rep])
|
131
|
-
else
|
132
|
-
@wrapped.run(rep, is_outdated: is_outdated)
|
133
|
-
end
|
134
|
-
|
135
|
-
rep.compiled = true
|
136
|
-
@compiled_content_cache[rep] = @snapshot_repo.get_all(rep)
|
137
|
-
end
|
138
|
-
|
139
|
-
contract Nanoc::Int::ItemRep, C::KeywordArgs[is_outdated: C::Bool] => C::Bool
|
140
|
-
def can_reuse_content_for_rep?(rep, is_outdated:)
|
141
|
-
!is_outdated && !@compiled_content_cache[rep].nil?
|
142
|
-
end
|
143
|
-
end
|
144
|
-
|
145
|
-
# Provides functionality for suspending and resuming item rep compilation (using fibers).
|
146
|
-
class Resume
|
147
|
-
include Nanoc::Int::ContractsSupport
|
148
|
-
|
149
|
-
def initialize(wrapped:)
|
150
|
-
@wrapped = wrapped
|
151
|
-
end
|
152
|
-
|
153
|
-
contract Nanoc::Int::ItemRep, C::KeywordArgs[is_outdated: C::Bool] => C::Any
|
154
|
-
def run(rep, is_outdated:)
|
155
|
-
fiber = fiber_for(rep, is_outdated: is_outdated)
|
156
|
-
while fiber.alive?
|
157
|
-
Nanoc::Int::NotificationCenter.post(:compilation_started, rep)
|
158
|
-
res = fiber.resume
|
159
|
-
|
160
|
-
case res
|
161
|
-
when Nanoc::Int::Errors::UnmetDependency
|
162
|
-
Nanoc::Int::NotificationCenter.post(:compilation_suspended, rep, res)
|
163
|
-
raise(res)
|
164
|
-
when Proc
|
165
|
-
fiber.resume(res.call)
|
166
|
-
else
|
167
|
-
# TODO: raise
|
168
|
-
end
|
169
|
-
end
|
170
|
-
|
171
|
-
Nanoc::Int::NotificationCenter.post(:compilation_ended, rep)
|
172
|
-
end
|
173
|
-
|
174
|
-
private
|
175
|
-
|
176
|
-
contract Nanoc::Int::ItemRep, C::KeywordArgs[is_outdated: C::Bool] => Fiber
|
177
|
-
def fiber_for(rep, is_outdated:)
|
178
|
-
@fibers ||= {}
|
179
|
-
|
180
|
-
@fibers[rep] ||=
|
181
|
-
Fiber.new do
|
182
|
-
@wrapped.run(rep, is_outdated: is_outdated)
|
183
|
-
@fibers.delete(rep)
|
184
|
-
end
|
185
|
-
|
186
|
-
@fibers[rep]
|
187
|
-
end
|
188
|
-
end
|
189
|
-
|
190
|
-
class Write
|
191
|
-
include Nanoc::Int::ContractsSupport
|
192
|
-
|
193
|
-
def initialize(snapshot_repo:, wrapped:)
|
194
|
-
@snapshot_repo = snapshot_repo
|
195
|
-
@wrapped = wrapped
|
196
|
-
end
|
197
|
-
|
198
|
-
contract Nanoc::Int::ItemRep, C::KeywordArgs[is_outdated: C::Bool] => C::Any
|
199
|
-
def run(rep, is_outdated:)
|
200
|
-
@wrapped.run(rep, is_outdated: is_outdated)
|
201
|
-
|
202
|
-
rep.snapshot_defs.each do |sdef|
|
203
|
-
ItemRepWriter.new.write(rep, @snapshot_repo, sdef.name)
|
204
|
-
end
|
205
|
-
end
|
206
|
-
end
|
207
|
-
|
208
|
-
class MarkDone
|
209
|
-
include Nanoc::Int::ContractsSupport
|
210
|
-
|
211
|
-
def initialize(wrapped:, outdatedness_store:)
|
212
|
-
@wrapped = wrapped
|
213
|
-
@outdatedness_store = outdatedness_store
|
214
|
-
end
|
215
|
-
|
216
|
-
contract Nanoc::Int::ItemRep, C::KeywordArgs[is_outdated: C::Bool] => C::Any
|
217
|
-
def run(rep, is_outdated:)
|
218
|
-
@wrapped.run(rep, is_outdated: is_outdated)
|
219
|
-
@outdatedness_store.remove(rep)
|
220
|
-
end
|
221
|
-
end
|
222
|
-
end
|
223
|
-
|
224
|
-
module Stages
|
225
|
-
class Preprocess
|
226
|
-
def initialize(action_provider:, site:, dependency_store:, checksum_store:)
|
227
|
-
@action_provider = action_provider
|
228
|
-
@site = site
|
229
|
-
@dependency_store = dependency_store
|
230
|
-
@checksum_store = checksum_store
|
231
|
-
end
|
232
|
-
|
233
|
-
def run
|
234
|
-
@action_provider.preprocess(@site)
|
235
|
-
|
236
|
-
@dependency_store.objects = @site.items.to_a + @site.layouts.to_a
|
237
|
-
@checksum_store.objects = @site.items.to_a + @site.layouts.to_a + @site.code_snippets + [@site.config]
|
238
|
-
|
239
|
-
@site.freeze
|
240
|
-
end
|
241
|
-
end
|
242
|
-
|
243
|
-
class Prune
|
244
|
-
def initialize(config:, reps:)
|
245
|
-
@config = config
|
246
|
-
@reps = reps
|
247
|
-
end
|
248
|
-
|
249
|
-
def run
|
250
|
-
if @config[:prune][:auto_prune]
|
251
|
-
Nanoc::Pruner.new(@config, @reps, exclude: prune_config_exclude).run
|
252
|
-
end
|
253
|
-
end
|
254
|
-
|
255
|
-
private
|
256
|
-
|
257
|
-
def prune_config
|
258
|
-
@config[:prune] || {}
|
259
|
-
end
|
260
|
-
|
261
|
-
def prune_config_exclude
|
262
|
-
prune_config[:exclude] || {}
|
263
|
-
end
|
264
|
-
end
|
265
|
-
|
266
|
-
class DetermineOutdatedness
|
267
|
-
def initialize(reps:, outdatedness_checker:, outdatedness_store:)
|
268
|
-
@reps = reps
|
269
|
-
@outdatedness_checker = outdatedness_checker
|
270
|
-
@outdatedness_store = outdatedness_store
|
271
|
-
end
|
272
|
-
|
273
|
-
def run
|
274
|
-
outdated_reps_tmp = @reps.select do |r|
|
275
|
-
@outdatedness_store.include?(r) || @outdatedness_checker.outdated?(r)
|
276
|
-
end
|
277
|
-
|
278
|
-
outdated_items = outdated_reps_tmp.map(&:item).uniq
|
279
|
-
outdated_reps = Set.new(outdated_items.flat_map { |i| @reps[i] })
|
280
|
-
|
281
|
-
outdated_reps.each { |r| @outdatedness_store.add(r) }
|
282
|
-
|
283
|
-
yield(outdated_items)
|
284
|
-
end
|
285
|
-
end
|
286
|
-
|
287
|
-
class CompileReps
|
288
|
-
def initialize(outdatedness_store:, dependency_store:, action_provider:, compilation_context:, compiled_content_cache:)
|
289
|
-
@outdatedness_store = outdatedness_store
|
290
|
-
@dependency_store = dependency_store
|
291
|
-
@action_provider = action_provider
|
292
|
-
@compilation_context = compilation_context
|
293
|
-
@compiled_content_cache = compiled_content_cache
|
294
|
-
end
|
295
|
-
|
296
|
-
def run
|
297
|
-
selector = Nanoc::Int::ItemRepSelector.new(@outdatedness_store.to_a)
|
298
|
-
selector.each do |rep|
|
299
|
-
handle_errors_while(rep) { compile_rep(rep, is_outdated: @outdatedness_store.include?(rep)) }
|
300
|
-
end
|
301
|
-
ensure
|
302
|
-
@outdatedness_store.store
|
303
|
-
@compiled_content_cache.store
|
304
|
-
end
|
305
|
-
|
306
|
-
private
|
307
|
-
|
308
|
-
def handle_errors_while(item_rep)
|
309
|
-
yield
|
310
|
-
rescue => e
|
311
|
-
raise Nanoc::Int::Errors::CompilationError.new(e, item_rep)
|
312
|
-
end
|
313
|
-
|
314
|
-
def compile_rep(rep, is_outdated:)
|
315
|
-
item_rep_compiler.run(rep, is_outdated: is_outdated)
|
316
|
-
end
|
317
|
-
|
318
|
-
def item_rep_compiler
|
319
|
-
@_item_rep_compiler ||= begin
|
320
|
-
recalculate_phase = Phases::Recalculate.new(
|
321
|
-
action_provider: @action_provider,
|
322
|
-
dependency_store: @dependency_store,
|
323
|
-
compilation_context: @compilation_context,
|
324
|
-
)
|
325
|
-
|
326
|
-
cache_phase = Phases::Cache.new(
|
327
|
-
compiled_content_cache: @compiled_content_cache,
|
328
|
-
snapshot_repo: @compilation_context.snapshot_repo,
|
329
|
-
wrapped: recalculate_phase,
|
330
|
-
)
|
331
|
-
|
332
|
-
resume_phase = Phases::Resume.new(
|
333
|
-
wrapped: cache_phase,
|
334
|
-
)
|
335
|
-
|
336
|
-
write_phase = Phases::Write.new(
|
337
|
-
snapshot_repo: @compilation_context.snapshot_repo,
|
338
|
-
wrapped: resume_phase,
|
339
|
-
)
|
340
|
-
|
341
|
-
mark_done_phase = Phases::MarkDone.new(
|
342
|
-
wrapped: write_phase,
|
343
|
-
outdatedness_store: @outdatedness_store,
|
344
|
-
)
|
345
|
-
|
346
|
-
mark_done_phase
|
347
|
-
end
|
348
|
-
end
|
349
|
-
end
|
350
|
-
|
351
|
-
class Cleanup
|
352
|
-
def initialize(config)
|
353
|
-
@config = config
|
354
|
-
end
|
355
|
-
|
356
|
-
def run
|
357
|
-
cleanup_temps(Nanoc::Filter::TMP_BINARY_ITEMS_DIR)
|
358
|
-
cleanup_temps(Nanoc::Int::ItemRepWriter::TMP_TEXT_ITEMS_DIR)
|
359
|
-
cleanup_unused_stores
|
360
|
-
end
|
361
|
-
|
362
|
-
private
|
363
|
-
|
364
|
-
def cleanup_temps(dir)
|
365
|
-
Nanoc::Int::TempFilenameFactory.instance.cleanup(dir)
|
366
|
-
end
|
367
|
-
|
368
|
-
def cleanup_unused_stores
|
369
|
-
used_paths = @config.output_dirs.map { |d| Nanoc::Int::Store.tmp_path_prefix(d) }
|
370
|
-
all_paths = Dir.glob('tmp/nanoc/*')
|
371
|
-
(all_paths - used_paths).each do |obsolete_path|
|
372
|
-
FileUtils.rm_rf(obsolete_path)
|
373
|
-
end
|
374
|
-
end
|
375
|
-
end
|
376
|
-
end
|
377
|
-
|
378
75
|
include Nanoc::Int::ContractsSupport
|
379
76
|
|
380
77
|
# @api private
|
@@ -431,7 +128,7 @@ module Nanoc::Int
|
|
431
128
|
determine_outdatedness
|
432
129
|
forget_dependencies_if_needed
|
433
130
|
store
|
434
|
-
|
131
|
+
compile_reps_stage.run
|
435
132
|
store_output_state
|
436
133
|
@action_provider.postprocess(@site, @reps)
|
437
134
|
ensure
|
@@ -530,10 +227,6 @@ module Nanoc::Int
|
|
530
227
|
@outdated_items.each { |i| @dependency_store.forget_dependencies_for(i) }
|
531
228
|
end
|
532
229
|
|
533
|
-
def compile_reps
|
534
|
-
compile_reps_stage.run
|
535
|
-
end
|
536
|
-
|
537
230
|
# Returns all stores that can load/store data that can be used for
|
538
231
|
# compilation.
|
539
232
|
def stores
|
@@ -7,18 +7,24 @@ module Nanoc::Int
|
|
7
7
|
@reps = reps
|
8
8
|
end
|
9
9
|
|
10
|
+
NONE = Object.new
|
11
|
+
|
10
12
|
def each
|
11
13
|
graph = Nanoc::Int::DirectedGraph.new(@reps)
|
12
14
|
|
15
|
+
prio_dependent = Set.new
|
16
|
+
prio_in_progress = Set.new
|
13
17
|
loop do
|
14
|
-
|
15
|
-
|
18
|
+
rep = find(graph, prio_dependent, prio_in_progress)
|
19
|
+
break if NONE.equal?(rep)
|
16
20
|
|
17
21
|
begin
|
22
|
+
prio_in_progress << rep
|
18
23
|
yield(rep)
|
24
|
+
prio_in_progress.delete(rep)
|
19
25
|
graph.delete_vertex(rep)
|
20
26
|
rescue => e
|
21
|
-
handle_error(e, rep, graph)
|
27
|
+
handle_error(e, rep, graph, prio_dependent)
|
22
28
|
end
|
23
29
|
end
|
24
30
|
|
@@ -28,7 +34,32 @@ module Nanoc::Int
|
|
28
34
|
end
|
29
35
|
end
|
30
36
|
|
31
|
-
def
|
37
|
+
def find(graph, prio_dependent, prio_in_progress)
|
38
|
+
if graph.roots.empty?
|
39
|
+
NONE
|
40
|
+
elsif prio_dependent.any?
|
41
|
+
find_prio(graph, prio_dependent, prio_dependent, prio_in_progress)
|
42
|
+
elsif prio_in_progress.any?
|
43
|
+
find_prio(graph, prio_in_progress, prio_dependent, prio_in_progress)
|
44
|
+
else
|
45
|
+
graph.roots.each { |e| break e }
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def find_prio(graph, prio, prio_dependent, prio_in_progress)
|
50
|
+
until prio.empty?
|
51
|
+
rep = prio.each { |e| break e }
|
52
|
+
if graph.roots.include?(rep)
|
53
|
+
return rep
|
54
|
+
else
|
55
|
+
prio.delete(rep)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
find(graph, prio_dependent, prio_in_progress)
|
60
|
+
end
|
61
|
+
|
62
|
+
def handle_error(e, rep, graph, prio_dependent)
|
32
63
|
actual_error =
|
33
64
|
if e.is_a?(Nanoc::Int::Errors::CompilationError)
|
34
65
|
e.unwrap
|
@@ -37,14 +68,15 @@ module Nanoc::Int
|
|
37
68
|
end
|
38
69
|
|
39
70
|
if actual_error.is_a?(Nanoc::Int::Errors::UnmetDependency)
|
40
|
-
handle_dependency_error(actual_error, rep, graph)
|
71
|
+
handle_dependency_error(actual_error, rep, graph, prio_dependent)
|
41
72
|
else
|
42
73
|
raise(e)
|
43
74
|
end
|
44
75
|
end
|
45
76
|
|
46
|
-
def handle_dependency_error(e, rep, graph)
|
77
|
+
def handle_dependency_error(e, rep, graph, prio_dependent)
|
47
78
|
other_rep = e.rep
|
79
|
+
prio_dependent << other_rep
|
48
80
|
graph.add_edge(other_rep, rep)
|
49
81
|
unless graph.vertices.include?(other_rep)
|
50
82
|
graph.add_vertex(other_rep)
|
data/lib/nanoc/base/services.rb
CHANGED
@@ -15,4 +15,7 @@ require_relative 'services/temp_filename_factory'
|
|
15
15
|
require_relative 'services/outdatedness_rule'
|
16
16
|
require_relative 'services/outdatedness_rules'
|
17
17
|
|
18
|
+
require_relative 'services/compiler/phases'
|
19
|
+
require_relative 'services/compiler/stages'
|
20
|
+
|
18
21
|
require_relative 'services/outdatedness_checker'
|
@@ -211,10 +211,26 @@ module Nanoc::CLI::Commands
|
|
211
211
|
|
212
212
|
protected
|
213
213
|
|
214
|
+
def profiling_table
|
215
|
+
headers = ['', 'count', 'min', 'avg', 'max', 'tot']
|
216
|
+
|
217
|
+
rows = durations_per_filter.to_a.sort_by { |r| r[1] }.map do |row|
|
218
|
+
filter_name, samples = *row
|
219
|
+
count = samples.size
|
220
|
+
min = samples.min
|
221
|
+
tot = samples.reduce(0, &:+)
|
222
|
+
avg = tot / count
|
223
|
+
max = samples.max
|
224
|
+
|
225
|
+
[filter_name.to_s, count.to_s] + [min, avg, max, tot].map { |r| "#{format('%4.2f', r)}s" }
|
226
|
+
end
|
227
|
+
|
228
|
+
[headers] + rows
|
229
|
+
end
|
230
|
+
|
214
231
|
def print_profiling_feedback
|
215
232
|
# Get max filter length
|
216
|
-
|
217
|
-
return if max_filter_name_length.nil?
|
233
|
+
return if durations_per_filter.empty?
|
218
234
|
|
219
235
|
# Print warning if necessary
|
220
236
|
if @reps.any? { |r| !r.compiled? }
|
@@ -223,37 +239,24 @@ module Nanoc::CLI::Commands
|
|
223
239
|
'some items were not compiled.'
|
224
240
|
end
|
225
241
|
|
226
|
-
# Print header
|
227
242
|
puts
|
228
|
-
|
229
|
-
|
243
|
+
print_table profiling_table
|
244
|
+
end
|
230
245
|
|
231
|
-
|
232
|
-
|
233
|
-
|
246
|
+
def print_table(table)
|
247
|
+
lengths = table.transpose.map { |r| r.map(&:size).max }
|
248
|
+
|
249
|
+
print_row(table[0], lengths)
|
250
|
+
|
251
|
+
puts "#{'-' * lengths[0]}-+-#{lengths[1..-1].map { |length| '-' * length }.join('---')}"
|
252
|
+
|
253
|
+
table[1..-1].each { |row| print_row(row, lengths) }
|
234
254
|
end
|
235
255
|
|
236
|
-
def print_row(row,
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
# Calculate stats
|
241
|
-
count = samples.size
|
242
|
-
min = samples.min
|
243
|
-
tot = samples.reduce(0) { |acc, elem| acc + elem }
|
244
|
-
avg = tot / count
|
245
|
-
max = samples.max
|
246
|
-
|
247
|
-
# Format stats
|
248
|
-
count = format('%4d', count)
|
249
|
-
min = format('%4.2f', min)
|
250
|
-
avg = format('%4.2f', avg)
|
251
|
-
max = format('%4.2f', max)
|
252
|
-
tot = format('%5.2f', tot)
|
253
|
-
|
254
|
-
# Output stats
|
255
|
-
key = format("%#{length}s", filter_name)
|
256
|
-
puts "#{key} | #{count} #{min}s #{avg}s #{max}s #{tot}s"
|
256
|
+
def print_row(row, lengths)
|
257
|
+
values = row.zip(lengths).map { |text, length| text.rjust length }
|
258
|
+
|
259
|
+
puts values[0] + ' | ' + values[1..-1].join(' ')
|
257
260
|
end
|
258
261
|
|
259
262
|
def durations_per_filter
|
@@ -164,7 +164,7 @@ module Nanoc::DataSources
|
|
164
164
|
content,
|
165
165
|
attributes,
|
166
166
|
identifier,
|
167
|
-
content_checksum_data: proto_doc
|
167
|
+
content_checksum_data: content_checksum_data_for(proto_doc),
|
168
168
|
attributes_checksum_data: attributes_checksum_data_for(proto_doc, content_filename, meta_filename),
|
169
169
|
)
|
170
170
|
end
|
@@ -173,10 +173,18 @@ module Nanoc::DataSources
|
|
173
173
|
res
|
174
174
|
end
|
175
175
|
|
176
|
+
def content_checksum_data_for(proto_doc)
|
177
|
+
Digest::SHA1.digest(
|
178
|
+
proto_doc.content_checksum_data || '',
|
179
|
+
)
|
180
|
+
end
|
181
|
+
|
176
182
|
def attributes_checksum_data_for(proto_doc, content_filename, meta_filename)
|
177
|
-
|
178
|
-
|
179
|
-
|
183
|
+
Digest::SHA1.digest(
|
184
|
+
YAML.dump(
|
185
|
+
attributes: proto_doc.attributes_checksum_data,
|
186
|
+
extra_attributes: extra_attributes_for(content_filename, meta_filename),
|
187
|
+
),
|
180
188
|
)
|
181
189
|
end
|
182
190
|
|
data/lib/nanoc/version.rb
CHANGED
@@ -76,83 +76,6 @@ describe Nanoc::Int::Compiler do
|
|
76
76
|
allow(action_provider).to receive(:memory_for).with(other_rep).and_return(memory)
|
77
77
|
end
|
78
78
|
|
79
|
-
describe '#compile_reps' do
|
80
|
-
subject do
|
81
|
-
compiler.send(:determine_outdatedness)
|
82
|
-
compiler.send(:compile_reps)
|
83
|
-
end
|
84
|
-
|
85
|
-
before do
|
86
|
-
allow(action_provider).to receive(:snapshots_defs_for).with(rep).and_return(snapshot_defs_for_rep)
|
87
|
-
allow(action_provider).to receive(:snapshots_defs_for).with(other_rep).and_return(snapshot_defs_for_rep)
|
88
|
-
end
|
89
|
-
|
90
|
-
let(:snapshot_defs_for_rep) do
|
91
|
-
[Nanoc::Int::SnapshotDef.new(:last)]
|
92
|
-
end
|
93
|
-
|
94
|
-
let(:snapshot_defs_for_other_rep) do
|
95
|
-
[Nanoc::Int::SnapshotDef.new(:last)]
|
96
|
-
end
|
97
|
-
|
98
|
-
it 'compiles individual reps' do
|
99
|
-
expect { subject }.to change { compiler.snapshot_repo.get(rep, :last) }
|
100
|
-
.from(nil)
|
101
|
-
.to(some_textual_content('3'))
|
102
|
-
end
|
103
|
-
|
104
|
-
it 'removes the item rep from the outdatedness store' do
|
105
|
-
expect(compiler.outdatedness_store.include?(rep)).not_to be
|
106
|
-
expect { subject }.not_to change { compiler.outdatedness_store.include?(rep) }
|
107
|
-
end
|
108
|
-
|
109
|
-
context 'rep in outdatedness store' do
|
110
|
-
before do
|
111
|
-
compiler.outdatedness_store.add(rep)
|
112
|
-
end
|
113
|
-
|
114
|
-
it 'removes the item rep from the outdatedness store' do
|
115
|
-
expect { subject }.to change { compiler.outdatedness_store.include?(rep) }.from(true).to(false)
|
116
|
-
end
|
117
|
-
end
|
118
|
-
|
119
|
-
context 'exception' do
|
120
|
-
let(:item) { Nanoc::Int::Item.new('<%= raise "lol" %>', {}, '/hi.md') }
|
121
|
-
|
122
|
-
it 'wraps exception' do
|
123
|
-
expect { subject }.to raise_error(Nanoc::Int::Errors::CompilationError)
|
124
|
-
end
|
125
|
-
|
126
|
-
it 'contains the right item rep in the wrapped exception' do
|
127
|
-
expect { subject }.to raise_error do |err|
|
128
|
-
expect(err.item_rep).to eql(rep)
|
129
|
-
end
|
130
|
-
end
|
131
|
-
|
132
|
-
it 'contains the right wrapped exception' do
|
133
|
-
expect { subject }.to raise_error do |err|
|
134
|
-
expect(err.unwrap).to be_a(RuntimeError)
|
135
|
-
expect(err.unwrap.message).to eq('lol')
|
136
|
-
end
|
137
|
-
end
|
138
|
-
|
139
|
-
it 'adds the item rep to the outdatedness store' do
|
140
|
-
expect { subject rescue nil }.to change { compiler.outdatedness_store.include?(rep) }.from(false).to(true)
|
141
|
-
end
|
142
|
-
|
143
|
-
context 'rep in outdatedness store' do
|
144
|
-
before do
|
145
|
-
compiler.outdatedness_store.add(rep)
|
146
|
-
end
|
147
|
-
|
148
|
-
it 'keeps the item rep in the outdatedness store' do
|
149
|
-
expect(compiler.outdatedness_store.include?(rep)).to be
|
150
|
-
expect { subject rescue nil }.not_to change { compiler.outdatedness_store.include?(rep) }
|
151
|
-
end
|
152
|
-
end
|
153
|
-
end
|
154
|
-
end
|
155
|
-
|
156
79
|
describe '#compile_rep' do
|
157
80
|
let(:stage) { compiler.send(:compile_reps_stage) }
|
158
81
|
|
@@ -8,7 +8,71 @@ describe Nanoc::Int::Compiler::Stages::Cleanup do
|
|
8
8
|
describe '#run' do
|
9
9
|
subject { stage.run }
|
10
10
|
|
11
|
-
|
11
|
+
it 'removes temporary binary items' do
|
12
|
+
a = Nanoc::Int::TempFilenameFactory.instance.create(Nanoc::Filter::TMP_BINARY_ITEMS_DIR)
|
13
|
+
File.write(a, 'hello there')
|
14
|
+
|
15
|
+
expect { subject }
|
16
|
+
.to change { File.file?(a) }
|
17
|
+
.from(true).to(false)
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'removes temporary textual items' do
|
21
|
+
a = Nanoc::Int::TempFilenameFactory.instance.create(Nanoc::Int::ItemRepWriter::TMP_TEXT_ITEMS_DIR)
|
22
|
+
File.write(a, 'hello there')
|
23
|
+
|
24
|
+
expect { subject }
|
25
|
+
.to change { File.file?(a) }
|
26
|
+
.from(true).to(false)
|
27
|
+
end
|
28
|
+
|
29
|
+
shared_examples 'an old store' do
|
30
|
+
it 'removes the old store' do
|
31
|
+
FileUtils.mkdir_p('tmp')
|
32
|
+
File.write('tmp/' + store_name, 'stuff')
|
33
|
+
|
34
|
+
expect { subject }
|
35
|
+
.to change { File.file?('tmp/' + store_name) }
|
36
|
+
.from(true).to(false)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
context 'tmp/checksums' do
|
41
|
+
let(:store_name) { 'checksums' }
|
42
|
+
it_behaves_like 'an old store'
|
43
|
+
end
|
44
|
+
|
45
|
+
context 'tmp/compiled_content' do
|
46
|
+
let(:store_name) { 'compiled_content' }
|
47
|
+
it_behaves_like 'an old store'
|
48
|
+
end
|
49
|
+
|
50
|
+
context 'tmp/dependencies' do
|
51
|
+
let(:store_name) { 'dependencies' }
|
52
|
+
it_behaves_like 'an old store'
|
53
|
+
end
|
54
|
+
|
55
|
+
context 'tmp/outdatedness' do
|
56
|
+
let(:store_name) { 'outdatedness' }
|
57
|
+
it_behaves_like 'an old store'
|
58
|
+
end
|
59
|
+
|
60
|
+
context 'tmp/rule_memory' do
|
61
|
+
let(:store_name) { 'rule_memory' }
|
62
|
+
it_behaves_like 'an old store'
|
63
|
+
end
|
64
|
+
|
65
|
+
context 'tmp/somethingelse' do
|
66
|
+
it 'does not removes the store' do
|
67
|
+
FileUtils.mkdir_p('tmp')
|
68
|
+
File.write('tmp/somethingelse', 'stuff')
|
69
|
+
|
70
|
+
expect { subject }
|
71
|
+
.not_to change { File.file?('tmp/somethingelse') }
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
it 'removes stores for unused output paths' do
|
12
76
|
FileUtils.mkdir_p('tmp/nanoc/2f0692fb1a1d')
|
13
77
|
FileUtils.mkdir_p('tmp/nanoc/1a2195bfef6c')
|
14
78
|
FileUtils.mkdir_p('tmp/nanoc/1029d67644815')
|