nanoc-core 4.11.12 → 4.11.13

Sign up to get free protection for your applications and to get access to all the features.
Files changed (73) hide show
  1. checksums.yaml +4 -4
  2. data/lib/nanoc/core.rb +37 -0
  3. data/lib/nanoc/core/basic_item_rep_collection_view.rb +88 -0
  4. data/lib/nanoc/core/basic_item_rep_view.rb +83 -0
  5. data/lib/nanoc/core/basic_item_view.rb +54 -0
  6. data/lib/nanoc/core/checksummer.rb +2 -0
  7. data/lib/nanoc/core/compilation_item_rep_collection_view.rb +12 -0
  8. data/lib/nanoc/core/compilation_item_rep_view.rb +51 -0
  9. data/lib/nanoc/core/compilation_item_view.rb +47 -0
  10. data/lib/nanoc/core/compilation_phases/abstract.rb +48 -0
  11. data/lib/nanoc/core/compilation_phases/cache.rb +43 -0
  12. data/lib/nanoc/core/compilation_phases/mark_done.rb +23 -0
  13. data/lib/nanoc/core/compilation_phases/notify.rb +19 -0
  14. data/lib/nanoc/core/compilation_phases/recalculate.rb +49 -0
  15. data/lib/nanoc/core/compilation_phases/resume.rb +52 -0
  16. data/lib/nanoc/core/compilation_phases/write.rb +84 -0
  17. data/lib/nanoc/core/compilation_stages/build_reps.rb +36 -0
  18. data/lib/nanoc/core/compilation_stages/calculate_checksums.rb +42 -0
  19. data/lib/nanoc/core/compilation_stages/cleanup.rb +43 -0
  20. data/lib/nanoc/core/compilation_stages/compile_reps.rb +96 -0
  21. data/lib/nanoc/core/compilation_stages/determine_outdatedness.rb +49 -0
  22. data/lib/nanoc/core/compilation_stages/forget_outdated_dependencies.rb +20 -0
  23. data/lib/nanoc/core/compilation_stages/load_stores.rb +35 -0
  24. data/lib/nanoc/core/compilation_stages/postprocess.rb +21 -0
  25. data/lib/nanoc/core/compilation_stages/preprocess.rb +32 -0
  26. data/lib/nanoc/core/compilation_stages/prune.rb +30 -0
  27. data/lib/nanoc/core/compilation_stages/store_post_compilation_state.rb +20 -0
  28. data/lib/nanoc/core/compilation_stages/store_pre_compilation_state.rb +32 -0
  29. data/lib/nanoc/core/compiler.rb +214 -0
  30. data/lib/nanoc/core/compiler_loader.rb +48 -0
  31. data/lib/nanoc/core/config_loader.rb +95 -0
  32. data/lib/nanoc/core/config_view.rb +67 -0
  33. data/lib/nanoc/core/configuration.rb +2 -4
  34. data/lib/nanoc/core/document_view_mixin.rb +87 -0
  35. data/lib/nanoc/core/errors.rb +97 -0
  36. data/lib/nanoc/core/executor.rb +134 -0
  37. data/lib/nanoc/core/feature.rb +92 -0
  38. data/lib/nanoc/core/filter.rb +269 -0
  39. data/lib/nanoc/core/identifiable_collection_view.rb +111 -0
  40. data/lib/nanoc/core/item_collection_with_reps_view.rb +12 -0
  41. data/lib/nanoc/core/item_collection_without_reps_view.rb +12 -0
  42. data/lib/nanoc/core/item_rep_builder.rb +54 -0
  43. data/lib/nanoc/core/item_rep_selector.rb +67 -0
  44. data/lib/nanoc/core/item_rep_writer.rb +85 -0
  45. data/lib/nanoc/core/layout_collection_view.rb +12 -0
  46. data/lib/nanoc/core/layout_view.rb +9 -0
  47. data/lib/nanoc/core/mutable_config_view.rb +16 -0
  48. data/lib/nanoc/core/mutable_document_view_mixin.rb +60 -0
  49. data/lib/nanoc/core/mutable_identifiable_collection_view.rb +19 -0
  50. data/lib/nanoc/core/mutable_item_collection_view.rb +34 -0
  51. data/lib/nanoc/core/mutable_item_view.rb +9 -0
  52. data/lib/nanoc/core/mutable_layout_collection_view.rb +26 -0
  53. data/lib/nanoc/core/mutable_layout_view.rb +9 -0
  54. data/lib/nanoc/core/outdatedness_checker.rb +222 -0
  55. data/lib/nanoc/core/outdatedness_rules/attributes_modified.rb +41 -0
  56. data/lib/nanoc/core/outdatedness_rules/code_snippets_modified.rb +31 -0
  57. data/lib/nanoc/core/outdatedness_rules/content_modified.rb +21 -0
  58. data/lib/nanoc/core/outdatedness_rules/item_collection_extended.rb +20 -0
  59. data/lib/nanoc/core/outdatedness_rules/layout_collection_extended.rb +20 -0
  60. data/lib/nanoc/core/outdatedness_rules/not_written.rb +17 -0
  61. data/lib/nanoc/core/outdatedness_rules/rules_modified.rb +45 -0
  62. data/lib/nanoc/core/outdatedness_rules/uses_always_outdated_filter.rb +26 -0
  63. data/lib/nanoc/core/post_compile_item_collection_view.rb +12 -0
  64. data/lib/nanoc/core/post_compile_item_rep_collection_view.rb +12 -0
  65. data/lib/nanoc/core/post_compile_item_rep_view.rb +33 -0
  66. data/lib/nanoc/core/post_compile_item_view.rb +20 -0
  67. data/lib/nanoc/core/pruner.rb +119 -0
  68. data/lib/nanoc/core/site_loader.rb +102 -0
  69. data/lib/nanoc/core/trivial_error.rb +10 -0
  70. data/lib/nanoc/core/version.rb +1 -1
  71. data/lib/nanoc/core/view.rb +43 -0
  72. data/lib/nanoc/core/view_context_for_compilation.rb +6 -6
  73. metadata +95 -2
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Nanoc
4
+ module Core
5
+ module CompilationPhases
6
+ # Provides functionality for (re)calculating the content of an item rep, with caching or
7
+ # outdatedness checking. Delegates to s::Recalculate if outdated or no cache available.
8
+ class Cache < Abstract
9
+ include Nanoc::Core::ContractsSupport
10
+
11
+ def initialize(wrapped:, compiled_content_cache:, compiled_content_store:)
12
+ super(wrapped: wrapped)
13
+
14
+ @compiled_content_cache = compiled_content_cache
15
+ @compiled_content_store = compiled_content_store
16
+ end
17
+
18
+ contract Nanoc::Core::ItemRep, C::KeywordArgs[is_outdated: C::Bool], C::Func[C::None => C::Any] => C::Any
19
+ def run(rep, is_outdated:)
20
+ if can_reuse_content_for_rep?(rep, is_outdated: is_outdated)
21
+ Nanoc::Core::NotificationCenter.post(:cached_content_used, rep)
22
+
23
+ @compiled_content_store.set_all(rep, @compiled_content_cache[rep])
24
+ else
25
+ yield
26
+ end
27
+
28
+ rep.compiled = true
29
+ @compiled_content_cache[rep] = @compiled_content_store.get_all(rep)
30
+ end
31
+
32
+ contract Nanoc::Core::ItemRep, C::KeywordArgs[is_outdated: C::Bool] => C::Bool
33
+ def can_reuse_content_for_rep?(rep, is_outdated:)
34
+ if is_outdated
35
+ false
36
+ else
37
+ @compiled_content_cache.full_cache_available?(rep)
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Nanoc
4
+ module Core
5
+ module CompilationPhases
6
+ class MarkDone < Abstract
7
+ include Nanoc::Core::ContractsSupport
8
+
9
+ def initialize(wrapped:, outdatedness_store:)
10
+ super(wrapped: wrapped)
11
+
12
+ @outdatedness_store = outdatedness_store
13
+ end
14
+
15
+ contract Nanoc::Core::ItemRep, C::KeywordArgs[is_outdated: C::Bool], C::Func[C::None => C::Any] => C::Any
16
+ def run(rep, is_outdated:) # rubocop:disable Lint/UnusedMethodArgument
17
+ yield
18
+ @outdatedness_store.remove(rep)
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Nanoc
4
+ module Core
5
+ module CompilationPhases
6
+ # Provides functionality for notifying start and end of compilation.
7
+ class Notify < Abstract
8
+ include Nanoc::Core::ContractsSupport
9
+
10
+ contract Nanoc::Core::ItemRep, C::KeywordArgs[is_outdated: C::Bool], C::Func[C::None => C::Any] => C::Any
11
+ def run(rep, is_outdated:) # rubocop:disable Lint/UnusedMethodArgument
12
+ Nanoc::Core::NotificationCenter.post(:compilation_started, rep)
13
+ yield
14
+ Nanoc::Core::NotificationCenter.post(:compilation_ended, rep)
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Nanoc
4
+ module Core
5
+ module CompilationPhases
6
+ # Provides functionality for (re)calculating the content of an item rep, without caching or
7
+ # outdatedness checking.
8
+ class Recalculate < Abstract
9
+ include Nanoc::Core::ContractsSupport
10
+
11
+ def initialize(action_sequences:, dependency_store:, compilation_context:)
12
+ super(wrapped: nil)
13
+
14
+ @action_sequences = action_sequences
15
+ @dependency_store = dependency_store
16
+ @compilation_context = compilation_context
17
+ end
18
+
19
+ contract Nanoc::Core::ItemRep, C::KeywordArgs[is_outdated: C::Bool], C::Func[C::None => C::Any] => C::Any
20
+ def run(rep, is_outdated:) # rubocop:disable Lint/UnusedMethodArgument
21
+ dependency_tracker = Nanoc::Core::DependencyTracker.new(@dependency_store)
22
+ dependency_tracker.enter(rep.item)
23
+
24
+ executor = Nanoc::Core::Executor.new(rep, @compilation_context, dependency_tracker)
25
+
26
+ @compilation_context.compiled_content_store.set_current(rep, rep.item.content)
27
+
28
+ actions = @action_sequences[rep]
29
+ actions.each do |action|
30
+ case action
31
+ when Nanoc::Core::ProcessingActions::Filter
32
+ executor.filter(action.filter_name, action.params)
33
+ when Nanoc::Core::ProcessingActions::Layout
34
+ executor.layout(action.layout_identifier, action.params)
35
+ when Nanoc::Core::ProcessingActions::Snapshot
36
+ action.snapshot_names.each do |snapshot_name|
37
+ executor.snapshot(snapshot_name)
38
+ end
39
+ else
40
+ raise Nanoc::Core::Errors::InternalInconsistency, "unknown action #{action.inspect}"
41
+ end
42
+ end
43
+ ensure
44
+ dependency_tracker.exit
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Nanoc
4
+ module Core
5
+ module CompilationPhases
6
+ # Provides functionality for suspending and resuming item rep compilation (using fibers).
7
+ class Resume < Abstract
8
+ include Nanoc::Core::ContractsSupport
9
+
10
+ DONE = Object.new
11
+
12
+ contract Nanoc::Core::ItemRep, C::KeywordArgs[is_outdated: C::Bool], C::Func[C::None => C::Any] => C::Any
13
+ def run(rep, is_outdated:)
14
+ fiber = fiber_for(rep, is_outdated: is_outdated) { yield }
15
+ while fiber.alive?
16
+ res = fiber.resume
17
+
18
+ case res
19
+ when Nanoc::Core::Errors::UnmetDependency
20
+ Nanoc::Core::NotificationCenter.post(:compilation_suspended, rep, res.rep, res.snapshot_name)
21
+ raise(res)
22
+ when Proc
23
+ fiber.resume(res.call)
24
+ when DONE # rubocop:disable Lint/EmptyWhen
25
+ # ignore
26
+ else
27
+ raise Nanoc::Core::Errors::InternalInconsistency.new(
28
+ "Fiber yielded object of unexpected type #{res.class}",
29
+ )
30
+ end
31
+ end
32
+ end
33
+
34
+ private
35
+
36
+ contract Nanoc::Core::ItemRep, C::KeywordArgs[is_outdated: C::Bool], C::Func[C::None => C::Any] => Fiber
37
+ def fiber_for(rep, is_outdated:) # rubocop:disable Lint/UnusedMethodArgument
38
+ @fibers ||= {}
39
+
40
+ @fibers[rep] ||=
41
+ Fiber.new do
42
+ yield
43
+ @fibers.delete(rep)
44
+ DONE
45
+ end
46
+
47
+ @fibers[rep]
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,84 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Nanoc
4
+ module Core
5
+ module CompilationPhases
6
+ class Write < Abstract
7
+ include Nanoc::Core::ContractsSupport
8
+
9
+ class Worker
10
+ def initialize(queue:, compiled_content_store:)
11
+ @queue = queue
12
+ @compiled_content_store = compiled_content_store
13
+ end
14
+
15
+ def start
16
+ @thread = Thread.new do
17
+ Thread.current.abort_on_exception = true
18
+ Thread.current.priority = -1 # schedule I/O work ASAP
19
+
20
+ writer = Nanoc::Core::ItemRepWriter.new
21
+
22
+ while rep = @queue.pop # rubocop:disable Lint/AssignmentInCondition
23
+ writer.write_all(rep, @compiled_content_store)
24
+ end
25
+ end
26
+ end
27
+
28
+ def join
29
+ @thread.join
30
+ end
31
+ end
32
+
33
+ class WorkerPool
34
+ def initialize(queue:, size:, compiled_content_store:)
35
+ @workers = Array.new(size) { Worker.new(queue: queue, compiled_content_store: compiled_content_store) }
36
+ end
37
+
38
+ def start
39
+ @workers.each(&:start)
40
+ end
41
+
42
+ def join
43
+ @workers.each(&:join)
44
+ end
45
+ end
46
+
47
+ QUEUE_SIZE = 40
48
+ WORKER_POOL_SIZE = 5
49
+
50
+ def initialize(compiled_content_store:, wrapped:)
51
+ super(wrapped: wrapped)
52
+
53
+ @compiled_content_store = compiled_content_store
54
+
55
+ @queue = SizedQueue.new(QUEUE_SIZE)
56
+ @worker_pool = WorkerPool.new(queue: @queue, size: WORKER_POOL_SIZE, compiled_content_store: @compiled_content_store)
57
+ end
58
+
59
+ def start
60
+ super
61
+ @worker_pool.start
62
+ end
63
+
64
+ def stop
65
+ super
66
+ @queue.close
67
+ @worker_pool.join
68
+ end
69
+
70
+ contract Nanoc::Core::ItemRep, C::KeywordArgs[is_outdated: C::Bool], C::Func[C::None => C::Any] => C::Any
71
+ def run(rep, is_outdated:) # rubocop:disable Lint/UnusedMethodArgument
72
+ yield
73
+
74
+ # Caution: Notification must be posted before enqueueing the rep,
75
+ # or we risk a race condition where the :rep_write_ended
76
+ # notification happens before the :rep_write_enqueued one.
77
+ Nanoc::Core::NotificationCenter.post(:rep_write_enqueued, rep)
78
+
79
+ @queue << rep
80
+ end
81
+ end
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Nanoc
4
+ module Core
5
+ module CompilationStages
6
+ class BuildReps < Nanoc::Core::CompilationStage
7
+ include Nanoc::Core::ContractsSupport
8
+
9
+ contract C::KeywordArgs[site: Nanoc::Core::Site, action_provider: Nanoc::Core::ActionProvider] => C::Any
10
+ def initialize(site:, action_provider:)
11
+ @site = site
12
+ @action_provider = action_provider
13
+ end
14
+
15
+ def run
16
+ reps = Nanoc::Core::ItemRepRepo.new
17
+
18
+ builder = Nanoc::Core::ItemRepBuilder.new(
19
+ @site, @action_provider, reps
20
+ )
21
+
22
+ action_sequences = builder.run
23
+
24
+ @site.layouts.each do |layout|
25
+ action_sequences[layout] = @action_provider.action_sequence_for(layout)
26
+ end
27
+
28
+ {
29
+ reps: reps,
30
+ action_sequences: action_sequences,
31
+ }
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Nanoc
4
+ module Core
5
+ module CompilationStages
6
+ class CalculateChecksums < Nanoc::Core::CompilationStage
7
+ def initialize(items:, layouts:, code_snippets:, config:)
8
+ @items = items
9
+ @layouts = layouts
10
+ @code_snippets = code_snippets
11
+ @config = config
12
+ end
13
+
14
+ def run
15
+ checksums = {}
16
+
17
+ [@items, @layouts].each do |documents|
18
+ documents.each do |document|
19
+ checksums[[document.reference, :content]] =
20
+ Nanoc::Core::Checksummer.calc_for_content_of(document)
21
+ checksums[[document.reference, :each_attribute]] =
22
+ Nanoc::Core::Checksummer.calc_for_each_attribute_of(document)
23
+ end
24
+ end
25
+
26
+ [@items, @layouts, @code_snippets].each do |objs|
27
+ objs.each do |obj|
28
+ checksums[obj.reference] = Nanoc::Core::Checksummer.calc(obj)
29
+ end
30
+ end
31
+
32
+ checksums[@config.reference] =
33
+ Nanoc::Core::Checksummer.calc(@config)
34
+ checksums[[@config.reference, :each_attribute]] =
35
+ Nanoc::Core::Checksummer.calc_for_each_attribute_of(@config)
36
+
37
+ Nanoc::Core::ChecksumCollection.new(checksums)
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Nanoc
4
+ module Core
5
+ module CompilationStages
6
+ class Cleanup < Nanoc::Core::CompilationStage
7
+ def initialize(output_dirs)
8
+ @output_dirs = output_dirs
9
+ end
10
+
11
+ def run
12
+ cleanup_temps(Nanoc::Core::Filter::TMP_BINARY_ITEMS_DIR)
13
+ cleanup_temps(Nanoc::Core::ItemRepWriter::TMP_TEXT_ITEMS_DIR)
14
+ cleanup_unused_stores
15
+ cleanup_old_stores
16
+ end
17
+
18
+ private
19
+
20
+ def cleanup_temps(dir)
21
+ Nanoc::Core::TempFilenameFactory.instance.cleanup(dir)
22
+ end
23
+
24
+ def cleanup_unused_stores
25
+ used_paths = @output_dirs.map { |d| Nanoc::Core::Store.tmp_path_prefix(d) }
26
+ all_paths = Dir.glob('tmp/nanoc/*')
27
+ (all_paths - used_paths).each do |obsolete_path|
28
+ FileUtils.rm_rf(obsolete_path)
29
+ end
30
+ end
31
+
32
+ def cleanup_old_stores
33
+ %w[checksums compiled_content dependencies outdatedness action_sequence].each do |fn|
34
+ full_fn = File.join('tmp', fn)
35
+ if File.file?(full_fn)
36
+ FileUtils.rm_f(full_fn)
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,96 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Nanoc
4
+ module Core
5
+ module CompilationStages
6
+ class CompileReps < Nanoc::Core::CompilationStage
7
+ include Nanoc::Core::ContractsSupport
8
+ include Nanoc::Core::Assertions::Mixin
9
+
10
+ def initialize(reps:, outdatedness_store:, dependency_store:, action_sequences:, compilation_context:, compiled_content_cache:)
11
+ @reps = reps
12
+ @outdatedness_store = outdatedness_store
13
+ @dependency_store = dependency_store
14
+ @action_sequences = action_sequences
15
+ @compilation_context = compilation_context
16
+ @compiled_content_cache = compiled_content_cache
17
+ end
18
+
19
+ def run
20
+ outdated_reps = @reps.select { |r| @outdatedness_store.include?(r) }
21
+ selector = Nanoc::Core::ItemRepSelector.new(outdated_reps)
22
+ run_phase_stack do |phase_stack|
23
+ selector.each do |rep|
24
+ handle_errors_while(rep) do
25
+ compile_rep(rep, phase_stack: phase_stack, is_outdated: @outdatedness_store.include?(rep))
26
+ end
27
+ end
28
+ end
29
+
30
+ assert Nanoc::Core::Assertions::AllItemRepsHaveCompiledContent.new(
31
+ compiled_content_cache: @compiled_content_cache,
32
+ item_reps: @reps,
33
+ )
34
+ ensure
35
+ @outdatedness_store.store
36
+ @compiled_content_cache.prune(items: @reps.map(&:item).uniq)
37
+ @compiled_content_cache.store
38
+ end
39
+
40
+ private
41
+
42
+ def handle_errors_while(item_rep)
43
+ yield
44
+ rescue Exception => e # rubocop:disable Lint/RescueException
45
+ raise Nanoc::Core::Errors::CompilationError.new(e, item_rep)
46
+ end
47
+
48
+ def compile_rep(rep, phase_stack:, is_outdated:)
49
+ phase_stack.call(rep, is_outdated: is_outdated)
50
+ end
51
+
52
+ def run_phase_stack
53
+ phase_stack = build_phase_stack
54
+ phase_stack.start
55
+ yield(phase_stack)
56
+ ensure
57
+ phase_stack.stop
58
+ end
59
+
60
+ def build_phase_stack
61
+ recalculate_phase = Nanoc::Core::CompilationPhases::Recalculate.new(
62
+ action_sequences: @action_sequences,
63
+ dependency_store: @dependency_store,
64
+ compilation_context: @compilation_context,
65
+ )
66
+
67
+ cache_phase = Nanoc::Core::CompilationPhases::Cache.new(
68
+ compiled_content_cache: @compiled_content_cache,
69
+ compiled_content_store: @compilation_context.compiled_content_store,
70
+ wrapped: recalculate_phase,
71
+ )
72
+
73
+ resume_phase = Nanoc::Core::CompilationPhases::Resume.new(
74
+ wrapped: cache_phase,
75
+ )
76
+
77
+ write_phase = Nanoc::Core::CompilationPhases::Write.new(
78
+ compiled_content_store: @compilation_context.compiled_content_store,
79
+ wrapped: resume_phase,
80
+ )
81
+
82
+ mark_done_phase = Nanoc::Core::CompilationPhases::MarkDone.new(
83
+ wrapped: write_phase,
84
+ outdatedness_store: @outdatedness_store,
85
+ )
86
+
87
+ notify_phrase = Nanoc::Core::CompilationPhases::Notify.new(
88
+ wrapped: mark_done_phase,
89
+ )
90
+
91
+ notify_phrase
92
+ end
93
+ end
94
+ end
95
+ end
96
+ end