nanoc-core 4.11.12 → 4.11.17

Sign up to get free protection for your applications and to get access to all the features.
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