nanoc 4.6.0 → 4.6.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (30) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile.lock +7 -7
  3. data/NEWS.md +13 -3
  4. data/README.md +1 -1
  5. data/lib/nanoc/base/entities/context.rb +14 -2
  6. data/lib/nanoc/base/services/compiler/phases/cache.rb +32 -0
  7. data/lib/nanoc/base/services/compiler/phases/mark_done.rb +16 -0
  8. data/lib/nanoc/base/services/compiler/phases/recalculate.rb +38 -0
  9. data/lib/nanoc/base/services/compiler/phases/resume.rb +46 -0
  10. data/lib/nanoc/base/services/compiler/phases/write.rb +19 -0
  11. data/lib/nanoc/base/services/compiler/phases.rb +8 -0
  12. data/lib/nanoc/base/services/compiler/stages/cleanup.rb +37 -0
  13. data/lib/nanoc/base/services/compiler/stages/compile_reps.rb +65 -0
  14. data/lib/nanoc/base/services/compiler/stages/determine_outdatedness.rb +22 -0
  15. data/lib/nanoc/base/services/compiler/stages/preprocess.rb +19 -0
  16. data/lib/nanoc/base/services/compiler/stages/prune.rb +24 -0
  17. data/lib/nanoc/base/services/compiler/stages.rb +8 -0
  18. data/lib/nanoc/base/services/compiler.rb +1 -308
  19. data/lib/nanoc/base/services/item_rep_selector.rb +38 -6
  20. data/lib/nanoc/base/services.rb +3 -0
  21. data/lib/nanoc/cli/commands/compile.rb +32 -29
  22. data/lib/nanoc/data_sources/filesystem.rb +12 -4
  23. data/lib/nanoc/version.rb +1 -1
  24. data/spec/nanoc/base/compiler_spec.rb +0 -77
  25. data/spec/nanoc/base/services/compiler/stages/cleanup_spec.rb +65 -1
  26. data/spec/nanoc/base/services/compiler/stages/compile_reps_spec.rb +141 -0
  27. data/spec/nanoc/base/services/item_rep_selector_spec.rb +16 -1
  28. data/spec/nanoc/cli/commands/compile/timing_recorder_spec.rb +3 -3
  29. data/spec/nanoc/data_sources/filesystem_spec.rb +23 -11
  30. 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
- compile_reps
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
- break if graph.roots.empty?
15
- rep = graph.roots.each { |e| break e }
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 handle_error(e, rep, graph)
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)
@@ -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
- max_filter_name_length = durations_per_filter.keys.map { |k| k.to_s.size }.max
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
- puts ' ' * max_filter_name_length + ' | count min avg max tot'
229
- puts '-' * max_filter_name_length + '-+-----------------------------------'
243
+ print_table profiling_table
244
+ end
230
245
 
231
- durations_per_filter.to_a.sort_by { |r| r[1] }.each do |row|
232
- print_row(row, max_filter_name_length)
233
- end
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, length)
237
- # Extract data
238
- filter_name, samples = *row
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.content_checksum_data,
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
- YAML.dump(
178
- attributes: proto_doc.attributes_checksum_data,
179
- extra_attributes: extra_attributes_for(content_filename, meta_filename),
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
@@ -1,4 +1,4 @@
1
1
  module Nanoc
2
2
  # The current Nanoc version.
3
- VERSION = '4.6.0'.freeze
3
+ VERSION = '4.6.1'.freeze
4
4
  end
@@ -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
- example do
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')