nanoc-core 4.11.12 → 4.11.17

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 (78) 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/changes_stream.rb +55 -0
  7. data/lib/nanoc/core/checksum_store.rb +1 -1
  8. data/lib/nanoc/core/checksummer.rb +4 -2
  9. data/lib/nanoc/core/compilation_item_rep_collection_view.rb +12 -0
  10. data/lib/nanoc/core/compilation_item_rep_view.rb +57 -0
  11. data/lib/nanoc/core/compilation_item_view.rb +47 -0
  12. data/lib/nanoc/core/compilation_phases/abstract.rb +48 -0
  13. data/lib/nanoc/core/compilation_phases/cache.rb +43 -0
  14. data/lib/nanoc/core/compilation_phases/mark_done.rb +23 -0
  15. data/lib/nanoc/core/compilation_phases/notify.rb +19 -0
  16. data/lib/nanoc/core/compilation_phases/recalculate.rb +49 -0
  17. data/lib/nanoc/core/compilation_phases/resume.rb +52 -0
  18. data/lib/nanoc/core/compilation_phases/write.rb +84 -0
  19. data/lib/nanoc/core/compilation_stages/build_reps.rb +36 -0
  20. data/lib/nanoc/core/compilation_stages/calculate_checksums.rb +42 -0
  21. data/lib/nanoc/core/compilation_stages/cleanup.rb +43 -0
  22. data/lib/nanoc/core/compilation_stages/compile_reps.rb +96 -0
  23. data/lib/nanoc/core/compilation_stages/determine_outdatedness.rb +49 -0
  24. data/lib/nanoc/core/compilation_stages/forget_outdated_dependencies.rb +20 -0
  25. data/lib/nanoc/core/compilation_stages/load_stores.rb +35 -0
  26. data/lib/nanoc/core/compilation_stages/postprocess.rb +21 -0
  27. data/lib/nanoc/core/compilation_stages/preprocess.rb +32 -0
  28. data/lib/nanoc/core/compilation_stages/prune.rb +30 -0
  29. data/lib/nanoc/core/compilation_stages/store_post_compilation_state.rb +20 -0
  30. data/lib/nanoc/core/compilation_stages/store_pre_compilation_state.rb +32 -0
  31. data/lib/nanoc/core/compiled_content_cache.rb +2 -2
  32. data/lib/nanoc/core/compiler.rb +214 -0
  33. data/lib/nanoc/core/compiler_loader.rb +48 -0
  34. data/lib/nanoc/core/config_loader.rb +95 -0
  35. data/lib/nanoc/core/config_view.rb +67 -0
  36. data/lib/nanoc/core/configuration.rb +2 -4
  37. data/lib/nanoc/core/contracts_support.rb +20 -0
  38. data/lib/nanoc/core/dependency_store.rb +3 -3
  39. data/lib/nanoc/core/document_view_mixin.rb +87 -0
  40. data/lib/nanoc/core/errors.rb +108 -0
  41. data/lib/nanoc/core/executor.rb +134 -0
  42. data/lib/nanoc/core/feature.rb +92 -0
  43. data/lib/nanoc/core/filter.rb +269 -0
  44. data/lib/nanoc/core/identifiable_collection_view.rb +111 -0
  45. data/lib/nanoc/core/item_collection_with_reps_view.rb +12 -0
  46. data/lib/nanoc/core/item_collection_without_reps_view.rb +12 -0
  47. data/lib/nanoc/core/item_rep_builder.rb +54 -0
  48. data/lib/nanoc/core/item_rep_selector.rb +67 -0
  49. data/lib/nanoc/core/item_rep_writer.rb +85 -0
  50. data/lib/nanoc/core/layout_collection_view.rb +12 -0
  51. data/lib/nanoc/core/layout_view.rb +9 -0
  52. data/lib/nanoc/core/mutable_config_view.rb +16 -0
  53. data/lib/nanoc/core/mutable_document_view_mixin.rb +60 -0
  54. data/lib/nanoc/core/mutable_identifiable_collection_view.rb +19 -0
  55. data/lib/nanoc/core/mutable_item_collection_view.rb +34 -0
  56. data/lib/nanoc/core/mutable_item_view.rb +9 -0
  57. data/lib/nanoc/core/mutable_layout_collection_view.rb +26 -0
  58. data/lib/nanoc/core/mutable_layout_view.rb +9 -0
  59. data/lib/nanoc/core/outdatedness_checker.rb +222 -0
  60. data/lib/nanoc/core/outdatedness_rules/attributes_modified.rb +41 -0
  61. data/lib/nanoc/core/outdatedness_rules/code_snippets_modified.rb +31 -0
  62. data/lib/nanoc/core/outdatedness_rules/content_modified.rb +21 -0
  63. data/lib/nanoc/core/outdatedness_rules/item_collection_extended.rb +20 -0
  64. data/lib/nanoc/core/outdatedness_rules/layout_collection_extended.rb +20 -0
  65. data/lib/nanoc/core/outdatedness_rules/not_written.rb +17 -0
  66. data/lib/nanoc/core/outdatedness_rules/rules_modified.rb +45 -0
  67. data/lib/nanoc/core/outdatedness_rules/uses_always_outdated_filter.rb +26 -0
  68. data/lib/nanoc/core/post_compile_item_collection_view.rb +12 -0
  69. data/lib/nanoc/core/post_compile_item_rep_collection_view.rb +12 -0
  70. data/lib/nanoc/core/post_compile_item_rep_view.rb +33 -0
  71. data/lib/nanoc/core/post_compile_item_view.rb +20 -0
  72. data/lib/nanoc/core/pruner.rb +123 -0
  73. data/lib/nanoc/core/site_loader.rb +102 -0
  74. data/lib/nanoc/core/trivial_error.rb +10 -0
  75. data/lib/nanoc/core/version.rb +1 -1
  76. data/lib/nanoc/core/view.rb +43 -0
  77. data/lib/nanoc/core/view_context_for_compilation.rb +6 -6
  78. metadata +97 -3
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Nanoc
4
+ module Core
5
+ class CompilationItemView < ::Nanoc::Core::BasicItemView
6
+ # Returns the compiled content.
7
+ #
8
+ # @param [String] rep The name of the representation
9
+ # from which the compiled content should be fetched. By default, the
10
+ # compiled content will be fetched from the default representation.
11
+ #
12
+ # @param [String] snapshot The name of the snapshot from which to
13
+ # fetch the compiled content. By default, the returned compiled content
14
+ # will be the content compiled right before the first layout call (if
15
+ # any).
16
+ #
17
+ # @return [String] The content of the given rep at the given snapshot.
18
+ def compiled_content(rep: :default, snapshot: nil)
19
+ reps.fetch(rep).compiled_content(snapshot: snapshot)
20
+ end
21
+
22
+ # Returns the item path, as used when being linked to. It starts
23
+ # with a slash and it is relative to the output directory. It does not
24
+ # include the path to the output directory. It will not include the
25
+ # filename if the filename is an index filename.
26
+ #
27
+ # @param [String] rep The name of the representation
28
+ # from which the path should be fetched. By default, the path will be
29
+ # fetched from the default representation.
30
+ #
31
+ # @param [Symbol] snapshot The snapshot for which the
32
+ # path should be returned.
33
+ #
34
+ # @return [String] The item’s path.
35
+ def path(rep: :default, snapshot: :last)
36
+ reps.fetch(rep).path(snapshot: snapshot)
37
+ end
38
+
39
+ # Returns the representations of this item.
40
+ #
41
+ # @return [Nanoc::Core::BasicItemRepCollectionView]
42
+ def reps
43
+ Nanoc::Core::CompilationItemRepCollectionView.new(@context.reps[_unwrap], @context)
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Nanoc
4
+ module Core
5
+ module CompilationPhases
6
+ class Abstract
7
+ include Nanoc::Core::ContractsSupport
8
+
9
+ def initialize(wrapped:)
10
+ @wrapped = wrapped
11
+ end
12
+
13
+ def start
14
+ @wrapped&.start
15
+ end
16
+
17
+ def stop
18
+ @wrapped&.stop
19
+ end
20
+
21
+ def call(rep, is_outdated:)
22
+ notify(:phase_started, rep)
23
+ run(rep, is_outdated: is_outdated) do
24
+ notify(:phase_yielded, rep)
25
+ @wrapped.call(rep, is_outdated: is_outdated)
26
+ notify(:phase_resumed, rep)
27
+ end
28
+ notify(:phase_ended, rep)
29
+ rescue
30
+ notify(:phase_aborted, rep)
31
+ raise
32
+ end
33
+
34
+ contract Nanoc::Core::ItemRep, C::KeywordArgs[is_outdated: C::Bool], C::Func[C::None => C::Any] => C::Any
35
+ def run(_rep, is_outdated:)
36
+ raise NotImplementedError
37
+ end
38
+
39
+ private
40
+
41
+ def notify(sym, rep)
42
+ name = self.class.to_s.sub(/^.*::/, '')
43
+ Nanoc::Core::NotificationCenter.post(sym, name, rep)
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
@@ -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
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