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.
- checksums.yaml +4 -4
- data/lib/nanoc/core.rb +37 -0
- data/lib/nanoc/core/basic_item_rep_collection_view.rb +88 -0
- data/lib/nanoc/core/basic_item_rep_view.rb +83 -0
- data/lib/nanoc/core/basic_item_view.rb +54 -0
- data/lib/nanoc/core/changes_stream.rb +55 -0
- data/lib/nanoc/core/checksum_store.rb +1 -1
- data/lib/nanoc/core/checksummer.rb +4 -2
- data/lib/nanoc/core/compilation_item_rep_collection_view.rb +12 -0
- data/lib/nanoc/core/compilation_item_rep_view.rb +57 -0
- data/lib/nanoc/core/compilation_item_view.rb +47 -0
- data/lib/nanoc/core/compilation_phases/abstract.rb +48 -0
- data/lib/nanoc/core/compilation_phases/cache.rb +43 -0
- data/lib/nanoc/core/compilation_phases/mark_done.rb +23 -0
- data/lib/nanoc/core/compilation_phases/notify.rb +19 -0
- data/lib/nanoc/core/compilation_phases/recalculate.rb +49 -0
- data/lib/nanoc/core/compilation_phases/resume.rb +52 -0
- data/lib/nanoc/core/compilation_phases/write.rb +84 -0
- data/lib/nanoc/core/compilation_stages/build_reps.rb +36 -0
- data/lib/nanoc/core/compilation_stages/calculate_checksums.rb +42 -0
- data/lib/nanoc/core/compilation_stages/cleanup.rb +43 -0
- data/lib/nanoc/core/compilation_stages/compile_reps.rb +96 -0
- data/lib/nanoc/core/compilation_stages/determine_outdatedness.rb +49 -0
- data/lib/nanoc/core/compilation_stages/forget_outdated_dependencies.rb +20 -0
- data/lib/nanoc/core/compilation_stages/load_stores.rb +35 -0
- data/lib/nanoc/core/compilation_stages/postprocess.rb +21 -0
- data/lib/nanoc/core/compilation_stages/preprocess.rb +32 -0
- data/lib/nanoc/core/compilation_stages/prune.rb +30 -0
- data/lib/nanoc/core/compilation_stages/store_post_compilation_state.rb +20 -0
- data/lib/nanoc/core/compilation_stages/store_pre_compilation_state.rb +32 -0
- data/lib/nanoc/core/compiled_content_cache.rb +2 -2
- data/lib/nanoc/core/compiler.rb +214 -0
- data/lib/nanoc/core/compiler_loader.rb +48 -0
- data/lib/nanoc/core/config_loader.rb +95 -0
- data/lib/nanoc/core/config_view.rb +67 -0
- data/lib/nanoc/core/configuration.rb +2 -4
- data/lib/nanoc/core/contracts_support.rb +20 -0
- data/lib/nanoc/core/dependency_store.rb +3 -3
- data/lib/nanoc/core/document_view_mixin.rb +87 -0
- data/lib/nanoc/core/errors.rb +108 -0
- data/lib/nanoc/core/executor.rb +134 -0
- data/lib/nanoc/core/feature.rb +92 -0
- data/lib/nanoc/core/filter.rb +269 -0
- data/lib/nanoc/core/identifiable_collection_view.rb +111 -0
- data/lib/nanoc/core/item_collection_with_reps_view.rb +12 -0
- data/lib/nanoc/core/item_collection_without_reps_view.rb +12 -0
- data/lib/nanoc/core/item_rep_builder.rb +54 -0
- data/lib/nanoc/core/item_rep_selector.rb +67 -0
- data/lib/nanoc/core/item_rep_writer.rb +85 -0
- data/lib/nanoc/core/layout_collection_view.rb +12 -0
- data/lib/nanoc/core/layout_view.rb +9 -0
- data/lib/nanoc/core/mutable_config_view.rb +16 -0
- data/lib/nanoc/core/mutable_document_view_mixin.rb +60 -0
- data/lib/nanoc/core/mutable_identifiable_collection_view.rb +19 -0
- data/lib/nanoc/core/mutable_item_collection_view.rb +34 -0
- data/lib/nanoc/core/mutable_item_view.rb +9 -0
- data/lib/nanoc/core/mutable_layout_collection_view.rb +26 -0
- data/lib/nanoc/core/mutable_layout_view.rb +9 -0
- data/lib/nanoc/core/outdatedness_checker.rb +222 -0
- data/lib/nanoc/core/outdatedness_rules/attributes_modified.rb +41 -0
- data/lib/nanoc/core/outdatedness_rules/code_snippets_modified.rb +31 -0
- data/lib/nanoc/core/outdatedness_rules/content_modified.rb +21 -0
- data/lib/nanoc/core/outdatedness_rules/item_collection_extended.rb +20 -0
- data/lib/nanoc/core/outdatedness_rules/layout_collection_extended.rb +20 -0
- data/lib/nanoc/core/outdatedness_rules/not_written.rb +17 -0
- data/lib/nanoc/core/outdatedness_rules/rules_modified.rb +45 -0
- data/lib/nanoc/core/outdatedness_rules/uses_always_outdated_filter.rb +26 -0
- data/lib/nanoc/core/post_compile_item_collection_view.rb +12 -0
- data/lib/nanoc/core/post_compile_item_rep_collection_view.rb +12 -0
- data/lib/nanoc/core/post_compile_item_rep_view.rb +33 -0
- data/lib/nanoc/core/post_compile_item_view.rb +20 -0
- data/lib/nanoc/core/pruner.rb +123 -0
- data/lib/nanoc/core/site_loader.rb +102 -0
- data/lib/nanoc/core/trivial_error.rb +10 -0
- data/lib/nanoc/core/version.rb +1 -1
- data/lib/nanoc/core/view.rb +43 -0
- data/lib/nanoc/core/view_context_for_compilation.rb +6 -6
- metadata +97 -3
@@ -0,0 +1,111 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Nanoc
|
4
|
+
module Core
|
5
|
+
class IdentifiableCollectionView < ::Nanoc::Core::View
|
6
|
+
include Enumerable
|
7
|
+
|
8
|
+
NOTHING = Object.new
|
9
|
+
|
10
|
+
# @api private
|
11
|
+
def initialize(objects, context)
|
12
|
+
super(context)
|
13
|
+
@objects = objects
|
14
|
+
end
|
15
|
+
|
16
|
+
# @api private
|
17
|
+
def _unwrap
|
18
|
+
@objects
|
19
|
+
end
|
20
|
+
|
21
|
+
# @abstract
|
22
|
+
#
|
23
|
+
# @api private
|
24
|
+
def view_class
|
25
|
+
raise NotImplementedError
|
26
|
+
end
|
27
|
+
|
28
|
+
# Calls the given block once for each object, passing that object as a parameter.
|
29
|
+
#
|
30
|
+
# @yieldparam [#identifier] object
|
31
|
+
#
|
32
|
+
# @yieldreturn [void]
|
33
|
+
#
|
34
|
+
# @return [self]
|
35
|
+
def each
|
36
|
+
@context.dependency_tracker.bounce(_unwrap, raw_content: true)
|
37
|
+
@objects.each { |i| yield view_class.new(i, @context) }
|
38
|
+
self
|
39
|
+
end
|
40
|
+
|
41
|
+
# @return [Integer]
|
42
|
+
def size
|
43
|
+
@context.dependency_tracker.bounce(_unwrap, raw_content: true)
|
44
|
+
@objects.size
|
45
|
+
end
|
46
|
+
|
47
|
+
# Finds all objects whose identifier matches the given argument.
|
48
|
+
#
|
49
|
+
# @param [String, Regex] arg
|
50
|
+
#
|
51
|
+
# @return [Enumerable]
|
52
|
+
def find_all(arg = NOTHING, &block)
|
53
|
+
if NOTHING.equal?(arg)
|
54
|
+
@context.dependency_tracker.bounce(_unwrap, raw_content: true)
|
55
|
+
return @objects.map { |i| view_class.new(i, @context) }.select(&block)
|
56
|
+
end
|
57
|
+
|
58
|
+
prop_attribute =
|
59
|
+
case arg
|
60
|
+
when String, Nanoc::Core::Identifier
|
61
|
+
[arg.to_s]
|
62
|
+
when Regexp
|
63
|
+
[arg]
|
64
|
+
else
|
65
|
+
true
|
66
|
+
end
|
67
|
+
|
68
|
+
@context.dependency_tracker.bounce(_unwrap, raw_content: prop_attribute)
|
69
|
+
@objects.find_all(arg).map { |i| view_class.new(i, @context) }
|
70
|
+
end
|
71
|
+
|
72
|
+
# @overload [](string)
|
73
|
+
#
|
74
|
+
# Finds the object whose identifier matches the given string.
|
75
|
+
#
|
76
|
+
# If the glob syntax is enabled, the string can be a glob, in which case
|
77
|
+
# this method finds the first object that matches the given glob.
|
78
|
+
#
|
79
|
+
# @param [String] string
|
80
|
+
#
|
81
|
+
# @return [nil] if no object matches the string
|
82
|
+
#
|
83
|
+
# @return [#identifier] if an object was found
|
84
|
+
#
|
85
|
+
# @overload [](regex)
|
86
|
+
#
|
87
|
+
# Finds the object whose identifier matches the given regular expression.
|
88
|
+
#
|
89
|
+
# @param [Regex] regex
|
90
|
+
#
|
91
|
+
# @return [nil] if no object matches the regex
|
92
|
+
#
|
93
|
+
# @return [#identifier] if an object was found
|
94
|
+
def [](arg)
|
95
|
+
prop_attribute =
|
96
|
+
case arg
|
97
|
+
when String, Nanoc::Core::Identifier
|
98
|
+
[arg.to_s]
|
99
|
+
when Regexp
|
100
|
+
[arg]
|
101
|
+
else
|
102
|
+
true
|
103
|
+
end
|
104
|
+
|
105
|
+
@context.dependency_tracker.bounce(_unwrap, raw_content: prop_attribute)
|
106
|
+
res = @objects[arg]
|
107
|
+
res && view_class.new(res, @context)
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Nanoc
|
4
|
+
module Core
|
5
|
+
# @api private
|
6
|
+
class ItemRepBuilder
|
7
|
+
include Nanoc::Core::ContractsSupport
|
8
|
+
|
9
|
+
attr_reader :reps
|
10
|
+
|
11
|
+
contract Nanoc::Core::Site, Nanoc::Core::ActionProvider, Nanoc::Core::ItemRepRepo => C::Any
|
12
|
+
def initialize(site, action_provider, reps)
|
13
|
+
@site = site
|
14
|
+
@action_provider = action_provider
|
15
|
+
@reps = reps
|
16
|
+
end
|
17
|
+
|
18
|
+
def run
|
19
|
+
@site.items.each do |item|
|
20
|
+
@action_provider.rep_names_for(item).each do |rep_name|
|
21
|
+
@reps << Nanoc::Core::ItemRep.new(item, rep_name)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
action_sequences = Nanoc::Core::ItemRepRouter.new(@reps, @action_provider, @site).run
|
26
|
+
|
27
|
+
@reps.each do |rep|
|
28
|
+
rep.snapshot_defs = self.class.snapshot_defs_for(action_sequences[rep])
|
29
|
+
end
|
30
|
+
|
31
|
+
action_sequences
|
32
|
+
end
|
33
|
+
|
34
|
+
contract Nanoc::Core::ActionSequence => C::ArrayOf[Nanoc::Core::SnapshotDef]
|
35
|
+
def self.snapshot_defs_for(action_sequence)
|
36
|
+
is_binary = action_sequence.item_rep.item.content.binary?
|
37
|
+
snapshot_defs = []
|
38
|
+
|
39
|
+
action_sequence.each do |action|
|
40
|
+
case action
|
41
|
+
when Nanoc::Core::ProcessingActions::Snapshot
|
42
|
+
action.snapshot_names.each do |snapshot_name|
|
43
|
+
snapshot_defs << Nanoc::Core::SnapshotDef.new(snapshot_name, binary: is_binary)
|
44
|
+
end
|
45
|
+
when Nanoc::Core::ProcessingActions::Filter
|
46
|
+
is_binary = Nanoc::Core::Filter.named!(action.filter_name).to_binary?
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
snapshot_defs
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Nanoc
|
4
|
+
module Core
|
5
|
+
# Yields item reps to compile.
|
6
|
+
class ItemRepSelector
|
7
|
+
def initialize(reps)
|
8
|
+
@reps = reps
|
9
|
+
end
|
10
|
+
|
11
|
+
class MicroGraph
|
12
|
+
def initialize(reps)
|
13
|
+
@reps = Set.new(reps)
|
14
|
+
@stack = []
|
15
|
+
end
|
16
|
+
|
17
|
+
def next
|
18
|
+
if @stack.any?
|
19
|
+
@stack.last
|
20
|
+
elsif @reps.any?
|
21
|
+
@reps.each { |rep| break rep }.tap do |rep|
|
22
|
+
@reps.delete(rep)
|
23
|
+
@stack.push(rep)
|
24
|
+
end
|
25
|
+
else
|
26
|
+
nil
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def mark_ok
|
31
|
+
@stack.pop
|
32
|
+
end
|
33
|
+
|
34
|
+
def mark_failed(dep)
|
35
|
+
if @stack.include?(dep)
|
36
|
+
raise Nanoc::Core::Errors::DependencyCycle.new(@stack + [dep])
|
37
|
+
end
|
38
|
+
|
39
|
+
@reps.delete(dep)
|
40
|
+
@stack.push(dep)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def each
|
45
|
+
mg = MicroGraph.new(@reps)
|
46
|
+
|
47
|
+
loop do
|
48
|
+
rep = mg.next
|
49
|
+
break if rep.nil?
|
50
|
+
|
51
|
+
begin
|
52
|
+
yield(rep)
|
53
|
+
mg.mark_ok
|
54
|
+
rescue => e
|
55
|
+
actual_error = e.is_a?(Nanoc::Core::Errors::CompilationError) ? e.unwrap : e
|
56
|
+
|
57
|
+
if actual_error.is_a?(Nanoc::Core::Errors::UnmetDependency)
|
58
|
+
mg.mark_failed(actual_error.rep)
|
59
|
+
else
|
60
|
+
raise(e)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Nanoc
|
4
|
+
module Core
|
5
|
+
class ItemRepWriter
|
6
|
+
include Nanoc::Core::ContractsSupport
|
7
|
+
include Nanoc::Core::Assertions::Mixin
|
8
|
+
|
9
|
+
TMP_TEXT_ITEMS_DIR = 'text_items'
|
10
|
+
|
11
|
+
def write_all(item_rep, compiled_content_store)
|
12
|
+
written_paths = Set.new
|
13
|
+
|
14
|
+
item_rep.snapshot_defs.map(&:name).each do |snapshot_name|
|
15
|
+
write(item_rep, compiled_content_store, snapshot_name, written_paths)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def write(item_rep, compiled_content_store, snapshot_name, written_paths)
|
20
|
+
item_rep.raw_paths.fetch(snapshot_name, []).each do |raw_path|
|
21
|
+
write_single(item_rep, compiled_content_store, snapshot_name, raw_path, written_paths)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def write_single(item_rep, compiled_content_store, snapshot_name, raw_path, written_paths)
|
26
|
+
assert Nanoc::Core::Assertions::PathIsAbsolute.new(path: raw_path)
|
27
|
+
|
28
|
+
# Don’t write twice
|
29
|
+
# TODO: test written_paths behavior
|
30
|
+
return if written_paths.include?(raw_path)
|
31
|
+
|
32
|
+
written_paths << raw_path
|
33
|
+
|
34
|
+
# Create parent directory
|
35
|
+
FileUtils.mkdir_p(File.dirname(raw_path))
|
36
|
+
|
37
|
+
# Check if file will be created
|
38
|
+
is_created = !File.file?(raw_path)
|
39
|
+
|
40
|
+
# Notify
|
41
|
+
Nanoc::Core::NotificationCenter.post(
|
42
|
+
:rep_write_started, item_rep, raw_path
|
43
|
+
)
|
44
|
+
|
45
|
+
content = compiled_content_store.get(item_rep, snapshot_name)
|
46
|
+
if content.binary?
|
47
|
+
temp_path = content.filename
|
48
|
+
else
|
49
|
+
temp_path = temp_filename
|
50
|
+
File.write(temp_path, content.string)
|
51
|
+
end
|
52
|
+
|
53
|
+
# Check whether content was modified
|
54
|
+
is_modified = is_created || !FileUtils.identical?(raw_path, temp_path)
|
55
|
+
|
56
|
+
# Notify ready for diff generation
|
57
|
+
if !is_created && is_modified && !content.binary?
|
58
|
+
Nanoc::Core::NotificationCenter.post(
|
59
|
+
:rep_ready_for_diff, raw_path, File.read(raw_path, encoding: 'UTF-8'), content.string
|
60
|
+
)
|
61
|
+
end
|
62
|
+
|
63
|
+
# Write
|
64
|
+
if is_modified
|
65
|
+
begin
|
66
|
+
FileUtils.ln(temp_path, raw_path, force: true)
|
67
|
+
rescue Errno::EXDEV, Errno::EACCES
|
68
|
+
FileUtils.cp(temp_path, raw_path)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
item_rep.modified = is_modified
|
73
|
+
|
74
|
+
# Notify
|
75
|
+
Nanoc::Core::NotificationCenter.post(
|
76
|
+
:rep_write_ended, item_rep, content.binary?, raw_path, is_created, is_modified
|
77
|
+
)
|
78
|
+
end
|
79
|
+
|
80
|
+
def temp_filename
|
81
|
+
Nanoc::Core::TempFilenameFactory.instance.create(TMP_TEXT_ITEMS_DIR)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Nanoc
|
4
|
+
module Core
|
5
|
+
class MutableConfigView < Nanoc::Core::ConfigView
|
6
|
+
# Sets the value for the given attribute.
|
7
|
+
#
|
8
|
+
# @param [Symbol] key
|
9
|
+
#
|
10
|
+
# @see Hash#[]=
|
11
|
+
def []=(key, value)
|
12
|
+
@config[key] = value
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Nanoc
|
4
|
+
module Core
|
5
|
+
module MutableDocumentViewMixin
|
6
|
+
# @api private
|
7
|
+
class DisallowedAttributeValueError < Nanoc::Core::Error
|
8
|
+
attr_reader :value
|
9
|
+
|
10
|
+
def initialize(value)
|
11
|
+
@value = value
|
12
|
+
end
|
13
|
+
|
14
|
+
def message
|
15
|
+
"The #{value.class} cannot be stored inside an attribute. Store its identifier instead."
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def raw_content=(arg)
|
20
|
+
_unwrap.content = Nanoc::Core::Content.create(arg)
|
21
|
+
end
|
22
|
+
|
23
|
+
# Sets the value for the given attribute.
|
24
|
+
#
|
25
|
+
# @param [Symbol] key
|
26
|
+
#
|
27
|
+
# @see Hash#[]=
|
28
|
+
def []=(key, value)
|
29
|
+
disallowed_value_classes = Set.new([
|
30
|
+
Nanoc::Core::Item,
|
31
|
+
Nanoc::Core::Layout,
|
32
|
+
Nanoc::Core::CompilationItemView,
|
33
|
+
Nanoc::Core::LayoutView,
|
34
|
+
])
|
35
|
+
if disallowed_value_classes.include?(value.class)
|
36
|
+
raise DisallowedAttributeValueError.new(value)
|
37
|
+
end
|
38
|
+
|
39
|
+
_unwrap.set_attribute(key, value)
|
40
|
+
end
|
41
|
+
|
42
|
+
# Sets the identifier to the given argument.
|
43
|
+
#
|
44
|
+
# @param [String, Nanoc::Core::Identifier] arg
|
45
|
+
def identifier=(arg)
|
46
|
+
_unwrap.identifier = Nanoc::Core::Identifier.from(arg)
|
47
|
+
end
|
48
|
+
|
49
|
+
# Updates the attributes based on the given hash.
|
50
|
+
#
|
51
|
+
# @param [Hash] hash
|
52
|
+
#
|
53
|
+
# @return [self]
|
54
|
+
def update_attributes(hash)
|
55
|
+
hash.each { |k, v| _unwrap.set_attribute(k, v) }
|
56
|
+
self
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|