nanoc 4.11.8 → 4.11.9
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.
- checksums.yaml +4 -4
- data/NEWS.md +8 -0
- data/lib/nanoc.rb +4 -1
- data/lib/nanoc/base.rb +0 -1
- data/lib/nanoc/base/errors.rb +4 -49
- data/lib/nanoc/base/repos.rb +0 -15
- data/lib/nanoc/base/repos/site_loader.rb +1 -1
- data/lib/nanoc/base/services.rb +0 -2
- data/lib/nanoc/base/services/compiler.rb +1 -1
- data/lib/nanoc/base/services/compiler/phases/recalculate.rb +1 -1
- data/lib/nanoc/base/services/compiler/stages/build_reps.rb +1 -1
- data/lib/nanoc/base/services/compiler/stages/cleanup.rb +1 -1
- data/lib/nanoc/base/services/compiler/stages/load_stores.rb +1 -1
- data/lib/nanoc/base/services/compiler_loader.rb +6 -6
- data/lib/nanoc/base/services/outdatedness_checker.rb +10 -10
- data/lib/nanoc/base/services/outdatedness_rules/attributes_modified.rb +4 -4
- data/lib/nanoc/base/services/outdatedness_rules/code_snippets_modified.rb +2 -2
- data/lib/nanoc/base/services/outdatedness_rules/content_modified.rb +2 -2
- data/lib/nanoc/base/services/outdatedness_rules/item_collection_extended.rb +3 -3
- data/lib/nanoc/base/services/outdatedness_rules/layout_collection_extended.rb +3 -3
- data/lib/nanoc/base/services/outdatedness_rules/not_written.rb +2 -2
- data/lib/nanoc/base/services/outdatedness_rules/rules_modified.rb +3 -3
- data/lib/nanoc/base/services/outdatedness_rules/uses_always_outdated_filter.rb +2 -2
- data/lib/nanoc/base/services/pruner.rb +1 -1
- data/lib/nanoc/base/views/view_context_for_compilation.rb +1 -1
- data/lib/nanoc/base/views/view_context_for_pre_compilation.rb +1 -1
- data/lib/nanoc/base/views/view_context_for_shell.rb +2 -2
- data/lib/nanoc/checking/check.rb +17 -1
- data/lib/nanoc/cli/commands/shell.rb +1 -1
- data/lib/nanoc/cli/error_handler.rb +1 -1
- data/lib/nanoc/filters/handlebars.rb +2 -2
- data/lib/nanoc/filters/sass/importer.rb +3 -2
- data/lib/nanoc/rule_dsl/action_provider.rb +1 -1
- data/lib/nanoc/spec.rb +4 -4
- data/lib/nanoc/version.rb +1 -1
- metadata +5 -21
- data/lib/nanoc/base/entities.rb +0 -7
- data/lib/nanoc/base/entities/outdatedness_reasons.rb +0 -88
- data/lib/nanoc/base/entities/outdatedness_status.rb +0 -27
- data/lib/nanoc/base/repos/action_sequence_store.rb +0 -50
- data/lib/nanoc/base/repos/binary_compiled_content_cache.rb +0 -128
- data/lib/nanoc/base/repos/checksum_store.rb +0 -74
- data/lib/nanoc/base/repos/compiled_content_cache.rb +0 -68
- data/lib/nanoc/base/repos/compiled_content_store.rb +0 -77
- data/lib/nanoc/base/repos/dependency_store.rb +0 -204
- data/lib/nanoc/base/repos/item_rep_repo.rb +0 -37
- data/lib/nanoc/base/repos/outdatedness_store.rb +0 -55
- data/lib/nanoc/base/repos/prefixed_data_source.rb +0 -31
- data/lib/nanoc/base/repos/store.rb +0 -114
- data/lib/nanoc/base/repos/textual_compiled_content_cache.rb +0 -82
- data/lib/nanoc/base/services/dependency_tracker.rb +0 -63
- data/lib/nanoc/base/services/outdatedness_rule.rb +0 -34
@@ -1,128 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Nanoc
|
4
|
-
module Int
|
5
|
-
# Represents a cache than can be used to store already compiled content,
|
6
|
-
# to prevent it from being needlessly recompiled.
|
7
|
-
#
|
8
|
-
# @api private
|
9
|
-
class BinaryCompiledContentCache < ::Nanoc::Int::Store
|
10
|
-
include Nanoc::Core::ContractsSupport
|
11
|
-
|
12
|
-
contract C::KeywordArgs[config: Nanoc::Core::Configuration] => C::Any
|
13
|
-
def initialize(config:)
|
14
|
-
super(Nanoc::Int::Store.tmp_path_for(config: config, store_name: 'binary_content'), 1)
|
15
|
-
|
16
|
-
@cache = {}
|
17
|
-
end
|
18
|
-
|
19
|
-
contract Nanoc::Core::ItemRep => C::Maybe[C::HashOf[Symbol => Nanoc::Core::Content]]
|
20
|
-
# Returns the cached compiled content for the given item representation.
|
21
|
-
#
|
22
|
-
# This cached compiled content is a hash where the keys are the snapshot
|
23
|
-
# names, and the values the compiled content at the given snapshot.
|
24
|
-
def [](rep)
|
25
|
-
item_cache = @cache[rep.item.identifier] || {}
|
26
|
-
|
27
|
-
rep_cache = item_cache[rep.name]
|
28
|
-
return nil if rep_cache.nil?
|
29
|
-
|
30
|
-
rep_cache.transform_values do |filename|
|
31
|
-
Nanoc::Core::Content.create(filename, binary: true)
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
|
-
contract Nanoc::Core::ItemRep => C::Bool
|
36
|
-
def include?(rep)
|
37
|
-
item_cache = @cache[rep.item.identifier] || {}
|
38
|
-
item_cache.key?(rep.name)
|
39
|
-
end
|
40
|
-
|
41
|
-
contract Nanoc::Core::ItemRep, C::HashOf[Symbol => Nanoc::Core::BinaryContent] => C::HashOf[Symbol => Nanoc::Core::Content]
|
42
|
-
# Sets the compiled content for the given representation.
|
43
|
-
#
|
44
|
-
# This cached compiled content is a hash where the keys are the snapshot
|
45
|
-
# names, and the values the compiled content at the given snapshot.
|
46
|
-
def []=(rep, content)
|
47
|
-
@cache[rep.item.identifier] ||= {}
|
48
|
-
@cache[rep.item.identifier][rep.name] ||= {}
|
49
|
-
rep_cache = @cache[rep.item.identifier][rep.name]
|
50
|
-
|
51
|
-
content.each do |snapshot, binary_content|
|
52
|
-
filename = build_filename(rep, snapshot)
|
53
|
-
rep_cache[snapshot] = filename
|
54
|
-
|
55
|
-
# Avoid reassigning the same content if this binary cached content was
|
56
|
-
# already used, because it was available and the item wasn’t oudated.
|
57
|
-
next if binary_content.filename == filename
|
58
|
-
|
59
|
-
# Copy
|
60
|
-
#
|
61
|
-
# NOTE: hardlinking is not an option in this case, because hardlinking
|
62
|
-
# would make it possible for the content to be (inadvertently)
|
63
|
-
# changed outside of Nanoc.
|
64
|
-
FileUtils.mkdir_p(File.dirname(filename))
|
65
|
-
FileUtils.cp(binary_content.filename, filename)
|
66
|
-
end
|
67
|
-
end
|
68
|
-
|
69
|
-
def prune(items:)
|
70
|
-
item_identifiers = Set.new(items.map(&:identifier))
|
71
|
-
|
72
|
-
@cache.each_key do |key|
|
73
|
-
# TODO: remove unused item reps
|
74
|
-
next if item_identifiers.include?(key)
|
75
|
-
|
76
|
-
@cache.delete(key)
|
77
|
-
path = dirname_for_item_identifier(key)
|
78
|
-
FileUtils.rm_rf(path)
|
79
|
-
end
|
80
|
-
end
|
81
|
-
|
82
|
-
def data
|
83
|
-
@cache
|
84
|
-
end
|
85
|
-
|
86
|
-
def data=(new_data)
|
87
|
-
@cache = {}
|
88
|
-
|
89
|
-
new_data.each_pair do |item_identifier, content_per_rep|
|
90
|
-
@cache[item_identifier] ||= content_per_rep
|
91
|
-
end
|
92
|
-
end
|
93
|
-
|
94
|
-
private
|
95
|
-
|
96
|
-
def dirname
|
97
|
-
filename + '_data'
|
98
|
-
end
|
99
|
-
|
100
|
-
def string_to_path_component(string)
|
101
|
-
string.gsub(/[^a-zA-Z0-9]+/, '_') +
|
102
|
-
'-' +
|
103
|
-
Digest::SHA1.hexdigest(string)[0..9]
|
104
|
-
end
|
105
|
-
|
106
|
-
def dirname_for_item_identifier(item_identifier)
|
107
|
-
File.join(
|
108
|
-
dirname,
|
109
|
-
string_to_path_component(item_identifier.to_s),
|
110
|
-
)
|
111
|
-
end
|
112
|
-
|
113
|
-
def dirname_for_item_rep(rep)
|
114
|
-
File.join(
|
115
|
-
dirname_for_item_identifier(rep.item.identifier),
|
116
|
-
string_to_path_component(rep.name.to_s),
|
117
|
-
)
|
118
|
-
end
|
119
|
-
|
120
|
-
def build_filename(rep, snapshot_name)
|
121
|
-
File.join(
|
122
|
-
dirname_for_item_rep(rep),
|
123
|
-
string_to_path_component(snapshot_name.to_s),
|
124
|
-
)
|
125
|
-
end
|
126
|
-
end
|
127
|
-
end
|
128
|
-
end
|
@@ -1,74 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Nanoc
|
4
|
-
module Int
|
5
|
-
# Stores checksums for objects in order to be able to detect whether a file
|
6
|
-
# has changed since the last site compilation.
|
7
|
-
#
|
8
|
-
# @api private
|
9
|
-
class ChecksumStore < ::Nanoc::Int::Store
|
10
|
-
include Nanoc::Core::ContractsSupport
|
11
|
-
|
12
|
-
attr_writer :checksums
|
13
|
-
attr_accessor :objects
|
14
|
-
|
15
|
-
c_obj = C::Or[Nanoc::Core::Item, Nanoc::Core::Layout, Nanoc::Core::Configuration, Nanoc::Core::CodeSnippet]
|
16
|
-
|
17
|
-
contract C::KeywordArgs[config: Nanoc::Core::Configuration, objects: C::IterOf[c_obj]] => C::Any
|
18
|
-
def initialize(config:, objects:)
|
19
|
-
super(Nanoc::Int::Store.tmp_path_for(config: config, store_name: 'checksums'), 2)
|
20
|
-
|
21
|
-
@objects = objects
|
22
|
-
|
23
|
-
@checksums = {}
|
24
|
-
end
|
25
|
-
|
26
|
-
contract c_obj => C::Maybe[String]
|
27
|
-
def [](obj)
|
28
|
-
@checksums[obj.reference]
|
29
|
-
end
|
30
|
-
|
31
|
-
contract c_obj => self
|
32
|
-
def add(obj)
|
33
|
-
if obj.is_a?(Nanoc::Core::Document)
|
34
|
-
@checksums[[obj.reference, :content]] = Nanoc::Core::Checksummer.calc_for_content_of(obj)
|
35
|
-
end
|
36
|
-
|
37
|
-
if obj.is_a?(Nanoc::Core::Document) || obj.is_a?(Nanoc::Core::Configuration)
|
38
|
-
@checksums[[obj.reference, :each_attribute]] = Nanoc::Core::Checksummer.calc_for_each_attribute_of(obj)
|
39
|
-
end
|
40
|
-
|
41
|
-
@checksums[obj.reference] = Nanoc::Core::Checksummer.calc(obj)
|
42
|
-
|
43
|
-
self
|
44
|
-
end
|
45
|
-
|
46
|
-
contract c_obj => C::Maybe[String]
|
47
|
-
def content_checksum_for(obj)
|
48
|
-
@checksums[[obj.reference, :content]]
|
49
|
-
end
|
50
|
-
|
51
|
-
contract c_obj => C::Maybe[C::HashOf[Symbol, String]]
|
52
|
-
def attributes_checksum_for(obj)
|
53
|
-
@checksums[[obj.reference, :each_attribute]]
|
54
|
-
end
|
55
|
-
|
56
|
-
protected
|
57
|
-
|
58
|
-
def data
|
59
|
-
@checksums
|
60
|
-
end
|
61
|
-
|
62
|
-
def data=(new_data)
|
63
|
-
references = Set.new(@objects.map(&:reference))
|
64
|
-
|
65
|
-
@checksums = {}
|
66
|
-
new_data.each_pair do |key, checksum|
|
67
|
-
if references.include?(key) || references.include?(key.first)
|
68
|
-
@checksums[key] = checksum
|
69
|
-
end
|
70
|
-
end
|
71
|
-
end
|
72
|
-
end
|
73
|
-
end
|
74
|
-
end
|
@@ -1,68 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Nanoc
|
4
|
-
module Int
|
5
|
-
# Represents a cache than can be used to store already compiled content,
|
6
|
-
# to prevent it from being needlessly recompiled.
|
7
|
-
#
|
8
|
-
# @api private
|
9
|
-
class CompiledContentCache < ::Nanoc::Int::Store
|
10
|
-
include Nanoc::Core::ContractsSupport
|
11
|
-
|
12
|
-
contract C::KeywordArgs[config: Nanoc::Core::Configuration] => C::Any
|
13
|
-
def initialize(config:)
|
14
|
-
@textual_cache = Nanoc::Int::TextualCompiledContentCache.new(config: config)
|
15
|
-
@binary_cache = Nanoc::Int::BinaryCompiledContentCache.new(config: config)
|
16
|
-
|
17
|
-
@wrapped_caches = [@textual_cache, @binary_cache]
|
18
|
-
end
|
19
|
-
|
20
|
-
contract Nanoc::Core::ItemRep => C::Maybe[C::HashOf[Symbol => Nanoc::Core::Content]]
|
21
|
-
# Returns the cached compiled content for the given item representation.
|
22
|
-
#
|
23
|
-
# This cached compiled content is a hash where the keys are the snapshot
|
24
|
-
# names. and the values the compiled content at the given snapshot.
|
25
|
-
def [](rep)
|
26
|
-
textual_content_map = @textual_cache[rep]
|
27
|
-
binary_content_map = @binary_cache[rep]
|
28
|
-
|
29
|
-
# If either the textual or the binary content cache is nil, assume the
|
30
|
-
# cache is entirely absent.
|
31
|
-
#
|
32
|
-
# This is necessary to support the case where only textual content is
|
33
|
-
# cached (which was the case in older versions of Nanoc).
|
34
|
-
return nil if [textual_content_map, binary_content_map].any?(&:nil?)
|
35
|
-
|
36
|
-
textual_content_map.merge(binary_content_map)
|
37
|
-
end
|
38
|
-
|
39
|
-
contract Nanoc::Core::ItemRep, C::HashOf[Symbol => Nanoc::Core::Content] => C::Any
|
40
|
-
# Sets the compiled content for the given representation.
|
41
|
-
#
|
42
|
-
# This cached compiled content is a hash where the keys are the snapshot
|
43
|
-
# names and the values the compiled content at the given snapshot.
|
44
|
-
def []=(rep, content)
|
45
|
-
@textual_cache[rep] = content.select { |_key, c| c.textual? }
|
46
|
-
@binary_cache[rep] = content.select { |_key, c| c.binary? }
|
47
|
-
end
|
48
|
-
|
49
|
-
def prune(*args)
|
50
|
-
@wrapped_caches.each { |w| w.prune(*args) }
|
51
|
-
end
|
52
|
-
|
53
|
-
# True if there is cached compiled content available for this item, and
|
54
|
-
# all entries are present (either textual or binary).
|
55
|
-
def full_cache_available?(rep)
|
56
|
-
@textual_cache.include?(rep) && @binary_cache.include?(rep)
|
57
|
-
end
|
58
|
-
|
59
|
-
def load(*args)
|
60
|
-
@wrapped_caches.each { |w| w.load(*args) }
|
61
|
-
end
|
62
|
-
|
63
|
-
def store(*args)
|
64
|
-
@wrapped_caches.each { |w| w.store(*args) }
|
65
|
-
end
|
66
|
-
end
|
67
|
-
end
|
68
|
-
end
|
@@ -1,77 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Nanoc
|
4
|
-
module Int
|
5
|
-
# @api private
|
6
|
-
class CompiledContentStore
|
7
|
-
include Nanoc::Core::ContractsSupport
|
8
|
-
|
9
|
-
def initialize
|
10
|
-
@contents = Hash.new { |hash, rep| hash[rep] = {} }
|
11
|
-
@current_content = {}
|
12
|
-
end
|
13
|
-
|
14
|
-
contract Nanoc::Core::ItemRep, Symbol => C::Maybe[Nanoc::Core::Content]
|
15
|
-
def get(rep, snapshot_name)
|
16
|
-
@contents[rep][snapshot_name]
|
17
|
-
end
|
18
|
-
|
19
|
-
contract Nanoc::Core::ItemRep => C::Maybe[Nanoc::Core::Content]
|
20
|
-
def get_current(rep)
|
21
|
-
@current_content[rep]
|
22
|
-
end
|
23
|
-
|
24
|
-
contract Nanoc::Core::ItemRep, Symbol, Nanoc::Core::Content => C::Any
|
25
|
-
def set(rep, snapshot_name, contents)
|
26
|
-
@contents[rep][snapshot_name] = contents
|
27
|
-
end
|
28
|
-
|
29
|
-
contract Nanoc::Core::ItemRep, Nanoc::Core::Content => C::Any
|
30
|
-
def set_current(rep, content)
|
31
|
-
@current_content[rep] = content
|
32
|
-
end
|
33
|
-
|
34
|
-
contract Nanoc::Core::ItemRep => C::HashOf[Symbol => Nanoc::Core::Content]
|
35
|
-
def get_all(rep)
|
36
|
-
@contents[rep]
|
37
|
-
end
|
38
|
-
|
39
|
-
contract Nanoc::Core::ItemRep, C::HashOf[Symbol => Nanoc::Core::Content] => C::Any
|
40
|
-
def set_all(rep, contents_per_snapshot)
|
41
|
-
@contents[rep] = contents_per_snapshot
|
42
|
-
end
|
43
|
-
|
44
|
-
contract C::KeywordArgs[rep: Nanoc::Core::ItemRep, snapshot: C::Optional[C::Maybe[Symbol]]] => Nanoc::Core::Content
|
45
|
-
def raw_compiled_content(rep:, snapshot: nil)
|
46
|
-
# Get name of last pre-layout snapshot
|
47
|
-
has_pre = rep.snapshot_defs.any? { |sd| sd.name == :pre }
|
48
|
-
snapshot_name = snapshot || (has_pre ? :pre : :last)
|
49
|
-
|
50
|
-
# Check existance of snapshot
|
51
|
-
snapshot_def = rep.snapshot_defs.reverse.find { |sd| sd.name == snapshot_name }
|
52
|
-
unless snapshot_def
|
53
|
-
raise Nanoc::Int::Errors::NoSuchSnapshot.new(rep, snapshot_name)
|
54
|
-
end
|
55
|
-
|
56
|
-
# Return content if it is available
|
57
|
-
content = get(rep, snapshot_name)
|
58
|
-
return content if content
|
59
|
-
|
60
|
-
# Content is unavailable; notify and try again
|
61
|
-
Fiber.yield(Nanoc::Int::Errors::UnmetDependency.new(rep, snapshot_name))
|
62
|
-
get(rep, snapshot_name)
|
63
|
-
end
|
64
|
-
|
65
|
-
contract C::KeywordArgs[rep: Nanoc::Core::ItemRep, snapshot: C::Optional[C::Maybe[Symbol]]] => String
|
66
|
-
def compiled_content(rep:, snapshot: nil)
|
67
|
-
snapshot_content = raw_compiled_content(rep: rep, snapshot: snapshot)
|
68
|
-
|
69
|
-
if snapshot_content.binary?
|
70
|
-
raise Nanoc::Int::Errors::CannotGetCompiledContentOfBinaryItem.new(rep)
|
71
|
-
end
|
72
|
-
|
73
|
-
snapshot_content.string
|
74
|
-
end
|
75
|
-
end
|
76
|
-
end
|
77
|
-
end
|
@@ -1,204 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Nanoc
|
4
|
-
module Int
|
5
|
-
# @api private
|
6
|
-
class DependencyStore < ::Nanoc::Int::Store
|
7
|
-
include Nanoc::Core::ContractsSupport
|
8
|
-
|
9
|
-
attr_reader :items
|
10
|
-
attr_reader :layouts
|
11
|
-
|
12
|
-
contract Nanoc::Core::ItemCollection, Nanoc::Core::LayoutCollection, Nanoc::Core::Configuration => C::Any
|
13
|
-
def initialize(items, layouts, config)
|
14
|
-
super(Nanoc::Int::Store.tmp_path_for(config: config, store_name: 'dependencies'), 5)
|
15
|
-
|
16
|
-
@items = items
|
17
|
-
@layouts = layouts
|
18
|
-
|
19
|
-
@refs2objs = {}
|
20
|
-
items.each { |o| add_vertex_for(o) }
|
21
|
-
layouts.each { |o| add_vertex_for(o) }
|
22
|
-
add_vertex_for(config)
|
23
|
-
add_vertex_for(items)
|
24
|
-
add_vertex_for(layouts)
|
25
|
-
|
26
|
-
@new_objects = []
|
27
|
-
@graph = Nanoc::Core::DirectedGraph.new([nil] + objs2refs(@items) + objs2refs(@layouts))
|
28
|
-
end
|
29
|
-
|
30
|
-
C_OBJ_SRC = Nanoc::Core::Item
|
31
|
-
C_OBJ_DST = C::Or[Nanoc::Core::Item, Nanoc::Core::Layout, Nanoc::Core::Configuration, Nanoc::Core::IdentifiableCollection]
|
32
|
-
|
33
|
-
contract C_OBJ_SRC => C::ArrayOf[Nanoc::Core::Dependency]
|
34
|
-
def dependencies_causing_outdatedness_of(object)
|
35
|
-
objects_causing_outdatedness_of(object).map do |other_object|
|
36
|
-
props = props_for(other_object, object)
|
37
|
-
|
38
|
-
Nanoc::Core::Dependency.new(
|
39
|
-
other_object,
|
40
|
-
object,
|
41
|
-
Nanoc::Core::DependencyProps.new(
|
42
|
-
raw_content: props.fetch(:raw_content, false),
|
43
|
-
attributes: props.fetch(:attributes, false),
|
44
|
-
compiled_content: props.fetch(:compiled_content, false),
|
45
|
-
path: props.fetch(:path, false),
|
46
|
-
),
|
47
|
-
)
|
48
|
-
end
|
49
|
-
end
|
50
|
-
|
51
|
-
def items=(items)
|
52
|
-
@items = items
|
53
|
-
items.each { |o| @refs2objs[obj2ref(o)] = o }
|
54
|
-
add_vertex_for(items)
|
55
|
-
end
|
56
|
-
|
57
|
-
def layouts=(layouts)
|
58
|
-
@layouts = layouts
|
59
|
-
layouts.each { |o| @refs2objs[obj2ref(o)] = o }
|
60
|
-
add_vertex_for(layouts)
|
61
|
-
end
|
62
|
-
|
63
|
-
def new_items
|
64
|
-
@new_objects.select { |o| o.is_a?(Nanoc::Core::Item) }
|
65
|
-
end
|
66
|
-
|
67
|
-
def new_layouts
|
68
|
-
@new_objects.select { |o| o.is_a?(Nanoc::Core::Layout) }
|
69
|
-
end
|
70
|
-
|
71
|
-
# Returns the direct dependencies for the given object.
|
72
|
-
#
|
73
|
-
# The direct dependencies of the given object include the items and
|
74
|
-
# layouts that, when outdated will cause the given object to be marked as
|
75
|
-
# outdated. Indirect dependencies will not be returned (e.g. if A depends
|
76
|
-
# on B which depends on C, then the direct dependencies of A do not
|
77
|
-
# include C).
|
78
|
-
#
|
79
|
-
# The direct predecessors can include nil, which indicates an item that is
|
80
|
-
# no longer present in the site.
|
81
|
-
#
|
82
|
-
# @param [Nanoc::Core::Item, Nanoc::Core::Layout] object The object for
|
83
|
-
# which to fetch the direct predecessors
|
84
|
-
#
|
85
|
-
# @return [Array<Nanoc::Core::Item, Nanoc::Core::Layout, nil>] The direct
|
86
|
-
# predecessors of
|
87
|
-
# the given object
|
88
|
-
def objects_causing_outdatedness_of(object)
|
89
|
-
refs2objs(@graph.direct_predecessors_of(obj2ref(object)))
|
90
|
-
end
|
91
|
-
|
92
|
-
C_RAW_CONTENT = C::Or[C::IterOf[C::Or[String, Regexp]], C::Bool]
|
93
|
-
C_ATTR = C::Or[C::IterOf[Symbol], C::Bool]
|
94
|
-
C_KEYWORD_PROPS = C::KeywordArgs[raw_content: C::Optional[C_RAW_CONTENT], attributes: C::Optional[C_ATTR], compiled_content: C::Optional[C::Bool], path: C::Optional[C::Bool]]
|
95
|
-
|
96
|
-
contract C::Maybe[C_OBJ_SRC], C::Maybe[C_OBJ_DST], C_KEYWORD_PROPS => C::Any
|
97
|
-
# Records a dependency from `src` to `dst` in the dependency graph. When
|
98
|
-
# `dst` is oudated, `src` will also become outdated.
|
99
|
-
#
|
100
|
-
# @param [Nanoc::Core::Item, Nanoc::Core::Layout] src The source of the dependency,
|
101
|
-
# i.e. the object that will become outdated if dst is outdated
|
102
|
-
#
|
103
|
-
# @param [Nanoc::Core::Item, Nanoc::Core::Layout] dst The destination of the
|
104
|
-
# dependency, i.e. the object that will cause the source to become
|
105
|
-
# outdated if the destination is outdated
|
106
|
-
#
|
107
|
-
# @return [void]
|
108
|
-
def record_dependency(src, dst, raw_content: false, attributes: false, compiled_content: false, path: false)
|
109
|
-
return if src == dst
|
110
|
-
|
111
|
-
add_vertex_for(src)
|
112
|
-
add_vertex_for(dst)
|
113
|
-
|
114
|
-
src_ref = obj2ref(src)
|
115
|
-
dst_ref = obj2ref(dst)
|
116
|
-
|
117
|
-
existing_props = Nanoc::Core::DependencyProps.new(@graph.props_for(dst_ref, src_ref) || {})
|
118
|
-
new_props = Nanoc::Core::DependencyProps.new(raw_content: raw_content, attributes: attributes, compiled_content: compiled_content, path: path)
|
119
|
-
props = existing_props.merge(new_props)
|
120
|
-
|
121
|
-
@graph.add_edge(dst_ref, src_ref, props: props.to_h)
|
122
|
-
end
|
123
|
-
|
124
|
-
def add_vertex_for(obj)
|
125
|
-
@refs2objs[obj2ref(obj)] = obj
|
126
|
-
end
|
127
|
-
|
128
|
-
# Empties the list of dependencies for the given object. This is necessary
|
129
|
-
# before recompiling the given object, because otherwise old dependencies
|
130
|
-
# will stick around and new dependencies will appear twice. This function
|
131
|
-
# removes all incoming edges for the given vertex.
|
132
|
-
#
|
133
|
-
# @param [Nanoc::Core::Item, Nanoc::Core::Layout] object The object for which to
|
134
|
-
# forget all dependencies
|
135
|
-
#
|
136
|
-
# @return [void]
|
137
|
-
def forget_dependencies_for(object)
|
138
|
-
@graph.delete_edges_to(obj2ref(object))
|
139
|
-
end
|
140
|
-
|
141
|
-
protected
|
142
|
-
|
143
|
-
def obj2ref(obj)
|
144
|
-
obj&.reference
|
145
|
-
end
|
146
|
-
|
147
|
-
def ref2obj(reference)
|
148
|
-
if reference
|
149
|
-
@refs2objs[reference]
|
150
|
-
else
|
151
|
-
nil
|
152
|
-
end
|
153
|
-
end
|
154
|
-
|
155
|
-
def objs2refs(objs)
|
156
|
-
objs.map { |o| obj2ref(o) }
|
157
|
-
end
|
158
|
-
|
159
|
-
def refs2objs(refs)
|
160
|
-
refs.map { |r| ref2obj(r) }
|
161
|
-
end
|
162
|
-
|
163
|
-
def props_for(from, to)
|
164
|
-
props = @graph.props_for(obj2ref(from), obj2ref(to)) || {}
|
165
|
-
|
166
|
-
if props.values.any? { |v| v }
|
167
|
-
props
|
168
|
-
else
|
169
|
-
{ raw_content: true, attributes: true, compiled_content: true, path: true }
|
170
|
-
end
|
171
|
-
end
|
172
|
-
|
173
|
-
def data
|
174
|
-
{
|
175
|
-
edges: @graph.edges,
|
176
|
-
vertices: @graph.vertices,
|
177
|
-
}
|
178
|
-
end
|
179
|
-
|
180
|
-
def data=(new_data)
|
181
|
-
objects = Set.new(@items.to_a + @layouts.to_a)
|
182
|
-
refs = objs2refs(objects)
|
183
|
-
|
184
|
-
# Create new graph
|
185
|
-
@graph = Nanoc::Core::DirectedGraph.new([nil] + refs)
|
186
|
-
|
187
|
-
# Load vertices
|
188
|
-
previous_refs = new_data[:vertices]
|
189
|
-
previous_objects = Set.new(refs2objs(previous_refs))
|
190
|
-
|
191
|
-
# Load edges
|
192
|
-
new_data[:edges].each do |edge|
|
193
|
-
from_index, to_index, props = *edge
|
194
|
-
from = from_index && previous_refs[from_index]
|
195
|
-
to = to_index && previous_refs[to_index]
|
196
|
-
@graph.add_edge(from, to, props: props)
|
197
|
-
end
|
198
|
-
|
199
|
-
# Record dependency from all items on new items
|
200
|
-
@new_objects = objects - previous_objects
|
201
|
-
end
|
202
|
-
end
|
203
|
-
end
|
204
|
-
end
|