nanoc-core 4.11.12 → 4.11.13

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.
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